diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2022-02-24 01:57:18 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2022-02-24 01:57:18 +0000 |
commit | b24b5b9049e889ee4eb39b565bcc8d48bd45ab48 (patch) | |
tree | 658ca4e6b41655f49463c85edbaeda48979c394c /lib/mesa/src/vulkan/util | |
parent | 57768bbb154c2879d34ec20e401b19472e77aaf7 (diff) |
Import Mesa 21.3.7
Diffstat (limited to 'lib/mesa/src/vulkan/util')
30 files changed, 4056 insertions, 63 deletions
diff --git a/lib/mesa/src/vulkan/util/meson.build b/lib/mesa/src/vulkan/util/meson.build index 1a3723990..234e7f1be 100644 --- a/lib/mesa/src/vulkan/util/meson.build +++ b/lib/mesa/src/vulkan/util/meson.build @@ -34,16 +34,32 @@ vk_entrypoints_gen_depend_files = [ files('vk_dispatch_table_gen.py'), vk_dispatch_table_gen_depend_files, ] +vk_cmd_queue_gen_depend_files = [ + files('vk_dispatch_table_gen.py'), + vk_dispatch_table_gen_depend_files, +] +vk_commands_gen_depend_files = [ + files('vk_dispatch_table_gen.py'), + vk_dispatch_table_gen_depend_files, +] +vk_physical_device_features_gen_depend_files = [ +] vk_entrypoints_gen = files('vk_entrypoints_gen.py') vk_extensions_gen = files('vk_extensions_gen.py') vk_icd_gen = files('vk_icd_gen.py') +vk_commands_gen = files('vk_commands_gen.py') files_vulkan_util = files( + 'vk_alloc.c', 'vk_alloc.h', 'vk_cmd_copy.c', + 'vk_command_buffer.c', + 'vk_command_buffer.h', 'vk_debug_report.c', 'vk_debug_report.h', + 'vk_debug_utils.c', + 'vk_debug_utils.h', 'vk_deferred_operation.c', 'vk_deferred_operation.h', 'vk_descriptors.c', @@ -51,15 +67,22 @@ files_vulkan_util = files( 'vk_device.c', 'vk_device.h', 'vk_format.c', + 'vk_image.c', + 'vk_image.h', 'vk_instance.c', 'vk_instance.h', + 'vk_log.c', + 'vk_log.h', 'vk_object.c', 'vk_object.h', 'vk_physical_device.c', 'vk_physical_device.h', + 'vk_queue.c', + 'vk_queue.h', 'vk_render_pass.c', 'vk_shader_module.c', 'vk_shader_module.h', + 'vk_synchronization2.c', 'vk_util.c', 'vk_util.h', ) @@ -89,7 +112,7 @@ vk_dispatch_table = custom_target( vk_enum_to_str = custom_target( 'vk_enum_to_str', input : ['gen_enum_to_str.py', vk_api_xml], - output : ['vk_enum_to_str.c', 'vk_enum_to_str.h'], + output : ['vk_enum_to_str.c', 'vk_enum_to_str.h', 'vk_enum_defines.h'], command : [ prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--outdir', meson.current_build_dir() @@ -107,12 +130,34 @@ vk_extensions = custom_target( depend_files : vk_extensions_gen_depend_files, ) +vk_cmd_queue = custom_target( + 'vk_cmd_queue', + input : ['vk_cmd_queue_gen.py', vk_api_xml], + output : ['vk_cmd_queue.c', 'vk_cmd_queue.h'], + command : [ + prog_python, '@INPUT0@', '--xml', '@INPUT1@', + '--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@' + ], + depend_files : vk_cmd_queue_gen_depend_files, +) + +vk_physical_device_features = custom_target( + 'vk_physical_device_features', + input : ['vk_physical_device_features.py', vk_api_xml], + output : ['vk_physical_device_features.c'], + command : [ + prog_python, '@INPUT0@', '--xml', '@INPUT1@', + '--out-c', '@OUTPUT0@' + ], + depend_files : vk_physical_device_features_gen_depend_files, +) + libvulkan_util = static_library( 'vulkan_util', [files_vulkan_util, vk_common_entrypoints, vk_dispatch_table, - vk_enum_to_str, vk_extensions], + vk_enum_to_str, vk_extensions, vk_cmd_queue, vk_physical_device_features], include_directories : [inc_include, inc_src, inc_gallium], - dependencies : [vulkan_wsi_deps, idep_mesautil], + dependencies : [vulkan_wsi_deps, idep_mesautil, idep_nir_headers], # For glsl_type_singleton link_with : libcompiler, c_args : [vulkan_wsi_args], @@ -127,7 +172,7 @@ idep_vulkan_util_headers = declare_dependency( # This is likely a bug in the Meson VS backend, as MSVC with ninja works fine. # See this discussion here: -# https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10506 +# https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10506 if get_option('backend').startswith('vs') idep_vulkan_util = declare_dependency( link_with : libvulkan_util, diff --git a/lib/mesa/src/vulkan/util/vk_alloc.c b/lib/mesa/src/vulkan/util/vk_alloc.c new file mode 100644 index 000000000..c687f92ae --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_alloc.c @@ -0,0 +1,55 @@ +/* + * Copyright 2021 Google LLC + * SPDX-License-Identifier: MIT + */ + +#include "vk_alloc.h" + +#include <stdlib.h> + +#if __STDC_VERSION__ >= 201112L && !defined(_MSC_VER) +#include <stddef.h> +#define MAX_ALIGN alignof(max_align_t) +#else +/* long double might be 128-bit, but our callers do not need that anyway(?) */ +#include <stdint.h> +#define MAX_ALIGN alignof(uint64_t) +#endif + +static VKAPI_ATTR void * VKAPI_CALL +vk_default_alloc(void *pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope) +{ + assert(MAX_ALIGN % alignment == 0); + return malloc(size); +} + +static VKAPI_ATTR void * VKAPI_CALL +vk_default_realloc(void *pUserData, + void *pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope) +{ + assert(MAX_ALIGN % alignment == 0); + return realloc(pOriginal, size); +} + +static VKAPI_ATTR void VKAPI_CALL +vk_default_free(void *pUserData, void *pMemory) +{ + free(pMemory); +} + +const VkAllocationCallbacks * +vk_default_allocator(void) +{ + static const VkAllocationCallbacks allocator = { + .pfnAllocation = vk_default_alloc, + .pfnReallocation = vk_default_realloc, + .pfnFree = vk_default_free, + }; + return &allocator; +} diff --git a/lib/mesa/src/vulkan/util/vk_cmd_copy.c b/lib/mesa/src/vulkan/util/vk_cmd_copy.c index 5c71dbb38..9fcb0c23d 100644 --- a/lib/mesa/src/vulkan/util/vk_cmd_copy.c +++ b/lib/mesa/src/vulkan/util/vk_cmd_copy.c @@ -23,15 +23,7 @@ #include "vk_common_entrypoints.h" #include "vk_device.h" - -#define STACK_ARRAY_SIZE 8 - -#define STACK_ARRAY(type, name, size) \ - type _stack_##name[STACK_ARRAY_SIZE], *const name = \ - (size) <= STACK_ARRAY_SIZE ? _stack_##name : malloc((size) * sizeof(type)) - -#define STACK_ARRAY_FINISH(name) \ - if (name != _stack_##name) free(name) +#include "vk_util.h" VKAPI_ATTR void VKAPI_CALL vk_common_CmdCopyBuffer(VkCommandBuffer commandBuffer, diff --git a/lib/mesa/src/vulkan/util/vk_cmd_queue_gen.py b/lib/mesa/src/vulkan/util/vk_cmd_queue_gen.py new file mode 100644 index 000000000..539392a31 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_cmd_queue_gen.py @@ -0,0 +1,446 @@ +# coding=utf-8 +COPYRIGHT=u""" +/* Copyright © 2015-2021 Intel Corporation + * Copyright © 2021 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +""" + +import argparse +import os +import re +from collections import namedtuple +import xml.etree.ElementTree as et + +from mako.template import Template + +# Mesa-local imports must be declared in meson variable +# '{file_without_suffix}_depend_files'. +from vk_dispatch_table_gen import get_entrypoints_from_xml, EntrypointParam + +MANUAL_COMMANDS = ['CmdPushDescriptorSetKHR', # This script doesn't know how to copy arrays in structs in arrays + 'CmdPushDescriptorSetWithTemplateKHR', # pData's size cannot be calculated from the xml + 'CmdDrawMultiEXT', # The size of the elements is specified in a stride param + 'CmdDrawMultiIndexedEXT', # The size of the elements is specified in a stride param + 'CmdBindDescriptorSets', # The VkPipelineLayout object could be released before the command is executed + ] + +TEMPLATE_H = Template(COPYRIGHT + """\ +/* This file generated from ${filename}, don't edit directly. */ + +#pragma once + +#include "util/list.h" + +#define VK_PROTOTYPES +#include <vulkan/vulkan.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_cmd_queue { + VkAllocationCallbacks *alloc; + struct list_head cmds; +}; + +enum vk_cmd_type { +% for c in commands: +% if c.guard is not None: +#ifdef ${c.guard} +% endif + ${to_enum_name(c.name)}, +% if c.guard is not None: +#endif // ${c.guard} +% endif +% endfor +}; + +extern const char *vk_cmd_queue_type_names[]; + +% for c in commands: +% if len(c.params) <= 1: # Avoid "error C2016: C requires that a struct or union have at least one member" +<% continue %> +% endif +% if c.guard is not None: +#ifdef ${c.guard} +% endif +struct ${to_struct_name(c.name)} { +% for p in c.params[1:]: + ${to_field_decl(p.decl)}; +% endfor +}; +% if c.guard is not None: +#endif // ${c.guard} +% endif +% endfor + +struct vk_cmd_queue_entry { + struct list_head cmd_link; + enum vk_cmd_type type; + union { +% for c in commands: +% if len(c.params) <= 1: +<% continue %> +% endif +% if c.guard is not None: +#ifdef ${c.guard} +% endif + struct ${to_struct_name(c.name)} ${to_struct_field_name(c.name)}; +% if c.guard is not None: +#endif // ${c.guard} +% endif +% endfor + } u; + void *driver_data; +}; + +% for c in commands: +% if c.name in manual_commands: +<% continue %> +% endif +% if c.guard is not None: +#ifdef ${c.guard} +% endif + void vk_enqueue_${to_underscore(c.name)}(struct vk_cmd_queue *queue +% for p in c.params[1:]: + , ${p.decl} +% endfor + ); +% if c.guard is not None: +#endif // ${c.guard} +% endif + +% endfor + +void vk_free_queue(struct vk_cmd_queue *queue); + +#ifdef __cplusplus +} +#endif +""", output_encoding='utf-8') + +TEMPLATE_C = Template(COPYRIGHT + """ +/* This file generated from ${filename}, don't edit directly. */ + +#include "${header}" + +#define VK_PROTOTYPES +#include <vulkan/vulkan.h> + +#include "vk_alloc.h" + +const char *vk_cmd_queue_type_names[] = { +% for c in commands: +% if c.guard is not None: +#ifdef ${c.guard} +% endif + "${to_enum_name(c.name)}", +% if c.guard is not None: +#endif // ${c.guard} +% endif +% endfor +}; + +% for c in commands: +% if c.name in manual_commands: +<% continue %> +% endif +% if c.guard is not None: +#ifdef ${c.guard} +% endif +void vk_enqueue_${to_underscore(c.name)}(struct vk_cmd_queue *queue +% for p in c.params[1:]: +, ${p.decl} +% endfor +) +{ + struct vk_cmd_queue_entry *cmd = vk_zalloc(queue->alloc, + sizeof(*cmd), 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!cmd) + return; + + cmd->type = ${to_enum_name(c.name)}; + list_addtail(&cmd->cmd_link, &queue->cmds); + +% for p in c.params[1:]: +% if p.len: + if (${p.name}) { + ${get_array_copy(c, p)} + } +% elif '[' in p.decl: + memcpy(cmd->u.${to_struct_field_name(c.name)}.${to_field_name(p.name)}, ${p.name}, + sizeof(*${p.name}) * ${get_array_len(p)}); +% elif p.type == "void": + cmd->u.${to_struct_field_name(c.name)}.${to_field_name(p.name)} = (${remove_suffix(p.decl.replace("const", ""), p.name)}) ${p.name}; +% elif '*' in p.decl: + ${get_struct_copy("cmd->u.%s.%s" % (to_struct_field_name(c.name), to_field_name(p.name)), p.name, p.type, 'sizeof(%s)' % p.type, types)} +% else: + cmd->u.${to_struct_field_name(c.name)}.${to_field_name(p.name)} = ${p.name}; +% endif +% endfor +} +% if c.guard is not None: +#endif // ${c.guard} +% endif + +% endfor + +void +vk_free_queue(struct vk_cmd_queue *queue) +{ + struct vk_cmd_queue_entry *tmp, *cmd; + LIST_FOR_EACH_ENTRY_SAFE(cmd, tmp, &queue->cmds, cmd_link) { + switch(cmd->type) { +% for c in commands: +% if c.guard is not None: +#ifdef ${c.guard} +% endif + case ${to_enum_name(c.name)}: +% for p in c.params[1:]: +% if p.len: + vk_free(queue->alloc, (${remove_suffix(p.decl.replace("const", ""), p.name)})cmd->u.${to_struct_field_name(c.name)}.${to_field_name(p.name)}); +% elif '*' in p.decl: + ${get_struct_free(c, p, types)} +% endif +% endfor + break; +% if c.guard is not None: +#endif // ${c.guard} +% endif +% endfor + } + vk_free(queue->alloc, cmd); + } +} + +""", output_encoding='utf-8') + +def remove_prefix(text, prefix): + if text.startswith(prefix): + return text[len(prefix):] + return text + +def remove_suffix(text, suffix): + if text.endswith(suffix): + return text[:-len(suffix)] + return text + +def to_underscore(name): + return remove_prefix(re.sub('([A-Z]+)', r'_\1', name).lower(), '_') + +def to_struct_field_name(name): + return to_underscore(name).replace('cmd_', '') + +def to_field_name(name): + return remove_prefix(to_underscore(name).replace('cmd_', ''), 'p_') + +def to_field_decl(decl): + decl = decl.replace('const ', '') + [decl, name] = decl.rsplit(' ', 1) + return decl + ' ' + to_field_name(name) + +def to_enum_name(name): + return "VK_%s" % to_underscore(name).upper() + +def to_struct_name(name): + return "vk_%s" % to_underscore(name) + +def get_array_len(param): + return param.decl[param.decl.find("[") + 1:param.decl.find("]")] + +def get_array_copy(command, param): + field_name = "cmd->u.%s.%s" % (to_struct_field_name(command.name), to_field_name(param.name)) + if param.type == "void": + field_size = "1" + else: + field_size = "sizeof(*%s)" % field_name + allocation = "%s = vk_zalloc(queue->alloc, %s * %s, 8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);" % (field_name, field_size, param.len) + const_cast = remove_suffix(param.decl.replace("const", ""), param.name) + copy = "memcpy((%s)%s, %s, %s * %s);" % (const_cast, field_name, param.name, field_size, param.len) + return "%s\n %s" % (allocation, copy) + +def get_array_member_copy(struct, src_name, member): + field_name = "%s->%s" % (struct, member.name) + len_field_name = "%s->%s" % (struct, member.len) + allocation = "%s = vk_zalloc(queue->alloc, sizeof(*%s) * %s, 8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);" % (field_name, field_name, len_field_name) + const_cast = remove_suffix(member.decl.replace("const", ""), member.name) + copy = "memcpy((%s)%s, %s->%s, sizeof(*%s) * %s);" % (const_cast, field_name, src_name, member.name, field_name, len_field_name) + return "%s\n %s\n" % (allocation, copy) + +def get_pnext_member_copy(struct, src_type, member, types, level): + if not types[src_type].extended_by: + return "" + field_name = "%s->%s" % (struct, member.name) + pnext_decl = "const VkBaseInStructure *pnext = %s;" % field_name + case_stmts = "" + for type in types[src_type].extended_by: + case_stmts += """ + case %s: + %s + break; + """ % (type.enum, get_struct_copy(field_name, "pnext", type.name, "sizeof(%s)" % type.name, types, level)) + return """ + %s + if (pnext) { + switch ((int32_t)pnext->sType) { + %s + } + } + """ % (pnext_decl, case_stmts) + +def get_struct_copy(dst, src_name, src_type, size, types, level=0): + global tmp_dst_idx + global tmp_src_idx + + allocation = "%s = vk_zalloc(queue->alloc, %s, 8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);" % (dst, size) + copy = "memcpy((void*)%s, %s, %s);" % (dst, src_name, size) + + level += 1 + tmp_dst = "%s *tmp_dst%d = (void *) %s; (void) tmp_dst%d;" % (src_type, level, dst, level) + tmp_src = "%s *tmp_src%d = (void *) %s; (void) tmp_src%d;" % (src_type, level, src_name, level) + + member_copies = "" + if src_type in types: + for member in types[src_type].members: + if member.len and member.len != 'null-terminated': + member_copies += get_array_member_copy("tmp_dst%d" % level, "tmp_src%d" % level, member) + elif member.name == 'pNext': + member_copies += get_pnext_member_copy("tmp_dst%d" % level, src_type, member, types, level) + + null_assignment = "%s = NULL;" % dst + if_stmt = "if (%s) {" % src_name + return "%s\n %s\n %s\n %s\n %s \n %s } else {\n %s\n }" % (if_stmt, allocation, copy, tmp_dst, tmp_src, member_copies, null_assignment) + +def get_struct_free(command, param, types): + field_name = "cmd->u.%s.%s" % (to_struct_field_name(command.name), to_field_name(param.name)) + const_cast = remove_suffix(param.decl.replace("const", ""), param.name) + driver_data_free = "vk_free(queue->alloc, cmd->driver_data);\n" + struct_free = "vk_free(queue->alloc, (%s)%s);" % (const_cast, field_name) + member_frees = "" + if (param.type in types): + for member in types[param.type].members: + if member.len and member.len != 'null-terminated': + member_name = "cmd->u.%s.%s->%s" % (to_struct_field_name(command.name), to_field_name(param.name), member.name) + const_cast = remove_suffix(member.decl.replace("const", ""), member.name) + member_frees += "vk_free(queue->alloc, (%s)%s);\n" % (const_cast, member_name) + return "%s %s %s\n" % (member_frees, driver_data_free, struct_free) + +EntrypointType = namedtuple('EntrypointType', 'name enum members extended_by') + +def get_types(doc): + """Extract the types from the registry.""" + types = {} + + for _type in doc.findall('./types/type'): + if _type.attrib.get('category') != 'struct': + continue + members = [] + type_enum = None + for p in _type.findall('./member'): + member = EntrypointParam(type=p.find('./type').text, + name=p.find('./name').text, + decl=''.join(p.itertext()), + len=p.attrib.get('len', None)) + members.append(member) + + if p.find('./name').text == 'sType': + type_enum = p.attrib.get('values') + types[_type.attrib['name']] = EntrypointType(name=_type.attrib['name'], enum=type_enum, members=members, extended_by=[]) + + for _type in doc.findall('./types/type'): + if _type.attrib.get('category') != 'struct': + continue + if _type.attrib.get('structextends') is None: + continue + for extended in _type.attrib.get('structextends').split(','): + types[extended].extended_by.append(types[_type.attrib['name']]) + + return types + +def get_types_from_xml(xml_files): + types = {} + + for filename in xml_files: + doc = et.parse(filename) + types.update(get_types(doc)) + + return types + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--out-c', required=True, help='Output C file.') + parser.add_argument('--out-h', required=True, help='Output H file.') + parser.add_argument('--xml', + help='Vulkan API XML file.', + required=True, action='append', dest='xml_files') + args = parser.parse_args() + + commands = [] + for e in get_entrypoints_from_xml(args.xml_files): + if e.name.startswith('Cmd') and \ + not e.alias: + commands.append(e) + + types = get_types_from_xml(args.xml_files) + + assert os.path.dirname(args.out_c) == os.path.dirname(args.out_h) + + environment = { + 'header': os.path.basename(args.out_h), + 'commands': commands, + 'filename': os.path.basename(__file__), + 'to_underscore': to_underscore, + 'get_array_len': get_array_len, + 'to_struct_field_name': to_struct_field_name, + 'to_field_name': to_field_name, + 'to_field_decl': to_field_decl, + 'to_enum_name': to_enum_name, + 'to_struct_name': to_struct_name, + 'get_array_copy': get_array_copy, + 'get_struct_copy': get_struct_copy, + 'get_struct_free': get_struct_free, + 'types': types, + 'manual_commands': MANUAL_COMMANDS, + 'remove_suffix': remove_suffix, + } + + try: + with open(args.out_h, 'wb') as f: + guard = os.path.basename(args.out_h).replace('.', '_').upper() + f.write(TEMPLATE_H.render(guard=guard, **environment)) + with open(args.out_c, 'wb') as f: + f.write(TEMPLATE_C.render(**environment)) + except Exception: + # In the event there's an error, this imports some helpers from mako + # to print a useful stack trace and prints it, then exits with + # status 1, if python is run with debug; otherwise it just raises + # the exception + if __debug__: + import sys + from mako import exceptions + sys.stderr.write(exceptions.text_error_template().render() + '\n') + sys.exit(1) + raise + +if __name__ == '__main__': + main() diff --git a/lib/mesa/src/vulkan/util/vk_command_buffer.c b/lib/mesa/src/vulkan/util/vk_command_buffer.c new file mode 100644 index 000000000..35b346d1e --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_command_buffer.c @@ -0,0 +1,52 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_command_buffer.h" + +VkResult +vk_command_buffer_init(struct vk_command_buffer *command_buffer, + struct vk_device *device) +{ + memset(command_buffer, 0, sizeof(*command_buffer)); + vk_object_base_init(device, &command_buffer->base, + VK_OBJECT_TYPE_COMMAND_BUFFER); + + util_dynarray_init(&command_buffer->labels, NULL); + command_buffer->region_begin = true; + + return VK_SUCCESS; +} + +void +vk_command_buffer_reset(struct vk_command_buffer *command_buffer) +{ + util_dynarray_clear(&command_buffer->labels); + command_buffer->region_begin = true; +} + +void +vk_command_buffer_finish(struct vk_command_buffer *command_buffer) +{ + util_dynarray_fini(&command_buffer->labels); + vk_object_base_finish(&command_buffer->base); +} diff --git a/lib/mesa/src/vulkan/util/vk_command_buffer.h b/lib/mesa/src/vulkan/util/vk_command_buffer.h new file mode 100644 index 000000000..36622cfd9 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_command_buffer.h @@ -0,0 +1,95 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef VK_COMMAND_BUFFER_H +#define VK_COMMAND_BUFFER_H + +#include "vk_object.h" +#include "util/u_dynarray.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_command_buffer { + struct vk_object_base base; + + /** + * VK_EXT_debug_utils + * + * The next two fields represent debug labels storage. + * + * VK_EXT_debug_utils spec requires that upon triggering a debug message + * with a command buffer attached to it, all "active" labels will also be + * provided to the callback. The spec describes two distinct ways of + * attaching a debug label to the command buffer: opening a label region + * and inserting a single label. + * + * Label region is active between the corresponding `*BeginDebugUtilsLabel` + * and `*EndDebugUtilsLabel` calls. The spec doesn't mention any limits on + * nestedness of label regions. This implementation assumes that there + * aren't any. + * + * The spec, however, doesn't explain the lifetime of a label submitted by + * an `*InsertDebugUtilsLabel` call. The LunarG whitepaper [1] (pp 12-15) + * provides a more detailed explanation along with some examples. According + * to those, such label remains active until the next `*DebugUtilsLabel` + * call. This means that there can be no more than one such label at a + * time. + * + * \c labels contains all active labels at this point in order of submission + * \c region_begin denotes whether the most recent label opens a new region + * If \t labels is empty \t region_begin must be true. + * + * Anytime we modify labels, we first check for \c region_begin. If it's + * false, it means that the most recent label was submitted by + * `*InsertDebugUtilsLabel` and we need to remove it before doing anything + * else. + * + * See the discussion here: + * https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10318#note_1061317 + * + * [1] https://www.lunarg.com/wp-content/uploads/2018/05/Vulkan-Debug-Utils_05_18_v1.pdf + */ + struct util_dynarray labels; + bool region_begin; +}; + +VK_DEFINE_HANDLE_CASTS(vk_command_buffer, base, VkCommandBuffer, + VK_OBJECT_TYPE_COMMAND_BUFFER) + +VkResult MUST_CHECK +vk_command_buffer_init(struct vk_command_buffer *command_buffer, + struct vk_device *device); + +void +vk_command_buffer_reset(struct vk_command_buffer *command_buffer); + +void +vk_command_buffer_finish(struct vk_command_buffer *command_buffer); + +#ifdef __cplusplus +} +#endif + +#endif /* VK_COMMAND_BUFFER_H */ diff --git a/lib/mesa/src/vulkan/util/vk_commands_gen.py b/lib/mesa/src/vulkan/util/vk_commands_gen.py new file mode 100644 index 000000000..610c835ff --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_commands_gen.py @@ -0,0 +1,143 @@ +# coding=utf-8 +COPYRIGHT=u""" +/* Copyright © 2015-2021 Intel Corporation + * Copyright © 2021 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +""" + +import argparse +import os +import re +import xml.etree.ElementTree as et + +from mako.template import Template + +# Mesa-local imports must be declared in meson variable +# '{file_without_suffix}_depend_files'. +from vk_dispatch_table_gen import get_entrypoints_from_xml, EntrypointParam + +MANUAL_COMMANDS = ['CmdPushDescriptorSetKHR', # This script doesn't know how to copy arrays in structs in arrays + 'CmdPushDescriptorSetWithTemplateKHR', # pData's size cannot be calculated from the xml + 'CmdDrawMultiEXT', # The size of the elements is specified in a stride param + 'CmdDrawMultiIndexedEXT', # The size of the elements is specified in a stride param + 'CmdBindDescriptorSets', # The VkPipelineLayout object could be released before the command is executed + 'CmdCopyImageToBuffer', # There are wrappers that implement these in terms of the newer variants + 'CmdCopyImage', + 'CmdCopyBuffer', + 'CmdCopyImage', + 'CmdCopyBufferToImage', + 'CmdCopyImageToBuffer', + 'CmdBlitImage', + 'CmdResolveImage', + ] + +TEMPLATE_C = Template(COPYRIGHT + """ +/* This file generated from ${filename}, don't edit directly. */ + +#define VK_PROTOTYPES +#include <vulkan/vulkan.h> + +#include "lvp_private.h" +#include "pipe/p_context.h" +#include "vk_util.h" + +% for c in commands: +% if c.name in manual_commands: +<% continue %> +% endif +% if c.guard is not None: +#ifdef ${c.guard} +% endif +VKAPI_ATTR ${c.return_type} VKAPI_CALL lvp_${c.name} (VkCommandBuffer commandBuffer +% for p in c.params[1:]: +, ${p.decl} +% endfor +) +{ + LVP_FROM_HANDLE(lvp_cmd_buffer, cmd_buffer, commandBuffer); + + vk_enqueue_${to_underscore(c.name)}(&cmd_buffer->queue +% for p in c.params[1:]: +, ${p.name} +% endfor + ); + +% if c.return_type == 'VkResult': + return VK_SUCCESS; +% endif +} +% if c.guard is not None: +#endif // ${c.guard} +% endif +% endfor + +""", output_encoding='utf-8') + +def remove_prefix(text, prefix): + if text.startswith(prefix): + return text[len(prefix):] + return text + +def to_underscore(name): + return remove_prefix(re.sub('([A-Z]+)', r'_\1', name).lower(), '_') + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--out-c', required=True, help='Output C file.') + parser.add_argument('--xml', + help='Vulkan API XML file.', + required=True, action='append', dest='xml_files') + parser.add_argument('--prefix', + help='Prefix to use for all dispatch tables.', + action='append', default=[], dest='prefixes') + args = parser.parse_args() + + commands = [] + for e in get_entrypoints_from_xml(args.xml_files): + if e.name.startswith('Cmd') and \ + not e.alias: + commands.append(e) + + environment = { + 'commands': commands, + 'filename': os.path.basename(__file__), + 'to_underscore': to_underscore, + 'manual_commands': MANUAL_COMMANDS, + } + + try: + with open(args.out_c, 'wb') as f: + f.write(TEMPLATE_C.render(**environment)) + except Exception: + # In the event there's an error, this imports some helpers from mako + # to print a useful stack trace and prints it, then exits with + # status 1, if python is run with debug; otherwise it just raises + # the exception + if __debug__: + import sys + from mako import exceptions + sys.stderr.write(exceptions.text_error_template().render() + '\n') + sys.exit(1) + raise + +if __name__ == '__main__': + main() diff --git a/lib/mesa/src/vulkan/util/vk_debug_utils.c b/lib/mesa/src/vulkan/util/vk_debug_utils.c new file mode 100644 index 000000000..cd798af11 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_debug_utils.c @@ -0,0 +1,285 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_debug_utils.h" + +#include "vk_common_entrypoints.h" +#include "vk_command_buffer.h" +#include "vk_device.h" +#include "vk_queue.h" +#include "vk_object.h" +#include "vk_alloc.h" +#include "vk_util.h" +#include "stdarg.h" +#include "u_dynarray.h" + +void +vk_debug_message(struct vk_instance *instance, + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) +{ + mtx_lock(&instance->debug_utils.callbacks_mutex); + + list_for_each_entry(struct vk_debug_utils_messenger, messenger, + &instance->debug_utils.callbacks, link) { + if ((messenger->severity & severity) && + (messenger->type & types)) + messenger->callback(severity, types, pCallbackData, messenger->data); + } + + mtx_unlock(&instance->debug_utils.callbacks_mutex); +} + +/* This function intended to be used by the drivers to report a + * message to the special messenger, provided in the pNext chain while + * creating an instance. It's only meant to be used during + * vkCreateInstance or vkDestroyInstance calls. + */ +void +vk_debug_message_instance(struct vk_instance *instance, + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + const char *pMessageIdName, + int32_t messageIdNumber, + const char *pMessage) +{ + if (list_is_empty(&instance->debug_utils.instance_callbacks)) + return; + + const VkDebugUtilsMessengerCallbackDataEXT cbData = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT, + .pMessageIdName = pMessageIdName, + .messageIdNumber = messageIdNumber, + .pMessage = pMessage, + }; + + list_for_each_entry(struct vk_debug_utils_messenger, messenger, + &instance->debug_utils.instance_callbacks, link) { + if ((messenger->severity & severity) && + (messenger->type & types)) + messenger->callback(severity, types, &cbData, messenger->data); + } +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_CreateDebugUtilsMessengerEXT( + VkInstance _instance, + const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugUtilsMessengerEXT *pMessenger) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + + struct vk_debug_utils_messenger *messenger = + vk_alloc2(&instance->alloc, pAllocator, + sizeof(struct vk_debug_utils_messenger), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!messenger) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + if (pAllocator) + messenger->alloc = *pAllocator; + else + messenger->alloc = instance->alloc; + + vk_object_base_init(NULL, &messenger->base, + VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT); + + messenger->severity = pCreateInfo->messageSeverity; + messenger->type = pCreateInfo->messageType; + messenger->callback = pCreateInfo->pfnUserCallback; + messenger->data = pCreateInfo->pUserData; + + mtx_lock(&instance->debug_utils.callbacks_mutex); + list_addtail(&messenger->link, &instance->debug_utils.callbacks); + mtx_unlock(&instance->debug_utils.callbacks_mutex); + + *pMessenger = vk_debug_utils_messenger_to_handle(messenger); + + return VK_SUCCESS; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_SubmitDebugUtilsMessageEXT( + VkInstance _instance, + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + + vk_debug_message(instance, messageSeverity, messageTypes, pCallbackData); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_DestroyDebugUtilsMessengerEXT( + VkInstance _instance, + VkDebugUtilsMessengerEXT _messenger, + const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + VK_FROM_HANDLE(vk_debug_utils_messenger, messenger, _messenger); + + if (messenger == NULL) + return; + + mtx_lock(&instance->debug_utils.callbacks_mutex); + list_del(&messenger->link); + mtx_unlock(&instance->debug_utils.callbacks_mutex); + + vk_object_base_finish(&messenger->base); + vk_free2(&instance->alloc, pAllocator, messenger); +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_SetDebugUtilsObjectNameEXT( + VkDevice _device, + const VkDebugUtilsObjectNameInfoEXT *pNameInfo) +{ + VK_FROM_HANDLE(vk_device, device, _device); + struct vk_object_base *object = + vk_object_base_from_u64_handle(pNameInfo->objectHandle, + pNameInfo->objectType); + + if (object->object_name) { + vk_free(&device->alloc, object->object_name); + object->object_name = NULL; + } + object->object_name = vk_strdup(&device->alloc, pNameInfo->pObjectName, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!object->object_name) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_SetDebugUtilsObjectTagEXT( + VkDevice _device, + const VkDebugUtilsObjectTagInfoEXT *pTagInfo) +{ + /* no-op */ + return VK_SUCCESS; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdBeginDebugUtilsLabelEXT( + VkCommandBuffer _commandBuffer, + const VkDebugUtilsLabelEXT *pLabelInfo) +{ + VK_FROM_HANDLE(vk_command_buffer, command_buffer, _commandBuffer); + + /* If the latest label was submitted by CmdInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!command_buffer->region_begin) + (void)util_dynarray_pop(&command_buffer->labels, VkDebugUtilsLabelEXT); + + util_dynarray_append(&command_buffer->labels, VkDebugUtilsLabelEXT, + *pLabelInfo); + command_buffer->region_begin = true; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdEndDebugUtilsLabelEXT(VkCommandBuffer _commandBuffer) +{ + VK_FROM_HANDLE(vk_command_buffer, command_buffer, _commandBuffer); + + /* If the latest label was submitted by CmdInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!command_buffer->region_begin) + (void)util_dynarray_pop(&command_buffer->labels, VkDebugUtilsLabelEXT); + + (void)util_dynarray_pop(&command_buffer->labels, VkDebugUtilsLabelEXT); + command_buffer->region_begin = true; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdInsertDebugUtilsLabelEXT( + VkCommandBuffer _commandBuffer, + const VkDebugUtilsLabelEXT *pLabelInfo) +{ + VK_FROM_HANDLE(vk_command_buffer, command_buffer, _commandBuffer); + + /* If the latest label was submitted by CmdInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!command_buffer->region_begin) + (void)util_dynarray_pop(&command_buffer->labels, VkDebugUtilsLabelEXT); + + util_dynarray_append(&command_buffer->labels, VkDebugUtilsLabelEXT, + *pLabelInfo); + command_buffer->region_begin = false; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_QueueBeginDebugUtilsLabelEXT( + VkQueue _queue, + const VkDebugUtilsLabelEXT *pLabelInfo) +{ + VK_FROM_HANDLE(vk_queue, queue, _queue); + + /* If the latest label was submitted by QueueInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!queue->region_begin) + (void)util_dynarray_pop(&queue->labels, VkDebugUtilsLabelEXT); + + util_dynarray_append(&queue->labels, VkDebugUtilsLabelEXT, *pLabelInfo); + queue->region_begin = true; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_QueueEndDebugUtilsLabelEXT(VkQueue _queue) +{ + VK_FROM_HANDLE(vk_queue, queue, _queue); + + /* If the latest label was submitted by QueueInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!queue->region_begin) + (void)util_dynarray_pop(&queue->labels, VkDebugUtilsLabelEXT); + + (void)util_dynarray_pop(&queue->labels, VkDebugUtilsLabelEXT); + queue->region_begin = true; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_QueueInsertDebugUtilsLabelEXT( + VkQueue _queue, + const VkDebugUtilsLabelEXT *pLabelInfo) +{ + VK_FROM_HANDLE(vk_queue, queue, _queue); + + /* If the latest label was submitted by QueueInsertDebugUtilsLabelEXT, we + * should remove it first. + */ + if (!queue->region_begin) + (void)util_dynarray_pop(&queue->labels, VkDebugUtilsLabelEXT); + + util_dynarray_append(&queue->labels, VkDebugUtilsLabelEXT, *pLabelInfo); + queue->region_begin = false; +} diff --git a/lib/mesa/src/vulkan/util/vk_debug_utils.h b/lib/mesa/src/vulkan/util/vk_debug_utils.h new file mode 100644 index 000000000..0ffb4b38c --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_debug_utils.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef VK_DEBUG_UTILS_H +#define VK_DEBUG_UTILS_H + +#include "vk_instance.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_debug_utils_messenger { + struct vk_object_base base; + VkAllocationCallbacks alloc; + + struct list_head link; + + VkDebugUtilsMessageSeverityFlagsEXT severity; + VkDebugUtilsMessageTypeFlagsEXT type; + PFN_vkDebugUtilsMessengerCallbackEXT callback; + void *data; +}; + +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_debug_utils_messenger, base, + VkDebugUtilsMessengerEXT, + VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT) + +void +vk_debug_message(struct vk_instance *instance, + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData); + +void +vk_debug_message_instance(struct vk_instance *instance, + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + const char *pMessageIdName, + int32_t messageIdNumber, + const char *pMessage); + +#ifdef __cplusplus +} +#endif + +#endif /* VK_DEBUG_UTILS_H */ diff --git a/lib/mesa/src/vulkan/util/vk_device.c b/lib/mesa/src/vulkan/util/vk_device.c index cfaebc58d..e3617507b 100644 --- a/lib/mesa/src/vulkan/util/vk_device.c +++ b/lib/mesa/src/vulkan/util/vk_device.c @@ -25,7 +25,10 @@ #include "vk_common_entrypoints.h" #include "vk_instance.h" +#include "vk_log.h" #include "vk_physical_device.h" +#include "vk_queue.h" +#include "vk_util.h" #include "util/hash_table.h" #include "util/ralloc.h" @@ -60,21 +63,35 @@ vk_device_init(struct vk_device *device, } if (idx >= VK_DEVICE_EXTENSION_COUNT) - return VK_ERROR_EXTENSION_NOT_PRESENT; + return vk_errorf(physical_device, VK_ERROR_EXTENSION_NOT_PRESENT, + "%s not supported", + pCreateInfo->ppEnabledExtensionNames[i]); if (!physical_device->supported_extensions.extensions[idx]) - return VK_ERROR_EXTENSION_NOT_PRESENT; + return vk_errorf(physical_device, VK_ERROR_EXTENSION_NOT_PRESENT, + "%s not supported", + pCreateInfo->ppEnabledExtensionNames[i]); #ifdef ANDROID if (!vk_android_allowed_device_extensions.extensions[idx]) - return VK_ERROR_EXTENSION_NOT_PRESENT; + return vk_errorf(physical_device, VK_ERROR_EXTENSION_NOT_PRESENT, + "%s not supported", + pCreateInfo->ppEnabledExtensionNames[i]); #endif device->enabled_extensions.extensions[idx] = true; } + VkResult result = + vk_physical_device_check_device_features(physical_device, + pCreateInfo); + if (result != VK_SUCCESS) + return result; + p_atomic_set(&device->private_data_next_index, 0); + list_inithead(&device->queues); + #ifdef ANDROID mtx_init(&device->swapchain_private_mtx, mtx_plain); device->swapchain_private = NULL; @@ -86,6 +103,9 @@ vk_device_init(struct vk_device *device, void vk_device_finish(UNUSED struct vk_device *device) { + /* Drivers should tear down their own queues */ + assert(list_is_empty(&device->queues)); + #ifdef ANDROID if (device->swapchain_private) { hash_table_foreach(device->swapchain_private, entry) @@ -147,6 +167,35 @@ vk_common_GetDeviceQueue(VkDevice _device, } VKAPI_ATTR void VKAPI_CALL +vk_common_GetDeviceQueue2(VkDevice _device, + const VkDeviceQueueInfo2 *pQueueInfo, + VkQueue *pQueue) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + struct vk_queue *queue = NULL; + vk_foreach_queue(iter, device) { + if (iter->queue_family_index == pQueueInfo->queueFamilyIndex && + iter->index_in_family == pQueueInfo->queueIndex) { + queue = iter; + break; + } + } + + /* From the Vulkan 1.1.70 spec: + * + * "The queue returned by vkGetDeviceQueue2 must have the same flags + * value from this structure as that used at device creation time in a + * VkDeviceQueueCreateInfo instance. If no matching flags were specified + * at device creation time then pQueue will return VK_NULL_HANDLE." + */ + if (queue && queue->flags == pQueueInfo->flags) + *pQueue = vk_queue_to_handle(queue); + else + *pQueue = VK_NULL_HANDLE; +} + +VKAPI_ATTR void VKAPI_CALL vk_common_GetBufferMemoryRequirements(VkDevice _device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) @@ -219,3 +268,410 @@ vk_common_BindImageMemory(VkDevice _device, return device->dispatch_table.BindImageMemory2(_device, 1, &bind); } + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetImageSparseMemoryRequirements(VkDevice _device, + VkImage image, + uint32_t *pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements *pSparseMemoryRequirements) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + VkImageSparseMemoryRequirementsInfo2 info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, + .image = image, + }; + + if (!pSparseMemoryRequirements) { + device->dispatch_table.GetImageSparseMemoryRequirements2(_device, + &info, + pSparseMemoryRequirementCount, + NULL); + return; + } + + STACK_ARRAY(VkSparseImageMemoryRequirements2, mem_reqs2, *pSparseMemoryRequirementCount); + + for (unsigned i = 0; i < *pSparseMemoryRequirementCount; ++i) { + mem_reqs2[i].sType = VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2; + mem_reqs2[i].pNext = NULL; + } + + device->dispatch_table.GetImageSparseMemoryRequirements2(_device, + &info, + pSparseMemoryRequirementCount, + mem_reqs2); + + for (unsigned i = 0; i < *pSparseMemoryRequirementCount; ++i) + pSparseMemoryRequirements[i] = mem_reqs2[i].memoryRequirements; + + STACK_ARRAY_FINISH(mem_reqs2); +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_DeviceWaitIdle(VkDevice _device) +{ + VK_FROM_HANDLE(vk_device, device, _device); + const struct vk_device_dispatch_table *disp = &device->dispatch_table; + + vk_foreach_queue(queue, device) { + VkResult result = disp->QueueWaitIdle(vk_queue_to_handle(queue)); + if (result != VK_SUCCESS) + return result; + } + + return VK_SUCCESS; +} + +static void +copy_vk_struct_guts(VkBaseOutStructure *dst, VkBaseInStructure *src, size_t struct_size) +{ + STATIC_ASSERT(sizeof(*dst) == sizeof(*src)); + memcpy(dst + 1, src + 1, struct_size - sizeof(VkBaseOutStructure)); +} + +#define CORE_FEATURE(feature) features->feature = core->feature + +bool +vk_get_physical_device_core_1_1_feature_ext(struct VkBaseOutStructure *ext, + const VkPhysicalDeviceVulkan11Features *core) +{ + + switch (ext->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: { + VkPhysicalDevice16BitStorageFeatures *features = (void *)ext; + CORE_FEATURE(storageBuffer16BitAccess); + CORE_FEATURE(uniformAndStorageBuffer16BitAccess); + CORE_FEATURE(storagePushConstant16); + CORE_FEATURE(storageInputOutput16); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: { + VkPhysicalDeviceMultiviewFeatures *features = (void *)ext; + CORE_FEATURE(multiview); + CORE_FEATURE(multiviewGeometryShader); + CORE_FEATURE(multiviewTessellationShader); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: { + VkPhysicalDeviceProtectedMemoryFeatures *features = (void *)ext; + CORE_FEATURE(protectedMemory); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: { + VkPhysicalDeviceSamplerYcbcrConversionFeatures *features = (void *) ext; + CORE_FEATURE(samplerYcbcrConversion); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: { + VkPhysicalDeviceShaderDrawParametersFeatures *features = (void *)ext; + CORE_FEATURE(shaderDrawParameters); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: { + VkPhysicalDeviceVariablePointersFeatures *features = (void *)ext; + CORE_FEATURE(variablePointersStorageBuffer); + CORE_FEATURE(variablePointers); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: + copy_vk_struct_guts(ext, (void *)core, sizeof(*core)); + return true; + + default: + return false; + } +} + +bool +vk_get_physical_device_core_1_2_feature_ext(struct VkBaseOutStructure *ext, + const VkPhysicalDeviceVulkan12Features *core) +{ + + switch (ext->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR: { + VkPhysicalDevice8BitStorageFeaturesKHR *features = (void *)ext; + CORE_FEATURE(storageBuffer8BitAccess); + CORE_FEATURE(uniformAndStorageBuffer8BitAccess); + CORE_FEATURE(storagePushConstant8); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR: { + VkPhysicalDeviceBufferDeviceAddressFeaturesKHR *features = (void *)ext; + CORE_FEATURE(bufferDeviceAddress); + CORE_FEATURE(bufferDeviceAddressCaptureReplay); + CORE_FEATURE(bufferDeviceAddressMultiDevice); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT: { + VkPhysicalDeviceDescriptorIndexingFeaturesEXT *features = (void *)ext; + CORE_FEATURE(shaderInputAttachmentArrayDynamicIndexing); + CORE_FEATURE(shaderUniformTexelBufferArrayDynamicIndexing); + CORE_FEATURE(shaderStorageTexelBufferArrayDynamicIndexing); + CORE_FEATURE(shaderUniformBufferArrayNonUniformIndexing); + CORE_FEATURE(shaderSampledImageArrayNonUniformIndexing); + CORE_FEATURE(shaderStorageBufferArrayNonUniformIndexing); + CORE_FEATURE(shaderStorageImageArrayNonUniformIndexing); + CORE_FEATURE(shaderInputAttachmentArrayNonUniformIndexing); + CORE_FEATURE(shaderUniformTexelBufferArrayNonUniformIndexing); + CORE_FEATURE(shaderStorageTexelBufferArrayNonUniformIndexing); + CORE_FEATURE(descriptorBindingUniformBufferUpdateAfterBind); + CORE_FEATURE(descriptorBindingSampledImageUpdateAfterBind); + CORE_FEATURE(descriptorBindingStorageImageUpdateAfterBind); + CORE_FEATURE(descriptorBindingStorageBufferUpdateAfterBind); + CORE_FEATURE(descriptorBindingUniformTexelBufferUpdateAfterBind); + CORE_FEATURE(descriptorBindingStorageTexelBufferUpdateAfterBind); + CORE_FEATURE(descriptorBindingUpdateUnusedWhilePending); + CORE_FEATURE(descriptorBindingPartiallyBound); + CORE_FEATURE(descriptorBindingVariableDescriptorCount); + CORE_FEATURE(runtimeDescriptorArray); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR: { + VkPhysicalDeviceFloat16Int8FeaturesKHR *features = (void *)ext; + CORE_FEATURE(shaderFloat16); + CORE_FEATURE(shaderInt8); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT: { + VkPhysicalDeviceHostQueryResetFeaturesEXT *features = (void *)ext; + CORE_FEATURE(hostQueryReset); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR: { + VkPhysicalDeviceImagelessFramebufferFeaturesKHR *features = (void *)ext; + CORE_FEATURE(imagelessFramebuffer); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT: { + VkPhysicalDeviceScalarBlockLayoutFeaturesEXT *features =(void *)ext; + CORE_FEATURE(scalarBlockLayout); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR: { + VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR *features = (void *)ext; + CORE_FEATURE(separateDepthStencilLayouts); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR: { + VkPhysicalDeviceShaderAtomicInt64FeaturesKHR *features = (void *)ext; + CORE_FEATURE(shaderBufferInt64Atomics); + CORE_FEATURE(shaderSharedInt64Atomics); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR: { + VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR *features = (void *)ext; + CORE_FEATURE(shaderSubgroupExtendedTypes); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR: { + VkPhysicalDeviceTimelineSemaphoreFeaturesKHR *features = (void *) ext; + CORE_FEATURE(timelineSemaphore); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: { + VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR *features = (void *)ext; + CORE_FEATURE(uniformBufferStandardLayout); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR: { + VkPhysicalDeviceVulkanMemoryModelFeaturesKHR *features = (void *)ext; + CORE_FEATURE(vulkanMemoryModel); + CORE_FEATURE(vulkanMemoryModelDeviceScope); + CORE_FEATURE(vulkanMemoryModelAvailabilityVisibilityChains); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: + copy_vk_struct_guts(ext, (void *)core, sizeof(*core)); + return true; + + default: + return false; + } +} + +#undef CORE_FEATURE + +#define CORE_RENAMED_PROPERTY(ext_property, core_property) \ + memcpy(&properties->ext_property, &core->core_property, sizeof(core->core_property)) + +#define CORE_PROPERTY(property) CORE_RENAMED_PROPERTY(property, property) + +bool +vk_get_physical_device_core_1_1_property_ext(struct VkBaseOutStructure *ext, + const VkPhysicalDeviceVulkan11Properties *core) +{ + switch (ext->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: { + VkPhysicalDeviceIDProperties *properties = (void *)ext; + CORE_PROPERTY(deviceUUID); + CORE_PROPERTY(driverUUID); + CORE_PROPERTY(deviceLUID); + CORE_PROPERTY(deviceLUIDValid); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: { + VkPhysicalDeviceMaintenance3Properties *properties = (void *)ext; + CORE_PROPERTY(maxPerSetDescriptors); + CORE_PROPERTY(maxMemoryAllocationSize); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES: { + VkPhysicalDeviceMultiviewProperties *properties = (void *)ext; + CORE_PROPERTY(maxMultiviewViewCount); + CORE_PROPERTY(maxMultiviewInstanceIndex); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: { + VkPhysicalDevicePointClippingProperties *properties = (void *) ext; + CORE_PROPERTY(pointClippingBehavior); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES: { + VkPhysicalDeviceProtectedMemoryProperties *properties = (void *)ext; + CORE_PROPERTY(protectedNoFault); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES: { + VkPhysicalDeviceSubgroupProperties *properties = (void *)ext; + CORE_PROPERTY(subgroupSize); + CORE_RENAMED_PROPERTY(supportedStages, + subgroupSupportedStages); + CORE_RENAMED_PROPERTY(supportedOperations, + subgroupSupportedOperations); + CORE_RENAMED_PROPERTY(quadOperationsInAllStages, + subgroupQuadOperationsInAllStages); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES: + copy_vk_struct_guts(ext, (void *)core, sizeof(*core)); + return true; + + default: + return false; + } +} + +bool +vk_get_physical_device_core_1_2_property_ext(struct VkBaseOutStructure *ext, + const VkPhysicalDeviceVulkan12Properties *core) +{ + switch (ext->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR: { + VkPhysicalDeviceDepthStencilResolvePropertiesKHR *properties = (void *)ext; + CORE_PROPERTY(supportedDepthResolveModes); + CORE_PROPERTY(supportedStencilResolveModes); + CORE_PROPERTY(independentResolveNone); + CORE_PROPERTY(independentResolve); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT: { + VkPhysicalDeviceDescriptorIndexingPropertiesEXT *properties = (void *)ext; + CORE_PROPERTY(maxUpdateAfterBindDescriptorsInAllPools); + CORE_PROPERTY(shaderUniformBufferArrayNonUniformIndexingNative); + CORE_PROPERTY(shaderSampledImageArrayNonUniformIndexingNative); + CORE_PROPERTY(shaderStorageBufferArrayNonUniformIndexingNative); + CORE_PROPERTY(shaderStorageImageArrayNonUniformIndexingNative); + CORE_PROPERTY(shaderInputAttachmentArrayNonUniformIndexingNative); + CORE_PROPERTY(robustBufferAccessUpdateAfterBind); + CORE_PROPERTY(quadDivergentImplicitLod); + CORE_PROPERTY(maxPerStageDescriptorUpdateAfterBindSamplers); + CORE_PROPERTY(maxPerStageDescriptorUpdateAfterBindUniformBuffers); + CORE_PROPERTY(maxPerStageDescriptorUpdateAfterBindStorageBuffers); + CORE_PROPERTY(maxPerStageDescriptorUpdateAfterBindSampledImages); + CORE_PROPERTY(maxPerStageDescriptorUpdateAfterBindStorageImages); + CORE_PROPERTY(maxPerStageDescriptorUpdateAfterBindInputAttachments); + CORE_PROPERTY(maxPerStageUpdateAfterBindResources); + CORE_PROPERTY(maxDescriptorSetUpdateAfterBindSamplers); + CORE_PROPERTY(maxDescriptorSetUpdateAfterBindUniformBuffers); + CORE_PROPERTY(maxDescriptorSetUpdateAfterBindUniformBuffersDynamic); + CORE_PROPERTY(maxDescriptorSetUpdateAfterBindStorageBuffers); + CORE_PROPERTY(maxDescriptorSetUpdateAfterBindStorageBuffersDynamic); + CORE_PROPERTY(maxDescriptorSetUpdateAfterBindSampledImages); + CORE_PROPERTY(maxDescriptorSetUpdateAfterBindStorageImages); + CORE_PROPERTY(maxDescriptorSetUpdateAfterBindInputAttachments); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR: { + VkPhysicalDeviceDriverPropertiesKHR *properties = (void *) ext; + CORE_PROPERTY(driverID); + CORE_PROPERTY(driverName); + CORE_PROPERTY(driverInfo); + CORE_PROPERTY(conformanceVersion); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT: { + VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT *properties = (void *)ext; + CORE_PROPERTY(filterMinmaxImageComponentMapping); + CORE_PROPERTY(filterMinmaxSingleComponentFormats); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR : { + VkPhysicalDeviceFloatControlsPropertiesKHR *properties = (void *)ext; + CORE_PROPERTY(denormBehaviorIndependence); + CORE_PROPERTY(roundingModeIndependence); + CORE_PROPERTY(shaderDenormFlushToZeroFloat16); + CORE_PROPERTY(shaderDenormPreserveFloat16); + CORE_PROPERTY(shaderRoundingModeRTEFloat16); + CORE_PROPERTY(shaderRoundingModeRTZFloat16); + CORE_PROPERTY(shaderSignedZeroInfNanPreserveFloat16); + CORE_PROPERTY(shaderDenormFlushToZeroFloat32); + CORE_PROPERTY(shaderDenormPreserveFloat32); + CORE_PROPERTY(shaderRoundingModeRTEFloat32); + CORE_PROPERTY(shaderRoundingModeRTZFloat32); + CORE_PROPERTY(shaderSignedZeroInfNanPreserveFloat32); + CORE_PROPERTY(shaderDenormFlushToZeroFloat64); + CORE_PROPERTY(shaderDenormPreserveFloat64); + CORE_PROPERTY(shaderRoundingModeRTEFloat64); + CORE_PROPERTY(shaderRoundingModeRTZFloat64); + CORE_PROPERTY(shaderSignedZeroInfNanPreserveFloat64); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR: { + VkPhysicalDeviceTimelineSemaphorePropertiesKHR *properties = (void *) ext; + CORE_PROPERTY(maxTimelineSemaphoreValueDifference); + return true; + } + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES: + copy_vk_struct_guts(ext, (void *)core, sizeof(*core)); + return true; + + default: + return false; + } +} + +#undef CORE_RENAMED_PROPERTY +#undef CORE_PROPERTY + diff --git a/lib/mesa/src/vulkan/util/vk_device.h b/lib/mesa/src/vulkan/util/vk_device.h index e31688475..3bb0347e0 100644 --- a/lib/mesa/src/vulkan/util/vk_device.h +++ b/lib/mesa/src/vulkan/util/vk_device.h @@ -27,6 +27,8 @@ #include "vk_extensions.h" #include "vk_object.h" +#include "util/list.h" + #ifdef __cplusplus extern "C" { #endif @@ -43,6 +45,8 @@ struct vk_device { /* For VK_EXT_private_data */ uint32_t private_data_next_index; + struct list_head queues; + #ifdef ANDROID mtx_t swapchain_private_mtx; struct hash_table *swapchain_private; @@ -66,6 +70,16 @@ PFN_vkVoidFunction vk_device_get_proc_addr(const struct vk_device *device, const char *name); +bool vk_get_physical_device_core_1_1_feature_ext(struct VkBaseOutStructure *ext, + const VkPhysicalDeviceVulkan11Features *core); +bool vk_get_physical_device_core_1_2_feature_ext(struct VkBaseOutStructure *ext, + const VkPhysicalDeviceVulkan12Features *core); + +bool vk_get_physical_device_core_1_1_property_ext(struct VkBaseOutStructure *ext, + const VkPhysicalDeviceVulkan11Properties *core); +bool vk_get_physical_device_core_1_2_property_ext(struct VkBaseOutStructure *ext, + const VkPhysicalDeviceVulkan12Properties *core); + #ifdef __cplusplus } #endif diff --git a/lib/mesa/src/vulkan/util/vk_dispatch_table_gen.py b/lib/mesa/src/vulkan/util/vk_dispatch_table_gen.py index 7b566ba0f..eb6b0cd28 100644 --- a/lib/mesa/src/vulkan/util/vk_dispatch_table_gen.py +++ b/lib/mesa/src/vulkan/util/vk_dispatch_table_gen.py @@ -55,6 +55,7 @@ TEMPLATE_H = Template(COPYRIGHT + """\ /* Windows api conflict */ #ifdef _WIN32 +#include <windows.h> #ifdef CreateSemaphore #undef CreateSemaphore #endif @@ -67,8 +68,11 @@ TEMPLATE_H = Template(COPYRIGHT + """\ extern "C" { #endif -<%def name="dispatch_table(type, entrypoints)"> -struct vk_${type}_dispatch_table { +#ifdef _MSC_VER +VKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void); +#endif + +<%def name="dispatch_table(entrypoints)"> % for e in entrypoints: % if e.alias: <% continue %> @@ -101,8 +105,9 @@ struct vk_${type}_dispatch_table { #endif % endif % endfor -}; +</%def> +<%def name="entrypoint_table(type, entrypoints)"> struct vk_${type}_entrypoint_table { % for e in entrypoints: % if e.guard is not None: @@ -118,9 +123,37 @@ struct vk_${type}_entrypoint_table { }; </%def> -${dispatch_table('instance', instance_entrypoints)} -${dispatch_table('physical_device', physical_device_entrypoints)} -${dispatch_table('device', device_entrypoints)} +struct vk_instance_dispatch_table { + ${dispatch_table(instance_entrypoints)} +}; + +struct vk_physical_device_dispatch_table { + ${dispatch_table(physical_device_entrypoints)} +}; + +struct vk_device_dispatch_table { + ${dispatch_table(device_entrypoints)} +}; + +struct vk_dispatch_table { + union { + struct { + struct vk_instance_dispatch_table instance; + struct vk_physical_device_dispatch_table physical_device; + struct vk_device_dispatch_table device; + }; + + struct { + ${dispatch_table(instance_entrypoints)} + ${dispatch_table(physical_device_entrypoints)} + ${dispatch_table(device_entrypoints)} + }; + }; +}; + +${entrypoint_table('instance', instance_entrypoints)} +${entrypoint_table('physical_device', physical_device_entrypoints)} +${entrypoint_table('device', device_entrypoints)} void vk_instance_dispatch_table_load(struct vk_instance_dispatch_table *table, @@ -192,7 +225,7 @@ extern struct vk_device_dispatch_table vk_device_trampolines; #endif #endif /* VK_DISPATCH_TABLE_H */ -""", output_encoding='utf-8') +""") TEMPLATE_C = Template(COPYRIGHT + """\ /* This file generated from ${filename}, don't edit directly. */ @@ -435,6 +468,13 @@ vk_device_entrypoint_is_enabled(int index, uint32_t core_version, } } +#ifdef _MSC_VER +VKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void) +{ + unreachable(!"Entrypoint not implemented"); +} +#endif + <%def name="dispatch_table_from_entrypoints(type)"> void vk_${type}_dispatch_table_from_entrypoints( struct vk_${type}_dispatch_table *dispatch_table, @@ -448,8 +488,8 @@ void vk_${type}_dispatch_table_from_entrypoints( memset(dispatch_table, 0, sizeof(*dispatch_table)); for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) { #ifdef _MSC_VER - const uintptr_t zero = 0; - if (entry[i] == NULL || memcmp(entry[i], &zero, sizeof(zero)) == 0) + assert(entry[i] != NULL); + if (entry[i] == vk_entrypoint_stub) #else if (entry[i] == NULL) #endif @@ -461,7 +501,12 @@ void vk_${type}_dispatch_table_from_entrypoints( } else { for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) { unsigned disp_index = ${type}_compaction_table[i]; +#ifdef _MSC_VER + assert(entry[i] != NULL); + if (disp[disp_index] == NULL && entry[i] != vk_entrypoint_stub) +#else if (disp[disp_index] == NULL) +#endif disp[disp_index] = entry[i]; } } @@ -638,7 +683,7 @@ struct vk_device_dispatch_table vk_device_trampolines = { % endif % endfor }; -""", output_encoding='utf-8') +""") U32_MASK = 2**32 - 1 @@ -697,7 +742,7 @@ class StringIntMap(object): self.collisions[min(level, 9)] += 1 self.mapping[h & self.hash_mask] = idx -EntrypointParam = namedtuple('EntrypointParam', 'type name decl') +EntrypointParam = namedtuple('EntrypointParam', 'type name decl len') class EntrypointBase(object): def __init__(self, name): @@ -782,7 +827,8 @@ def get_entrypoints(doc, entrypoints_to_defines): params = [EntrypointParam( type=p.find('./type').text, name=p.find('./name').text, - decl=''.join(p.itertext()) + decl=''.join(p.itertext()), + len=p.attrib.get('len', None) ) for p in command.findall('./param')] guard = entrypoints_to_defines.get(name) # They really need to be unique @@ -898,13 +944,13 @@ def main(): # per entry point. try: if args.out_h: - with open(args.out_h, 'wb') as f: + with open(args.out_h, 'w') as f: f.write(TEMPLATE_H.render(instance_entrypoints=instance_entrypoints, physical_device_entrypoints=physical_device_entrypoints, device_entrypoints=device_entrypoints, filename=os.path.basename(__file__))) if args.out_c: - with open(args.out_c, 'wb') as f: + with open(args.out_c, 'w') as f: f.write(TEMPLATE_C.render(instance_entrypoints=instance_entrypoints, physical_device_entrypoints=physical_device_entrypoints, device_entrypoints=device_entrypoints, diff --git a/lib/mesa/src/vulkan/util/vk_entrypoints_gen.py b/lib/mesa/src/vulkan/util/vk_entrypoints_gen.py index a663d10e1..078b6daec 100644 --- a/lib/mesa/src/vulkan/util/vk_entrypoints_gen.py +++ b/lib/mesa/src/vulkan/util/vk_entrypoints_gen.py @@ -99,7 +99,7 @@ extern const struct vk_device_entrypoint_table ${p}_device_entrypoints; #endif #endif /* ${guard} */ -""", output_encoding='utf-8') +""") TEMPLATE_C = Template(COPYRIGHT + """ /* This file generated from ${filename}, don't edit directly. */ @@ -123,13 +123,12 @@ TEMPLATE_C = Template(COPYRIGHT + """ % endif % for p in prefixes: #ifdef _MSC_VER - ${e.return_type} (*${p}_${e.name}_Null)(${e.decl_params()}) = 0; #ifdef _M_IX86 % for args_size in [4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 60, 104]: - #pragma comment(linker, "/alternatename:_${p}_${e.name}@${args_size}=_${p}_${e.name}_Null") + #pragma comment(linker, "/alternatename:_${p}_${e.name}@${args_size}=_vk_entrypoint_stub@0") % endfor #else - #pragma comment(linker, "/alternatename:${p}_${e.name}=${p}_${e.name}_Null") + #pragma comment(linker, "/alternatename:${p}_${e.name}=vk_entrypoint_stub") #endif #else VKAPI_ATTR ${e.return_type} VKAPI_CALL ${p}_${e.name}(${e.decl_params()}) __attribute__ ((weak)); @@ -149,6 +148,8 @@ const struct vk_${type}_entrypoint_table ${p}_${type}_entrypoints = { % endif .${e.name} = ${p}_${e.name}, % if e.guard is not None: +#elif defined(_MSC_VER) + .${e.name} = (PFN_vkVoidFunction)vk_entrypoint_stub, #endif // ${e.guard} % endif % endfor @@ -159,7 +160,7 @@ const struct vk_${type}_entrypoint_table ${p}_${type}_entrypoints = { ${entrypoint_table('instance', instance_entrypoints, instance_prefixes)} ${entrypoint_table('physical_device', physical_device_entrypoints, physical_device_prefixes)} ${entrypoint_table('device', device_entrypoints, device_prefixes)} -""", output_encoding='utf-8') +""") def get_entrypoints_defines(doc): """Maps entry points to extension defines.""" @@ -236,10 +237,10 @@ def main(): # For outputting entrypoints.h we generate a anv_EntryPoint() prototype # per entry point. try: - with open(args.out_h, 'wb') as f: + with open(args.out_h, 'w') as f: guard = os.path.basename(args.out_h).replace('.', '_').upper() f.write(TEMPLATE_H.render(guard=guard, **environment)) - with open(args.out_c, 'wb') as f: + with open(args.out_c, 'w') as f: f.write(TEMPLATE_C.render(**environment)) except Exception: diff --git a/lib/mesa/src/vulkan/util/vk_extensions.py b/lib/mesa/src/vulkan/util/vk_extensions.py index 852951f05..75bdf3dd9 100644 --- a/lib/mesa/src/vulkan/util/vk_extensions.py +++ b/lib/mesa/src/vulkan/util/vk_extensions.py @@ -104,8 +104,10 @@ def get_all_exts_from_xml(xml): version = None for enum_elem in ext_elem.findall('.require/enum'): if enum_elem.attrib['name'].endswith('_SPEC_VERSION'): - assert version is None - version = int(enum_elem.attrib['value']) + # Skip alias SPEC_VERSIONs + if 'value' in enum_elem.attrib: + assert version is None + version = int(enum_elem.attrib['value']) ext = Extension(name, version, True) extensions.append(Extension(name, version, True)) diff --git a/lib/mesa/src/vulkan/util/vk_format.h b/lib/mesa/src/vulkan/util/vk_format.h index 813ec4c36..f03a35e2a 100644 --- a/lib/mesa/src/vulkan/util/vk_format.h +++ b/lib/mesa/src/vulkan/util/vk_format.h @@ -28,6 +28,10 @@ #include <vulkan/vulkan_core.h> #include "util/format/u_format.h" +#ifdef __cplusplus +extern "C" { +#endif + enum pipe_format vk_format_to_pipe_format(enum VkFormat vkformat); @@ -61,4 +65,31 @@ vk_format_has_stencil(VkFormat format) return aspects & VK_IMAGE_ASPECT_STENCIL_BIT; } +static inline VkFormat +vk_format_depth_only(VkFormat format) +{ + assert(vk_format_has_depth(format)); + switch (format) { + case VK_FORMAT_D16_UNORM_S8_UINT: + return VK_FORMAT_D16_UNORM; + case VK_FORMAT_D24_UNORM_S8_UINT: + return VK_FORMAT_X8_D24_UNORM_PACK32; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return VK_FORMAT_D32_SFLOAT; + default: + return format; + } +} + +static inline VkFormat +vk_format_stencil_only(VkFormat format) +{ + assert(vk_format_has_stencil(format)); + return VK_FORMAT_S8_UINT; +} + +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/mesa/src/vulkan/util/vk_image.c b/lib/mesa/src/vulkan/util/vk_image.c new file mode 100644 index 000000000..5e6db91dc --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_image.c @@ -0,0 +1,617 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_image.h" + +#include <vulkan/vulkan_android.h> + +#ifndef _WIN32 +#include <drm-uapi/drm_fourcc.h> +#endif + +#include "vk_alloc.h" +#include "vk_common_entrypoints.h" +#include "vk_device.h" +#include "vk_format.h" +#include "vk_util.h" +#include "vulkan/wsi/wsi_common.h" + +static VkExtent3D +sanitize_image_extent(const VkImageType imageType, + const VkExtent3D imageExtent) +{ + switch (imageType) { + case VK_IMAGE_TYPE_1D: + return (VkExtent3D) { imageExtent.width, 1, 1 }; + case VK_IMAGE_TYPE_2D: + return (VkExtent3D) { imageExtent.width, imageExtent.height, 1 }; + case VK_IMAGE_TYPE_3D: + return imageExtent; + default: + unreachable("invalid image type"); + } +} + +void +vk_image_init(struct vk_device *device, + struct vk_image *image, + const VkImageCreateInfo *pCreateInfo) +{ + vk_object_base_init(device, &image->base, VK_OBJECT_TYPE_IMAGE); + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO); + assert(pCreateInfo->mipLevels > 0); + assert(pCreateInfo->arrayLayers > 0); + assert(pCreateInfo->samples > 0); + assert(pCreateInfo->extent.width > 0); + assert(pCreateInfo->extent.height > 0); + assert(pCreateInfo->extent.depth > 0); + + if (pCreateInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) + assert(pCreateInfo->imageType == VK_IMAGE_TYPE_2D); + if (pCreateInfo->flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT) + assert(pCreateInfo->imageType == VK_IMAGE_TYPE_3D); + + image->create_flags = pCreateInfo->flags; + image->image_type = pCreateInfo->imageType; + vk_image_set_format(image, pCreateInfo->format); + image->extent = sanitize_image_extent(pCreateInfo->imageType, + pCreateInfo->extent); + image->mip_levels = pCreateInfo->mipLevels; + image->array_layers = pCreateInfo->arrayLayers; + image->samples = pCreateInfo->samples; + image->tiling = pCreateInfo->tiling; + image->usage = pCreateInfo->usage; + + if (image->aspects & VK_IMAGE_ASPECT_STENCIL_BIT) { + const VkImageStencilUsageCreateInfoEXT *stencil_usage_info = + vk_find_struct_const(pCreateInfo->pNext, + IMAGE_STENCIL_USAGE_CREATE_INFO_EXT); + image->stencil_usage = + stencil_usage_info ? stencil_usage_info->stencilUsage : + pCreateInfo->usage; + } else { + image->stencil_usage = 0; + } + + const VkExternalMemoryImageCreateInfo *ext_mem_info = + vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_IMAGE_CREATE_INFO); + if (ext_mem_info) + image->external_handle_types = ext_mem_info->handleTypes; + else + image->external_handle_types = 0; + + const struct wsi_image_create_info *wsi_info = + vk_find_struct_const(pCreateInfo->pNext, WSI_IMAGE_CREATE_INFO_MESA); + image->wsi_legacy_scanout = wsi_info && wsi_info->scanout; + +#ifndef _WIN32 + image->drm_format_mod = ((1ULL << 56) - 1) /* DRM_FORMAT_MOD_INVALID */; +#endif + +#ifdef ANDROID + const VkExternalFormatANDROID *ext_format = + vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_FORMAT_ANDROID); + if (ext_format && ext_format->externalFormat != 0) { + assert(image->format == VK_FORMAT_UNDEFINED); + assert(image->external_handle_types & + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID); + image->android_external_format = ext_format->externalFormat; + } else { + image->android_external_format = 0; + } +#endif +} + +void * +vk_image_create(struct vk_device *device, + const VkImageCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc, + size_t size) +{ + struct vk_image *image = + vk_zalloc2(&device->alloc, alloc, size, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (image == NULL) + return NULL; + + vk_image_init(device, image, pCreateInfo); + + return image; +} + +void +vk_image_finish(struct vk_image *image) +{ + vk_object_base_finish(&image->base); +} + +void +vk_image_destroy(struct vk_device *device, + const VkAllocationCallbacks *alloc, + struct vk_image *image) +{ + vk_object_free(device, alloc, image); +} + +#ifndef _WIN32 +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_GetImageDrmFormatModifierPropertiesEXT(UNUSED VkDevice device, + VkImage _image, + VkImageDrmFormatModifierPropertiesEXT *pProperties) +{ + VK_FROM_HANDLE(vk_image, image, _image); + + assert(pProperties->sType == + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT); + + assert(image->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT); + pProperties->drmFormatModifier = image->drm_format_mod; + + return VK_SUCCESS; +} +#endif + +void +vk_image_set_format(struct vk_image *image, VkFormat format) +{ + image->format = format; + image->aspects = vk_format_aspects(format); +} + +VkImageUsageFlags +vk_image_usage(const struct vk_image *image, + VkImageAspectFlags aspect_mask) +{ + assert(!(aspect_mask & ~image->aspects)); + + /* From the Vulkan 1.2.131 spec: + * + * "If the image was has a depth-stencil format and was created with + * a VkImageStencilUsageCreateInfo structure included in the pNext + * chain of VkImageCreateInfo, the usage is calculated based on the + * subresource.aspectMask provided: + * + * - If aspectMask includes only VK_IMAGE_ASPECT_STENCIL_BIT, the + * implicit usage is equal to + * VkImageStencilUsageCreateInfo::stencilUsage. + * + * - If aspectMask includes only VK_IMAGE_ASPECT_DEPTH_BIT, the + * implicit usage is equal to VkImageCreateInfo::usage. + * + * - If both aspects are included in aspectMask, the implicit usage + * is equal to the intersection of VkImageCreateInfo::usage and + * VkImageStencilUsageCreateInfo::stencilUsage. + */ + if (aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT) { + return image->stencil_usage; + } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT)) { + return image->usage & image->stencil_usage; + } else { + /* This also handles the color case */ + return image->usage; + } +} + +#define VK_IMAGE_ASPECT_ANY_COLOR_MASK_MESA ( \ + VK_IMAGE_ASPECT_COLOR_BIT | \ + VK_IMAGE_ASPECT_PLANE_0_BIT | \ + VK_IMAGE_ASPECT_PLANE_1_BIT | \ + VK_IMAGE_ASPECT_PLANE_2_BIT) + +/** Expands the given aspect mask relative to the image + * + * If the image has color plane aspects VK_IMAGE_ASPECT_COLOR_BIT has been + * requested, this returns the aspects of the underlying image. + * + * For example, + * + * VK_IMAGE_ASPECT_COLOR_BIT + * + * will be converted to + * + * VK_IMAGE_ASPECT_PLANE_0_BIT | + * VK_IMAGE_ASPECT_PLANE_1_BIT | + * VK_IMAGE_ASPECT_PLANE_2_BIT + * + * for an image of format VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM. + */ +VkImageAspectFlags +vk_image_expand_aspect_mask(const struct vk_image *image, + VkImageAspectFlags aspect_mask) +{ + if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) { + assert(image->aspects & VK_IMAGE_ASPECT_ANY_COLOR_MASK_MESA); + return image->aspects; + } else { + assert(aspect_mask && !(aspect_mask & ~image->aspects)); + return aspect_mask; + } +} + +static VkComponentSwizzle +remap_swizzle(VkComponentSwizzle swizzle, VkComponentSwizzle component) +{ + return swizzle == VK_COMPONENT_SWIZZLE_IDENTITY ? component : swizzle; +} + +void +vk_image_view_init(struct vk_device *device, + struct vk_image_view *image_view, + const VkImageViewCreateInfo *pCreateInfo) +{ + vk_object_base_init(device, &image_view->base, VK_OBJECT_TYPE_IMAGE_VIEW); + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO); + VK_FROM_HANDLE(vk_image, image, pCreateInfo->image); + + image_view->create_flags = pCreateInfo->flags; + image_view->image = image; + image_view->view_type = pCreateInfo->viewType; + + switch (image_view->view_type) { + case VK_IMAGE_VIEW_TYPE_1D: + case VK_IMAGE_VIEW_TYPE_1D_ARRAY: + assert(image->image_type == VK_IMAGE_TYPE_1D); + break; + case VK_IMAGE_VIEW_TYPE_2D: + case VK_IMAGE_VIEW_TYPE_2D_ARRAY: + if (image->create_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT) + assert(image->image_type == VK_IMAGE_TYPE_3D); + else + assert(image->image_type == VK_IMAGE_TYPE_2D); + break; + case VK_IMAGE_VIEW_TYPE_3D: + assert(image->image_type == VK_IMAGE_TYPE_3D); + break; + case VK_IMAGE_VIEW_TYPE_CUBE: + case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: + assert(image->image_type == VK_IMAGE_TYPE_2D); + assert(image->create_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT); + break; + default: + unreachable("Invalid image view type"); + } + + const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange; + + /* Some drivers may want to create color views of depth/stencil images + * to implement certain operations, which is not strictly allowed by the + * Vulkan spec, so handle this case separately. + */ + bool is_color_view_of_depth_stencil = + vk_format_is_depth_or_stencil(image->format) && + vk_format_is_color(pCreateInfo->format); + if (is_color_view_of_depth_stencil) { + assert(range->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT); + assert(util_format_get_blocksize(vk_format_to_pipe_format(image->format)) == + util_format_get_blocksize(vk_format_to_pipe_format(pCreateInfo->format))); + image_view->aspects = range->aspectMask; + } else { + image_view->aspects = + vk_image_expand_aspect_mask(image, range->aspectMask); + + /* From the Vulkan 1.2.184 spec: + * + * "If the image has a multi-planar format and + * subresourceRange.aspectMask is VK_IMAGE_ASPECT_COLOR_BIT, and image + * has been created with a usage value not containing any of the + * VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR, + * VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR, + * VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR, + * VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR, + * VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR, and + * VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR flags, then the format must + * be identical to the image format, and the sampler to be used with the + * image view must enable sampler Y′CBCR conversion." + * + * Since no one implements video yet, we can ignore the bits about video + * create flags and assume YCbCr formats match. + */ + if ((image->aspects & VK_IMAGE_ASPECT_PLANE_1_BIT) && + (range->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT)) + assert(pCreateInfo->format == image->format); + + /* From the Vulkan 1.2.184 spec: + * + * "Each depth/stencil format is only compatible with itself." + */ + if (image_view->aspects & (VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT)) + assert(pCreateInfo->format == image->format); + + if (!(image->create_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT)) + assert(pCreateInfo->format == image->format); + } + + /* Restrict the format to only the planes chosen. + * + * For combined depth and stencil images, this means the depth-only or + * stencil-only format if only one aspect is chosen and the full combined + * format if both aspects are chosen. + * + * For single-plane color images, we just take the format as-is. For + * multi-plane views of multi-plane images, this means we want the full + * multi-plane format. For single-plane views of multi-plane images, we + * want a format compatible with the one plane. Fortunately, this is + * already what the client gives us. The Vulkan 1.2.184 spec says: + * + * "If image was created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT and + * the image has a multi-planar format, and if + * subresourceRange.aspectMask is VK_IMAGE_ASPECT_PLANE_0_BIT, + * VK_IMAGE_ASPECT_PLANE_1_BIT, or VK_IMAGE_ASPECT_PLANE_2_BIT, format + * must be compatible with the corresponding plane of the image, and the + * sampler to be used with the image view must not enable sampler Y′CBCR + * conversion." + */ + if (image_view->aspects == VK_IMAGE_ASPECT_STENCIL_BIT) { + image_view->format = vk_format_stencil_only(pCreateInfo->format); + } else if (image_view->aspects == VK_IMAGE_ASPECT_DEPTH_BIT) { + image_view->format = vk_format_depth_only(pCreateInfo->format); + } else { + image_view->format = pCreateInfo->format; + } + + image_view->swizzle = (VkComponentMapping) { + .r = remap_swizzle(pCreateInfo->components.r, VK_COMPONENT_SWIZZLE_R), + .g = remap_swizzle(pCreateInfo->components.g, VK_COMPONENT_SWIZZLE_G), + .b = remap_swizzle(pCreateInfo->components.b, VK_COMPONENT_SWIZZLE_B), + .a = remap_swizzle(pCreateInfo->components.a, VK_COMPONENT_SWIZZLE_A), + }; + + assert(range->layerCount > 0); + assert(range->baseMipLevel < image->mip_levels); + + image_view->base_mip_level = range->baseMipLevel; + image_view->level_count = vk_image_subresource_level_count(image, range); + image_view->base_array_layer = range->baseArrayLayer; + image_view->layer_count = vk_image_subresource_layer_count(image, range); + + image_view->extent = + vk_image_mip_level_extent(image, image_view->base_mip_level); + + assert(image_view->base_mip_level + image_view->level_count + <= image->mip_levels); + switch (image->image_type) { + default: + unreachable("bad VkImageType"); + case VK_IMAGE_TYPE_1D: + case VK_IMAGE_TYPE_2D: + assert(image_view->base_array_layer + image_view->layer_count + <= image->array_layers); + break; + case VK_IMAGE_TYPE_3D: + assert(image_view->base_array_layer + image_view->layer_count + <= image_view->extent.depth); + break; + } + + /* If we are creating a color view from a depth/stencil image we compute + * usage from the underlying depth/stencil aspects. + */ + const VkImageUsageFlags image_usage = is_color_view_of_depth_stencil ? + vk_image_usage(image, image->aspects) : + vk_image_usage(image, image_view->aspects); + const VkImageViewUsageCreateInfo *usage_info = + vk_find_struct_const(pCreateInfo, IMAGE_VIEW_USAGE_CREATE_INFO); + image_view->usage = usage_info ? usage_info->usage : image_usage; + assert(!(image_view->usage & ~image_usage)); +} + +void +vk_image_view_finish(struct vk_image_view *image_view) +{ + vk_object_base_finish(&image_view->base); +} + +void * +vk_image_view_create(struct vk_device *device, + const VkImageViewCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc, + size_t size) +{ + struct vk_image_view *image_view = + vk_zalloc2(&device->alloc, alloc, size, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (image_view == NULL) + return NULL; + + vk_image_view_init(device, image_view, pCreateInfo); + + return image_view; +} + +void +vk_image_view_destroy(struct vk_device *device, + const VkAllocationCallbacks *alloc, + struct vk_image_view *image_view) +{ + vk_object_free(device, alloc, image_view); +} + +bool +vk_image_layout_is_read_only(VkImageLayout layout, + VkImageAspectFlagBits aspect) +{ + assert(util_bitcount(aspect) == 1); + + switch (layout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_PREINITIALIZED: + return true; /* These are only used for layout transitions */ + + case VK_IMAGE_LAYOUT_GENERAL: + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR: + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR: + return false; + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + case VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV: + case VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT: + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR: + return true; + + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: + return aspect == VK_IMAGE_ASPECT_DEPTH_BIT; + + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: + return aspect == VK_IMAGE_ASPECT_STENCIL_BIT; + + case VK_IMAGE_LAYOUT_MAX_ENUM: + unreachable("Invalid image layout."); + } + + unreachable("Invalid image layout."); +} + +VkImageUsageFlags +vk_image_layout_to_usage_flags(VkImageLayout layout, + VkImageAspectFlagBits aspect) +{ + assert(util_bitcount(aspect) == 1); + + switch (layout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_PREINITIALIZED: + return 0u; + + case VK_IMAGE_LAYOUT_GENERAL: + return ~0u; + + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + assert(aspect & VK_IMAGE_ASPECT_ANY_COLOR_MASK_MESA); + return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + assert(aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT)); + return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL: + assert(aspect & VK_IMAGE_ASPECT_DEPTH_BIT); + return vk_image_layout_to_usage_flags( + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, aspect); + + case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL: + assert(aspect & VK_IMAGE_ASPECT_STENCIL_BIT); + return vk_image_layout_to_usage_flags( + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, aspect); + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + assert(aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT)); + return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: + assert(aspect & VK_IMAGE_ASPECT_DEPTH_BIT); + return vk_image_layout_to_usage_flags( + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, aspect); + + case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL: + assert(aspect & VK_IMAGE_ASPECT_STENCIL_BIT); + return vk_image_layout_to_usage_flags( + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, aspect); + + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + return VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: + if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT) { + return vk_image_layout_to_usage_flags( + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, aspect); + } else if (aspect == VK_IMAGE_ASPECT_STENCIL_BIT) { + return vk_image_layout_to_usage_flags( + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, aspect); + } else { + assert(!"Must be a depth/stencil aspect"); + return 0; + } + + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: + if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT) { + return vk_image_layout_to_usage_flags( + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, aspect); + } else if (aspect == VK_IMAGE_ASPECT_STENCIL_BIT) { + return vk_image_layout_to_usage_flags( + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, aspect); + } else { + assert(!"Must be a depth/stencil aspect"); + return 0; + } + + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + assert(aspect == VK_IMAGE_ASPECT_COLOR_BIT); + /* This needs to be handled specially by the caller */ + return 0; + + case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR: + assert(aspect == VK_IMAGE_ASPECT_COLOR_BIT); + return vk_image_layout_to_usage_flags(VK_IMAGE_LAYOUT_GENERAL, aspect); + + case VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV: + assert(aspect == VK_IMAGE_ASPECT_COLOR_BIT); + return VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV; + + case VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT: + assert(aspect == VK_IMAGE_ASPECT_COLOR_BIT); + return VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT; + + case VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR: + if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT || + aspect == VK_IMAGE_ASPECT_STENCIL_BIT) { + return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } else { + assert(aspect == VK_IMAGE_ASPECT_COLOR_BIT); + return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + + case VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR: + return VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + + case VK_IMAGE_LAYOUT_MAX_ENUM: + unreachable("Invalid image layout."); + } + + unreachable("Invalid image layout."); +} diff --git a/lib/mesa/src/vulkan/util/vk_image.h b/lib/mesa/src/vulkan/util/vk_image.h new file mode 100644 index 000000000..beb260647 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_image.h @@ -0,0 +1,231 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef VK_IMAGE_H +#define VK_IMAGE_H + +#include "vk_object.h" + +#include "util/u_math.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_image { + struct vk_object_base base; + + VkImageCreateFlags create_flags; + VkImageType image_type; + VkFormat format; + VkExtent3D extent; + uint32_t mip_levels; + uint32_t array_layers; + VkSampleCountFlagBits samples; + VkImageTiling tiling; + VkImageUsageFlags usage; + + /* Derived from format */ + VkImageAspectFlags aspects; + + /* VK_EXT_separate_stencil_usage */ + VkImageUsageFlags stencil_usage; + + /* VK_KHR_external_memory */ + VkExternalMemoryHandleTypeFlags external_handle_types; + + /* wsi_image_create_info::scanout */ + bool wsi_legacy_scanout; + +#ifndef _WIN32 + /* VK_EXT_drm_format_modifier + * + * Initialized by vk_image_create/init() to DRM_FORMAT_MOD_INVALID. It's + * the job of the driver to parse the VK_EXT_drm_format_modifier extension + * structs and choose the actual modifier. + * + * Must be DRM_FORMAT_MOD_INVALID unless tiling is + * VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT. + */ + uint64_t drm_format_mod; +#endif + +#ifdef ANDROID + /* VK_ANDROID_external_memory_android_hardware_buffer */ + uint64_t android_external_format; +#endif +}; +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_image, base, VkImage, + VK_OBJECT_TYPE_IMAGE); + +void vk_image_init(struct vk_device *device, + struct vk_image *image, + const VkImageCreateInfo *pCreateInfo); +void vk_image_finish(struct vk_image *image); + +void *vk_image_create(struct vk_device *device, + const VkImageCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc, + size_t size); +void vk_image_destroy(struct vk_device *device, + const VkAllocationCallbacks *alloc, + struct vk_image *image); + +void vk_image_set_format(struct vk_image *image, VkFormat format); + +VkImageUsageFlags vk_image_usage(const struct vk_image *image, + VkImageAspectFlags aspect_mask); + +VkImageAspectFlags vk_image_expand_aspect_mask(const struct vk_image *image, + VkImageAspectFlags aspect_mask); + +static inline VkExtent3D +vk_image_mip_level_extent(const struct vk_image *image, + uint32_t mip_level) +{ + const VkExtent3D extent = { + u_minify(image->extent.width, mip_level), + u_minify(image->extent.height, mip_level), + u_minify(image->extent.depth, mip_level), + }; + return extent; +} + +/* This is defined as a macro so that it works for both + * VkImageSubresourceRange and VkImageSubresourceLayers + */ +#define vk_image_subresource_layer_count(_image, _range) \ + ((_range)->layerCount == VK_REMAINING_ARRAY_LAYERS ? \ + (_image)->array_layers - (_range)->baseArrayLayer : (_range)->layerCount) + +static inline uint32_t +vk_image_subresource_level_count(const struct vk_image *image, + const VkImageSubresourceRange *range) +{ + return range->levelCount == VK_REMAINING_MIP_LEVELS ? + image->mip_levels - range->baseMipLevel : range->levelCount; +} + +struct vk_image_view { + struct vk_object_base base; + + VkImageViewCreateFlags create_flags; + struct vk_image *image; + VkImageViewType view_type; + + /** Image view format, relative to the selected aspects + * + * For a depth/stencil image: + * + * - If vk_image_view::aspects contains both depth and stencil, this will + * be the full depth/stencil format of the image. + * + * - If only one aspect is selected, this will be the depth-only or + * stencil-only format, as per the selected aspect. + * + * For color images, we have three cases: + * + * 1. It's a single-plane image in which case this is the unmodified + * format provided to VkImageViewCreateInfo::format. + * + * 2. It's a YCbCr view of a multi-plane image in which case the + * client will have asked for VK_IMAGE_ASPECT_COLOR_BIT and the + * format provided will be the full planar format. In this case, + * the format will be the full format containing all the planes. + * + * 3. It's a single-plane view of a multi-plane image in which case + * the client will have asked for VK_IMAGE_ASPECT_PLANE_N_BIT and + * will have provided a format compatible with that specific + * plane of the multi-planar format. In this case, the format will be + * the plane-compatible format requested by the client. + */ + VkFormat format; + + /* Component mapping, aka swizzle + * + * Unlike the swizzle provided via VkImageViewCreateInfo::components, this + * will never contain VK_COMPONENT_SWIZZLE_IDENTITY. It will be resolved + * to VK_COMPONENT_SWIZZLE_R/G/B/A, as appropriate. + */ + VkComponentMapping swizzle; + + /** Aspects from the image represented by this view + * + * For depth/stencil images, this is the aspectMask provided by + * VkImageViewCreateinfo::subresourceRange::aspectMask. + * + * For color images, we have three cases: + * + * 1. It's a single-plane image in which case this only aspect is + * VK_IMAGE_ASPECT_COLOR_BIT. + * + * 2. It's a YCbCr view of a multi-plane image in which case the + * client will have asked for VK_IMAGE_ASPECT_COLOR_BIT and the + * format provided will be the full planar format. In this case, + * aspects will be the full set of plane aspects in the image. + * + * 3. It's a single-plane view of a multi-plane image in which case + * the client will have asked for VK_IMAGE_ASPECT_PLANE_N_BIT and + * will have provided a format compatible with that specific + * plane of the multi-planar format. In this case, aspects will be + * VK_IMAGE_ASPECT_PLANE_N_BIT where N is the selected plane. + * + * This seems almost backwards from the API but ensures that + * vk_image_view::aspects is always a subset of vk_image::aspects. + */ + VkImageAspectFlags aspects; + + uint32_t base_mip_level; + uint32_t level_count; + uint32_t base_array_layer; + uint32_t layer_count; + + /* Image extent at LOD 0 */ + VkExtent3D extent; + + /* VK_KHR_maintenance2 */ + VkImageUsageFlags usage; +}; + +void vk_image_view_init(struct vk_device *device, + struct vk_image_view *image_view, + const VkImageViewCreateInfo *pCreateInfo); +void vk_image_view_finish(struct vk_image_view *image_view); + +void *vk_image_view_create(struct vk_device *device, + const VkImageViewCreateInfo *pCreateInfo, + const VkAllocationCallbacks *alloc, + size_t size); +void vk_image_view_destroy(struct vk_device *device, + const VkAllocationCallbacks *alloc, + struct vk_image_view *image_view); + +bool vk_image_layout_is_read_only(VkImageLayout layout, + VkImageAspectFlagBits aspect); +VkImageUsageFlags vk_image_layout_to_usage_flags(VkImageLayout layout, + VkImageAspectFlagBits aspect); + +#ifdef __cplusplus +} +#endif + +#endif /* VK_IMAGE_H */ diff --git a/lib/mesa/src/vulkan/util/vk_instance.c b/lib/mesa/src/vulkan/util/vk_instance.c index 5787be170..931071509 100644 --- a/lib/mesa/src/vulkan/util/vk_instance.c +++ b/lib/mesa/src/vulkan/util/vk_instance.c @@ -25,7 +25,9 @@ #include "vk_alloc.h" #include "vk_common_entrypoints.h" +#include "vk_log.h" #include "vk_util.h" +#include "vk_debug_utils.h" #include "compiler/glsl_types.h" @@ -40,6 +42,38 @@ vk_instance_init(struct vk_instance *instance, vk_object_base_init(NULL, &instance->base, VK_OBJECT_TYPE_INSTANCE); instance->alloc = *alloc; + /* VK_EXT_debug_utils */ + /* These messengers will only be used during vkCreateInstance or + * vkDestroyInstance calls. We do this first so that it's safe to use + * vk_errorf and friends. + */ + list_inithead(&instance->debug_utils.instance_callbacks); + vk_foreach_struct_const(ext, pCreateInfo->pNext) { + if (ext->sType == + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { + const VkDebugUtilsMessengerCreateInfoEXT *debugMessengerCreateInfo = + (const VkDebugUtilsMessengerCreateInfoEXT *)ext; + struct vk_debug_utils_messenger *messenger = + vk_alloc2(alloc, alloc, sizeof(struct vk_debug_utils_messenger), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!messenger) + return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + vk_object_base_init(NULL, &messenger->base, + VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT); + + messenger->alloc = *alloc; + messenger->severity = debugMessengerCreateInfo->messageSeverity; + messenger->type = debugMessengerCreateInfo->messageType; + messenger->callback = debugMessengerCreateInfo->pfnUserCallback; + messenger->data = debugMessengerCreateInfo->pUserData; + + list_addtail(&messenger->link, + &instance->debug_utils.instance_callbacks); + } + } + instance->app_info = (struct vk_app_info) { .api_version = 0 }; if (pCreateInfo->pApplicationInfo) { const VkApplicationInfo *app = pCreateInfo->pApplicationInfo; @@ -69,14 +103,20 @@ vk_instance_init(struct vk_instance *instance, } if (idx >= VK_INSTANCE_EXTENSION_COUNT) - return VK_ERROR_EXTENSION_NOT_PRESENT; + return vk_errorf(instance, VK_ERROR_EXTENSION_NOT_PRESENT, + "%s not supported", + pCreateInfo->ppEnabledExtensionNames[i]); if (!supported_extensions->extensions[idx]) - return VK_ERROR_EXTENSION_NOT_PRESENT; + return vk_errorf(instance, VK_ERROR_EXTENSION_NOT_PRESENT, + "%s not supported", + pCreateInfo->ppEnabledExtensionNames[i]); #ifdef ANDROID if (!vk_android_allowed_instance_extensions.extensions[idx]) - return VK_ERROR_EXTENSION_NOT_PRESENT; + return vk_errorf(instance, VK_ERROR_EXTENSION_NOT_PRESENT, + "%s not supported", + pCreateInfo->ppEnabledExtensionNames[i]); #endif instance->enabled_extensions.extensions[idx] = true; @@ -89,10 +129,17 @@ vk_instance_init(struct vk_instance *instance, &instance->dispatch_table, &vk_common_instance_entrypoints, false); if (mtx_init(&instance->debug_report.callbacks_mutex, mtx_plain) != 0) - return VK_ERROR_INITIALIZATION_FAILED; + return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED); list_inithead(&instance->debug_report.callbacks); + if (mtx_init(&instance->debug_utils.callbacks_mutex, mtx_plain) != 0) { + mtx_destroy(&instance->debug_report.callbacks_mutex); + return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED); + } + + list_inithead(&instance->debug_utils.callbacks); + glsl_type_singleton_init_or_ref(); return VK_SUCCESS; @@ -102,7 +149,25 @@ void vk_instance_finish(struct vk_instance *instance) { glsl_type_singleton_decref(); + if (unlikely(!list_is_empty(&instance->debug_utils.callbacks))) { + list_for_each_entry_safe(struct vk_debug_utils_messenger, messenger, + &instance->debug_utils.callbacks, link) { + list_del(&messenger->link); + vk_object_base_finish(&messenger->base); + vk_free2(&instance->alloc, &messenger->alloc, messenger); + } + } + if (unlikely(!list_is_empty(&instance->debug_utils.instance_callbacks))) { + list_for_each_entry_safe(struct vk_debug_utils_messenger, messenger, + &instance->debug_utils.instance_callbacks, + link) { + list_del(&messenger->link); + vk_object_base_finish(&messenger->base); + vk_free2(&instance->alloc, &messenger->alloc, messenger); + } + } mtx_destroy(&instance->debug_report.callbacks_mutex); + mtx_destroy(&instance->debug_utils.callbacks_mutex); vk_free(&instance->alloc, (char *)instance->app_info.app_name); vk_free(&instance->alloc, (char *)instance->app_info.engine_name); vk_object_base_finish(&instance->base); diff --git a/lib/mesa/src/vulkan/util/vk_instance.h b/lib/mesa/src/vulkan/util/vk_instance.h index 5f195ca0d..88af1a6b4 100644 --- a/lib/mesa/src/vulkan/util/vk_instance.h +++ b/lib/mesa/src/vulkan/util/vk_instance.h @@ -56,6 +56,17 @@ struct vk_instance { mtx_t callbacks_mutex; struct list_head callbacks; } debug_report; + + /* VK_EXT_debug_utils */ + struct { + /* These callbacks are only used while creating or destroying an + * instance + */ + struct list_head instance_callbacks; + mtx_t callbacks_mutex; + /* Persistent callbacks */ + struct list_head callbacks; + } debug_utils; }; VK_DEFINE_HANDLE_CASTS(vk_instance, base, VkInstance, diff --git a/lib/mesa/src/vulkan/util/vk_log.c b/lib/mesa/src/vulkan/util/vk_log.c new file mode 100644 index 000000000..b085b369f --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_log.c @@ -0,0 +1,339 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_log.h" +#include "vk_debug_utils.h" +#include "vk_debug_report.h" + +#include "vk_command_buffer.h" +#include "vk_enum_to_str.h" +#include "vk_queue.h" +#include "vk_device.h" +#include "vk_physical_device.h" + +#include "ralloc.h" + +#include "log.h" + +static struct vk_device * +vk_object_to_device(struct vk_object_base *obj) +{ + assert(obj->device); + return obj->device; +} + +static struct vk_physical_device * +vk_object_to_physical_device(struct vk_object_base *obj) +{ + switch (obj->type) { + case VK_OBJECT_TYPE_INSTANCE: + unreachable("Unsupported object type"); + case VK_OBJECT_TYPE_PHYSICAL_DEVICE: + return container_of(obj, struct vk_physical_device, base); + case VK_OBJECT_TYPE_SURFACE_KHR: + case VK_OBJECT_TYPE_DISPLAY_KHR: + case VK_OBJECT_TYPE_DISPLAY_MODE_KHR: + case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT: + case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: + unreachable("Unsupported object type"); + default: + return vk_object_to_device(obj)->physical; + } +} + +static struct vk_instance * +vk_object_to_instance(struct vk_object_base *obj) +{ + if (obj == NULL) + return NULL; + + if (obj->type == VK_OBJECT_TYPE_INSTANCE) { + return container_of(obj, struct vk_instance, base); + } else { + return vk_object_to_physical_device(obj)->instance; + } +} + +void +__vk_log_impl(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + int object_count, + const void **objects_or_instance, + const char *file, + int line, + const char *format, + ...) +{ + struct vk_instance *instance = NULL; + struct vk_object_base **objects = NULL; + if (object_count == 0) { + instance = (struct vk_instance *) objects_or_instance; + } else { + objects = (struct vk_object_base **) objects_or_instance; + instance = vk_object_to_instance(objects[0]); + assert(instance->base.client_visible); + } + +#ifndef DEBUG + if (unlikely(!instance) || + (likely(list_is_empty(&instance->debug_utils.callbacks)) && + likely(list_is_empty(&instance->debug_report.callbacks)))) + return; +#endif + + va_list va; + char *message = NULL; + + va_start(va, format); + message = ralloc_vasprintf(NULL, format, va); + va_end(va); + + char *message_idname = ralloc_asprintf(NULL, "%s:%d", file, line); + +#if DEBUG + switch (severity) { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + mesa_logd("%s: %s", message_idname, message); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + mesa_logi("%s: %s", message_idname, message); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + if (types & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) + mesa_logw("%s: PERF: %s", message_idname, message); + else + mesa_logw("%s: %s", message_idname, message); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + mesa_loge("%s: %s", message_idname, message); + break; + default: + unreachable("Invalid debug message severity"); + break; + } + + if (!instance) { + ralloc_free(message); + ralloc_free(message_idname); + return; + } +#endif + + if (!instance->base.client_visible) { + vk_debug_message_instance(instance, severity, types, + message_idname, 0, message); + ralloc_free(message); + ralloc_free(message_idname); + return; + } + + /* If VK_EXT_debug_utils messengers have been set up, form the + * message */ + if (!list_is_empty(&instance->debug_utils.callbacks)) { + VkDebugUtilsMessengerCallbackDataEXT cb_data = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT, + .pMessageIdName = message_idname, + .messageIdNumber = 0, + .pMessage = message, + }; + + VkDebugUtilsObjectNameInfoEXT *object_name_infos = + ralloc_array(NULL, VkDebugUtilsObjectNameInfoEXT, object_count); + + ASSERTED int cmdbuf_n = 0, queue_n = 0; + for (int i = 0; i < object_count; i++) { + struct vk_object_base *base = objects[i]; + assert(base->client_visible); + + switch (base->type) { + case VK_OBJECT_TYPE_COMMAND_BUFFER: { + /* We allow at most one command buffer to be submitted at a time */ + assert(++cmdbuf_n <= 1); + struct vk_command_buffer *cmd_buffer = + (struct vk_command_buffer *)base; + if (cmd_buffer->labels.size > 0) { + cb_data.cmdBufLabelCount = util_dynarray_num_elements( + &cmd_buffer->labels, VkDebugUtilsLabelEXT); + cb_data.pCmdBufLabels = cmd_buffer->labels.data; + } + break; + } + + case VK_OBJECT_TYPE_QUEUE: { + /* We allow at most one queue to be submitted at a time */ + assert(++queue_n <= 1); + struct vk_queue *queue = (struct vk_queue *)base; + if (queue->labels.size > 0) { + cb_data.queueLabelCount = + util_dynarray_num_elements(&queue->labels, VkDebugUtilsLabelEXT); + cb_data.pQueueLabels = queue->labels.data; + } + break; + } + default: + break; + } + + object_name_infos[i] = (VkDebugUtilsObjectNameInfoEXT){ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = NULL, + .objectType = base->type, + .objectHandle = (uint64_t)(uintptr_t)base, + .pObjectName = base->object_name, + }; + } + cb_data.objectCount = object_count; + cb_data.pObjects = object_name_infos; + + vk_debug_message(instance, severity, types, &cb_data); + + ralloc_free(object_name_infos); + } + + /* If VK_EXT_debug_report callbacks also have been set up, forward + * the message there as well */ + if (!list_is_empty(&instance->debug_report.callbacks)) { + VkDebugReportFlagsEXT flags = 0; + + switch (severity) { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + if (types & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) + flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + else + flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT; + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT; + break; + default: + unreachable("Invalid debug message severity"); + break; + } + + /* VK_EXT_debug_report-provided callback accepts only one object + * related to the message. Since they are given to us in + * decreasing order of importance, we're forwarding the first + * one. + */ + vk_debug_report(instance, flags, object_count ? objects[0] : NULL, 0, + 0, message_idname, message); + } + + ralloc_free(message); + ralloc_free(message_idname); +} + +static struct vk_object_base * +vk_object_for_error(struct vk_object_base *obj, VkResult error) +{ + if (obj == NULL) + return NULL; + + switch (error) { + case VK_ERROR_OUT_OF_HOST_MEMORY: + case VK_ERROR_LAYER_NOT_PRESENT: + case VK_ERROR_EXTENSION_NOT_PRESENT: + case VK_ERROR_UNKNOWN: + return &vk_object_to_instance(obj)->base; + case VK_ERROR_FEATURE_NOT_PRESENT: + return &vk_object_to_physical_device(obj)->base; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + case VK_ERROR_MEMORY_MAP_FAILED: + case VK_ERROR_TOO_MANY_OBJECTS: + return &vk_object_to_device(obj)->base; + default: + return obj; + } +} + +VkResult +__vk_errorv(const void *_obj, VkResult error, + const char *file, int line, + const char *format, va_list va) +{ + struct vk_object_base *object = (struct vk_object_base *)_obj; + struct vk_instance *instance = vk_object_to_instance(object); + object = vk_object_for_error(object, error); + + /* If object->client_visible isn't set then the object hasn't been fully + * constructed and we shouldn't hand it back to the client. This typically + * happens if an error is thrown during object construction. This is safe + * to do as long as vk_object_base_init() has already been called. + */ + if (object && !object->client_visible) + object = NULL; + + const char *error_str = vk_Result_to_str(error); + + if (format) { + char *message = ralloc_vasprintf(NULL, format, va); + + if (object) { + __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, + VK_LOG_OBJS(object), file, line, + "%s (%s)", message, error_str); + } else { + __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, + VK_LOG_NO_OBJS(instance), file, line, + "%s (%s)", message, error_str); + } + + ralloc_free(message); + } else { + if (object) { + __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, + VK_LOG_OBJS(object), file, line, + "%s", error_str); + } else { + __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, + VK_LOG_NO_OBJS(instance), file, line, + "%s", error_str); + } + } + + return error; +} + +VkResult +__vk_errorf(const void *_obj, VkResult error, + const char *file, int line, + const char *format, ...) +{ + va_list va; + + va_start(va, format); + VkResult result = __vk_errorv(_obj, error, file, line, format, va); + va_end(va); + + return result; +} diff --git a/lib/mesa/src/vulkan/util/vk_log.h b/lib/mesa/src/vulkan/util/vk_log.h new file mode 100644 index 000000000..3f6a127e4 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_log.h @@ -0,0 +1,89 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_instance.h" + +/* __VK_ARG_N(...) returns the number of arguments provided to it */ +#define __VK_ARG_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N +#define __VK_ARG_N(...) __VK_ARG_SEQ(__VA_ARGS__,8,7,6,5,4,3,2,1,0) + +#define VK_LOG_OBJS(...) \ + __VK_ARG_N(__VA_ARGS__), (const void*[]){__VA_ARGS__} + +#define VK_LOG_NO_OBJS(instance) 0, (const void**)instance + +#define vk_logd(objects_macro, format, ...) \ + __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, \ + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, \ + objects_macro, __FILE__, __LINE__, format, ## __VA_ARGS__) + +#define vk_logi(objects_macro, format, ...) \ + __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, \ + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, \ + objects_macro, __FILE__, __LINE__, format, ## __VA_ARGS__) + +#define vk_logw(objects_macro, format, ...) \ + __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, \ + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, \ + objects_macro, __FILE__, __LINE__, format, ## __VA_ARGS__) + +#define vk_loge(objects_macro, format, ...) \ + __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, \ + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, \ + objects_macro, __FILE__, __LINE__, format, ## __VA_ARGS__) + +#define vk_perf(objects_macro, format, ...) \ + __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, \ + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, \ + objects_macro, __FILE__, __LINE__, format, ## __VA_ARGS__) + +#define __vk_log(severity, type, object_count, \ + objects_or_instance, file, line, format, ...) \ + __vk_log_impl(severity, type, object_count, objects_or_instance, \ + file, line, format, ## __VA_ARGS__) + +void PRINTFLIKE(7, 8) +__vk_log_impl(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT types, + int object_count, + const void **objects_or_instance, + const char *file, + int line, + const char *format, + ...); + +#define vk_error(obj, error) \ + __vk_errorf(obj, error, __FILE__, __LINE__, NULL) + +#define vk_errorf(obj, error, ...) \ + __vk_errorf(obj, error, __FILE__, __LINE__, __VA_ARGS__) + +VkResult +__vk_errorv(const void *_obj, VkResult error, + const char *file, int line, + const char *format, va_list va); + +VkResult PRINTFLIKE(5, 6) +__vk_errorf(const void *_obj, VkResult error, + const char *file, int line, + const char *format, ...); diff --git a/lib/mesa/src/vulkan/util/vk_object.c b/lib/mesa/src/vulkan/util/vk_object.c index af2c72ba9..52dbeaedd 100644 --- a/lib/mesa/src/vulkan/util/vk_object.c +++ b/lib/mesa/src/vulkan/util/vk_object.c @@ -28,35 +28,28 @@ #include "vk_device.h" #include "util/hash_table.h" #include "util/ralloc.h" - -static void -vk_object_base_reinit(struct vk_object_base *base) -{ - base->_loader_data.loaderMagic = ICD_LOADER_MAGIC; - util_sparse_array_init(&base->private_data, sizeof(uint64_t), 8); -} +#include "vk_enum_to_str.h" void vk_object_base_init(struct vk_device *device, struct vk_object_base *base, UNUSED VkObjectType obj_type) { - vk_object_base_reinit(base); + base->_loader_data.loaderMagic = ICD_LOADER_MAGIC; base->type = obj_type; base->device = device; + base->client_visible = false; + base->object_name = NULL; + util_sparse_array_init(&base->private_data, sizeof(uint64_t), 8); } void vk_object_base_finish(struct vk_object_base *base) { util_sparse_array_finish(&base->private_data); -} -void -vk_object_base_reset(struct vk_object_base *base) -{ - vk_object_base_finish(base); - vk_object_base_reinit(base); + if (base->object_name != NULL) + vk_free(&base->device->alloc, base->object_name); } void * @@ -113,12 +106,11 @@ vk_object_multizalloc(struct vk_device *device, const VkAllocationCallbacks *alloc, VkObjectType obj_type) { - void *ptr = vk_multialloc_alloc2(ma, &device->alloc, alloc, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + void *ptr = vk_multialloc_zalloc2(ma, &device->alloc, alloc, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (ptr == NULL) return NULL; - memset(ptr, 0, ma->size); vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type); return ptr; @@ -323,3 +315,18 @@ vk_common_GetPrivateDataEXT(VkDevice _device, objectType, objectHandle, privateDataSlot, pData); } + +const char * +vk_object_base_name(struct vk_object_base *obj) +{ + if (obj->object_name) + return obj->object_name; + + obj->object_name = vk_asprintf(&obj->device->alloc, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE, + "%s(0x%"PRIx64")", + vk_ObjectType_to_ObjectName(obj->type), + (uint64_t)(uintptr_t)obj); + + return obj->object_name; +} diff --git a/lib/mesa/src/vulkan/util/vk_object.h b/lib/mesa/src/vulkan/util/vk_object.h index c9c751ae2..5b968d90f 100644 --- a/lib/mesa/src/vulkan/util/vk_object.h +++ b/lib/mesa/src/vulkan/util/vk_object.h @@ -44,15 +44,20 @@ struct vk_object_base { struct vk_device *device; + /* True if this object is fully constructed and visible to the client */ + bool client_visible; + /* For VK_EXT_private_data */ struct util_sparse_array private_data; + + /* VK_EXT_debug_utils */ + char *object_name; }; void vk_object_base_init(UNUSED struct vk_device *device, struct vk_object_base *base, UNUSED VkObjectType obj_type); void vk_object_base_finish(UNUSED struct vk_object_base *base); -void vk_object_base_reset(struct vk_object_base *base); static inline void vk_object_base_assert_valid(ASSERTED struct vk_object_base *base, @@ -83,6 +88,8 @@ vk_object_base_from_u64_handle(uint64_t handle, VkObjectType obj_type) __driver_type ## _to_handle(struct __driver_type *_obj) \ { \ vk_object_base_assert_valid(&_obj->__base, __VK_TYPE); \ + if (_obj != NULL) \ + _obj->__base.client_visible = true; \ return (__VkType) _obj; \ } @@ -101,6 +108,8 @@ vk_object_base_from_u64_handle(uint64_t handle, VkObjectType obj_type) __driver_type ## _to_handle(struct __driver_type *_obj) \ { \ vk_object_base_assert_valid(&_obj->__base, __VK_TYPE); \ + if (_obj != NULL) \ + _obj->__base.client_visible = true; \ return (__VkType)(uintptr_t) _obj; \ } @@ -170,6 +179,9 @@ vk_object_base_get_private_data(struct vk_device *device, VkPrivateDataSlotEXT privateDataSlot, uint64_t *pData); +const char * +vk_object_base_name(struct vk_object_base *obj); + #ifdef __cplusplus } #endif diff --git a/lib/mesa/src/vulkan/util/vk_physical_device.c b/lib/mesa/src/vulkan/util/vk_physical_device.c index 18cab2e87..e6504c88e 100644 --- a/lib/mesa/src/vulkan/util/vk_physical_device.c +++ b/lib/mesa/src/vulkan/util/vk_physical_device.c @@ -139,7 +139,21 @@ vk_common_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, pdevice->dispatch_table.GetPhysicalDeviceMemoryProperties2(physicalDevice, &props2); - *pMemoryProperties = props2.memoryProperties; + /* dEQP-VK.api.info.get_physical_device_properties2.memory_properties memsets + * the struct to 0xcd and expects that the unused array elements are + * untouched. + */ + pMemoryProperties->memoryHeapCount = props2.memoryProperties.memoryHeapCount; + for (int i = 0; i < pMemoryProperties->memoryHeapCount; i++) { + pMemoryProperties->memoryHeaps[i].flags = props2.memoryProperties.memoryHeaps[i].flags; + pMemoryProperties->memoryHeaps[i].size = props2.memoryProperties.memoryHeaps[i].size; + } + + pMemoryProperties->memoryTypeCount = props2.memoryProperties.memoryTypeCount; + for (int i = 0; i < pMemoryProperties->memoryTypeCount; i++) { + pMemoryProperties->memoryTypes[i].heapIndex = props2.memoryProperties.memoryTypes[i].heapIndex; + pMemoryProperties->memoryTypes[i].propertyFlags = props2.memoryProperties.memoryTypes[i].propertyFlags; + } } VKAPI_ATTR void VKAPI_CALL @@ -191,3 +205,50 @@ vk_common_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice return result; } + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + uint32_t samples, + VkImageUsageFlags usage, + VkImageTiling tiling, + uint32_t *pNumProperties, + VkSparseImageFormatProperties *pProperties) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + + VkPhysicalDeviceSparseImageFormatInfo2 info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, + .format = format, + .type = type, + .samples = samples, + .usage = usage, + .tiling = tiling + }; + + if (!pProperties) { + pdevice->dispatch_table.GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, + &info, + pNumProperties, + NULL); + return; + } + + STACK_ARRAY(VkSparseImageFormatProperties2, props2, *pNumProperties); + + for (unsigned i = 0; i < *pNumProperties; ++i) { + props2[i].sType = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2; + props2[i].pNext = NULL; + } + + pdevice->dispatch_table.GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, + &info, + pNumProperties, + props2); + + for (unsigned i = 0; i < *pNumProperties; ++i) + pProperties[i] = props2[i].properties; + + STACK_ARRAY_FINISH(props2); +} diff --git a/lib/mesa/src/vulkan/util/vk_physical_device.h b/lib/mesa/src/vulkan/util/vk_physical_device.h index fea39ae9d..e66d86882 100644 --- a/lib/mesa/src/vulkan/util/vk_physical_device.h +++ b/lib/mesa/src/vulkan/util/vk_physical_device.h @@ -31,6 +31,8 @@ extern "C" { #endif +struct wsi_device; + struct vk_physical_device { struct vk_object_base base; struct vk_instance *instance; @@ -38,6 +40,8 @@ struct vk_physical_device { struct vk_device_extension_table supported_extensions; struct vk_physical_device_dispatch_table dispatch_table; + + struct wsi_device *wsi_device; }; VK_DEFINE_HANDLE_CASTS(vk_physical_device, base, VkPhysicalDevice, @@ -52,6 +56,10 @@ vk_physical_device_init(struct vk_physical_device *physical_device, void vk_physical_device_finish(struct vk_physical_device *physical_device); +VkResult +vk_physical_device_check_device_features(struct vk_physical_device *physical_device, + const VkDeviceCreateInfo *pCreateInfo); + #ifdef __cplusplus } #endif diff --git a/lib/mesa/src/vulkan/util/vk_physical_device_features.py b/lib/mesa/src/vulkan/util/vk_physical_device_features.py new file mode 100644 index 000000000..b9665e564 --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_physical_device_features.py @@ -0,0 +1,250 @@ +# coding=utf-8 +COPYRIGHT=u""" +/* Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +""" + +import argparse +import os +from collections import OrderedDict, namedtuple +import xml.etree.ElementTree as et + +from mako.template import Template + +TEMPLATE_C = Template(COPYRIGHT + """ +/* This file generated from ${filename}, don't edit directly. */ + +#include "vk_log.h" +#include "vk_physical_device.h" +#include "vk_util.h" + +static VkResult +check_physical_device_features(struct vk_physical_device *physical_device, + const VkPhysicalDeviceFeatures *supported, + const VkPhysicalDeviceFeatures *enabled, + const char *struct_name) +{ +% for flag in pdev_features: + if (enabled->${flag} && !supported->${flag}) + return vk_errorf(physical_device, VK_ERROR_FEATURE_NOT_PRESENT, + "%s.%s not supported", struct_name, "${flag}"); +% endfor + + return VK_SUCCESS; +} + +VkResult +vk_physical_device_check_device_features(struct vk_physical_device *physical_device, + const VkDeviceCreateInfo *pCreateInfo) +{ + VkPhysicalDevice vk_physical_device = + vk_physical_device_to_handle(physical_device); + + /* Query the device what kind of features are supported. */ + VkPhysicalDeviceFeatures2 supported_features2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + }; + +% for f in features: + ${f.name} supported_${f.name} = { .pNext = NULL }; +% endfor + + vk_foreach_struct_const(feat, pCreateInfo->pNext) { + VkBaseOutStructure *supported = NULL; + switch (feat->sType) { +% for f in features: + case ${f.vk_type}: + supported = (VkBaseOutStructure *) &supported_${f.name}; + break; +% endfor + default: + break; + } + + /* Not a feature struct. */ + if (!supported) + continue; + + /* Check for cycles in the list */ + if (supported->pNext != NULL || supported->sType != 0) + return VK_ERROR_UNKNOWN; + + supported->sType = feat->sType; + __vk_append_struct(&supported_features2, supported); + } + + physical_device->dispatch_table.GetPhysicalDeviceFeatures2( + vk_physical_device, &supported_features2); + + if (pCreateInfo->pEnabledFeatures) { + VkResult result = + check_physical_device_features(physical_device, + &supported_features2.features, + pCreateInfo->pEnabledFeatures, + "VkPhysicalDeviceFeatures"); + if (result != VK_SUCCESS) + return result; + } + + /* Iterate through additional feature structs */ + vk_foreach_struct_const(feat, pCreateInfo->pNext) { + /* Check each feature boolean for given structure. */ + switch (feat->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: { + const VkPhysicalDeviceFeatures2 *features2 = (const void *)feat; + VkResult result = + check_physical_device_features(physical_device, + &supported_features2.features, + &features2->features, + "VkPhysicalDeviceFeatures2.features"); + if (result != VK_SUCCESS) + return result; + break; + } +% for f in features: + case ${f.vk_type} : { + ${f.name} *a = &supported_${f.name}; + ${f.name} *b = (${f.name} *) feat; +% for flag in f.vk_flags: + if (b->${flag} && !a->${flag}) + return vk_errorf(physical_device, VK_ERROR_FEATURE_NOT_PRESENT, + "%s.%s not supported", "${f.name}", "${flag}"); +% endfor + break; + } +% endfor + default: + break; + } + } // for each extension structure + return VK_SUCCESS; +} + +""", output_encoding='utf-8') + +Feature = namedtuple('Feature', 'name vk_type vk_flags') + +def get_pdev_features(doc): + for _type in doc.findall('./types/type'): + if _type.attrib.get('name') != 'VkPhysicalDeviceFeatures': + continue + + flags = [] + + for p in _type.findall('./member'): + assert p.find('./type').text == 'VkBool32' + flags.append(p.find('./name').text) + + return flags + + return None + +def get_features(doc): + features = OrderedDict() + + provisional_structs = set() + + # we want to ignore struct types that are part of provisional extensions + for _extension in doc.findall('./extensions/extension'): + if _extension.attrib.get('provisional') != 'true': + continue + for p in _extension.findall('./require/type'): + provisional_structs.add(p.attrib.get('name')) + + # parse all struct types where structextends VkPhysicalDeviceFeatures2 + for _type in doc.findall('./types/type'): + if _type.attrib.get('category') != 'struct': + continue + if _type.attrib.get('structextends') != 'VkPhysicalDeviceFeatures2,VkDeviceCreateInfo': + continue + if _type.attrib.get('name') in provisional_structs: + continue + + # find Vulkan structure type + for elem in _type: + if "STRUCTURE_TYPE" in str(elem.attrib): + s_type = elem.attrib.get('values') + + # collect a list of feature flags + flags = [] + + for p in _type.findall('./member'): + m_name = p.find('./name').text + if m_name == 'pNext': + pass + elif m_name == 'sType': + s_type = p.attrib.get('values') + else: + assert p.find('./type').text == 'VkBool32' + flags.append(m_name) + + feat = Feature(name=_type.attrib.get('name'), vk_type=s_type, vk_flags=flags) + features[_type.attrib.get('name')] = feat + + return features.values() + +def get_features_from_xml(xml_files): + pdev_features = None + features = [] + + for filename in xml_files: + doc = et.parse(filename) + features += get_features(doc) + if not pdev_features: + pdev_features = get_pdev_features(doc) + + return pdev_features, features + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--out-c', required=True, help='Output C file.') + parser.add_argument('--xml', + help='Vulkan API XML file.', + required=True, action='append', dest='xml_files') + args = parser.parse_args() + + pdev_features, features = get_features_from_xml(args.xml_files) + + environment = { + 'filename': os.path.basename(__file__), + 'pdev_features': pdev_features, + 'features': features, + } + + try: + with open(args.out_c, 'wb') as f: + f.write(TEMPLATE_C.render(**environment)) + except Exception: + # In the event there's an error, this imports some helpers from mako + # to print a useful stack trace and prints it, then exits with + # status 1, if python is run with debug; otherwise it just raises + # the exception + if __debug__: + import sys + from mako import exceptions + sys.stderr.write(exceptions.text_error_template().render() + '\n') + sys.exit(1) + raise + +if __name__ == '__main__': + main() diff --git a/lib/mesa/src/vulkan/util/vk_queue.c b/lib/mesa/src/vulkan/util/vk_queue.c new file mode 100644 index 000000000..d1c0351ce --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_queue.c @@ -0,0 +1,56 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_queue.h" + +#include "vk_device.h" + +VkResult +vk_queue_init(struct vk_queue *queue, struct vk_device *device, + const VkDeviceQueueCreateInfo *pCreateInfo, + uint32_t index_in_family) +{ + memset(queue, 0, sizeof(*queue)); + vk_object_base_init(device, &queue->base, VK_OBJECT_TYPE_QUEUE); + + list_addtail(&queue->link, &device->queues); + + queue->flags = pCreateInfo->flags; + queue->queue_family_index = pCreateInfo->queueFamilyIndex; + + assert(index_in_family < pCreateInfo->queueCount); + queue->index_in_family = index_in_family; + + util_dynarray_init(&queue->labels, NULL); + queue->region_begin = true; + + return VK_SUCCESS; +} + +void +vk_queue_finish(struct vk_queue *queue) +{ + util_dynarray_fini(&queue->labels); + list_del(&queue->link); + vk_object_base_finish(&queue->base); +} diff --git a/lib/mesa/src/vulkan/util/vk_queue.h b/lib/mesa/src/vulkan/util/vk_queue.h new file mode 100644 index 000000000..1a63b1f9d --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_queue.h @@ -0,0 +1,112 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef VK_QUEUE_H +#define VK_QUEUE_H + +#include "vk_object.h" + +#include "util/list.h" +#include "util/u_dynarray.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_queue { + struct vk_object_base base; + + /* Link in vk_device::queues */ + struct list_head link; + + /* VkDeviceQueueCreateInfo::flags */ + VkDeviceQueueCreateFlags flags; + + /* VkDeviceQueueCreateInfo::queueFamilyIndex */ + uint32_t queue_family_index; + + /* Which queue this is within the queue family */ + uint32_t index_in_family; + + /** + * VK_EXT_debug_utils + * + * The next two fields represent debug labels storage. + * + * VK_EXT_debug_utils spec requires that upon triggering a debug message + * with a queue attached to it, all "active" labels will also be provided + * to the callback. The spec describes two distinct ways of attaching a + * debug label to the queue: opening a label region and inserting a single + * label. + * + * Label region is active between the corresponding `*BeginDebugUtilsLabel` + * and `*EndDebugUtilsLabel` calls. The spec doesn't mention any limits on + * nestedness of label regions. This implementation assumes that there + * aren't any. + * + * The spec, however, doesn't explain the lifetime of a label submitted by + * an `*InsertDebugUtilsLabel` call. The LunarG whitepaper [1] (pp 12-15) + * provides a more detailed explanation along with some examples. According + * to those, such label remains active until the next `*DebugUtilsLabel` + * call. This means that there can be no more than one such label at a + * time. + * + * \c labels contains all active labels at this point in order of submission + * \c region_begin denotes whether the most recent label opens a new region + * If \t labels is empty \t region_begin must be true. + * + * Anytime we modify labels, we first check for \c region_begin. If it's + * false, it means that the most recent label was submitted by + * `*InsertDebugUtilsLabel` and we need to remove it before doing anything + * else. + * + * See the discussion here: + * https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10318#note_1061317 + * + * [1] https://www.lunarg.com/wp-content/uploads/2018/05/Vulkan-Debug-Utils_05_18_v1.pdf + */ + struct util_dynarray labels; + bool region_begin; +}; + +VK_DEFINE_HANDLE_CASTS(vk_queue, base, VkQueue, VK_OBJECT_TYPE_QUEUE) + +VkResult MUST_CHECK +vk_queue_init(struct vk_queue *queue, struct vk_device *device, + const VkDeviceQueueCreateInfo *pCreateInfo, + uint32_t index_in_family); + +void +vk_queue_finish(struct vk_queue *queue); + +#define vk_foreach_queue(queue, device) \ + list_for_each_entry(struct vk_queue, queue, &(device)->queues, link) + +#define vk_foreach_queue_safe(queue, device) \ + list_for_each_entry_safe(struct vk_queue, queue, &(device)->queues, link) + +#ifdef __cplusplus +} +#endif + +#endif /* VK_QUEUE_H */ diff --git a/lib/mesa/src/vulkan/util/vk_shader_module.h b/lib/mesa/src/vulkan/util/vk_shader_module.h index d4e64dfc3..8140a49d0 100644 --- a/lib/mesa/src/vulkan/util/vk_shader_module.h +++ b/lib/mesa/src/vulkan/util/vk_shader_module.h @@ -46,7 +46,7 @@ VK_DEFINE_NONDISP_HANDLE_CASTS(vk_shader_module, base, VkShaderModule, /* this should only be used for stack-allocated, temporary objects */ #define vk_shader_module_handle_from_nir(_nir) \ - vk_shader_module_to_handle(&(struct vk_shader_module) { \ + ((VkShaderModule)(uintptr_t)&(struct vk_shader_module) { \ .base.type = VK_OBJECT_TYPE_SHADER_MODULE, \ .nir = _nir, \ }) diff --git a/lib/mesa/src/vulkan/util/vk_synchronization2.c b/lib/mesa/src/vulkan/util/vk_synchronization2.c new file mode 100644 index 000000000..0ad796c7b --- /dev/null +++ b/lib/mesa/src/vulkan/util/vk_synchronization2.c @@ -0,0 +1,405 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_alloc.h" +#include "vk_command_buffer.h" +#include "vk_common_entrypoints.h" +#include "vk_device.h" +#include "vk_queue.h" +#include "vk_util.h" +#include "../wsi/wsi_common.h" + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdWriteTimestamp( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query) +{ + VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); + struct vk_device *device = cmd_buffer->base.device; + + device->dispatch_table.CmdWriteTimestamp2KHR(commandBuffer, + (VkPipelineStageFlags2KHR) pipelineStage, + queryPool, + query); +} + +static VkMemoryBarrier2KHR +upgrade_memory_barrier(const VkMemoryBarrier *barrier, + VkPipelineStageFlags2KHR src_stage_mask2, + VkPipelineStageFlags2KHR dst_stage_mask2) +{ + return (VkMemoryBarrier2KHR) { + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR, + .srcStageMask = src_stage_mask2, + .srcAccessMask = (VkAccessFlags2KHR) barrier->srcAccessMask, + .dstStageMask = dst_stage_mask2, + .dstAccessMask = (VkAccessFlags2KHR) barrier->dstAccessMask, + }; +} + +static VkBufferMemoryBarrier2KHR +upgrade_buffer_memory_barrier(const VkBufferMemoryBarrier *barrier, + VkPipelineStageFlags2KHR src_stage_mask2, + VkPipelineStageFlags2KHR dst_stage_mask2) +{ + return (VkBufferMemoryBarrier2KHR) { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR, + .srcStageMask = src_stage_mask2, + .srcAccessMask = (VkAccessFlags2KHR) barrier->srcAccessMask, + .dstStageMask = dst_stage_mask2, + .dstAccessMask = (VkAccessFlags2KHR) barrier->dstAccessMask, + .srcQueueFamilyIndex = barrier->srcQueueFamilyIndex, + .dstQueueFamilyIndex = barrier->dstQueueFamilyIndex, + .buffer = barrier->buffer, + .offset = barrier->offset, + .size = barrier->size, + }; +} + +static VkImageMemoryBarrier2KHR +upgrade_image_memory_barrier(const VkImageMemoryBarrier *barrier, + VkPipelineStageFlags2KHR src_stage_mask2, + VkPipelineStageFlags2KHR dst_stage_mask2) +{ + return (VkImageMemoryBarrier2KHR) { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR, + .srcStageMask = src_stage_mask2, + .srcAccessMask = (VkAccessFlags2KHR) barrier->srcAccessMask, + .dstStageMask = dst_stage_mask2, + .dstAccessMask = (VkAccessFlags2KHR) barrier->dstAccessMask, + .oldLayout = barrier->oldLayout, + .newLayout = barrier->newLayout, + .srcQueueFamilyIndex = barrier->srcQueueFamilyIndex, + .dstQueueFamilyIndex = barrier->dstQueueFamilyIndex, + .image = barrier->image, + .subresourceRange = barrier->subresourceRange, + }; +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdPipelineBarrier( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers) +{ + VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); + struct vk_device *device = cmd_buffer->base.device; + + STACK_ARRAY(VkMemoryBarrier2KHR, memory_barriers, memoryBarrierCount); + STACK_ARRAY(VkBufferMemoryBarrier2KHR, buffer_barriers, bufferMemoryBarrierCount); + STACK_ARRAY(VkImageMemoryBarrier2KHR, image_barriers, imageMemoryBarrierCount); + + VkPipelineStageFlags2KHR src_stage_mask2 = (VkPipelineStageFlags2KHR) srcStageMask; + VkPipelineStageFlags2KHR dst_stage_mask2 = (VkPipelineStageFlags2KHR) dstStageMask; + + for (uint32_t i = 0; i < memoryBarrierCount; i++) { + memory_barriers[i] = upgrade_memory_barrier(&pMemoryBarriers[i], + src_stage_mask2, + dst_stage_mask2); + } + for (uint32_t i = 0; i < bufferMemoryBarrierCount; i++) { + buffer_barriers[i] = upgrade_buffer_memory_barrier(&pBufferMemoryBarriers[i], + src_stage_mask2, + dst_stage_mask2); + } + for (uint32_t i = 0; i < imageMemoryBarrierCount; i++) { + image_barriers[i] = upgrade_image_memory_barrier(&pImageMemoryBarriers[i], + src_stage_mask2, + dst_stage_mask2); + } + + VkDependencyInfoKHR dep_info = { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR, + .memoryBarrierCount = memoryBarrierCount, + .pMemoryBarriers = memory_barriers, + .bufferMemoryBarrierCount = bufferMemoryBarrierCount, + .pBufferMemoryBarriers = buffer_barriers, + .imageMemoryBarrierCount = imageMemoryBarrierCount, + .pImageMemoryBarriers = image_barriers, + }; + + device->dispatch_table.CmdPipelineBarrier2KHR(commandBuffer, &dep_info); + + STACK_ARRAY_FINISH(memory_barriers); + STACK_ARRAY_FINISH(buffer_barriers); + STACK_ARRAY_FINISH(image_barriers); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdSetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask) +{ + VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); + struct vk_device *device = cmd_buffer->base.device; + + VkMemoryBarrier2KHR mem_barrier = { + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR, + .srcStageMask = (VkPipelineStageFlags2KHR) stageMask, + .dstStageMask = (VkPipelineStageFlags2KHR) stageMask, + }; + VkDependencyInfoKHR dep_info = { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR, + .memoryBarrierCount = 1, + .pMemoryBarriers = &mem_barrier, + }; + + device->dispatch_table.CmdSetEvent2KHR(commandBuffer, event, &dep_info); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdResetEvent( + VkCommandBuffer commandBuffer, + VkEvent event, + VkPipelineStageFlags stageMask) +{ + VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); + struct vk_device *device = cmd_buffer->base.device; + + device->dispatch_table.CmdResetEvent2KHR(commandBuffer, + event, + (VkPipelineStageFlags2KHR) stageMask); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdWaitEvents( + VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent* pEvents, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags destStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers) +{ + VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); + struct vk_device *device = cmd_buffer->base.device; + + STACK_ARRAY(VkDependencyInfoKHR, deps, eventCount); + + /* Note that dstStageMask and srcStageMask in the CmdWaitEvent2() call + * are the same. This is to match the CmdSetEvent2() call from + * vk_common_CmdSetEvent(). The actual src->dst stage barrier will + * happen as part of the CmdPipelineBarrier() call below. + */ + VkMemoryBarrier2KHR stage_barrier = { + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR, + .srcStageMask = srcStageMask, + .dstStageMask = srcStageMask, + }; + + for (uint32_t i = 0; i < eventCount; i++) { + deps[i] = (VkDependencyInfoKHR) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR, + .memoryBarrierCount = 1, + .pMemoryBarriers = &stage_barrier, + }; + } + device->dispatch_table.CmdWaitEvents2KHR(commandBuffer, eventCount, pEvents, deps); + + STACK_ARRAY_FINISH(deps); + + /* Setting dependency to 0 because : + * + * - For BY_REGION_BIT and VIEW_LOCAL_BIT, events are not allowed inside a + * render pass so these don't apply. + * + * - For DEVICE_GROUP_BIT, we have the following bit of spec text: + * + * "Semaphore and event dependencies are device-local and only + * execute on the one physical device that performs the + * dependency." + */ + const VkDependencyFlags dep_flags = 0; + + device->dispatch_table.CmdPipelineBarrier(commandBuffer, + srcStageMask, destStageMask, + dep_flags, + memoryBarrierCount, pMemoryBarriers, + bufferMemoryBarrierCount, pBufferMemoryBarriers, + imageMemoryBarrierCount, pImageMemoryBarriers); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_CmdWriteBufferMarkerAMD( + VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + uint32_t marker) +{ + VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); + struct vk_device *device = cmd_buffer->base.device; + + device->dispatch_table.CmdWriteBufferMarker2AMD(commandBuffer, + (VkPipelineStageFlags2KHR) pipelineStage, + dstBuffer, + dstOffset, + marker); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_GetQueueCheckpointDataNV( + VkQueue queue, + uint32_t* pCheckpointDataCount, + VkCheckpointDataNV* pCheckpointData) +{ + unreachable("Entrypoint not implemented"); +} + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_QueueSubmit( + VkQueue _queue, + uint32_t submitCount, + const VkSubmitInfo* pSubmits, + VkFence fence) +{ + VK_FROM_HANDLE(vk_queue, queue, _queue); + struct vk_device *device = queue->base.device; + + STACK_ARRAY(VkSubmitInfo2KHR, submit_info_2, submitCount); + STACK_ARRAY(VkPerformanceQuerySubmitInfoKHR, perf_query_submit_info, submitCount); + STACK_ARRAY(struct wsi_memory_signal_submit_info, wsi_mem_submit_info, submitCount); + + uint32_t n_wait_semaphores = 0; + uint32_t n_command_buffers = 0; + uint32_t n_signal_semaphores = 0; + for (uint32_t s = 0; s < submitCount; s++) { + n_wait_semaphores += pSubmits[s].waitSemaphoreCount; + n_command_buffers += pSubmits[s].commandBufferCount; + n_signal_semaphores += pSubmits[s].signalSemaphoreCount; + } + + STACK_ARRAY(VkSemaphoreSubmitInfoKHR, wait_semaphores, n_wait_semaphores); + STACK_ARRAY(VkCommandBufferSubmitInfoKHR, command_buffers, n_command_buffers); + STACK_ARRAY(VkSemaphoreSubmitInfoKHR, signal_semaphores, n_signal_semaphores); + + n_wait_semaphores = 0; + n_command_buffers = 0; + n_signal_semaphores = 0; + + for (uint32_t s = 0; s < submitCount; s++) { + const VkTimelineSemaphoreSubmitInfoKHR *timeline_info = + vk_find_struct_const(pSubmits[s].pNext, + TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR); + const uint64_t *wait_values = + timeline_info && timeline_info->waitSemaphoreValueCount ? + timeline_info->pWaitSemaphoreValues : NULL; + const uint64_t *signal_values = + timeline_info && timeline_info->signalSemaphoreValueCount ? + timeline_info->pSignalSemaphoreValues : NULL; + + const VkDeviceGroupSubmitInfo *group_info = + vk_find_struct_const(pSubmits[s].pNext, DEVICE_GROUP_SUBMIT_INFO); + + for (uint32_t i = 0; i < pSubmits[s].waitSemaphoreCount; i++) { + wait_semaphores[n_wait_semaphores + i] = (VkSemaphoreSubmitInfoKHR) { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR, + .semaphore = pSubmits[s].pWaitSemaphores[i], + .value = wait_values ? wait_values[i] : 0, + .stageMask = pSubmits[s].pWaitDstStageMask[i], + .deviceIndex = group_info ? group_info->pWaitSemaphoreDeviceIndices[i] : 0, + }; + } + for (uint32_t i = 0; i < pSubmits[s].commandBufferCount; i++) { + command_buffers[n_command_buffers + i] = (VkCommandBufferSubmitInfoKHR) { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR, + .commandBuffer = pSubmits[s].pCommandBuffers[i], + .deviceMask = group_info ? group_info->pCommandBufferDeviceMasks[i] : 0, + }; + } + for (uint32_t i = 0; i < pSubmits[s].signalSemaphoreCount; i++) { + signal_semaphores[n_signal_semaphores + i] = (VkSemaphoreSubmitInfoKHR) { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR, + .semaphore = pSubmits[s].pSignalSemaphores[i], + .value = signal_values ? signal_values[i] : 0, + .stageMask = 0, + .deviceIndex = group_info ? group_info->pSignalSemaphoreDeviceIndices[i] : 0, + }; + } + + const VkProtectedSubmitInfo *protected_info = + vk_find_struct_const(pSubmits[s].pNext, PROTECTED_SUBMIT_INFO); + + submit_info_2[s] = (VkSubmitInfo2KHR) { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR, + .flags = ((protected_info && protected_info->protectedSubmit) ? + VK_SUBMIT_PROTECTED_BIT_KHR : 0), + .waitSemaphoreInfoCount = pSubmits[s].waitSemaphoreCount, + .pWaitSemaphoreInfos = &wait_semaphores[n_wait_semaphores], + .commandBufferInfoCount = pSubmits[s].commandBufferCount, + .pCommandBufferInfos = &command_buffers[n_command_buffers], + .signalSemaphoreInfoCount = pSubmits[s].signalSemaphoreCount, + .pSignalSemaphoreInfos = &signal_semaphores[n_signal_semaphores], + }; + + const VkPerformanceQuerySubmitInfoKHR *query_info = + vk_find_struct_const(pSubmits[s].pNext, + PERFORMANCE_QUERY_SUBMIT_INFO_KHR); + if (query_info) { + perf_query_submit_info[s] = *query_info; + perf_query_submit_info[s].pNext = NULL; + __vk_append_struct(&submit_info_2[s], &perf_query_submit_info[s]); + } + + const struct wsi_memory_signal_submit_info *mem_signal_info = + vk_find_struct_const(pSubmits[s].pNext, + WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA); + if (mem_signal_info) { + wsi_mem_submit_info[s] = *mem_signal_info; + wsi_mem_submit_info[s].pNext = NULL; + __vk_append_struct(&submit_info_2[s], &wsi_mem_submit_info[s]); + } + + n_wait_semaphores += pSubmits[s].waitSemaphoreCount; + n_command_buffers += pSubmits[s].commandBufferCount; + n_signal_semaphores += pSubmits[s].signalSemaphoreCount; + } + + VkResult result = device->dispatch_table.QueueSubmit2KHR(_queue, + submitCount, + submit_info_2, + fence); + + STACK_ARRAY_FINISH(wait_semaphores); + STACK_ARRAY_FINISH(command_buffers); + STACK_ARRAY_FINISH(signal_semaphores); + STACK_ARRAY_FINISH(submit_info_2); + STACK_ARRAY_FINISH(perf_query_submit_info); + STACK_ARRAY_FINISH(wsi_mem_submit_info); + + return result; +} |