diff options
Diffstat (limited to 'src')
32 files changed, 9891 insertions, 1 deletions
diff --git a/src/freedreno/meson.build b/src/freedreno/meson.build index a3db4b1622b..3f77b1d933e 100644 --- a/src/freedreno/meson.build +++ b/src/freedreno/meson.build @@ -22,3 +22,7 @@ inc_freedreno = include_directories(['.', './registers']) subdir('drm') subdir('ir3') + +if with_freedreno_vk + subdir('vulkan') +endif diff --git a/src/freedreno/vulkan/Android.mk b/src/freedreno/vulkan/Android.mk new file mode 100644 index 00000000000..f8df7a27f93 --- /dev/null +++ b/src/freedreno/vulkan/Android.mk @@ -0,0 +1,166 @@ +# Copyright © 2018 Advanced Micro Devices, Inc. +# Copyright © 2018 Mauro Rossi [email protected] + +# 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. + +LOCAL_PATH := $(call my-dir) + +# get VULKAN_FILES and VULKAN_GENERATED_FILES +include $(LOCAL_PATH)/Makefile.sources + +# The gallium includes are for the util/u_math.h include from main/macros.h + +TU_COMMON_INCLUDES := \ + $(MESA_TOP)/include \ + $(MESA_TOP)/src/ \ + $(MESA_TOP)/src/vulkan/wsi \ + $(MESA_TOP)/src/vulkan/util \ + $(MESA_TOP)/src/amd \ + $(MESA_TOP)/src/amd/common \ + $(MESA_TOP)/src/compiler \ + $(MESA_TOP)/src/mapi \ + $(MESA_TOP)/src/mesa \ + $(MESA_TOP)/src/mesa/drivers/dri/common \ + $(MESA_TOP)/src/gallium/auxiliary \ + $(MESA_TOP)/src/gallium/include \ + frameworks/native/vulkan/include + +TU_SHARED_LIBRARIES := libdrm_amdgpu + +ifeq ($(filter $(MESA_ANDROID_MAJOR_VERSION), 4 5 6 7),) +TU_SHARED_LIBRARIES += libnativewindow +endif + +# +# libmesa_tu_common +# + +include $(CLEAR_VARS) +LOCAL_MODULE := libmesa_tu_common +LOCAL_MODULE_CLASS := STATIC_LIBRARIES + +intermediates := $(call local-generated-sources-dir) + +LOCAL_SRC_FILES := \ + $(VULKAN_FILES) + +LOCAL_CFLAGS += -DFORCE_BUILD_AMDGPU # instructs LLVM to declare LLVMInitializeAMDGPU* functions + +$(call mesa-build-with-llvm) + +LOCAL_C_INCLUDES := \ + $(TU_COMMON_INCLUDES) \ + $(call generated-sources-dir-for,STATIC_LIBRARIES,libmesa_amd_common,,) \ + $(call generated-sources-dir-for,STATIC_LIBRARIES,libmesa_nir,,)/nir \ + $(call generated-sources-dir-for,STATIC_LIBRARIES,libmesa_tu_common,,) \ + $(call generated-sources-dir-for,STATIC_LIBRARIES,libmesa_vulkan_util,,)/util + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + libmesa_vulkan_util + +LOCAL_GENERATED_SOURCES += $(intermediates)/tu_entrypoints.c +LOCAL_GENERATED_SOURCES += $(intermediates)/tu_entrypoints.h +LOCAL_GENERATED_SOURCES += $(intermediates)/tu_extensions.c +LOCAL_GENERATED_SOURCES += $(intermediates)/tu_extensions.h +LOCAL_GENERATED_SOURCES += $(intermediates)/vk_format_table.c + +TU_ENTRYPOINTS_SCRIPT := $(MESA_TOP)/src/amd/vulkan/tu_entrypoints_gen.py +TU_EXTENSIONS_SCRIPT := $(MESA_TOP)/src/amd/vulkan/tu_extensions.py +VK_FORMAT_TABLE_SCRIPT := $(MESA_TOP)/src/amd/vulkan/vk_format_table.py +VK_FORMAT_PARSE_SCRIPT := $(MESA_TOP)/src/amd/vulkan/vk_format_parse.py + +vulkan_api_xml = $(MESA_TOP)/src/vulkan/registry/vk.xml +vk_format_layout_csv = $(MESA_TOP)/src/amd/vulkan/vk_format_layout.csv + +$(intermediates)/tu_entrypoints.c: $(TU_ENTRYPOINTS_SCRIPT) \ + $(TU_EXTENSIONS_SCRIPT) \ + $(vulkan_api_xml) + @mkdir -p $(dir $@) + $(MESA_PYTHON2) $(TU_ENTRYPOINTS_SCRIPT) \ + --xml $(vulkan_api_xml) \ + --outdir $(dir $@) + +$(intermediates)/tu_entrypoints.h: $(intermediates)/tu_entrypoints.c + +$(intermediates)/tu_extensions.c: $(TU_EXTENSIONS_SCRIPT) $(vulkan_api_xml) + @mkdir -p $(dir $@) + $(MESA_PYTHON2) $(TU_EXTENSIONS_SCRIPT) \ + --xml $(vulkan_api_xml) \ + --out-c $@ \ + --out-h $(addsuffix .h,$(basename $@)) + +$(intermediates)/tu_extensions.h: $(intermediates)/tu_extensions.c + +$(intermediates)/vk_format_table.c: $(VK_FORMAT_TABLE_SCRIPT) \ + $(VK_FORMAT_PARSE_SCRIPT) \ + $(vk_format_layout_csv) + @mkdir -p $(dir $@) + $(MESA_PYTHON2) $(VK_FORMAT_TABLE_SCRIPT) $(vk_format_layout_csv) > $@ + +LOCAL_SHARED_LIBRARIES += $(TU_SHARED_LIBRARIES) + +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(MESA_TOP)/src/amd/vulkan \ + $(intermediates) + +include $(MESA_COMMON_MK) +include $(BUILD_STATIC_LIBRARY) + +# +# libvulkan_radeon +# + +include $(CLEAR_VARS) + +LOCAL_MODULE := vulkan.tu +LOCAL_MODULE_CLASS := SHARED_LIBRARIES +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw + +LOCAL_LDFLAGS += -Wl,--build-id=sha1 + +LOCAL_SRC_FILES := \ + $(VULKAN_ANDROID_FILES) + +LOCAL_CFLAGS += -DFORCE_BUILD_AMDGPU # instructs LLVM to declare LLVMInitializeAMDGPU* functions + +$(call mesa-build-with-llvm) + +LOCAL_C_INCLUDES := \ + $(TU_COMMON_INCLUDES) \ + $(call generated-sources-dir-for,STATIC_LIBRARIES,libmesa_tu_common,,) + +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(MESA_TOP)/src/amd/vulkan \ + $(intermediates) + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + libmesa_util \ + libmesa_nir \ + libmesa_glsl \ + libmesa_compiler \ + libmesa_amdgpu_addrlib \ + libmesa_amd_common \ + libmesa_tu_common + +LOCAL_SHARED_LIBRARIES += $(TU_SHARED_LIBRARIES) libz libsync liblog + +include $(MESA_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) diff --git a/src/freedreno/vulkan/Makefile.am b/src/freedreno/vulkan/Makefile.am new file mode 100644 index 00000000000..0d4739b3f16 --- /dev/null +++ b/src/freedreno/vulkan/Makefile.am @@ -0,0 +1,200 @@ +# Copyright © 2016 Red Hat +# +# 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 Makefile.sources + +noinst_HEADERS = \ + $(top_srcdir)/include/vulkan/vk_platform.h \ + $(top_srcdir)/include/vulkan/vulkan_core.h \ + $(top_srcdir)/include/vulkan/vulkan_wayland.h \ + $(top_srcdir)/include/vulkan/vulkan_xcb.h \ + $(top_srcdir)/include/vulkan/vulkan_xlib.h \ + $(top_srcdir)/include/vulkan/vulkan.h + +lib_LTLIBRARIES = libvulkan_radeon.la + +# The gallium includes are for the util/u_math.h include from main/macros.h + +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/vulkan/wsi \ + -I$(top_builddir)/src/vulkan/util \ + -I$(top_srcdir)/src/vulkan/util \ + -I$(top_srcdir)/src/amd \ + -I$(top_srcdir)/src/amd/common \ + -I$(top_builddir)/src/compiler \ + -I$(top_builddir)/src/compiler/nir \ + -I$(top_srcdir)/src/compiler \ + -I$(top_srcdir)/src/mapi \ + -I$(top_srcdir)/src/mesa \ + -I$(top_srcdir)/src/mesa/drivers/dri/common \ + -I$(top_srcdir)/src/gallium/auxiliary \ + -I$(top_srcdir)/src/gallium/include \ + $(AMDGPU_CFLAGS) \ + $(VALGRIND_CFLAGS) \ + $(DEFINES) + +AM_CFLAGS = \ + $(VISIBILITY_CFLAGS) \ + $(PTHREAD_CFLAGS) \ + $(LLVM_CFLAGS) + +AM_CXXFLAGS = \ + $(VISIBILITY_CXXFLAGS) \ + $(LLVM_CXXFLAGS) + +VULKAN_SOURCES = \ + $(VULKAN_GENERATED_FILES) \ + $(VULKAN_FILES) + +VULKAN_LIB_DEPS = \ + libvulkan_common.la \ + $(top_builddir)/src/vulkan/libvulkan_util.la \ + $(top_builddir)/src/vulkan/libvulkan_wsi.la \ + $(top_builddir)/src/amd/common/libamd_common.la \ + $(top_builddir)/src/amd/addrlib/libamdgpu_addrlib.la \ + $(top_builddir)/src/compiler/nir/libnir.la \ + $(top_builddir)/src/util/libmesautil.la \ + $(LLVM_LIBS) \ + $(LIBELF_LIBS) \ + $(PTHREAD_LIBS) \ + $(AMDGPU_LIBS) \ + $(LIBDRM_LIBS) \ + $(PTHREAD_LIBS) \ + $(DLOPEN_LIBS) \ + -lm + +if HAVE_PLATFORM_DRM +AM_CPPFLAGS += \ + -DVK_USE_PLATFORM_DISPLAY_KHR + +VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES) +endif + +if HAVE_XLIB_LEASE +AM_CPPFLAGS += \ + -DVK_USE_PLATFORM_XLIB_XRANDR_EXT \ + $(XCB_RANDR_CFLAGS) \ + $(XLIB_RANDR_CFLAGS) + +VULKAN_LIB_DEPS += $(XCB_RANDR_LIBS) +endif + +if HAVE_PLATFORM_X11 +AM_CPPFLAGS += \ + $(XCB_DRI3_CFLAGS) \ + -DVK_USE_PLATFORM_XCB_KHR \ + -DVK_USE_PLATFORM_XLIB_KHR + +VULKAN_SOURCES += $(VULKAN_WSI_X11_FILES) + +VULKAN_LIB_DEPS += $(XCB_DRI3_LIBS) +endif + + +if HAVE_PLATFORM_WAYLAND +AM_CPPFLAGS += \ + $(WAYLAND_CLIENT_CFLAGS) \ + -DVK_USE_PLATFORM_WAYLAND_KHR + +VULKAN_SOURCES += $(VULKAN_WSI_WAYLAND_FILES) + +VULKAN_LIB_DEPS += \ + $(WAYLAND_CLIENT_LIBS) +endif + +if HAVE_PLATFORM_ANDROID +AM_CPPFLAGS += $(ANDROID_CPPFLAGS) +AM_CFLAGS += $(ANDROID_CFLAGS) +VULKAN_LIB_DEPS += $(ANDROID_LIBS) +VULKAN_SOURCES += $(VULKAN_ANDROID_FILES) +endif + +noinst_LTLIBRARIES = libvulkan_common.la +libvulkan_common_la_SOURCES = $(VULKAN_SOURCES) + +nodist_EXTRA_libvulkan_radeon_la_SOURCES = dummy.cpp +libvulkan_radeon_la_SOURCES = $(VULKAN_GEM_FILES) + +vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml + +tu_entrypoints.c: tu_entrypoints_gen.py tu_extensions.py $(vulkan_api_xml) + $(MKDIR_GEN) + $(AM_V_GEN)$(PYTHON2) $(srcdir)/tu_entrypoints_gen.py \ + --xml $(vulkan_api_xml) \ + --outdir $(builddir) +tu_entrypoints.h: tu_entrypoints.c + +tu_extensions.c: tu_extensions.py \ + $(vulkan_api_xml) + $(MKDIR_GEN) + $(AM_V_GEN)$(PYTHON2) $(srcdir)/tu_extensions.py \ + --xml $(vulkan_api_xml) \ + --out-c tu_extensions.c \ + --out-h tu_extensions.h +tu_extensions.h: tu_extensions.c + +vk_format_table.c: vk_format_table.py \ + vk_format_parse.py \ + vk_format_layout.csv + $(PYTHON2) $(srcdir)/vk_format_table.py $(srcdir)/vk_format_layout.csv > $@ + +BUILT_SOURCES = $(VULKAN_GENERATED_FILES) +CLEANFILES = $(BUILT_SOURCES) dev_icd.json radeon_icd.@[email protected] +EXTRA_DIST = \ + $(top_srcdir)/include/vulkan/vk_icd.h \ + tu_entrypoints_gen.py \ + tu_extensions.py \ + tu_icd.py \ + vk_format_layout.csv \ + vk_format_parse.py \ + vk_format_table.py \ + meson.build + +libvulkan_radeon_la_LIBADD = $(VULKAN_LIB_DEPS) + +libvulkan_radeon_la_LDFLAGS = \ + -shared \ + -module \ + -no-undefined \ + -avoid-version \ + $(BSYMBOLIC) \ + $(LLVM_LDFLAGS) \ + $(GC_SECTIONS) \ + $(LD_NO_UNDEFINED) + + +icdconfdir = @VULKAN_ICD_INSTALL_DIR@ +icdconf_DATA = radeon_icd.@[email protected] +# The following is used for development purposes, by setting VK_ICD_FILENAMES. +noinst_DATA = dev_icd.json + +dev_icd.json : tu_extensions.py tu_icd.py + $(AM_V_GEN)$(PYTHON2) $(srcdir)/tu_icd.py \ + --lib-path="${abs_top_builddir}/${LIB_DIR}" --out $@ + +radeon_icd.@[email protected] : tu_extensions.py tu_icd.py + $(AM_V_GEN)$(PYTHON2) $(srcdir)/tu_icd.py \ + --lib-path="${libdir}" --out $@ + +include $(top_srcdir)/install-lib-links.mk diff --git a/src/freedreno/vulkan/Makefile.sources b/src/freedreno/vulkan/Makefile.sources new file mode 100644 index 00000000000..8d64ab65e76 --- /dev/null +++ b/src/freedreno/vulkan/Makefile.sources @@ -0,0 +1,93 @@ +# Copyright © 2016 Red Hat +# +# 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. + +TU_WS_AMDGPU_FILES := \ + winsys/amdgpu/tu_amdgpu_bo.c \ + winsys/amdgpu/tu_amdgpu_bo.h \ + winsys/amdgpu/tu_amdgpu_cs.c \ + winsys/amdgpu/tu_amdgpu_cs.h \ + winsys/amdgpu/tu_amdgpu_surface.c \ + winsys/amdgpu/tu_amdgpu_surface.h \ + winsys/amdgpu/tu_amdgpu_winsys.c \ + winsys/amdgpu/tu_amdgpu_winsys.h \ + winsys/amdgpu/tu_amdgpu_winsys_public.h + +VULKAN_FILES := \ + tu_cmd_buffer.c \ + tu_cs.h \ + tu_debug.c \ + tu_debug.h \ + tu_device.c \ + tu_descriptor_set.c \ + tu_descriptor_set.h \ + tu_formats.c \ + tu_image.c \ + tu_meta.c \ + tu_meta.h \ + tu_meta_blit.c \ + tu_meta_blit2d.c \ + tu_meta_buffer.c \ + tu_meta_bufimage.c \ + tu_meta_clear.c \ + tu_meta_copy.c \ + tu_meta_decompress.c \ + tu_meta_fast_clear.c \ + tu_meta_resolve.c \ + tu_meta_resolve_cs.c \ + tu_meta_resolve_fs.c \ + tu_nir_to_llvm.c \ + tu_llvm_helper.cpp \ + tu_pass.c \ + tu_pipeline.c \ + tu_pipeline_cache.c \ + tu_private.h \ + tu_radeon_winsys.h \ + tu_shader.c \ + tu_shader_info.c \ + tu_shader.h \ + tu_shader_helper.h \ + tu_query.c \ + tu_util.c \ + tu_util.h \ + tu_wsi.c \ + si_cmd_buffer.c \ + vk_format.h \ + $(TU_WS_AMDGPU_FILES) + +VULKAN_ANDROID_FILES := \ + tu_android.c + +VULKAN_WSI_WAYLAND_FILES := \ + tu_wsi_wayland.c + +VULKAN_WSI_X11_FILES := \ + tu_wsi_x11.c + +VULKAN_WSI_DISPLAY_FILES := \ + tu_wsi_display.c + +VULKAN_GENERATED_FILES := \ + tu_entrypoints.c \ + tu_entrypoints.h \ + tu_extensions.c \ + tu_extensions.h \ + vk_format_table.c + diff --git a/src/freedreno/vulkan/meson.build b/src/freedreno/vulkan/meson.build new file mode 100644 index 00000000000..b7de6bd5bb8 --- /dev/null +++ b/src/freedreno/vulkan/meson.build @@ -0,0 +1,127 @@ +# Copyright © 2017 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 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. + +tu_entrypoints = custom_target( + 'tu_entrypoints.[ch]', + input : ['tu_entrypoints_gen.py', vk_api_xml], + output : ['tu_entrypoints.h', 'tu_entrypoints.c'], + command : [ + prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--outdir', + meson.current_build_dir() + ], + depend_files : files('tu_extensions.py'), +) + +tu_extensions_c = custom_target( + 'tu_extensions.c', + input : ['tu_extensions.py', vk_api_xml], + output : ['tu_extensions.c', 'tu_extensions.h'], + command : [ + prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--out-c', '@OUTPUT0@', + '--out-h', '@OUTPUT1@' + ], +) + +vk_format_table_c = custom_target( + 'vk_format_table.c', + input : ['vk_format_table.py', 'vk_format_layout.csv'], + output : 'vk_format_table.c', + command : [prog_python, '@INPUT@'], + depend_files : files('vk_format_parse.py'), + capture : true, +) + +libtu_files = files( + 'tu_cmd_buffer.c', + 'tu_device.c', + 'tu_descriptor_set.c', + 'tu_descriptor_set.h', + 'tu_formats.c', + 'tu_image.c', + 'tu_meta_blit.c', + 'tu_meta_buffer.c', + 'tu_meta_clear.c', + 'tu_meta_copy.c', + 'tu_meta_resolve.c', + 'tu_pass.c', + 'tu_pipeline.c', + 'tu_pipeline_cache.c', + 'tu_private.h', + 'tu_query.c', + 'tu_util.c', + 'tu_util.h', + 'vk_format.h', +) + +tu_deps = [] +tu_flags = [] + +libvulkan_freedreno = shared_library( + 'vulkan_freedreno', + [libtu_files, tu_entrypoints, tu_extensions_c, vk_format_table_c], + include_directories : [ + inc_common, inc_compiler, inc_vulkan_util, + ], + link_with : [ + libvulkan_util, + libmesa_util, + ], + dependencies : [ + dep_dl, + dep_elf, + dep_libdrm, + dep_llvm, + dep_m, + dep_thread, + dep_valgrind, + idep_nir, + ], + c_args : [c_vis_args, no_override_init_args, tu_flags], + link_args : [ld_args_bsymbolic, ld_args_gc_sections], + install : true, +) + +freedreno_icd = custom_target( + 'freedreno_icd', + input : 'tu_icd.py', + output : 'freedreno_icd.@[email protected]'.format(host_machine.cpu()), + command : [ + prog_python, '@INPUT@', + '--lib-path', join_paths(get_option('prefix'), get_option('libdir')), + '--out', '@OUTPUT@', + ], + depend_files : files('tu_extensions.py'), + build_by_default : true, + install_dir : with_vulkan_icd_dir, + install : true, +) + +tu_dev_icd = custom_target( + 'tu_dev_icd', + input : 'tu_icd.py', + output : 'dev_icd.json', + command : [ + prog_python, '@INPUT@', '--lib-path', meson.current_build_dir(), + '--out', '@OUTPUT@' + ], + depend_files : files('tu_extensions.py'), + build_by_default : true, + install : false, +) diff --git a/src/freedreno/vulkan/tu_android.c b/src/freedreno/vulkan/tu_android.c new file mode 100644 index 00000000000..fbc1bf84b84 --- /dev/null +++ b/src/freedreno/vulkan/tu_android.c @@ -0,0 +1,390 @@ +/* + * Copyright © 2017, Google Inc. + * + * 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 <hardware/gralloc.h> +#include <hardware/hardware.h> +#include <hardware/hwvulkan.h> +#include <libsync.h> +#include <vulkan/vk_android_native_buffer.h> +#include <vulkan/vk_icd.h> + +#include "tu_private.h" + +static int +tu_hal_open(const struct hw_module_t *mod, + const char *id, + struct hw_device_t **dev); +static int +tu_hal_close(struct hw_device_t *dev); + +static void UNUSED +static_asserts(void) +{ + STATIC_ASSERT(HWVULKAN_DISPATCH_MAGIC == ICD_LOADER_MAGIC); +} + +PUBLIC struct hwvulkan_module_t HAL_MODULE_INFO_SYM = { + .common = + { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = HWVULKAN_MODULE_API_VERSION_0_1, + .hal_api_version = HARDWARE_MAKE_API_VERSION(1, 0), + .id = HWVULKAN_HARDWARE_MODULE_ID, + .name = "AMD Vulkan HAL", + .author = "Google", + .methods = + &(hw_module_methods_t){ + .open = tu_hal_open, + }, + }, +}; + +/* If any bits in test_mask are set, then unset them and return true. */ +static inline bool +unmask32(uint32_t *inout_mask, uint32_t test_mask) +{ + uint32_t orig_mask = *inout_mask; + *inout_mask &= ~test_mask; + return *inout_mask != orig_mask; +} + +static int +tu_hal_open(const struct hw_module_t *mod, + const char *id, + struct hw_device_t **dev) +{ + assert(mod == &HAL_MODULE_INFO_SYM.common); + assert(strcmp(id, HWVULKAN_DEVICE_0) == 0); + + hwvulkan_device_t *hal_dev = malloc(sizeof(*hal_dev)); + if (!hal_dev) + return -1; + + *hal_dev = (hwvulkan_device_t){ + .common = + { + .tag = HARDWARE_DEVICE_TAG, + .version = HWVULKAN_DEVICE_API_VERSION_0_1, + .module = &HAL_MODULE_INFO_SYM.common, + .close = tu_hal_close, + }, + .EnumerateInstanceExtensionProperties = + tu_EnumerateInstanceExtensionProperties, + .CreateInstance = tu_CreateInstance, + .GetInstanceProcAddr = tu_GetInstanceProcAddr, + }; + + *dev = &hal_dev->common; + return 0; +} + +static int +tu_hal_close(struct hw_device_t *dev) +{ + /* hwvulkan.h claims that hw_device_t::close() is never called. */ + return -1; +} + +VkResult +tu_image_from_gralloc(VkDevice device_h, + const VkImageCreateInfo *base_info, + const VkNativeBufferANDROID *gralloc_info, + const VkAllocationCallbacks *alloc, + VkImage *out_image_h) + +{ + TU_FROM_HANDLE(tu_device, device, device_h); + VkImage image_h = VK_NULL_HANDLE; + struct tu_image *image = NULL; + struct tu_bo *bo = NULL; + VkResult result; + + result = tu_image_create( + device_h, + &(struct tu_image_create_info){ + .vk_info = base_info, .scanout = true, .no_metadata_planes = true }, + alloc, + &image_h); + + if (result != VK_SUCCESS) + return result; + + if (gralloc_info->handle->numFds != 1) { + return vk_errorf(device->instance, + VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR, + "VkNativeBufferANDROID::handle::numFds is %d, " + "expected 1", + gralloc_info->handle->numFds); + } + + /* Do not close the gralloc handle's dma_buf. The lifetime of the dma_buf + * must exceed that of the gralloc handle, and we do not own the gralloc + * handle. + */ + int dma_buf = gralloc_info->handle->data[0]; + + image = tu_image_from_handle(image_h); + + VkDeviceMemory memory_h; + + const VkMemoryDedicatedAllocateInfoKHR ded_alloc = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, + .pNext = NULL, + .buffer = VK_NULL_HANDLE, + .image = image_h + }; + + const VkImportMemoryFdInfoKHR import_info = { + .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, + .pNext = &ded_alloc, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR, + .fd = dup(dma_buf), + }; + /* Find the first VRAM memory type, or GART for PRIME images. */ + int memory_type_index = -1; + for (int i = 0; + i < device->physical_device->memory_properties.memoryTypeCount; + ++i) { + bool is_local = + !!(device->physical_device->memory_properties.memoryTypes[i] + .propertyFlags & + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (is_local) { + memory_type_index = i; + break; + } + } + + /* fallback */ + if (memory_type_index == -1) + memory_type_index = 0; + + result = + tu_AllocateMemory(device_h, + &(VkMemoryAllocateInfo){ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &import_info, + .allocationSize = image->size, + .memoryTypeIndex = memory_type_index, + }, + alloc, + &memory_h); + if (result != VK_SUCCESS) + goto fail_create_image; + + tu_BindImageMemory(device_h, image_h, memory_h, 0); + + image->owned_memory = memory_h; + /* Don't clobber the out-parameter until success is certain. */ + *out_image_h = image_h; + + return VK_SUCCESS; + +fail_create_image: +fail_size: + tu_DestroyImage(device_h, image_h, alloc); + + return result; +} + +VkResult +tu_GetSwapchainGrallocUsageANDROID(VkDevice device_h, + VkFormat format, + VkImageUsageFlags imageUsage, + int *grallocUsage) +{ + TU_FROM_HANDLE(tu_device, device, device_h); + struct tu_physical_device *phys_dev = device->physical_device; + VkPhysicalDevice phys_dev_h = tu_physical_device_to_handle(phys_dev); + VkResult result; + + *grallocUsage = 0; + + /* WARNING: Android Nougat's libvulkan.so hardcodes the VkImageUsageFlags + * returned to applications via + * VkSurfaceCapabilitiesKHR::supportedUsageFlags. + * The relevant code in libvulkan/swapchain.cpp contains this fun comment: + * + * TODO(jessehall): I think these are right, but haven't thought hard + * about it. Do we need to query the driver for support of any of + * these? + * + * Any disagreement between this function and the hardcoded + * VkSurfaceCapabilitiesKHR:supportedUsageFlags causes tests + * dEQP-VK.wsi.android.swapchain.*.image_usage to fail. + */ + + const VkPhysicalDeviceImageFormatInfo2KHR image_format_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR, + .format = format, + .type = VK_IMAGE_TYPE_2D, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = imageUsage, + }; + + VkImageFormatProperties2KHR image_format_props = { + .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR, + }; + + /* Check that requested format and usage are supported. */ + result = tu_GetPhysicalDeviceImageFormatProperties2( + phys_dev_h, &image_format_info, &image_format_props); + if (result != VK_SUCCESS) { + return vk_errorf(device->instance, + result, + "tu_GetPhysicalDeviceImageFormatProperties2 failed " + "inside %s", + __func__); + } + + if (unmask32(&imageUsage, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) + *grallocUsage |= GRALLOC_USAGE_HW_RENDER; + + if (unmask32(&imageUsage, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) + *grallocUsage |= GRALLOC_USAGE_HW_TEXTURE; + + /* All VkImageUsageFlags not explicitly checked here are unsupported for + * gralloc swapchains. + */ + if (imageUsage != 0) { + return vk_errorf(device->instance, + VK_ERROR_FORMAT_NOT_SUPPORTED, + "unsupported VkImageUsageFlags(0x%x) for gralloc " + "swapchain", + imageUsage); + } + + /* + * FINISHME: Advertise all display-supported formats. Mostly + * DRM_FORMAT_ARGB2101010 and DRM_FORMAT_ABGR2101010, but need to check + * what we need for 30-bit colors. + */ + if (format == VK_FORMAT_B8G8R8A8_UNORM || + format == VK_FORMAT_B5G6R5_UNORM_PACK16) { + *grallocUsage |= GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_COMPOSER | + GRALLOC_USAGE_EXTERNAL_DISP; + } + + if (*grallocUsage == 0) + return VK_ERROR_FORMAT_NOT_SUPPORTED; + + return VK_SUCCESS; +} + +VkResult +tu_AcquireImageANDROID(VkDevice device, + VkImage image_h, + int nativeFenceFd, + VkSemaphore semaphore, + VkFence fence) +{ + VkResult semaphore_result = VK_SUCCESS, fence_result = VK_SUCCESS; + + if (semaphore != VK_NULL_HANDLE) { + int semaphore_fd = + nativeFenceFd >= 0 ? dup(nativeFenceFd) : nativeFenceFd; + semaphore_result = tu_ImportSemaphoreFdKHR( + device, + &(VkImportSemaphoreFdInfoKHR){ + .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR, + .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR, + .fd = semaphore_fd, + .semaphore = semaphore, + }); + } + + if (fence != VK_NULL_HANDLE) { + int fence_fd = nativeFenceFd >= 0 ? dup(nativeFenceFd) : nativeFenceFd; + fence_result = tu_ImportFenceFdKHR( + device, + &(VkImportFenceFdInfoKHR){ + .sType = VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR, + .flags = VK_FENCE_IMPORT_TEMPORARY_BIT_KHR, + .fd = fence_fd, + .fence = fence, + }); + } + + close(nativeFenceFd); + + if (semaphore_result != VK_SUCCESS) + return semaphore_result; + return fence_result; +} + +VkResult +tu_QueueSignalReleaseImageANDROID(VkQueue _queue, + uint32_t waitSemaphoreCount, + const VkSemaphore *pWaitSemaphores, + VkImage image, + int *pNativeFenceFd) +{ + TU_FROM_HANDLE(tu_queue, queue, _queue); + VkResult result = VK_SUCCESS; + + if (waitSemaphoreCount == 0) { + if (pNativeFenceFd) + *pNativeFenceFd = -1; + return VK_SUCCESS; + } + + int fd = -1; + + for (uint32_t i = 0; i < waitSemaphoreCount; ++i) { + int tmp_fd; + result = tu_GetSemaphoreFdKHR( + tu_device_to_handle(queue->device), + &(VkSemaphoreGetFdInfoKHR){ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR, + .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR, + .semaphore = pWaitSemaphores[i], + }, + &tmp_fd); + if (result != VK_SUCCESS) { + if (fd >= 0) + close(fd); + return result; + } + + if (fd < 0) + fd = tmp_fd; + else if (tmp_fd >= 0) { + sync_accumulate("tu", &fd, tmp_fd); + close(tmp_fd); + } + } + + if (pNativeFenceFd) { + *pNativeFenceFd = fd; + } else if (fd >= 0) { + close(fd); + /* We still need to do the exports, to reset the semaphores, but + * otherwise we don't wait on them. */ + } + return VK_SUCCESS; +} diff --git a/src/freedreno/vulkan/tu_cmd_buffer.c b/src/freedreno/vulkan/tu_cmd_buffer.c new file mode 100644 index 00000000000..030e1112811 --- /dev/null +++ b/src/freedreno/vulkan/tu_cmd_buffer.c @@ -0,0 +1,936 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * based in part on anv driver which is: + * Copyright © 2015 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 "tu_private.h" +#include "vk_format.h" + +const struct tu_dynamic_state default_dynamic_state = { + .viewport = + { + .count = 0, + }, + .scissor = + { + .count = 0, + }, + .line_width = 1.0f, + .depth_bias = + { + .bias = 0.0f, + .clamp = 0.0f, + .slope = 0.0f, + }, + .blend_constants = { 0.0f, 0.0f, 0.0f, 0.0f }, + .depth_bounds = + { + .min = 0.0f, + .max = 1.0f, + }, + .stencil_compare_mask = + { + .front = ~0u, + .back = ~0u, + }, + .stencil_write_mask = + { + .front = ~0u, + .back = ~0u, + }, + .stencil_reference = + { + .front = 0u, + .back = 0u, + }, +}; + +static void +tu_bind_dynamic_state(struct tu_cmd_buffer *cmd_buffer, + const struct tu_dynamic_state *src) +{ + struct tu_dynamic_state *dest = &cmd_buffer->state.dynamic; + uint32_t copy_mask = src->mask; + uint32_t dest_mask = 0; + + /* Make sure to copy the number of viewports/scissors because they can + * only be specified at pipeline creation time. + */ + dest->viewport.count = src->viewport.count; + dest->scissor.count = src->scissor.count; + dest->discard_rectangle.count = src->discard_rectangle.count; + + if (copy_mask & TU_DYNAMIC_VIEWPORT) { + if (memcmp(&dest->viewport.viewports, + &src->viewport.viewports, + src->viewport.count * sizeof(VkViewport))) { + typed_memcpy(dest->viewport.viewports, + src->viewport.viewports, + src->viewport.count); + dest_mask |= TU_DYNAMIC_VIEWPORT; + } + } + + if (copy_mask & TU_DYNAMIC_SCISSOR) { + if (memcmp(&dest->scissor.scissors, + &src->scissor.scissors, + src->scissor.count * sizeof(VkRect2D))) { + typed_memcpy( + dest->scissor.scissors, src->scissor.scissors, src->scissor.count); + dest_mask |= TU_DYNAMIC_SCISSOR; + } + } + + if (copy_mask & TU_DYNAMIC_LINE_WIDTH) { + if (dest->line_width != src->line_width) { + dest->line_width = src->line_width; + dest_mask |= TU_DYNAMIC_LINE_WIDTH; + } + } + + if (copy_mask & TU_DYNAMIC_DEPTH_BIAS) { + if (memcmp( + &dest->depth_bias, &src->depth_bias, sizeof(src->depth_bias))) { + dest->depth_bias = src->depth_bias; + dest_mask |= TU_DYNAMIC_DEPTH_BIAS; + } + } + + if (copy_mask & TU_DYNAMIC_BLEND_CONSTANTS) { + if (memcmp(&dest->blend_constants, + &src->blend_constants, + sizeof(src->blend_constants))) { + typed_memcpy(dest->blend_constants, src->blend_constants, 4); + dest_mask |= TU_DYNAMIC_BLEND_CONSTANTS; + } + } + + if (copy_mask & TU_DYNAMIC_DEPTH_BOUNDS) { + if (memcmp(&dest->depth_bounds, + &src->depth_bounds, + sizeof(src->depth_bounds))) { + dest->depth_bounds = src->depth_bounds; + dest_mask |= TU_DYNAMIC_DEPTH_BOUNDS; + } + } + + if (copy_mask & TU_DYNAMIC_STENCIL_COMPARE_MASK) { + if (memcmp(&dest->stencil_compare_mask, + &src->stencil_compare_mask, + sizeof(src->stencil_compare_mask))) { + dest->stencil_compare_mask = src->stencil_compare_mask; + dest_mask |= TU_DYNAMIC_STENCIL_COMPARE_MASK; + } + } + + if (copy_mask & TU_DYNAMIC_STENCIL_WRITE_MASK) { + if (memcmp(&dest->stencil_write_mask, + &src->stencil_write_mask, + sizeof(src->stencil_write_mask))) { + dest->stencil_write_mask = src->stencil_write_mask; + dest_mask |= TU_DYNAMIC_STENCIL_WRITE_MASK; + } + } + + if (copy_mask & TU_DYNAMIC_STENCIL_REFERENCE) { + if (memcmp(&dest->stencil_reference, + &src->stencil_reference, + sizeof(src->stencil_reference))) { + dest->stencil_reference = src->stencil_reference; + dest_mask |= TU_DYNAMIC_STENCIL_REFERENCE; + } + } + + if (copy_mask & TU_DYNAMIC_DISCARD_RECTANGLE) { + if (memcmp(&dest->discard_rectangle.rectangles, + &src->discard_rectangle.rectangles, + src->discard_rectangle.count * sizeof(VkRect2D))) { + typed_memcpy(dest->discard_rectangle.rectangles, + src->discard_rectangle.rectangles, + src->discard_rectangle.count); + dest_mask |= TU_DYNAMIC_DISCARD_RECTANGLE; + } + } +} + +static VkResult +tu_create_cmd_buffer(struct tu_device *device, + struct tu_cmd_pool *pool, + VkCommandBufferLevel level, + VkCommandBuffer *pCommandBuffer) +{ + struct tu_cmd_buffer *cmd_buffer; + cmd_buffer = vk_zalloc( + &pool->alloc, sizeof(*cmd_buffer), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (cmd_buffer == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + cmd_buffer->_loader_data.loaderMagic = ICD_LOADER_MAGIC; + cmd_buffer->device = device; + cmd_buffer->pool = pool; + cmd_buffer->level = level; + + if (pool) { + list_addtail(&cmd_buffer->pool_link, &pool->cmd_buffers); + cmd_buffer->queue_family_index = pool->queue_family_index; + + } else { + /* Init the pool_link so we can safely call list_del when we destroy + * the command buffer + */ + list_inithead(&cmd_buffer->pool_link); + cmd_buffer->queue_family_index = TU_QUEUE_GENERAL; + } + + *pCommandBuffer = tu_cmd_buffer_to_handle(cmd_buffer); + + list_inithead(&cmd_buffer->upload.list); + + return VK_SUCCESS; +} + +static void +tu_cmd_buffer_destroy(struct tu_cmd_buffer *cmd_buffer) +{ + list_del(&cmd_buffer->pool_link); + + for (unsigned i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; i++) + free(cmd_buffer->descriptors[i].push_set.set.mapped_ptr); + + vk_free(&cmd_buffer->pool->alloc, cmd_buffer); +} + +static VkResult +tu_reset_cmd_buffer(struct tu_cmd_buffer *cmd_buffer) +{ + cmd_buffer->record_result = VK_SUCCESS; + + for (unsigned i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; i++) { + cmd_buffer->descriptors[i].dirty = 0; + cmd_buffer->descriptors[i].valid = 0; + cmd_buffer->descriptors[i].push_dirty = false; + } + + cmd_buffer->status = TU_CMD_BUFFER_STATUS_INITIAL; + + return cmd_buffer->record_result; +} + +VkResult +tu_AllocateCommandBuffers(VkDevice _device, + const VkCommandBufferAllocateInfo *pAllocateInfo, + VkCommandBuffer *pCommandBuffers) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_cmd_pool, pool, pAllocateInfo->commandPool); + + VkResult result = VK_SUCCESS; + uint32_t i; + + for (i = 0; i < pAllocateInfo->commandBufferCount; i++) { + + if (!list_empty(&pool->free_cmd_buffers)) { + struct tu_cmd_buffer *cmd_buffer = list_first_entry( + &pool->free_cmd_buffers, struct tu_cmd_buffer, pool_link); + + list_del(&cmd_buffer->pool_link); + list_addtail(&cmd_buffer->pool_link, &pool->cmd_buffers); + + result = tu_reset_cmd_buffer(cmd_buffer); + cmd_buffer->_loader_data.loaderMagic = ICD_LOADER_MAGIC; + cmd_buffer->level = pAllocateInfo->level; + + pCommandBuffers[i] = tu_cmd_buffer_to_handle(cmd_buffer); + } else { + result = tu_create_cmd_buffer( + device, pool, pAllocateInfo->level, &pCommandBuffers[i]); + } + if (result != VK_SUCCESS) + break; + } + + if (result != VK_SUCCESS) { + tu_FreeCommandBuffers( + _device, pAllocateInfo->commandPool, i, pCommandBuffers); + + /* From the Vulkan 1.0.66 spec: + * + * "vkAllocateCommandBuffers can be used to create multiple + * command buffers. If the creation of any of those command + * buffers fails, the implementation must destroy all + * successfully created command buffer objects from this + * command, set all entries of the pCommandBuffers array to + * NULL and return the error." + */ + memset(pCommandBuffers, + 0, + sizeof(*pCommandBuffers) * pAllocateInfo->commandBufferCount); + } + + return result; +} + +void +tu_FreeCommandBuffers(VkDevice device, + VkCommandPool commandPool, + uint32_t commandBufferCount, + const VkCommandBuffer *pCommandBuffers) +{ + for (uint32_t i = 0; i < commandBufferCount; i++) { + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, pCommandBuffers[i]); + + if (cmd_buffer) { + if (cmd_buffer->pool) { + list_del(&cmd_buffer->pool_link); + list_addtail(&cmd_buffer->pool_link, + &cmd_buffer->pool->free_cmd_buffers); + } else + tu_cmd_buffer_destroy(cmd_buffer); + } + } +} + +VkResult +tu_ResetCommandBuffer(VkCommandBuffer commandBuffer, + VkCommandBufferResetFlags flags) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + return tu_reset_cmd_buffer(cmd_buffer); +} + +VkResult +tu_BeginCommandBuffer(VkCommandBuffer commandBuffer, + const VkCommandBufferBeginInfo *pBeginInfo) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + VkResult result = VK_SUCCESS; + + if (cmd_buffer->status != TU_CMD_BUFFER_STATUS_INITIAL) { + /* If the command buffer has already been resetted with + * vkResetCommandBuffer, no need to do it again. + */ + result = tu_reset_cmd_buffer(cmd_buffer); + if (result != VK_SUCCESS) + return result; + } + + memset(&cmd_buffer->state, 0, sizeof(cmd_buffer->state)); + cmd_buffer->usage_flags = pBeginInfo->flags; + + /* setup initial configuration into command buffer */ + if (cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) { + switch (cmd_buffer->queue_family_index) { + case TU_QUEUE_GENERAL: + /* init */ + break; + default: + break; + } + } + + cmd_buffer->status = TU_CMD_BUFFER_STATUS_RECORDING; + + return result; +} + +void +tu_CmdBindVertexBuffers(VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer *pBuffers, + const VkDeviceSize *pOffsets) +{ +} + +void +tu_CmdBindIndexBuffer(VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType) +{ +} + +void +tu_CmdBindDescriptorSets(VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout _layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet *pDescriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t *pDynamicOffsets) +{ +} + +void +tu_CmdPushConstants(VkCommandBuffer commandBuffer, + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t offset, + uint32_t size, + const void *pValues) +{ +} + +VkResult +tu_EndCommandBuffer(VkCommandBuffer commandBuffer) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + + cmd_buffer->status = TU_CMD_BUFFER_STATUS_EXECUTABLE; + + return cmd_buffer->record_result; +} + +void +tu_CmdBindPipeline(VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipeline _pipeline) +{ +} + +void +tu_CmdSetViewport(VkCommandBuffer commandBuffer, + uint32_t firstViewport, + uint32_t viewportCount, + const VkViewport *pViewports) +{ +} + +void +tu_CmdSetScissor(VkCommandBuffer commandBuffer, + uint32_t firstScissor, + uint32_t scissorCount, + const VkRect2D *pScissors) +{ +} + +void +tu_CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) +{ +} + +void +tu_CmdSetDepthBias(VkCommandBuffer commandBuffer, + float depthBiasConstantFactor, + float depthBiasClamp, + float depthBiasSlopeFactor) +{ +} + +void +tu_CmdSetBlendConstants(VkCommandBuffer commandBuffer, + const float blendConstants[4]) +{ +} + +void +tu_CmdSetDepthBounds(VkCommandBuffer commandBuffer, + float minDepthBounds, + float maxDepthBounds) +{ +} + +void +tu_CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t compareMask) +{ +} + +void +tu_CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t writeMask) +{ +} + +void +tu_CmdSetStencilReference(VkCommandBuffer commandBuffer, + VkStencilFaceFlags faceMask, + uint32_t reference) +{ +} + +void +tu_CmdExecuteCommands(VkCommandBuffer commandBuffer, + uint32_t commandBufferCount, + const VkCommandBuffer *pCmdBuffers) +{ +} + +VkResult +tu_CreateCommandPool(VkDevice _device, + const VkCommandPoolCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkCommandPool *pCmdPool) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_cmd_pool *pool; + + pool = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*pool), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (pool == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + if (pAllocator) + pool->alloc = *pAllocator; + else + pool->alloc = device->alloc; + + list_inithead(&pool->cmd_buffers); + list_inithead(&pool->free_cmd_buffers); + + pool->queue_family_index = pCreateInfo->queueFamilyIndex; + + *pCmdPool = tu_cmd_pool_to_handle(pool); + + return VK_SUCCESS; +} + +void +tu_DestroyCommandPool(VkDevice _device, + VkCommandPool commandPool, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_cmd_pool, pool, commandPool); + + if (!pool) + return; + + list_for_each_entry_safe( + struct tu_cmd_buffer, cmd_buffer, &pool->cmd_buffers, pool_link) + { + tu_cmd_buffer_destroy(cmd_buffer); + } + + list_for_each_entry_safe( + struct tu_cmd_buffer, cmd_buffer, &pool->free_cmd_buffers, pool_link) + { + tu_cmd_buffer_destroy(cmd_buffer); + } + + vk_free2(&device->alloc, pAllocator, pool); +} + +VkResult +tu_ResetCommandPool(VkDevice device, + VkCommandPool commandPool, + VkCommandPoolResetFlags flags) +{ + TU_FROM_HANDLE(tu_cmd_pool, pool, commandPool); + VkResult result; + + list_for_each_entry( + struct tu_cmd_buffer, cmd_buffer, &pool->cmd_buffers, pool_link) + { + result = tu_reset_cmd_buffer(cmd_buffer); + if (result != VK_SUCCESS) + return result; + } + + return VK_SUCCESS; +} + +void +tu_TrimCommandPool(VkDevice device, + VkCommandPool commandPool, + VkCommandPoolTrimFlagsKHR flags) +{ + TU_FROM_HANDLE(tu_cmd_pool, pool, commandPool); + + if (!pool) + return; + + list_for_each_entry_safe( + struct tu_cmd_buffer, cmd_buffer, &pool->free_cmd_buffers, pool_link) + { + tu_cmd_buffer_destroy(cmd_buffer); + } +} + +void +tu_CmdBeginRenderPass(VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo *pRenderPassBegin, + VkSubpassContents contents) +{ +} + +void +tu_CmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, + const VkRenderPassBeginInfo *pRenderPassBeginInfo, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo) +{ + tu_CmdBeginRenderPass( + commandBuffer, pRenderPassBeginInfo, pSubpassBeginInfo->contents); +} + +void +tu_CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) +{ +} + +void +tu_CmdNextSubpass2KHR(VkCommandBuffer commandBuffer, + const VkSubpassBeginInfoKHR *pSubpassBeginInfo, + const VkSubpassEndInfoKHR *pSubpassEndInfo) +{ + tu_CmdNextSubpass(commandBuffer, pSubpassBeginInfo->contents); +} + +struct tu_draw_info +{ + /** + * Number of vertices. + */ + uint32_t count; + + /** + * Index of the first vertex. + */ + int32_t vertex_offset; + + /** + * First instance id. + */ + uint32_t first_instance; + + /** + * Number of instances. + */ + uint32_t instance_count; + + /** + * First index (indexed draws only). + */ + uint32_t first_index; + + /** + * Whether it's an indexed draw. + */ + bool indexed; + + /** + * Indirect draw parameters resource. + */ + struct tu_buffer *indirect; + uint64_t indirect_offset; + uint32_t stride; + + /** + * Draw count parameters resource. + */ + struct tu_buffer *count_buffer; + uint64_t count_buffer_offset; +}; + +static void +tu_draw(struct tu_cmd_buffer *cmd_buffer, const struct tu_draw_info *info) +{ +} + +void +tu_CmdDraw(VkCommandBuffer commandBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + struct tu_draw_info info = {}; + + info.count = vertexCount; + info.instance_count = instanceCount; + info.first_instance = firstInstance; + info.vertex_offset = firstVertex; + + tu_draw(cmd_buffer, &info); +} + +void +tu_CmdDrawIndexed(VkCommandBuffer commandBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + struct tu_draw_info info = {}; + + info.indexed = true; + info.count = indexCount; + info.instance_count = instanceCount; + info.first_index = firstIndex; + info.vertex_offset = vertexOffset; + info.first_instance = firstInstance; + + tu_draw(cmd_buffer, &info); +} + +void +tu_CmdDrawIndirect(VkCommandBuffer commandBuffer, + VkBuffer _buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + TU_FROM_HANDLE(tu_buffer, buffer, _buffer); + struct tu_draw_info info = {}; + + info.count = drawCount; + info.indirect = buffer; + info.indirect_offset = offset; + info.stride = stride; + + tu_draw(cmd_buffer, &info); +} + +void +tu_CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, + VkBuffer _buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + TU_FROM_HANDLE(tu_buffer, buffer, _buffer); + struct tu_draw_info info = {}; + + info.indexed = true; + info.count = drawCount; + info.indirect = buffer; + info.indirect_offset = offset; + info.stride = stride; + + tu_draw(cmd_buffer, &info); +} + +struct tu_dispatch_info +{ + /** + * Determine the layout of the grid (in block units) to be used. + */ + uint32_t blocks[3]; + + /** + * A starting offset for the grid. If unaligned is set, the offset + * must still be aligned. + */ + uint32_t offsets[3]; + /** + * Whether it's an unaligned compute dispatch. + */ + bool unaligned; + + /** + * Indirect compute parameters resource. + */ + struct tu_buffer *indirect; + uint64_t indirect_offset; +}; + +static void +tu_dispatch(struct tu_cmd_buffer *cmd_buffer, + const struct tu_dispatch_info *info) +{ +} + +void +tu_CmdDispatchBase(VkCommandBuffer commandBuffer, + uint32_t base_x, + uint32_t base_y, + uint32_t base_z, + uint32_t x, + uint32_t y, + uint32_t z) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + struct tu_dispatch_info info = {}; + + info.blocks[0] = x; + info.blocks[1] = y; + info.blocks[2] = z; + + info.offsets[0] = base_x; + info.offsets[1] = base_y; + info.offsets[2] = base_z; + tu_dispatch(cmd_buffer, &info); +} + +void +tu_CmdDispatch(VkCommandBuffer commandBuffer, + uint32_t x, + uint32_t y, + uint32_t z) +{ + tu_CmdDispatchBase(commandBuffer, 0, 0, 0, x, y, z); +} + +void +tu_CmdDispatchIndirect(VkCommandBuffer commandBuffer, + VkBuffer _buffer, + VkDeviceSize offset) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + TU_FROM_HANDLE(tu_buffer, buffer, _buffer); + struct tu_dispatch_info info = {}; + + info.indirect = buffer; + info.indirect_offset = offset; + + tu_dispatch(cmd_buffer, &info); +} + +void +tu_CmdEndRenderPass(VkCommandBuffer commandBuffer) +{ +} + +void +tu_CmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, + const VkSubpassEndInfoKHR *pSubpassEndInfo) +{ + tu_CmdEndRenderPass(commandBuffer); +} + +struct tu_barrier_info +{ + uint32_t eventCount; + const VkEvent *pEvents; + VkPipelineStageFlags srcStageMask; +}; + +static void +tu_barrier(struct tu_cmd_buffer *cmd_buffer, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *pImageMemoryBarriers, + const struct tu_barrier_info *info) +{ +} + +void +tu_CmdPipelineBarrier(VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags destStageMask, + VkBool32 byRegion, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *pImageMemoryBarriers) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + struct tu_barrier_info info; + + info.eventCount = 0; + info.pEvents = NULL; + info.srcStageMask = srcStageMask; + + tu_barrier(cmd_buffer, + memoryBarrierCount, + pMemoryBarriers, + bufferMemoryBarrierCount, + pBufferMemoryBarriers, + imageMemoryBarrierCount, + pImageMemoryBarriers, + &info); +} + +static void +write_event(struct tu_cmd_buffer *cmd_buffer, + struct tu_event *event, + VkPipelineStageFlags stageMask, + unsigned value) +{ +} + +void +tu_CmdSetEvent(VkCommandBuffer commandBuffer, + VkEvent _event, + VkPipelineStageFlags stageMask) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + TU_FROM_HANDLE(tu_event, event, _event); + + write_event(cmd_buffer, event, stageMask, 1); +} + +void +tu_CmdResetEvent(VkCommandBuffer commandBuffer, + VkEvent _event, + VkPipelineStageFlags stageMask) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + TU_FROM_HANDLE(tu_event, event, _event); + + write_event(cmd_buffer, event, stageMask, 0); +} + +void +tu_CmdWaitEvents(VkCommandBuffer commandBuffer, + uint32_t eventCount, + const VkEvent *pEvents, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *pImageMemoryBarriers) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + struct tu_barrier_info info; + + info.eventCount = eventCount; + info.pEvents = pEvents; + info.srcStageMask = 0; + + tu_barrier(cmd_buffer, + memoryBarrierCount, + pMemoryBarriers, + bufferMemoryBarrierCount, + pBufferMemoryBarriers, + imageMemoryBarrierCount, + pImageMemoryBarriers, + &info); +} + +void +tu_CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) +{ + /* No-op */ +} diff --git a/src/freedreno/vulkan/tu_descriptor_set.c b/src/freedreno/vulkan/tu_descriptor_set.c new file mode 100644 index 00000000000..a9dd6df1727 --- /dev/null +++ b/src/freedreno/vulkan/tu_descriptor_set.c @@ -0,0 +1,565 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * 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 <assert.h> +#include <fcntl.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> + +#include "tu_private.h" +#include "util/mesa-sha1.h" +#include "vk_util.h" + +static int +binding_compare(const void *av, const void *bv) +{ + const VkDescriptorSetLayoutBinding *a = + (const VkDescriptorSetLayoutBinding *)av; + const VkDescriptorSetLayoutBinding *b = + (const VkDescriptorSetLayoutBinding *)bv; + + return (a->binding < b->binding) ? -1 : (a->binding > b->binding) ? 1 : 0; +} + +static VkDescriptorSetLayoutBinding * +create_sorted_bindings(const VkDescriptorSetLayoutBinding *bindings, + unsigned count) +{ + VkDescriptorSetLayoutBinding *sorted_bindings = + malloc(count * sizeof(VkDescriptorSetLayoutBinding)); + if (!sorted_bindings) + return NULL; + + memcpy( + sorted_bindings, bindings, count * sizeof(VkDescriptorSetLayoutBinding)); + + qsort(sorted_bindings, + count, + sizeof(VkDescriptorSetLayoutBinding), + binding_compare); + + return sorted_bindings; +} + +VkResult +tu_CreateDescriptorSetLayout( + VkDevice _device, + const VkDescriptorSetLayoutCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDescriptorSetLayout *pSetLayout) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_descriptor_set_layout *set_layout; + + assert(pCreateInfo->sType == + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO); + const VkDescriptorSetLayoutBindingFlagsCreateInfoEXT *variable_flags = + vk_find_struct_const(pCreateInfo->pNext, + DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT); + + uint32_t max_binding = 0; + uint32_t immutable_sampler_count = 0; + for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) { + max_binding = MAX2(max_binding, pCreateInfo->pBindings[j].binding); + if (pCreateInfo->pBindings[j].pImmutableSamplers) + immutable_sampler_count += pCreateInfo->pBindings[j].descriptorCount; + } + + uint32_t samplers_offset = + sizeof(struct tu_descriptor_set_layout) + + (max_binding + 1) * sizeof(set_layout->binding[0]); + size_t size = + samplers_offset + immutable_sampler_count * 4 * sizeof(uint32_t); + + set_layout = vk_alloc2( + &device->alloc, pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!set_layout) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + set_layout->flags = pCreateInfo->flags; + + /* We just allocate all the samplers at the end of the struct */ + uint32_t *samplers = (uint32_t *)&set_layout->binding[max_binding + 1]; + + VkDescriptorSetLayoutBinding *bindings = + create_sorted_bindings(pCreateInfo->pBindings, pCreateInfo->bindingCount); + if (!bindings) { + vk_free2(&device->alloc, pAllocator, set_layout); + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + } + + set_layout->binding_count = max_binding + 1; + set_layout->shader_stages = 0; + set_layout->dynamic_shader_stages = 0; + set_layout->has_immutable_samplers = false; + set_layout->size = 0; + + memset( + set_layout->binding, 0, size - sizeof(struct tu_descriptor_set_layout)); + + uint32_t buffer_count = 0; + uint32_t dynamic_offset_count = 0; + + for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) { + const VkDescriptorSetLayoutBinding *binding = bindings + j; + uint32_t b = binding->binding; + uint32_t alignment; + unsigned binding_buffer_count = 0; + + switch (binding->descriptorType) { + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + assert(!(pCreateInfo->flags & + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR)); + set_layout->binding[b].dynamic_offset_count = 1; + set_layout->dynamic_shader_stages |= binding->stageFlags; + set_layout->binding[b].size = 0; + binding_buffer_count = 1; + alignment = 1; + break; + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + set_layout->binding[b].size = 16; + binding_buffer_count = 1; + alignment = 16; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + /* main descriptor + fmask descriptor */ + set_layout->binding[b].size = 64; + binding_buffer_count = 1; + alignment = 32; + break; + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + /* main descriptor + fmask descriptor + sampler */ + set_layout->binding[b].size = 96; + binding_buffer_count = 1; + alignment = 32; + break; + case VK_DESCRIPTOR_TYPE_SAMPLER: + set_layout->binding[b].size = 16; + alignment = 16; + break; + default: + unreachable("unknown descriptor type\n"); + break; + } + + set_layout->size = align(set_layout->size, alignment); + set_layout->binding[b].type = binding->descriptorType; + set_layout->binding[b].array_size = binding->descriptorCount; + set_layout->binding[b].offset = set_layout->size; + set_layout->binding[b].buffer_offset = buffer_count; + set_layout->binding[b].dynamic_offset_offset = dynamic_offset_count; + + if (variable_flags && binding->binding < variable_flags->bindingCount && + (variable_flags->pBindingFlags[binding->binding] & + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT)) { + assert(!binding->pImmutableSamplers); /* Terribly ill defined how many + samplers are valid */ + assert(binding->binding == max_binding); + + set_layout->has_variable_descriptors = true; + } + + if (binding->pImmutableSamplers) { + set_layout->binding[b].immutable_samplers_offset = samplers_offset; + set_layout->has_immutable_samplers = true; + } + + set_layout->size += + binding->descriptorCount * set_layout->binding[b].size; + buffer_count += binding->descriptorCount * binding_buffer_count; + dynamic_offset_count += + binding->descriptorCount * set_layout->binding[b].dynamic_offset_count; + set_layout->shader_stages |= binding->stageFlags; + } + + free(bindings); + + set_layout->buffer_count = buffer_count; + set_layout->dynamic_offset_count = dynamic_offset_count; + + *pSetLayout = tu_descriptor_set_layout_to_handle(set_layout); + + return VK_SUCCESS; +} + +void +tu_DestroyDescriptorSetLayout(VkDevice _device, + VkDescriptorSetLayout _set_layout, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_descriptor_set_layout, set_layout, _set_layout); + + if (!set_layout) + return; + + vk_free2(&device->alloc, pAllocator, set_layout); +} + +void +tu_GetDescriptorSetLayoutSupport( + VkDevice device, + const VkDescriptorSetLayoutCreateInfo *pCreateInfo, + VkDescriptorSetLayoutSupport *pSupport) +{ + VkDescriptorSetLayoutBinding *bindings = + create_sorted_bindings(pCreateInfo->pBindings, pCreateInfo->bindingCount); + if (!bindings) { + pSupport->supported = false; + return; + } + + const VkDescriptorSetLayoutBindingFlagsCreateInfoEXT *variable_flags = + vk_find_struct_const(pCreateInfo->pNext, + DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT); + VkDescriptorSetVariableDescriptorCountLayoutSupportEXT *variable_count = + vk_find_struct( + (void *)pCreateInfo->pNext, + DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT); + if (variable_count) { + variable_count->maxVariableDescriptorCount = 0; + } + + bool supported = true; + uint64_t size = 0; + for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) { + const VkDescriptorSetLayoutBinding *binding = bindings + i; + + uint64_t descriptor_size = 0; + uint64_t descriptor_alignment = 1; + switch (binding->descriptorType) { + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + break; + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + descriptor_size = 16; + descriptor_alignment = 16; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + descriptor_size = 64; + descriptor_alignment = 32; + break; + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + descriptor_size = 96; + descriptor_alignment = 32; + break; + case VK_DESCRIPTOR_TYPE_SAMPLER: + descriptor_size = 16; + descriptor_alignment = 16; + break; + default: + unreachable("unknown descriptor type\n"); + break; + } + + if (size && !align_u64(size, descriptor_alignment)) { + supported = false; + } + size = align_u64(size, descriptor_alignment); + + uint64_t max_count = UINT64_MAX; + if (descriptor_size) + max_count = (UINT64_MAX - size) / descriptor_size; + + if (max_count < binding->descriptorCount) { + supported = false; + } + if (variable_flags && binding->binding < variable_flags->bindingCount && + variable_count && + (variable_flags->pBindingFlags[binding->binding] & + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT)) { + variable_count->maxVariableDescriptorCount = + MIN2(UINT32_MAX, max_count); + } + size += binding->descriptorCount * descriptor_size; + } + + free(bindings); + + pSupport->supported = supported; +} + +/* + * Pipeline layouts. These have nothing to do with the pipeline. They are + * just multiple descriptor set layouts pasted together. + */ + +VkResult +tu_CreatePipelineLayout(VkDevice _device, + const VkPipelineLayoutCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkPipelineLayout *pPipelineLayout) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_pipeline_layout *layout; + struct mesa_sha1 ctx; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO); + + layout = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*layout), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (layout == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + layout->num_sets = pCreateInfo->setLayoutCount; + + unsigned dynamic_offset_count = 0; + + _mesa_sha1_init(&ctx); + for (uint32_t set = 0; set < pCreateInfo->setLayoutCount; set++) { + TU_FROM_HANDLE( + tu_descriptor_set_layout, set_layout, pCreateInfo->pSetLayouts[set]); + layout->set[set].layout = set_layout; + + layout->set[set].dynamic_offset_start = dynamic_offset_count; + for (uint32_t b = 0; b < set_layout->binding_count; b++) { + dynamic_offset_count += set_layout->binding[b].array_size * + set_layout->binding[b].dynamic_offset_count; + if (set_layout->binding[b].immutable_samplers_offset) + _mesa_sha1_update( + &ctx, + tu_immutable_samplers(set_layout, set_layout->binding + b), + set_layout->binding[b].array_size * 4 * sizeof(uint32_t)); + } + _mesa_sha1_update(&ctx, + set_layout->binding, + sizeof(set_layout->binding[0]) * + set_layout->binding_count); + } + + layout->dynamic_offset_count = dynamic_offset_count; + layout->push_constant_size = 0; + + for (unsigned i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) { + const VkPushConstantRange *range = pCreateInfo->pPushConstantRanges + i; + layout->push_constant_size = + MAX2(layout->push_constant_size, range->offset + range->size); + } + + layout->push_constant_size = align(layout->push_constant_size, 16); + _mesa_sha1_update( + &ctx, &layout->push_constant_size, sizeof(layout->push_constant_size)); + _mesa_sha1_final(&ctx, layout->sha1); + *pPipelineLayout = tu_pipeline_layout_to_handle(layout); + + return VK_SUCCESS; +} + +void +tu_DestroyPipelineLayout(VkDevice _device, + VkPipelineLayout _pipelineLayout, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_pipeline_layout, pipeline_layout, _pipelineLayout); + + if (!pipeline_layout) + return; + vk_free2(&device->alloc, pAllocator, pipeline_layout); +} + +#define EMPTY 1 + +VkResult +tu_CreateDescriptorPool(VkDevice _device, + const VkDescriptorPoolCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDescriptorPool *pDescriptorPool) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_descriptor_pool *pool; + + return VK_SUCCESS; +} + +void +tu_DestroyDescriptorPool(VkDevice _device, + VkDescriptorPool _pool, + const VkAllocationCallbacks *pAllocator) +{ +} + +VkResult +tu_ResetDescriptorPool(VkDevice _device, + VkDescriptorPool descriptorPool, + VkDescriptorPoolResetFlags flags) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_descriptor_pool, pool, descriptorPool); + + return VK_SUCCESS; +} + +VkResult +tu_AllocateDescriptorSets(VkDevice _device, + const VkDescriptorSetAllocateInfo *pAllocateInfo, + VkDescriptorSet *pDescriptorSets) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_descriptor_pool, pool, pAllocateInfo->descriptorPool); + + return VK_SUCCESS; +} + +VkResult +tu_FreeDescriptorSets(VkDevice _device, + VkDescriptorPool descriptorPool, + uint32_t count, + const VkDescriptorSet *pDescriptorSets) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_descriptor_pool, pool, descriptorPool); + + return VK_SUCCESS; +} + +void +tu_update_descriptor_sets(struct tu_device *device, + struct tu_cmd_buffer *cmd_buffer, + VkDescriptorSet dstSetOverride, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites, + uint32_t descriptorCopyCount, + const VkCopyDescriptorSet *pDescriptorCopies) +{ +} + +void +tu_UpdateDescriptorSets(VkDevice _device, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites, + uint32_t descriptorCopyCount, + const VkCopyDescriptorSet *pDescriptorCopies) +{ + TU_FROM_HANDLE(tu_device, device, _device); + + tu_update_descriptor_sets(device, + NULL, + VK_NULL_HANDLE, + descriptorWriteCount, + pDescriptorWrites, + descriptorCopyCount, + pDescriptorCopies); +} + +VkResult +tu_CreateDescriptorUpdateTemplate( + VkDevice _device, + const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE( + tu_descriptor_set_layout, set_layout, pCreateInfo->descriptorSetLayout); + const uint32_t entry_count = pCreateInfo->descriptorUpdateEntryCount; + const size_t size = + sizeof(struct tu_descriptor_update_template) + + sizeof(struct tu_descriptor_update_template_entry) * entry_count; + struct tu_descriptor_update_template *templ; + uint32_t i; + + templ = vk_alloc2( + &device->alloc, pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!templ) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + *pDescriptorUpdateTemplate = tu_descriptor_update_template_to_handle(templ); + return VK_SUCCESS; +} + +void +tu_DestroyDescriptorUpdateTemplate( + VkDevice _device, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE( + tu_descriptor_update_template, templ, descriptorUpdateTemplate); + + if (!templ) + return; + + vk_free2(&device->alloc, pAllocator, templ); +} + +void +tu_update_descriptor_set_with_template( + struct tu_device *device, + struct tu_cmd_buffer *cmd_buffer, + struct tu_descriptor_set *set, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + const void *pData) +{ + TU_FROM_HANDLE( + tu_descriptor_update_template, templ, descriptorUpdateTemplate); +} + +void +tu_UpdateDescriptorSetWithTemplate( + VkDevice _device, + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + const void *pData) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_descriptor_set, set, descriptorSet); + + tu_update_descriptor_set_with_template( + device, NULL, set, descriptorUpdateTemplate, pData); +} + +VkResult +tu_CreateSamplerYcbcrConversion( + VkDevice device, + const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSamplerYcbcrConversion *pYcbcrConversion) +{ + *pYcbcrConversion = VK_NULL_HANDLE; + return VK_SUCCESS; +} + +void +tu_DestroySamplerYcbcrConversion(VkDevice device, + VkSamplerYcbcrConversion ycbcrConversion, + const VkAllocationCallbacks *pAllocator) +{ + /* Do nothing. */ +} diff --git a/src/freedreno/vulkan/tu_descriptor_set.h b/src/freedreno/vulkan/tu_descriptor_set.h new file mode 100644 index 00000000000..087eb3ddc20 --- /dev/null +++ b/src/freedreno/vulkan/tu_descriptor_set.h @@ -0,0 +1,102 @@ +/* + * Copyright © 2016 Bas Nieuwenhuizen + * + * 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 TU_DESCRIPTOR_SET_H +#define TU_DESCRIPTOR_SET_H + +#include <vulkan/vulkan.h> + +#define MAX_SETS 32 + +struct tu_descriptor_set_binding_layout +{ + VkDescriptorType type; + + /* Number of array elements in this binding */ + uint32_t array_size; + + uint32_t offset; + uint32_t buffer_offset; + uint16_t dynamic_offset_offset; + + uint16_t dynamic_offset_count; + /* redundant with the type, each for a single array element */ + uint32_t size; + + /* Offset in the tu_descriptor_set_layout of the immutable samplers, or 0 + * if there are no immutable samplers. */ + uint32_t immutable_samplers_offset; +}; + +struct tu_descriptor_set_layout +{ + /* The create flags for this descriptor set layout */ + VkDescriptorSetLayoutCreateFlags flags; + + /* Number of bindings in this descriptor set */ + uint32_t binding_count; + + /* Total size of the descriptor set with room for all array entries */ + uint32_t size; + + /* Shader stages affected by this descriptor set */ + uint16_t shader_stages; + uint16_t dynamic_shader_stages; + + /* Number of buffers in this descriptor set */ + uint32_t buffer_count; + + /* Number of dynamic offsets used by this descriptor set */ + uint16_t dynamic_offset_count; + + bool has_immutable_samplers; + bool has_variable_descriptors; + + /* Bindings in this descriptor set */ + struct tu_descriptor_set_binding_layout binding[0]; +}; + +struct tu_pipeline_layout +{ + struct + { + struct tu_descriptor_set_layout *layout; + uint32_t size; + uint32_t dynamic_offset_start; + } set[MAX_SETS]; + + uint32_t num_sets; + uint32_t push_constant_size; + uint32_t dynamic_offset_count; + + unsigned char sha1[20]; +}; + +static inline const uint32_t * +tu_immutable_samplers(const struct tu_descriptor_set_layout *set, + const struct tu_descriptor_set_binding_layout *binding) +{ + return (const uint32_t *)((const char *)set + + binding->immutable_samplers_offset); +} +#endif /* TU_DESCRIPTOR_SET_H */ diff --git a/src/freedreno/vulkan/tu_device.c b/src/freedreno/vulkan/tu_device.c new file mode 100644 index 00000000000..4b86bd507fa --- /dev/null +++ b/src/freedreno/vulkan/tu_device.c @@ -0,0 +1,1839 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * based in part on anv driver which is: + * Copyright © 2015 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 "tu_private.h" +#include "util/debug.h" +#include "util/disk_cache.h" +#include "util/strtod.h" +#include "vk_format.h" +#include "vk_util.h" +#include <fcntl.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> +#include <xf86drm.h> + +static int +tu_device_get_cache_uuid(uint16_t family, void *uuid) +{ + uint32_t mesa_timestamp; + uint16_t f = family; + memset(uuid, 0, VK_UUID_SIZE); + if (!disk_cache_get_function_timestamp(tu_device_get_cache_uuid, + &mesa_timestamp)) + return -1; + + memcpy(uuid, &mesa_timestamp, 4); + memcpy((char *)uuid + 4, &f, 2); + snprintf((char *)uuid + 6, VK_UUID_SIZE - 10, "tu"); + return 0; +} + +static void +tu_get_driver_uuid(void *uuid) +{ + memset(uuid, 0, VK_UUID_SIZE); +} + +static void +tu_get_device_uuid(void *uuid) +{ + stub(); +} + +static VkResult +tu_physical_device_init(struct tu_physical_device *device, + struct tu_instance *instance, + drmDevicePtr drm_device) +{ + const char *path = drm_device->nodes[DRM_NODE_RENDER]; + VkResult result; + drmVersionPtr version; + int fd; + int master_fd = -1; + + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) { + if (instance->debug_flags & TU_DEBUG_STARTUP) + tu_logi("Could not open device '%s'", path); + + return vk_error(instance, VK_ERROR_INCOMPATIBLE_DRIVER); + } + + version = drmGetVersion(fd); + if (!version) { + close(fd); + + if (instance->debug_flags & TU_DEBUG_STARTUP) + tu_logi("Could not get the kernel driver version for device '%s'", + path); + + return vk_errorf(instance, + VK_ERROR_INCOMPATIBLE_DRIVER, + "failed to get version %s: %m", + path); + } + + if (strcmp(version->name, "amdgpu")) { + drmFreeVersion(version); + if (master_fd != -1) + close(master_fd); + close(fd); + + if (instance->debug_flags & TU_DEBUG_STARTUP) + tu_logi("Device '%s' is not using the amdgpu kernel driver.", path); + + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + drmFreeVersion(version); + + if (instance->debug_flags & TU_DEBUG_STARTUP) + tu_logi("Found compatible device '%s'.", path); + + device->_loader_data.loaderMagic = ICD_LOADER_MAGIC; + device->instance = instance; + assert(strlen(path) < ARRAY_SIZE(device->path)); + strncpy(device->path, path, ARRAY_SIZE(device->path)); + + if (instance->enabled_extensions.KHR_display) { + master_fd = open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC); + if (master_fd >= 0) { + /* TODO: free master_fd is accel is not working? */ + abort(); + } + } + + device->master_fd = master_fd; + device->local_fd = fd; + + if (tu_device_get_cache_uuid(0 /* TODO */, device->cache_uuid)) { + result = vk_errorf( + instance, VK_ERROR_INITIALIZATION_FAILED, "cannot generate UUID"); + goto fail; + } + + /* The gpu id is already embedded in the uuid so we just pass "tu" + * when creating the cache. + */ + char buf[VK_UUID_SIZE * 2 + 1]; + disk_cache_format_hex_id(buf, device->cache_uuid, VK_UUID_SIZE * 2); + device->disk_cache = disk_cache_create(device->name, buf, 0); + + fprintf(stderr, + "WARNING: tu is not a conformant vulkan implementation, " + "testing use only.\n"); + + tu_get_driver_uuid(&device->device_uuid); + tu_get_device_uuid(&device->device_uuid); + + tu_fill_device_extension_table(device, &device->supported_extensions); + + if (result != VK_SUCCESS) { + vk_error(instance, result); + goto fail; + } + + return VK_SUCCESS; + +fail: + close(fd); + if (master_fd != -1) + close(master_fd); + return result; +} + +static void +tu_physical_device_finish(struct tu_physical_device *device) +{ + disk_cache_destroy(device->disk_cache); + close(device->local_fd); + if (device->master_fd != -1) + close(device->master_fd); +} + +static void * +default_alloc_func(void *pUserData, + size_t size, + size_t align, + VkSystemAllocationScope allocationScope) +{ + return malloc(size); +} + +static void * +default_realloc_func(void *pUserData, + void *pOriginal, + size_t size, + size_t align, + VkSystemAllocationScope allocationScope) +{ + return realloc(pOriginal, size); +} + +static void +default_free_func(void *pUserData, void *pMemory) +{ + free(pMemory); +} + +static const VkAllocationCallbacks default_alloc = { + .pUserData = NULL, + .pfnAllocation = default_alloc_func, + .pfnReallocation = default_realloc_func, + .pfnFree = default_free_func, +}; + +static const struct debug_control tu_debug_options[] = { { "startup", + TU_DEBUG_STARTUP }, + { NULL, 0 } }; + +const char * +tu_get_debug_option_name(int id) +{ + assert(id < ARRAY_SIZE(tu_debug_options) - 1); + return tu_debug_options[id].string; +} + +static int +tu_get_instance_extension_index(const char *name) +{ + for (unsigned i = 0; i < TU_INSTANCE_EXTENSION_COUNT; ++i) { + if (strcmp(name, tu_instance_extensions[i].extensionName) == 0) + return i; + } + return -1; +} + +VkResult +tu_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkInstance *pInstance) +{ + struct tu_instance *instance; + VkResult result; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO); + + uint32_t client_version; + if (pCreateInfo->pApplicationInfo && + pCreateInfo->pApplicationInfo->apiVersion != 0) { + client_version = pCreateInfo->pApplicationInfo->apiVersion; + } else { + tu_EnumerateInstanceVersion(&client_version); + } + + instance = vk_zalloc2(&default_alloc, + pAllocator, + sizeof(*instance), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); + if (!instance) + return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY); + + instance->_loader_data.loaderMagic = ICD_LOADER_MAGIC; + + if (pAllocator) + instance->alloc = *pAllocator; + else + instance->alloc = default_alloc; + + instance->api_version = client_version; + instance->physical_device_count = -1; + + instance->debug_flags = + parse_debug_string(getenv("TU_DEBUG"), tu_debug_options); + + if (instance->debug_flags & TU_DEBUG_STARTUP) + tu_logi("Created an instance"); + + for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { + const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i]; + int index = tu_get_instance_extension_index(ext_name); + + if (index < 0 || !tu_supported_instance_extensions.extensions[index]) { + vk_free2(&default_alloc, pAllocator, instance); + return vk_error(instance, VK_ERROR_EXTENSION_NOT_PRESENT); + } + + instance->enabled_extensions.extensions[index] = true; + } + + result = vk_debug_report_instance_init(&instance->debug_report_callbacks); + if (result != VK_SUCCESS) { + vk_free2(&default_alloc, pAllocator, instance); + return vk_error(instance, result); + } + + _mesa_locale_init(); + + VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false)); + + *pInstance = tu_instance_to_handle(instance); + + return VK_SUCCESS; +} + +void +tu_DestroyInstance(VkInstance _instance, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_instance, instance, _instance); + + if (!instance) + return; + + for (int i = 0; i < instance->physical_device_count; ++i) { + tu_physical_device_finish(instance->physical_devices + i); + } + + VG(VALGRIND_DESTROY_MEMPOOL(instance)); + + _mesa_locale_fini(); + + vk_debug_report_instance_destroy(&instance->debug_report_callbacks); + + vk_free(&instance->alloc, instance); +} + +static VkResult +tu_enumerate_devices(struct tu_instance *instance) +{ + /* TODO: Check for more devices ? */ + drmDevicePtr devices[8]; + VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER; + int max_devices; + + instance->physical_device_count = 0; + + max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); + + if (instance->debug_flags & TU_DEBUG_STARTUP) + tu_logi("Found %d drm nodes", max_devices); + + if (max_devices < 1) + return vk_error(instance, VK_ERROR_INCOMPATIBLE_DRIVER); + + for (unsigned i = 0; i < (unsigned)max_devices; i++) { + if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER && + devices[i]->bustype == DRM_BUS_PCI && + devices[i]->deviceinfo.pci->vendor_id == 0) { + + result = tu_physical_device_init(instance->physical_devices + + instance->physical_device_count, + instance, + devices[i]); + if (result == VK_SUCCESS) + ++instance->physical_device_count; + else if (result != VK_ERROR_INCOMPATIBLE_DRIVER) + break; + } + } + drmFreeDevices(devices, max_devices); + + return result; +} + +VkResult +tu_EnumeratePhysicalDevices(VkInstance _instance, + uint32_t *pPhysicalDeviceCount, + VkPhysicalDevice *pPhysicalDevices) +{ + TU_FROM_HANDLE(tu_instance, instance, _instance); + VkResult result; + + if (instance->physical_device_count < 0) { + result = tu_enumerate_devices(instance); + if (result != VK_SUCCESS && result != VK_ERROR_INCOMPATIBLE_DRIVER) + return result; + } + + if (!pPhysicalDevices) { + *pPhysicalDeviceCount = instance->physical_device_count; + } else { + *pPhysicalDeviceCount = + MIN2(*pPhysicalDeviceCount, instance->physical_device_count); + for (unsigned i = 0; i < *pPhysicalDeviceCount; ++i) + pPhysicalDevices[i] = + tu_physical_device_to_handle(instance->physical_devices + i); + } + + return *pPhysicalDeviceCount < instance->physical_device_count + ? VK_INCOMPLETE + : VK_SUCCESS; +} + +VkResult +tu_EnumeratePhysicalDeviceGroups( + VkInstance _instance, + uint32_t *pPhysicalDeviceGroupCount, + VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) +{ + TU_FROM_HANDLE(tu_instance, instance, _instance); + VkResult result; + + if (instance->physical_device_count < 0) { + result = tu_enumerate_devices(instance); + if (result != VK_SUCCESS && result != VK_ERROR_INCOMPATIBLE_DRIVER) + return result; + } + + if (!pPhysicalDeviceGroupProperties) { + *pPhysicalDeviceGroupCount = instance->physical_device_count; + } else { + *pPhysicalDeviceGroupCount = + MIN2(*pPhysicalDeviceGroupCount, instance->physical_device_count); + for (unsigned i = 0; i < *pPhysicalDeviceGroupCount; ++i) { + pPhysicalDeviceGroupProperties[i].physicalDeviceCount = 1; + pPhysicalDeviceGroupProperties[i].physicalDevices[0] = + tu_physical_device_to_handle(instance->physical_devices + i); + pPhysicalDeviceGroupProperties[i].subsetAllocation = false; + } + } + return *pPhysicalDeviceGroupCount < instance->physical_device_count + ? VK_INCOMPLETE + : VK_SUCCESS; +} + +void +tu_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures *pFeatures) +{ + memset(pFeatures, 0, sizeof(*pFeatures)); + + *pFeatures = (VkPhysicalDeviceFeatures){ + .robustBufferAccess = false, + .fullDrawIndexUint32 = false, + .imageCubeArray = false, + .independentBlend = false, + .geometryShader = false, + .tessellationShader = false, + .sampleRateShading = false, + .dualSrcBlend = false, + .logicOp = false, + .multiDrawIndirect = false, + .drawIndirectFirstInstance = false, + .depthClamp = false, + .depthBiasClamp = false, + .fillModeNonSolid = false, + .depthBounds = false, + .wideLines = false, + .largePoints = false, + .alphaToOne = false, + .multiViewport = false, + .samplerAnisotropy = false, + .textureCompressionETC2 = false, + .textureCompressionASTC_LDR = false, + .textureCompressionBC = false, + .occlusionQueryPrecise = false, + .pipelineStatisticsQuery = false, + .vertexPipelineStoresAndAtomics = false, + .fragmentStoresAndAtomics = false, + .shaderTessellationAndGeometryPointSize = false, + .shaderImageGatherExtended = false, + .shaderStorageImageExtendedFormats = false, + .shaderStorageImageMultisample = false, + .shaderUniformBufferArrayDynamicIndexing = false, + .shaderSampledImageArrayDynamicIndexing = false, + .shaderStorageBufferArrayDynamicIndexing = false, + .shaderStorageImageArrayDynamicIndexing = false, + .shaderStorageImageReadWithoutFormat = false, + .shaderStorageImageWriteWithoutFormat = false, + .shaderClipDistance = false, + .shaderCullDistance = false, + .shaderFloat64 = false, + .shaderInt64 = false, + .shaderInt16 = false, + .sparseBinding = false, + .variableMultisampleRate = false, + .inheritedQueries = false, + }; +} + +void +tu_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2KHR *pFeatures) +{ + vk_foreach_struct(ext, pFeatures->pNext) + { + switch (ext->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR: { + VkPhysicalDeviceVariablePointerFeaturesKHR *features = (void *)ext; + features->variablePointersStorageBuffer = true; + features->variablePointers = false; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR: { + VkPhysicalDeviceMultiviewFeaturesKHR *features = + (VkPhysicalDeviceMultiviewFeaturesKHR *)ext; + features->multiview = true; + features->multiviewGeometryShader = true; + features->multiviewTessellationShader = true; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES: { + VkPhysicalDeviceShaderDrawParameterFeatures *features = + (VkPhysicalDeviceShaderDrawParameterFeatures *)ext; + features->shaderDrawParameters = true; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: { + VkPhysicalDeviceProtectedMemoryFeatures *features = + (VkPhysicalDeviceProtectedMemoryFeatures *)ext; + features->protectedMemory = false; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: { + VkPhysicalDevice16BitStorageFeatures *features = + (VkPhysicalDevice16BitStorageFeatures *)ext; + features->storageBuffer16BitAccess = false; + features->uniformAndStorageBuffer16BitAccess = false; + features->storagePushConstant16 = false; + features->storageInputOutput16 = false; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: { + VkPhysicalDeviceSamplerYcbcrConversionFeatures *features = + (VkPhysicalDeviceSamplerYcbcrConversionFeatures *)ext; + features->samplerYcbcrConversion = false; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT: { + VkPhysicalDeviceDescriptorIndexingFeaturesEXT *features = + (VkPhysicalDeviceDescriptorIndexingFeaturesEXT *)ext; + features->shaderInputAttachmentArrayDynamicIndexing = true; + features->shaderUniformTexelBufferArrayDynamicIndexing = true; + features->shaderStorageTexelBufferArrayDynamicIndexing = true; + features->shaderUniformBufferArrayNonUniformIndexing = false; + features->shaderSampledImageArrayNonUniformIndexing = false; + features->shaderStorageBufferArrayNonUniformIndexing = false; + features->shaderStorageImageArrayNonUniformIndexing = false; + features->shaderInputAttachmentArrayNonUniformIndexing = false; + features->shaderUniformTexelBufferArrayNonUniformIndexing = false; + features->shaderStorageTexelBufferArrayNonUniformIndexing = false; + features->descriptorBindingUniformBufferUpdateAfterBind = true; + features->descriptorBindingSampledImageUpdateAfterBind = true; + features->descriptorBindingStorageImageUpdateAfterBind = true; + features->descriptorBindingStorageBufferUpdateAfterBind = true; + features->descriptorBindingUniformTexelBufferUpdateAfterBind = true; + features->descriptorBindingStorageTexelBufferUpdateAfterBind = true; + features->descriptorBindingUpdateUnusedWhilePending = true; + features->descriptorBindingPartiallyBound = true; + features->descriptorBindingVariableDescriptorCount = true; + features->runtimeDescriptorArray = true; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT: { + VkPhysicalDeviceConditionalRenderingFeaturesEXT *features = + (VkPhysicalDeviceConditionalRenderingFeaturesEXT *)ext; + features->conditionalRendering = true; + features->inheritedConditionalRendering = false; + break; + } + default: + break; + } + } + return tu_GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features); +} + +void +tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties *pProperties) +{ + TU_FROM_HANDLE(tu_physical_device, pdevice, physicalDevice); + VkSampleCountFlags sample_counts = 0xf; + + /* make sure that the entire descriptor set is addressable with a signed + * 32-bit int. So the sum of all limits scaled by descriptor size has to + * be at most 2 GiB. the combined image & samples object count as one of + * both. This limit is for the pipeline layout, not for the set layout, but + * there is no set limit, so we just set a pipeline limit. I don't think + * any app is going to hit this soon. */ + size_t max_descriptor_set_size = + ((1ull << 31) - 16 * MAX_DYNAMIC_BUFFERS) / + (32 /* uniform buffer, 32 due to potential space wasted on alignment */ + + 32 /* storage buffer, 32 due to potential space wasted on alignment */ + + 32 /* sampler, largest when combined with image */ + + 64 /* sampled image */ + 64 /* storage image */); + + VkPhysicalDeviceLimits limits = { + .maxImageDimension1D = (1 << 14), + .maxImageDimension2D = (1 << 14), + .maxImageDimension3D = (1 << 11), + .maxImageDimensionCube = (1 << 14), + .maxImageArrayLayers = (1 << 11), + .maxTexelBufferElements = 128 * 1024 * 1024, + .maxUniformBufferRange = UINT32_MAX, + .maxStorageBufferRange = UINT32_MAX, + .maxPushConstantsSize = MAX_PUSH_CONSTANTS_SIZE, + .maxMemoryAllocationCount = UINT32_MAX, + .maxSamplerAllocationCount = 64 * 1024, + .bufferImageGranularity = 64, /* A cache line */ + .sparseAddressSpaceSize = 0xffffffffu, /* buffer max size */ + .maxBoundDescriptorSets = MAX_SETS, + .maxPerStageDescriptorSamplers = max_descriptor_set_size, + .maxPerStageDescriptorUniformBuffers = max_descriptor_set_size, + .maxPerStageDescriptorStorageBuffers = max_descriptor_set_size, + .maxPerStageDescriptorSampledImages = max_descriptor_set_size, + .maxPerStageDescriptorStorageImages = max_descriptor_set_size, + .maxPerStageDescriptorInputAttachments = max_descriptor_set_size, + .maxPerStageResources = max_descriptor_set_size, + .maxDescriptorSetSamplers = max_descriptor_set_size, + .maxDescriptorSetUniformBuffers = max_descriptor_set_size, + .maxDescriptorSetUniformBuffersDynamic = MAX_DYNAMIC_UNIFORM_BUFFERS, + .maxDescriptorSetStorageBuffers = max_descriptor_set_size, + .maxDescriptorSetStorageBuffersDynamic = MAX_DYNAMIC_STORAGE_BUFFERS, + .maxDescriptorSetSampledImages = max_descriptor_set_size, + .maxDescriptorSetStorageImages = max_descriptor_set_size, + .maxDescriptorSetInputAttachments = max_descriptor_set_size, + .maxVertexInputAttributes = 32, + .maxVertexInputBindings = 32, + .maxVertexInputAttributeOffset = 2047, + .maxVertexInputBindingStride = 2048, + .maxVertexOutputComponents = 128, + .maxTessellationGenerationLevel = 64, + .maxTessellationPatchSize = 32, + .maxTessellationControlPerVertexInputComponents = 128, + .maxTessellationControlPerVertexOutputComponents = 128, + .maxTessellationControlPerPatchOutputComponents = 120, + .maxTessellationControlTotalOutputComponents = 4096, + .maxTessellationEvaluationInputComponents = 128, + .maxTessellationEvaluationOutputComponents = 128, + .maxGeometryShaderInvocations = 127, + .maxGeometryInputComponents = 64, + .maxGeometryOutputComponents = 128, + .maxGeometryOutputVertices = 256, + .maxGeometryTotalOutputComponents = 1024, + .maxFragmentInputComponents = 128, + .maxFragmentOutputAttachments = 8, + .maxFragmentDualSrcAttachments = 1, + .maxFragmentCombinedOutputResources = 8, + .maxComputeSharedMemorySize = 32768, + .maxComputeWorkGroupCount = { 65535, 65535, 65535 }, + .maxComputeWorkGroupInvocations = 2048, + .maxComputeWorkGroupSize = { 2048, 2048, 2048 }, + .subPixelPrecisionBits = 4 /* FIXME */, + .subTexelPrecisionBits = 4 /* FIXME */, + .mipmapPrecisionBits = 4 /* FIXME */, + .maxDrawIndexedIndexValue = UINT32_MAX, + .maxDrawIndirectCount = UINT32_MAX, + .maxSamplerLodBias = 16, + .maxSamplerAnisotropy = 16, + .maxViewports = MAX_VIEWPORTS, + .maxViewportDimensions = { (1 << 14), (1 << 14) }, + .viewportBoundsRange = { INT16_MIN, INT16_MAX }, + .viewportSubPixelBits = 8, + .minMemoryMapAlignment = 4096, /* A page */ + .minTexelBufferOffsetAlignment = 1, + .minUniformBufferOffsetAlignment = 4, + .minStorageBufferOffsetAlignment = 4, + .minTexelOffset = -32, + .maxTexelOffset = 31, + .minTexelGatherOffset = -32, + .maxTexelGatherOffset = 31, + .minInterpolationOffset = -2, + .maxInterpolationOffset = 2, + .subPixelInterpolationOffsetBits = 8, + .maxFramebufferWidth = (1 << 14), + .maxFramebufferHeight = (1 << 14), + .maxFramebufferLayers = (1 << 10), + .framebufferColorSampleCounts = sample_counts, + .framebufferDepthSampleCounts = sample_counts, + .framebufferStencilSampleCounts = sample_counts, + .framebufferNoAttachmentsSampleCounts = sample_counts, + .maxColorAttachments = MAX_RTS, + .sampledImageColorSampleCounts = sample_counts, + .sampledImageIntegerSampleCounts = VK_SAMPLE_COUNT_1_BIT, + .sampledImageDepthSampleCounts = sample_counts, + .sampledImageStencilSampleCounts = sample_counts, + .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT, + .maxSampleMaskWords = 1, + .timestampComputeAndGraphics = true, + .timestampPeriod = 1, + .maxClipDistances = 8, + .maxCullDistances = 8, + .maxCombinedClipAndCullDistances = 8, + .discreteQueuePriorities = 1, + .pointSizeRange = { 0.125, 255.875 }, + .lineWidthRange = { 0.0, 7.9921875 }, + .pointSizeGranularity = (1.0 / 8.0), + .lineWidthGranularity = (1.0 / 128.0), + .strictLines = false, /* FINISHME */ + .standardSampleLocations = true, + .optimalBufferCopyOffsetAlignment = 128, + .optimalBufferCopyRowPitchAlignment = 128, + .nonCoherentAtomSize = 64, + }; + + *pProperties = (VkPhysicalDeviceProperties){ + .apiVersion = tu_physical_device_api_version(pdevice), + .driverVersion = vk_get_driver_version(), + .vendorID = 0, /* TODO */ + .deviceID = 0, + .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, + .limits = limits, + .sparseProperties = { 0 }, + }; + + strcpy(pProperties->deviceName, pdevice->name); + memcpy(pProperties->pipelineCacheUUID, pdevice->cache_uuid, VK_UUID_SIZE); +} + +void +tu_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2KHR *pProperties) +{ + TU_FROM_HANDLE(tu_physical_device, pdevice, physicalDevice); + tu_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties); + + vk_foreach_struct(ext, pProperties->pNext) + { + switch (ext->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: { + VkPhysicalDevicePushDescriptorPropertiesKHR *properties = + (VkPhysicalDevicePushDescriptorPropertiesKHR *)ext; + properties->maxPushDescriptors = MAX_PUSH_DESCRIPTORS; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR: { + VkPhysicalDeviceIDPropertiesKHR *properties = + (VkPhysicalDeviceIDPropertiesKHR *)ext; + memcpy(properties->driverUUID, pdevice->driver_uuid, VK_UUID_SIZE); + memcpy(properties->deviceUUID, pdevice->device_uuid, VK_UUID_SIZE); + properties->deviceLUIDValid = false; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR: { + VkPhysicalDeviceMultiviewPropertiesKHR *properties = + (VkPhysicalDeviceMultiviewPropertiesKHR *)ext; + properties->maxMultiviewViewCount = MAX_VIEWS; + properties->maxMultiviewInstanceIndex = INT_MAX; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR: { + VkPhysicalDevicePointClippingPropertiesKHR *properties = + (VkPhysicalDevicePointClippingPropertiesKHR *)ext; + properties->pointClippingBehavior = + VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: { + VkPhysicalDeviceMaintenance3Properties *properties = + (VkPhysicalDeviceMaintenance3Properties *)ext; + /* Make sure everything is addressable by a signed 32-bit int, and + * our largest descriptors are 96 bytes. */ + properties->maxPerSetDescriptors = (1ull << 31) / 96; + /* Our buffer size fields allow only this much */ + properties->maxMemoryAllocationSize = 0xFFFFFFFFull; + break; + } + default: + break; + } + } +} + +static void +tu_get_physical_device_queue_family_properties( + struct tu_physical_device *pdevice, + uint32_t *pCount, + VkQueueFamilyProperties **pQueueFamilyProperties) +{ + int num_queue_families = 1; + int idx; + if (pQueueFamilyProperties == NULL) { + *pCount = num_queue_families; + return; + } + + if (!*pCount) + return; + + idx = 0; + if (*pCount >= 1) { + *pQueueFamilyProperties[idx] = (VkQueueFamilyProperties){ + .queueFlags = + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, + .queueCount = 1, + .timestampValidBits = 64, + .minImageTransferGranularity = (VkExtent3D){ 1, 1, 1 }, + }; + idx++; + } + + *pCount = idx; +} + +void +tu_GetPhysicalDeviceQueueFamilyProperties( + VkPhysicalDevice physicalDevice, + uint32_t *pCount, + VkQueueFamilyProperties *pQueueFamilyProperties) +{ + TU_FROM_HANDLE(tu_physical_device, pdevice, physicalDevice); + if (!pQueueFamilyProperties) { + return tu_get_physical_device_queue_family_properties( + pdevice, pCount, NULL); + return; + } + VkQueueFamilyProperties *properties[] = { + pQueueFamilyProperties + 0, + }; + tu_get_physical_device_queue_family_properties(pdevice, pCount, properties); + assert(*pCount <= 1); +} + +void +tu_GetPhysicalDeviceQueueFamilyProperties2( + VkPhysicalDevice physicalDevice, + uint32_t *pCount, + VkQueueFamilyProperties2KHR *pQueueFamilyProperties) +{ + TU_FROM_HANDLE(tu_physical_device, pdevice, physicalDevice); + if (!pQueueFamilyProperties) { + return tu_get_physical_device_queue_family_properties( + pdevice, pCount, NULL); + return; + } + VkQueueFamilyProperties *properties[] = { + &pQueueFamilyProperties[0].queueFamilyProperties, + }; + tu_get_physical_device_queue_family_properties(pdevice, pCount, properties); + assert(*pCount <= 1); +} + +void +tu_GetPhysicalDeviceMemoryProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties *pMemoryProperties) +{ + stub(); +} + +void +tu_GetPhysicalDeviceMemoryProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2KHR *pMemoryProperties) +{ + return tu_GetPhysicalDeviceMemoryProperties( + physicalDevice, &pMemoryProperties->memoryProperties); +} + +static int +tu_queue_init(struct tu_device *device, + struct tu_queue *queue, + uint32_t queue_family_index, + int idx, + VkDeviceQueueCreateFlags flags) +{ + queue->_loader_data.loaderMagic = ICD_LOADER_MAGIC; + queue->device = device; + queue->queue_family_index = queue_family_index; + queue->queue_idx = idx; + queue->flags = flags; + + return VK_SUCCESS; +} + +static void +tu_queue_finish(struct tu_queue *queue) +{ +} + +static int +tu_get_device_extension_index(const char *name) +{ + for (unsigned i = 0; i < TU_DEVICE_EXTENSION_COUNT; ++i) { + if (strcmp(name, tu_device_extensions[i].extensionName) == 0) + return i; + } + return -1; +} + +VkResult +tu_CreateDevice(VkPhysicalDevice physicalDevice, + const VkDeviceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDevice *pDevice) +{ + TU_FROM_HANDLE(tu_physical_device, physical_device, physicalDevice); + VkResult result; + struct tu_device *device; + + /* Check enabled features */ + if (pCreateInfo->pEnabledFeatures) { + VkPhysicalDeviceFeatures supported_features; + tu_GetPhysicalDeviceFeatures(physicalDevice, &supported_features); + VkBool32 *supported_feature = (VkBool32 *)&supported_features; + VkBool32 *enabled_feature = (VkBool32 *)pCreateInfo->pEnabledFeatures; + unsigned num_features = + sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32); + for (uint32_t i = 0; i < num_features; i++) { + if (enabled_feature[i] && !supported_feature[i]) + return vk_error(physical_device->instance, + VK_ERROR_FEATURE_NOT_PRESENT); + } + } + + device = vk_zalloc2(&physical_device->instance->alloc, + pAllocator, + sizeof(*device), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); + if (!device) + return vk_error(physical_device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + device->_loader_data.loaderMagic = ICD_LOADER_MAGIC; + device->instance = physical_device->instance; + device->physical_device = physical_device; + + if (pAllocator) + device->alloc = *pAllocator; + else + device->alloc = physical_device->instance->alloc; + + for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { + const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i]; + int index = tu_get_device_extension_index(ext_name); + if (index < 0 || + !physical_device->supported_extensions.extensions[index]) { + vk_free(&device->alloc, device); + return vk_error(physical_device->instance, + VK_ERROR_EXTENSION_NOT_PRESENT); + } + + device->enabled_extensions.extensions[index] = true; + } + + for (unsigned i = 0; i < pCreateInfo->queueCreateInfoCount; i++) { + const VkDeviceQueueCreateInfo *queue_create = + &pCreateInfo->pQueueCreateInfos[i]; + uint32_t qfi = queue_create->queueFamilyIndex; + device->queues[qfi] = + vk_alloc(&device->alloc, + queue_create->queueCount * sizeof(struct tu_queue), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); + if (!device->queues[qfi]) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + memset(device->queues[qfi], + 0, + queue_create->queueCount * sizeof(struct tu_queue)); + + device->queue_count[qfi] = queue_create->queueCount; + + for (unsigned q = 0; q < queue_create->queueCount; q++) { + result = tu_queue_init( + device, &device->queues[qfi][q], qfi, q, queue_create->flags); + if (result != VK_SUCCESS) + goto fail; + } + } + + VkPipelineCacheCreateInfo ci; + ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + ci.pNext = NULL; + ci.flags = 0; + ci.pInitialData = NULL; + ci.initialDataSize = 0; + VkPipelineCache pc; + result = + tu_CreatePipelineCache(tu_device_to_handle(device), &ci, NULL, &pc); + if (result != VK_SUCCESS) + goto fail; + + device->mem_cache = tu_pipeline_cache_from_handle(pc); + + *pDevice = tu_device_to_handle(device); + return VK_SUCCESS; + +fail: + for (unsigned i = 0; i < TU_MAX_QUEUE_FAMILIES; i++) { + for (unsigned q = 0; q < device->queue_count[i]; q++) + tu_queue_finish(&device->queues[i][q]); + if (device->queue_count[i]) + vk_free(&device->alloc, device->queues[i]); + } + + vk_free(&device->alloc, device); + return result; +} + +void +tu_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + + if (!device) + return; + + for (unsigned i = 0; i < TU_MAX_QUEUE_FAMILIES; i++) { + for (unsigned q = 0; q < device->queue_count[i]; q++) + tu_queue_finish(&device->queues[i][q]); + if (device->queue_count[i]) + vk_free(&device->alloc, device->queues[i]); + } + + VkPipelineCache pc = tu_pipeline_cache_to_handle(device->mem_cache); + tu_DestroyPipelineCache(tu_device_to_handle(device), pc, NULL); + + vk_free(&device->alloc, device); +} + +VkResult +tu_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount, + VkLayerProperties *pProperties) +{ + if (pProperties == NULL) { + *pPropertyCount = 0; + return VK_SUCCESS; + } + + /* None supported at this time */ + return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT); +} + +VkResult +tu_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkLayerProperties *pProperties) +{ + if (pProperties == NULL) { + *pPropertyCount = 0; + return VK_SUCCESS; + } + + /* None supported at this time */ + return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT); +} + +void +tu_GetDeviceQueue2(VkDevice _device, + const VkDeviceQueueInfo2 *pQueueInfo, + VkQueue *pQueue) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_queue *queue; + + queue = + &device->queues[pQueueInfo->queueFamilyIndex][pQueueInfo->queueIndex]; + if (pQueueInfo->flags != queue->flags) { + /* 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." + */ + *pQueue = VK_NULL_HANDLE; + return; + } + + *pQueue = tu_queue_to_handle(queue); +} + +void +tu_GetDeviceQueue(VkDevice _device, + uint32_t queueFamilyIndex, + uint32_t queueIndex, + VkQueue *pQueue) +{ + const VkDeviceQueueInfo2 info = + (VkDeviceQueueInfo2){.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, + .queueFamilyIndex = queueFamilyIndex, + .queueIndex = queueIndex }; + + tu_GetDeviceQueue2(_device, &info, pQueue); +} + +VkResult +tu_QueueSubmit(VkQueue _queue, + uint32_t submitCount, + const VkSubmitInfo *pSubmits, + VkFence _fence) +{ + return VK_SUCCESS; +} + +VkResult +tu_QueueWaitIdle(VkQueue _queue) +{ + return VK_SUCCESS; +} + +VkResult +tu_DeviceWaitIdle(VkDevice _device) +{ + TU_FROM_HANDLE(tu_device, device, _device); + + for (unsigned i = 0; i < TU_MAX_QUEUE_FAMILIES; i++) { + for (unsigned q = 0; q < device->queue_count[i]; q++) { + tu_QueueWaitIdle(tu_queue_to_handle(&device->queues[i][q])); + } + } + return VK_SUCCESS; +} + +VkResult +tu_EnumerateInstanceExtensionProperties(const char *pLayerName, + uint32_t *pPropertyCount, + VkExtensionProperties *pProperties) +{ + VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount); + + for (int i = 0; i < TU_INSTANCE_EXTENSION_COUNT; i++) { + if (tu_supported_instance_extensions.extensions[i]) { + vk_outarray_append(&out, prop) { *prop = tu_instance_extensions[i]; } + } + } + + return vk_outarray_status(&out); +} + +VkResult +tu_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, + const char *pLayerName, + uint32_t *pPropertyCount, + VkExtensionProperties *pProperties) +{ + TU_FROM_HANDLE(tu_physical_device, device, physicalDevice); + VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount); + + for (int i = 0; i < TU_DEVICE_EXTENSION_COUNT; i++) { + if (device->supported_extensions.extensions[i]) { + vk_outarray_append(&out, prop) { *prop = tu_device_extensions[i]; } + } + } + + return vk_outarray_status(&out); +} + +PFN_vkVoidFunction +tu_GetInstanceProcAddr(VkInstance _instance, const char *pName) +{ + TU_FROM_HANDLE(tu_instance, instance, _instance); + + return tu_lookup_entrypoint_checked(pName, + instance ? instance->api_version : 0, + instance ? &instance->enabled_extensions + : NULL, + NULL); +} + +/* The loader wants us to expose a second GetInstanceProcAddr function + * to work around certain LD_PRELOAD issues seen in apps. + */ +PUBLIC +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL +vk_icdGetInstanceProcAddr(VkInstance instance, const char *pName); + +PUBLIC +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL +vk_icdGetInstanceProcAddr(VkInstance instance, const char *pName) +{ + return tu_GetInstanceProcAddr(instance, pName); +} + +PFN_vkVoidFunction +tu_GetDeviceProcAddr(VkDevice _device, const char *pName) +{ + TU_FROM_HANDLE(tu_device, device, _device); + + return tu_lookup_entrypoint_checked(pName, + device->instance->api_version, + &device->instance->enabled_extensions, + &device->enabled_extensions); +} + +static VkResult +tu_alloc_memory(struct tu_device *device, + const VkMemoryAllocateInfo *pAllocateInfo, + const VkAllocationCallbacks *pAllocator, + VkDeviceMemory *pMem) +{ + struct tu_device_memory *mem; + + assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO); + + if (pAllocateInfo->allocationSize == 0) { + /* Apparently, this is allowed */ + *pMem = VK_NULL_HANDLE; + return VK_SUCCESS; + } + + mem = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*mem), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (mem == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + *pMem = tu_device_memory_to_handle(mem); + + return VK_SUCCESS; +} + +VkResult +tu_AllocateMemory(VkDevice _device, + const VkMemoryAllocateInfo *pAllocateInfo, + const VkAllocationCallbacks *pAllocator, + VkDeviceMemory *pMem) +{ + TU_FROM_HANDLE(tu_device, device, _device); + return tu_alloc_memory(device, pAllocateInfo, pAllocator, pMem); +} + +void +tu_FreeMemory(VkDevice _device, + VkDeviceMemory _mem, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_device_memory, mem, _mem); + + if (mem == NULL) + return; + + vk_free2(&device->alloc, pAllocator, mem); +} + +VkResult +tu_MapMemory(VkDevice _device, + VkDeviceMemory _memory, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + void **ppData) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_device_memory, mem, _memory); + + if (mem == NULL) { + *ppData = NULL; + return VK_SUCCESS; + } + + if (mem->user_ptr) + *ppData = mem->user_ptr; + + if (*ppData) { + *ppData += offset; + return VK_SUCCESS; + } + + return vk_error(device->instance, VK_ERROR_MEMORY_MAP_FAILED); +} + +void +tu_UnmapMemory(VkDevice _device, VkDeviceMemory _memory) +{ + TU_FROM_HANDLE(tu_device_memory, mem, _memory); + + if (mem == NULL) + return; +} + +VkResult +tu_FlushMappedMemoryRanges(VkDevice _device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange *pMemoryRanges) +{ + return VK_SUCCESS; +} + +VkResult +tu_InvalidateMappedMemoryRanges(VkDevice _device, + uint32_t memoryRangeCount, + const VkMappedMemoryRange *pMemoryRanges) +{ + return VK_SUCCESS; +} + +void +tu_GetBufferMemoryRequirements(VkDevice _device, + VkBuffer _buffer, + VkMemoryRequirements *pMemoryRequirements) +{ + TU_FROM_HANDLE(tu_buffer, buffer, _buffer); + + pMemoryRequirements->alignment = 16; + pMemoryRequirements->size = + align64(buffer->size, pMemoryRequirements->alignment); +} + +void +tu_GetBufferMemoryRequirements2( + VkDevice device, + const VkBufferMemoryRequirementsInfo2KHR *pInfo, + VkMemoryRequirements2KHR *pMemoryRequirements) +{ + tu_GetBufferMemoryRequirements( + device, pInfo->buffer, &pMemoryRequirements->memoryRequirements); +} + +void +tu_GetImageMemoryRequirements(VkDevice _device, + VkImage _image, + VkMemoryRequirements *pMemoryRequirements) +{ + TU_FROM_HANDLE(tu_image, image, _image); + + /* TODO: memory type */ + + pMemoryRequirements->size = image->size; + pMemoryRequirements->alignment = image->alignment; +} + +void +tu_GetImageMemoryRequirements2(VkDevice device, + const VkImageMemoryRequirementsInfo2KHR *pInfo, + VkMemoryRequirements2KHR *pMemoryRequirements) +{ + tu_GetImageMemoryRequirements( + device, pInfo->image, &pMemoryRequirements->memoryRequirements); +} + +void +tu_GetImageSparseMemoryRequirements( + VkDevice device, + VkImage image, + uint32_t *pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements *pSparseMemoryRequirements) +{ + stub(); +} + +void +tu_GetImageSparseMemoryRequirements2( + VkDevice device, + const VkImageSparseMemoryRequirementsInfo2KHR *pInfo, + uint32_t *pSparseMemoryRequirementCount, + VkSparseImageMemoryRequirements2KHR *pSparseMemoryRequirements) +{ + stub(); +} + +void +tu_GetDeviceMemoryCommitment(VkDevice device, + VkDeviceMemory memory, + VkDeviceSize *pCommittedMemoryInBytes) +{ + *pCommittedMemoryInBytes = 0; +} + +VkResult +tu_BindBufferMemory2(VkDevice device, + uint32_t bindInfoCount, + const VkBindBufferMemoryInfoKHR *pBindInfos) +{ + return VK_SUCCESS; +} + +VkResult +tu_BindBufferMemory(VkDevice device, + VkBuffer buffer, + VkDeviceMemory memory, + VkDeviceSize memoryOffset) +{ + const VkBindBufferMemoryInfoKHR info = { + .sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR, + .buffer = buffer, + .memory = memory, + .memoryOffset = memoryOffset + }; + + return tu_BindBufferMemory2(device, 1, &info); +} + +VkResult +tu_BindImageMemory2(VkDevice device, + uint32_t bindInfoCount, + const VkBindImageMemoryInfoKHR *pBindInfos) +{ + return VK_SUCCESS; +} + +VkResult +tu_BindImageMemory(VkDevice device, + VkImage image, + VkDeviceMemory memory, + VkDeviceSize memoryOffset) +{ + const VkBindImageMemoryInfoKHR info = { + .sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR, + .image = image, + .memory = memory, + .memoryOffset = memoryOffset + }; + + return tu_BindImageMemory2(device, 1, &info); +} + +VkResult +tu_QueueBindSparse(VkQueue _queue, + uint32_t bindInfoCount, + const VkBindSparseInfo *pBindInfo, + VkFence _fence) +{ + return VK_SUCCESS; +} + +VkResult +tu_CreateFence(VkDevice _device, + const VkFenceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkFence *pFence) +{ + TU_FROM_HANDLE(tu_device, device, _device); + + struct tu_fence *fence = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*fence), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!fence) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + *pFence = tu_fence_to_handle(fence); + + return VK_SUCCESS; +} + +void +tu_DestroyFence(VkDevice _device, + VkFence _fence, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_fence, fence, _fence); + + if (!fence) + return; + + vk_free2(&device->alloc, pAllocator, fence); +} + +VkResult +tu_WaitForFences(VkDevice _device, + uint32_t fenceCount, + const VkFence *pFences, + VkBool32 waitAll, + uint64_t timeout) +{ + return VK_SUCCESS; +} + +VkResult +tu_ResetFences(VkDevice _device, uint32_t fenceCount, const VkFence *pFences) +{ + return VK_SUCCESS; +} + +VkResult +tu_GetFenceStatus(VkDevice _device, VkFence _fence) +{ + return VK_SUCCESS; +} + +// Queue semaphore functions + +VkResult +tu_CreateSemaphore(VkDevice _device, + const VkSemaphoreCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSemaphore *pSemaphore) +{ + TU_FROM_HANDLE(tu_device, device, _device); + + struct tu_semaphore *sem = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*sem), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!sem) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + *pSemaphore = tu_semaphore_to_handle(sem); + return VK_SUCCESS; +} + +void +tu_DestroySemaphore(VkDevice _device, + VkSemaphore _semaphore, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_semaphore, sem, _semaphore); + if (!_semaphore) + return; + + vk_free2(&device->alloc, pAllocator, sem); +} + +VkResult +tu_CreateEvent(VkDevice _device, + const VkEventCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkEvent *pEvent) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_event *event = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*event), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!event) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + *pEvent = tu_event_to_handle(event); + + return VK_SUCCESS; +} + +void +tu_DestroyEvent(VkDevice _device, + VkEvent _event, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_event, event, _event); + + if (!event) + return; + vk_free2(&device->alloc, pAllocator, event); +} + +VkResult +tu_GetEventStatus(VkDevice _device, VkEvent _event) +{ + TU_FROM_HANDLE(tu_event, event, _event); + + if (*event->map == 1) + return VK_EVENT_SET; + return VK_EVENT_RESET; +} + +VkResult +tu_SetEvent(VkDevice _device, VkEvent _event) +{ + TU_FROM_HANDLE(tu_event, event, _event); + *event->map = 1; + + return VK_SUCCESS; +} + +VkResult +tu_ResetEvent(VkDevice _device, VkEvent _event) +{ + TU_FROM_HANDLE(tu_event, event, _event); + *event->map = 0; + + return VK_SUCCESS; +} + +VkResult +tu_CreateBuffer(VkDevice _device, + const VkBufferCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkBuffer *pBuffer) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_buffer *buffer; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO); + + buffer = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*buffer), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (buffer == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + buffer->size = pCreateInfo->size; + buffer->usage = pCreateInfo->usage; + buffer->flags = pCreateInfo->flags; + + *pBuffer = tu_buffer_to_handle(buffer); + + return VK_SUCCESS; +} + +void +tu_DestroyBuffer(VkDevice _device, + VkBuffer _buffer, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_buffer, buffer, _buffer); + + if (!buffer) + return; + + vk_free2(&device->alloc, pAllocator, buffer); +} + +static uint32_t +tu_surface_max_layer_count(struct tu_image_view *iview) +{ + return iview->type == VK_IMAGE_VIEW_TYPE_3D + ? iview->extent.depth + : (iview->base_layer + iview->layer_count); +} + +VkResult +tu_CreateFramebuffer(VkDevice _device, + const VkFramebufferCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkFramebuffer *pFramebuffer) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_framebuffer *framebuffer; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO); + + size_t size = + sizeof(*framebuffer) + + sizeof(struct tu_attachment_info) * pCreateInfo->attachmentCount; + framebuffer = vk_alloc2( + &device->alloc, pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (framebuffer == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + framebuffer->attachment_count = pCreateInfo->attachmentCount; + framebuffer->width = pCreateInfo->width; + framebuffer->height = pCreateInfo->height; + framebuffer->layers = pCreateInfo->layers; + for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { + VkImageView _iview = pCreateInfo->pAttachments[i]; + struct tu_image_view *iview = tu_image_view_from_handle(_iview); + framebuffer->attachments[i].attachment = iview; + + framebuffer->width = MIN2(framebuffer->width, iview->extent.width); + framebuffer->height = MIN2(framebuffer->height, iview->extent.height); + framebuffer->layers = + MIN2(framebuffer->layers, tu_surface_max_layer_count(iview)); + } + + *pFramebuffer = tu_framebuffer_to_handle(framebuffer); + return VK_SUCCESS; +} + +void +tu_DestroyFramebuffer(VkDevice _device, + VkFramebuffer _fb, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_framebuffer, fb, _fb); + + if (!fb) + return; + vk_free2(&device->alloc, pAllocator, fb); +} + +static void +tu_init_sampler(struct tu_device *device, + struct tu_sampler *sampler, + const VkSamplerCreateInfo *pCreateInfo) +{ +} + +VkResult +tu_CreateSampler(VkDevice _device, + const VkSamplerCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSampler *pSampler) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_sampler *sampler; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO); + + sampler = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*sampler), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!sampler) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + tu_init_sampler(device, sampler, pCreateInfo); + *pSampler = tu_sampler_to_handle(sampler); + + return VK_SUCCESS; +} + +void +tu_DestroySampler(VkDevice _device, + VkSampler _sampler, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_sampler, sampler, _sampler); + + if (!sampler) + return; + vk_free2(&device->alloc, pAllocator, sampler); +} + +/* vk_icd.h does not declare this function, so we declare it here to + * suppress Wmissing-prototypes. + */ +PUBLIC VKAPI_ATTR VkResult VKAPI_CALL +vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *pSupportedVersion); + +PUBLIC VKAPI_ATTR VkResult VKAPI_CALL +vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *pSupportedVersion) +{ + /* For the full details on loader interface versioning, see + * <https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md>. + * What follows is a condensed summary, to help you navigate the large and + * confusing official doc. + * + * - Loader interface v0 is incompatible with later versions. We don't + * support it. + * + * - In loader interface v1: + * - The first ICD entrypoint called by the loader is + * vk_icdGetInstanceProcAddr(). The ICD must statically expose this + * entrypoint. + * - The ICD must statically expose no other Vulkan symbol unless it is + * linked with -Bsymbolic. + * - Each dispatchable Vulkan handle created by the ICD must be + * a pointer to a struct whose first member is VK_LOADER_DATA. The + * ICD must initialize VK_LOADER_DATA.loadMagic to ICD_LOADER_MAGIC. + * - The loader implements vkCreate{PLATFORM}SurfaceKHR() and + * vkDestroySurfaceKHR(). The ICD must be capable of working with + * such loader-managed surfaces. + * + * - Loader interface v2 differs from v1 in: + * - The first ICD entrypoint called by the loader is + * vk_icdNegotiateLoaderICDInterfaceVersion(). The ICD must + * statically expose this entrypoint. + * + * - Loader interface v3 differs from v2 in: + * - The ICD must implement vkCreate{PLATFORM}SurfaceKHR(), + * vkDestroySurfaceKHR(), and other API which uses VKSurfaceKHR, + * because the loader no longer does so. + */ + *pSupportedVersion = MIN2(*pSupportedVersion, 3u); + return VK_SUCCESS; +} + +void +tu_GetPhysicalDeviceExternalSemaphoreProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfoKHR *pExternalSemaphoreInfo, + VkExternalSemaphorePropertiesKHR *pExternalSemaphoreProperties) +{ + pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; + pExternalSemaphoreProperties->compatibleHandleTypes = 0; + pExternalSemaphoreProperties->externalSemaphoreFeatures = 0; +} + +void +tu_GetPhysicalDeviceExternalFenceProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfoKHR *pExternalFenceInfo, + VkExternalFencePropertiesKHR *pExternalFenceProperties) +{ + pExternalFenceProperties->exportFromImportedHandleTypes = 0; + pExternalFenceProperties->compatibleHandleTypes = 0; + pExternalFenceProperties->externalFenceFeatures = 0; +} + +VkResult +tu_CreateDebugReportCallbackEXT( + VkInstance _instance, + const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugReportCallbackEXT *pCallback) +{ + TU_FROM_HANDLE(tu_instance, instance, _instance); + return vk_create_debug_report_callback(&instance->debug_report_callbacks, + pCreateInfo, + pAllocator, + &instance->alloc, + pCallback); +} + +void +tu_DestroyDebugReportCallbackEXT(VkInstance _instance, + VkDebugReportCallbackEXT _callback, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_instance, instance, _instance); + vk_destroy_debug_report_callback(&instance->debug_report_callbacks, + _callback, + pAllocator, + &instance->alloc); +} + +void +tu_DebugReportMessageEXT(VkInstance _instance, + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char *pLayerPrefix, + const char *pMessage) +{ + TU_FROM_HANDLE(tu_instance, instance, _instance); + vk_debug_report(&instance->debug_report_callbacks, + flags, + objectType, + object, + location, + messageCode, + pLayerPrefix, + pMessage); +} + +void +tu_GetDeviceGroupPeerMemoryFeatures( + VkDevice device, + uint32_t heapIndex, + uint32_t localDeviceIndex, + uint32_t remoteDeviceIndex, + VkPeerMemoryFeatureFlags *pPeerMemoryFeatures) +{ + assert(localDeviceIndex == remoteDeviceIndex); + + *pPeerMemoryFeatures = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT | + VK_PEER_MEMORY_FEATURE_COPY_DST_BIT | + VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT | + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT; +} diff --git a/src/freedreno/vulkan/tu_entrypoints_gen.py b/src/freedreno/vulkan/tu_entrypoints_gen.py new file mode 100644 index 00000000000..865ad1de843 --- /dev/null +++ b/src/freedreno/vulkan/tu_entrypoints_gen.py @@ -0,0 +1,506 @@ +# coding=utf-8 +# +# Copyright © 2015, 2017 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 functools +import math +import os +import xml.etree.cElementTree as et + +from collections import OrderedDict, namedtuple +from mako.template import Template + +from tu_extensions import VkVersion, MAX_API_VERSION, EXTENSIONS + +# We generate a static hash table for entry point lookup +# (vkGetProcAddress). We use a linear congruential generator for our hash +# function and a power-of-two size table. The prime numbers are determined +# experimentally. + +# We currently don't use layers in tu, but keeping the ability for anv +# anyways, so we can use it for device groups. +LAYERS = [ + 'tu' +] + +TEMPLATE_H = Template("""\ +/* This file generated from ${filename}, don't edit directly. */ + +struct tu_dispatch_table { + union { + void *entrypoints[${len(entrypoints)}]; + struct { + % for e in entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + PFN_${e.name} ${e.name}; +#else + void *${e.name}; +# endif + % else: + PFN_${e.name} ${e.name}; + % endif + % endfor + }; + }; +}; + +% for e in entrypoints: + % if e.alias: + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif + % for layer in LAYERS: + ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}); + % endfor + % if e.guard is not None: +#endif // ${e.guard} + % endif +% endfor +""", output_encoding='utf-8') + +TEMPLATE_C = Template(u"""\ +/* + * Copyright © 2015 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. + */ + +/* This file generated from ${filename}, don't edit directly. */ + +#include "tu_private.h" + +struct string_map_entry { + uint32_t name; + uint32_t hash; + uint32_t num; +}; + +/* We use a big string constant to avoid lots of relocations from the entry + * point table to lots of little strings. The entries in the entry point table + * store the index into this big string. + */ + +static const char strings[] = +% for s in strmap.sorted_strings: + "${s.string}\\0" +% endfor +; + +static const struct string_map_entry string_map_entries[] = { +% for s in strmap.sorted_strings: + { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */ +% endfor +}; + +/* Hash table stats: + * size ${len(strmap.sorted_strings)} entries + * collisions entries: +% for i in range(10): + * ${i}${'+' if i == 9 else ' '} ${strmap.collisions[i]} +% endfor + */ + +#define none 0xffff +static const uint16_t string_map[${strmap.hash_size}] = { +% for e in strmap.mapping: + ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' }, +% endfor +}; + +/* Weak aliases for all potential implementations. These will resolve to + * NULL if they're not defined, which lets the resolve_entrypoint() function + * either pick the correct entry point. + */ + +% for layer in LAYERS: + % for e in entrypoints: + % if e.alias: + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif + ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}) __attribute__ ((weak)); + % if e.guard is not None: +#endif // ${e.guard} + % endif + % endfor + + const struct tu_dispatch_table ${layer}_layer = { + % for e in entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + % endif + .${e.name} = ${e.prefixed_name(layer)}, + % if e.guard is not None: +#endif // ${e.guard} + % endif + % endfor + }; +% endfor + +static void * __attribute__ ((noinline)) +tu_resolve_entrypoint(uint32_t index) +{ + return tu_layer.entrypoints[index]; +} + +/** Return true if the core version or extension in which the given entrypoint + * is defined is enabled. + * + * If instance is NULL, we only allow the 3 commands explicitly allowed by the vk + * spec. + * + * If device is NULL, all device extensions are considered enabled. + */ +static bool +tu_entrypoint_is_enabled(int index, uint32_t core_version, + const struct tu_instance_extension_table *instance, + const struct tu_device_extension_table *device) +{ + switch (index) { +% for e in entrypoints: + case ${e.num}: + % if not e.device_command: + if (device) return false; + % endif + % if e.name == 'vkCreateInstance' or e.name == 'vkEnumerateInstanceExtensionProperties' or e.name == 'vkEnumerateInstanceLayerProperties' or e.name == 'vkEnumerateInstanceVersion': + return !device; + % elif e.core_version: + return instance && ${e.core_version.c_vk_version()} <= core_version; + % elif e.extensions: + % for ext in e.extensions: + % if ext.type == 'instance': + if (instance && instance->${ext.name[3:]}) return true; + % else: + if (instance && (!device || device->${ext.name[3:]})) return true; + % endif + %endfor + return false; + % else: + return instance; + % endif +% endfor + default: + return false; + } +} + +static int +tu_lookup_entrypoint(const char *name) +{ + static const uint32_t prime_factor = ${strmap.prime_factor}; + static const uint32_t prime_step = ${strmap.prime_step}; + const struct string_map_entry *e; + uint32_t hash, h; + uint16_t i; + const char *p; + + hash = 0; + for (p = name; *p; p++) + hash = hash * prime_factor + *p; + + h = hash; + while (1) { + i = string_map[h & ${strmap.hash_mask}]; + if (i == none) + return -1; + e = &string_map_entries[i]; + if (e->hash == hash && strcmp(name, strings + e->name) == 0) + return e->num; + h += prime_step; + } + + return -1; +} + +void * +tu_lookup_entrypoint_unchecked(const char *name) +{ + int index = tu_lookup_entrypoint(name); + if (index < 0) + return NULL; + return tu_resolve_entrypoint(index); +} + +void * +tu_lookup_entrypoint_checked(const char *name, + uint32_t core_version, + const struct tu_instance_extension_table *instance, + const struct tu_device_extension_table *device) +{ + int index = tu_lookup_entrypoint(name); + if (index < 0 || !tu_entrypoint_is_enabled(index, core_version, instance, device)) + return NULL; + return tu_resolve_entrypoint(index); +}""", output_encoding='utf-8') + +U32_MASK = 2**32 - 1 + +PRIME_FACTOR = 5024183 +PRIME_STEP = 19 + +def round_to_pow2(x): + return 2**int(math.ceil(math.log(x, 2))) + +class StringIntMapEntry(object): + def __init__(self, string, num): + self.string = string + self.num = num + + # Calculate the same hash value that we will calculate in C. + h = 0 + for c in string: + h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK + self.hash = h + + self.offset = None + +class StringIntMap(object): + def __init__(self): + self.baked = False + self.strings = dict() + + def add_string(self, string, num): + assert not self.baked + assert string not in self.strings + assert num >= 0 and num < 2**31 + self.strings[string] = StringIntMapEntry(string, num) + + def bake(self): + self.sorted_strings = \ + sorted(self.strings.values(), key=lambda x: x.string) + offset = 0 + for entry in self.sorted_strings: + entry.offset = offset + offset += len(entry.string) + 1 + + # Save off some values that we'll need in C + self.hash_size = round_to_pow2(len(self.strings) * 1.25) + self.hash_mask = self.hash_size - 1 + self.prime_factor = PRIME_FACTOR + self.prime_step = PRIME_STEP + + self.mapping = [-1] * self.hash_size + self.collisions = [0] * 10 + for idx, s in enumerate(self.sorted_strings): + level = 0 + h = s.hash + while self.mapping[h & self.hash_mask] >= 0: + h = h + PRIME_STEP + level = level + 1 + self.collisions[min(level, 9)] += 1 + self.mapping[h & self.hash_mask] = idx + +EntrypointParam = namedtuple('EntrypointParam', 'type name decl') + +class EntrypointBase(object): + def __init__(self, name): + self.name = name + self.alias = None + self.guard = None + self.enabled = False + self.num = None + # Extensions which require this entrypoint + self.core_version = None + self.extensions = [] + +class Entrypoint(EntrypointBase): + def __init__(self, name, return_type, params, guard = None): + super(Entrypoint, self).__init__(name) + self.return_type = return_type + self.params = params + self.guard = guard + self.device_command = len(params) > 0 and (params[0].type == 'VkDevice' or params[0].type == 'VkQueue' or params[0].type == 'VkCommandBuffer') + + def prefixed_name(self, prefix): + assert self.name.startswith('vk') + return prefix + '_' + self.name[2:] + + def decl_params(self): + return ', '.join(p.decl for p in self.params) + + def call_params(self): + return ', '.join(p.name for p in self.params) + +class EntrypointAlias(EntrypointBase): + def __init__(self, name, entrypoint): + super(EntrypointAlias, self).__init__(name) + self.alias = entrypoint + self.device_command = entrypoint.device_command + + def prefixed_name(self, prefix): + return self.alias.prefixed_name(prefix) + +def get_entrypoints(doc, entrypoints_to_defines, start_index): + """Extract the entry points from the registry.""" + entrypoints = OrderedDict() + + for command in doc.findall('./commands/command'): + if 'alias' in command.attrib: + alias = command.attrib['name'] + target = command.attrib['alias'] + entrypoints[alias] = EntrypointAlias(alias, entrypoints[target]) + else: + name = command.find('./proto/name').text + ret_type = command.find('./proto/type').text + params = [EntrypointParam( + type = p.find('./type').text, + name = p.find('./name').text, + decl = ''.join(p.itertext()) + ) for p in command.findall('./param')] + guard = entrypoints_to_defines.get(name) + # They really need to be unique + assert name not in entrypoints + entrypoints[name] = Entrypoint(name, ret_type, params, guard) + + for feature in doc.findall('./feature'): + assert feature.attrib['api'] == 'vulkan' + version = VkVersion(feature.attrib['number']) + if version > MAX_API_VERSION: + continue + + for command in feature.findall('./require/command'): + e = entrypoints[command.attrib['name']] + e.enabled = True + assert e.core_version is None + e.core_version = version + + supported_exts = dict((ext.name, ext) for ext in EXTENSIONS) + for extension in doc.findall('.extensions/extension'): + ext_name = extension.attrib['name'] + if ext_name not in supported_exts: + continue + + ext = supported_exts[ext_name] + ext.type = extension.attrib['type'] + + for command in extension.findall('./require/command'): + e = entrypoints[command.attrib['name']] + e.enabled = True + assert e.core_version is None + e.extensions.append(ext) + + # if the base command is not supported by the driver yet, don't alias aliases + for e in entrypoints.values(): + if e.alias and not e.alias.enabled: + e_clone = copy.deepcopy(e.alias) + e_clone.enabled = True + e_clone.name = e.name + entrypoints[e.name] = e_clone + + return [e for e in entrypoints.values() if e.enabled] + + +def get_entrypoints_defines(doc): + """Maps entry points to extension defines.""" + entrypoints_to_defines = {} + + for extension in doc.findall('./extensions/extension[@protect]'): + define = extension.attrib['protect'] + + for entrypoint in extension.findall('./require/command'): + fullname = entrypoint.attrib['name'] + entrypoints_to_defines[fullname] = define + + for extension in doc.findall('./extensions/extension[@platform]'): + platform = extension.attrib['platform'] + ext = '_KHR' + if platform.upper() == 'XLIB_XRANDR': + ext = '_EXT' + define = 'VK_USE_PLATFORM_' + platform.upper() + ext + + for entrypoint in extension.findall('./require/command'): + fullname = entrypoint.attrib['name'] + entrypoints_to_defines[fullname] = define + + return entrypoints_to_defines + + +def gen_code(entrypoints): + """Generate the C code.""" + strmap = StringIntMap() + for e in entrypoints: + strmap.add_string(e.name, e.num) + strmap.bake() + + return TEMPLATE_C.render(entrypoints=entrypoints, + LAYERS=LAYERS, + strmap=strmap, + filename=os.path.basename(__file__)) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--outdir', help='Where to write the files.', + required=True) + parser.add_argument('--xml', + help='Vulkan API XML file.', + required=True, + action='append', + dest='xml_files') + args = parser.parse_args() + + entrypoints = [] + + for filename in args.xml_files: + doc = et.parse(filename) + entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc), + start_index=len(entrypoints)) + + for num, e in enumerate(entrypoints): + e.num = num + + # For outputting entrypoints.h we generate a tu_EntryPoint() prototype + # per entry point. + with open(os.path.join(args.outdir, 'tu_entrypoints.h'), 'wb') as f: + f.write(TEMPLATE_H.render(entrypoints=entrypoints, + LAYERS=LAYERS, + filename=os.path.basename(__file__))) + with open(os.path.join(args.outdir, 'tu_entrypoints.c'), 'wb') as f: + f.write(gen_code(entrypoints)) + + +if __name__ == '__main__': + main() diff --git a/src/freedreno/vulkan/tu_extensions.py b/src/freedreno/vulkan/tu_extensions.py new file mode 100644 index 00000000000..37b4f0ca0f0 --- /dev/null +++ b/src/freedreno/vulkan/tu_extensions.py @@ -0,0 +1,275 @@ +COPYRIGHT = """\ +/* + * Copyright 2017 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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 copy +import re +import xml.etree.cElementTree as et + +from mako.template import Template + +MAX_API_VERSION = '1.1.82' + +class Extension: + def __init__(self, name, ext_version, enable): + self.name = name + self.ext_version = int(ext_version) + if enable is True: + self.enable = 'true'; + elif enable is False: + self.enable = 'false'; + else: + self.enable = enable; + +# On Android, we disable all surface and swapchain extensions. Android's Vulkan +# loader implements VK_KHR_surface and VK_KHR_swapchain, and applications +# cannot access the driver's implementation. Moreoever, if the driver exposes +# the those extension strings, then tests dEQP-VK.api.info.instance.extensions +# and dEQP-VK.api.info.device fail due to the duplicated strings. +EXTENSIONS = [ + Extension('VK_KHR_bind_memory2', 1, True), + Extension('VK_KHR_create_renderpass2', 1, True), + Extension('VK_KHR_dedicated_allocation', 1, True), + Extension('VK_KHR_get_display_properties2', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), + Extension('VK_KHR_get_memory_requirements2', 1, True), + Extension('VK_KHR_get_physical_device_properties2', 1, True), + Extension('VK_KHR_get_surface_capabilities2', 1, 'TU_HAS_SURFACE'), + Extension('VK_KHR_maintenance1', 1, True), + Extension('VK_KHR_maintenance2', 1, True), + Extension('VK_KHR_maintenance3', 1, True), + Extension('VK_KHR_surface', 25, 'TU_HAS_SURFACE'), + Extension('VK_KHR_swapchain', 68, 'TU_HAS_SURFACE'), + Extension('VK_KHR_wayland_surface', 6, 'VK_USE_PLATFORM_WAYLAND_KHR'), + Extension('VK_KHR_xcb_surface', 6, 'VK_USE_PLATFORM_XCB_KHR'), + Extension('VK_KHR_xlib_surface', 6, 'VK_USE_PLATFORM_XLIB_KHR'), + Extension('VK_KHR_display', 23, 'VK_USE_PLATFORM_DISPLAY_KHR'), + Extension('VK_EXT_direct_mode_display', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), + Extension('VK_EXT_acquire_xlib_display', 1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'), + Extension('VK_EXT_display_surface_counter', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), + Extension('VK_EXT_display_control', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), + Extension('VK_EXT_debug_report', 9, True), +] + +class VkVersion: + def __init__(self, string): + split = string.split('.') + self.major = int(split[0]) + self.minor = int(split[1]) + if len(split) > 2: + assert len(split) == 3 + self.patch = int(split[2]) + else: + self.patch = None + + # Sanity check. The range bits are required by the definition of the + # VK_MAKE_VERSION macro + assert self.major < 1024 and self.minor < 1024 + assert self.patch is None or self.patch < 4096 + assert(str(self) == string) + + def __str__(self): + ver_list = [str(self.major), str(self.minor)] + if self.patch is not None: + ver_list.append(str(self.patch)) + return '.'.join(ver_list) + + def c_vk_version(self): + patch = self.patch if self.patch is not None else 0 + ver_list = [str(self.major), str(self.minor), str(patch)] + return 'VK_MAKE_VERSION(' + ', '.join(ver_list) + ')' + + def __int_ver(self): + # This is just an expansion of VK_VERSION + patch = self.patch if self.patch is not None else 0 + return (self.major << 22) | (self.minor << 12) | patch + + def __gt__(self, other): + # If only one of them has a patch version, "ignore" it by making + # other's patch version match self. + if (self.patch is None) != (other.patch is None): + other = copy.copy(other) + other.patch = self.patch + + return self.__int_ver() > other.__int_ver() + +MAX_API_VERSION = VkVersion(MAX_API_VERSION) + +def _init_exts_from_xml(xml): + """ Walk the Vulkan XML and fill out extra extension information. """ + + xml = et.parse(xml) + + ext_name_map = {} + for ext in EXTENSIONS: + ext_name_map[ext.name] = ext + + for ext_elem in xml.findall('.extensions/extension'): + ext_name = ext_elem.attrib['name'] + if ext_name not in ext_name_map: + continue + + ext = ext_name_map[ext_name] + ext.type = ext_elem.attrib['type'] + +_TEMPLATE_H = Template(COPYRIGHT + """ +#ifndef TU_EXTENSIONS_H +#define TU_EXTENSIONS_H + +enum { + TU_INSTANCE_EXTENSION_COUNT = ${len(instance_extensions)}, + TU_DEVICE_EXTENSION_COUNT = ${len(device_extensions)}, +}; + +struct tu_instance_extension_table { + union { + bool extensions[TU_INSTANCE_EXTENSION_COUNT]; + struct { +%for ext in instance_extensions: + bool ${ext.name[3:]}; +%endfor + }; + }; +}; + +struct tu_device_extension_table { + union { + bool extensions[TU_DEVICE_EXTENSION_COUNT]; + struct { +%for ext in device_extensions: + bool ${ext.name[3:]}; +%endfor + }; + }; +}; + +extern const VkExtensionProperties tu_instance_extensions[TU_INSTANCE_EXTENSION_COUNT]; +extern const VkExtensionProperties tu_device_extensions[TU_DEVICE_EXTENSION_COUNT]; +extern const struct tu_instance_extension_table tu_supported_instance_extensions; + + +struct tu_physical_device; + +void tu_fill_device_extension_table(const struct tu_physical_device *device, + struct tu_device_extension_table* table); +#endif +""") + +_TEMPLATE_C = Template(COPYRIGHT + """ +#include "tu_private.h" + +#include "vk_util.h" + +/* Convert the VK_USE_PLATFORM_* defines to booleans */ +%for platform in ['ANDROID_KHR', 'WAYLAND_KHR', 'XCB_KHR', 'XLIB_KHR', 'DISPLAY_KHR', 'XLIB_XRANDR_EXT']: +#ifdef VK_USE_PLATFORM_${platform} +# undef VK_USE_PLATFORM_${platform} +# define VK_USE_PLATFORM_${platform} true +#else +# define VK_USE_PLATFORM_${platform} false +#endif +%endfor + +/* And ANDROID too */ +#ifdef ANDROID +# undef ANDROID +# define ANDROID true +#else +# define ANDROID false +#endif + +#define TU_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\ + VK_USE_PLATFORM_XCB_KHR || \\ + VK_USE_PLATFORM_XLIB_KHR || \\ + VK_USE_PLATFORM_DISPLAY_KHR) + + +const VkExtensionProperties tu_instance_extensions[TU_INSTANCE_EXTENSION_COUNT] = { +%for ext in instance_extensions: + {"${ext.name}", ${ext.ext_version}}, +%endfor +}; + +const VkExtensionProperties tu_device_extensions[TU_DEVICE_EXTENSION_COUNT] = { +%for ext in device_extensions: + {"${ext.name}", ${ext.ext_version}}, +%endfor +}; + +const struct tu_instance_extension_table tu_supported_instance_extensions = { +%for ext in instance_extensions: + .${ext.name[3:]} = ${ext.enable}, +%endfor +}; + +void tu_fill_device_extension_table(const struct tu_physical_device *device, + struct tu_device_extension_table* table) +{ +%for ext in device_extensions: + table->${ext.name[3:]} = ${ext.enable}; +%endfor +} + +VkResult tu_EnumerateInstanceVersion( + uint32_t* pApiVersion) +{ + *pApiVersion = ${MAX_API_VERSION.c_vk_version()}; + return VK_SUCCESS; +} + +uint32_t +tu_physical_device_api_version(struct tu_physical_device *dev) +{ + return VK_MAKE_VERSION(1, 1, 82); +} +""") + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--out-c', help='Output C file.', required=True) + parser.add_argument('--out-h', help='Output H file.', required=True) + parser.add_argument('--xml', + help='Vulkan API XML file.', + required=True, + action='append', + dest='xml_files') + args = parser.parse_args() + + for filename in args.xml_files: + _init_exts_from_xml(filename) + + for ext in EXTENSIONS: + assert ext.type == 'instance' or ext.type == 'device' + + template_env = { + 'MAX_API_VERSION': MAX_API_VERSION, + 'instance_extensions': [e for e in EXTENSIONS if e.type == 'instance'], + 'device_extensions': [e for e in EXTENSIONS if e.type == 'device'], + } + + with open(args.out_c, 'w') as f: + f.write(_TEMPLATE_C.render(**template_env)) + with open(args.out_h, 'w') as f: + f.write(_TEMPLATE_H.render(**template_env)) diff --git a/src/freedreno/vulkan/tu_formats.c b/src/freedreno/vulkan/tu_formats.c new file mode 100644 index 00000000000..09f8c93a187 --- /dev/null +++ b/src/freedreno/vulkan/tu_formats.c @@ -0,0 +1,410 @@ + +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * 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 "tu_private.h" + +#include "vk_format.h" + +#include "vk_util.h" + +#include "util/format_r11g11b10f.h" +#include "util/format_srgb.h" +#include "util/u_half.h" + +static void +tu_physical_device_get_format_properties( + struct tu_physical_device *physical_device, + VkFormat format, + VkFormatProperties *out_properties) +{ + VkFormatFeatureFlags linear = 0, tiled = 0, buffer = 0; + const struct vk_format_description *desc = vk_format_description(format); + if (!desc) { + out_properties->linearTilingFeatures = linear; + out_properties->optimalTilingFeatures = tiled; + out_properties->bufferFeatures = buffer; + return; + } + + out_properties->linearTilingFeatures = linear; + out_properties->optimalTilingFeatures = tiled; + out_properties->bufferFeatures = buffer; +} + +void +tu_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties *pFormatProperties) +{ + TU_FROM_HANDLE(tu_physical_device, physical_device, physicalDevice); + + tu_physical_device_get_format_properties( + physical_device, format, pFormatProperties); +} + +void +tu_GetPhysicalDeviceFormatProperties2( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2KHR *pFormatProperties) +{ + TU_FROM_HANDLE(tu_physical_device, physical_device, physicalDevice); + + tu_physical_device_get_format_properties( + physical_device, format, &pFormatProperties->formatProperties); +} + +static VkResult +tu_get_image_format_properties(struct tu_physical_device *physical_device, + const VkPhysicalDeviceImageFormatInfo2KHR *info, + VkImageFormatProperties *pImageFormatProperties) + +{ + VkFormatProperties format_props; + VkFormatFeatureFlags format_feature_flags; + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArraySize; + VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT; + + tu_physical_device_get_format_properties( + physical_device, info->format, &format_props); + if (info->tiling == VK_IMAGE_TILING_LINEAR) { + format_feature_flags = format_props.linearTilingFeatures; + } else if (info->tiling == VK_IMAGE_TILING_OPTIMAL) { + format_feature_flags = format_props.optimalTilingFeatures; + } else { + unreachable("bad VkImageTiling"); + } + + if (format_feature_flags == 0) + goto unsupported; + + if (info->type != VK_IMAGE_TYPE_2D && + vk_format_is_depth_or_stencil(info->format)) + goto unsupported; + + switch (info->type) { + default: + unreachable("bad vkimage type\n"); + case VK_IMAGE_TYPE_1D: + maxExtent.width = 16384; + maxExtent.height = 1; + maxExtent.depth = 1; + maxMipLevels = 15; /* log2(maxWidth) + 1 */ + maxArraySize = 2048; + break; + case VK_IMAGE_TYPE_2D: + maxExtent.width = 16384; + maxExtent.height = 16384; + maxExtent.depth = 1; + maxMipLevels = 15; /* log2(maxWidth) + 1 */ + maxArraySize = 2048; + break; + case VK_IMAGE_TYPE_3D: + maxExtent.width = 2048; + maxExtent.height = 2048; + maxExtent.depth = 2048; + maxMipLevels = 12; /* log2(maxWidth) + 1 */ + maxArraySize = 1; + break; + } + + if (info->tiling == VK_IMAGE_TILING_OPTIMAL && + info->type == VK_IMAGE_TYPE_2D && + (format_feature_flags & + (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) && + !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && + !(info->usage & VK_IMAGE_USAGE_STORAGE_BIT)) { + sampleCounts |= + VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT | VK_SAMPLE_COUNT_8_BIT; + } + + if (info->usage & VK_IMAGE_USAGE_SAMPLED_BIT) { + if (!(format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { + goto unsupported; + } + } + + if (info->usage & VK_IMAGE_USAGE_STORAGE_BIT) { + if (!(format_feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { + goto unsupported; + } + } + + if (info->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { + if (!(format_feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { + goto unsupported; + } + } + + if (info->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + if (!(format_feature_flags & + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + goto unsupported; + } + } + + *pImageFormatProperties = (VkImageFormatProperties){ + .maxExtent = maxExtent, + .maxMipLevels = maxMipLevels, + .maxArrayLayers = maxArraySize, + .sampleCounts = sampleCounts, + + /* FINISHME: Accurately calculate + * VkImageFormatProperties::maxResourceSize. + */ + .maxResourceSize = UINT32_MAX, + }; + + return VK_SUCCESS; +unsupported: + *pImageFormatProperties = (VkImageFormatProperties){ + .maxExtent = { 0, 0, 0 }, + .maxMipLevels = 0, + .maxArrayLayers = 0, + .sampleCounts = 0, + .maxResourceSize = 0, + }; + + return VK_ERROR_FORMAT_NOT_SUPPORTED; +} + +VkResult +tu_GetPhysicalDeviceImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags createFlags, + VkImageFormatProperties *pImageFormatProperties) +{ + TU_FROM_HANDLE(tu_physical_device, physical_device, physicalDevice); + + const VkPhysicalDeviceImageFormatInfo2KHR info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR, + .pNext = NULL, + .format = format, + .type = type, + .tiling = tiling, + .usage = usage, + .flags = createFlags, + }; + + return tu_get_image_format_properties( + physical_device, &info, pImageFormatProperties); +} + +static void +get_external_image_format_properties( + const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo, + VkExternalMemoryHandleTypeFlagBitsKHR handleType, + VkExternalMemoryPropertiesKHR *external_properties) +{ + VkExternalMemoryFeatureFlagBitsKHR flags = 0; + VkExternalMemoryHandleTypeFlagsKHR export_flags = 0; + VkExternalMemoryHandleTypeFlagsKHR compat_flags = 0; + switch (handleType) { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: + switch (pImageFormatInfo->type) { + case VK_IMAGE_TYPE_2D: + flags = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR | + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR | + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR; + compat_flags = export_flags = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + break; + default: + break; + } + break; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + flags = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR; + compat_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; + break; + default: + break; + } + + *external_properties = (VkExternalMemoryPropertiesKHR){ + .externalMemoryFeatures = flags, + .exportFromImportedHandleTypes = export_flags, + .compatibleHandleTypes = compat_flags, + }; +} + +VkResult +tu_GetPhysicalDeviceImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2KHR *base_info, + VkImageFormatProperties2KHR *base_props) +{ + TU_FROM_HANDLE(tu_physical_device, physical_device, physicalDevice); + const VkPhysicalDeviceExternalImageFormatInfoKHR *external_info = NULL; + VkExternalImageFormatPropertiesKHR *external_props = NULL; + VkResult result; + + result = tu_get_image_format_properties( + physical_device, base_info, &base_props->imageFormatProperties); + if (result != VK_SUCCESS) + return result; + + /* Extract input structs */ + vk_foreach_struct_const(s, base_info->pNext) + { + switch (s->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR: + external_info = (const void *)s; + break; + default: + break; + } + } + + /* Extract output structs */ + vk_foreach_struct(s, base_props->pNext) + { + switch (s->sType) { + case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR: + external_props = (void *)s; + break; + default: + break; + } + } + + /* From the Vulkan 1.0.42 spec: + * + * If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2KHR will + * behave as if VkPhysicalDeviceExternalImageFormatInfoKHR was not + * present and VkExternalImageFormatPropertiesKHR will be ignored. + */ + if (external_info && external_info->handleType != 0) { + switch (external_info->handleType) { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + get_external_image_format_properties( + base_info, + external_info->handleType, + &external_props->externalMemoryProperties); + break; + default: + /* From the Vulkan 1.0.42 spec: + * + * If handleType is not compatible with the [parameters] + * specified + * in VkPhysicalDeviceImageFormatInfo2KHR, then + * vkGetPhysicalDeviceImageFormatProperties2KHR returns + * VK_ERROR_FORMAT_NOT_SUPPORTED. + */ + result = + vk_errorf(physical_device->instance, + VK_ERROR_FORMAT_NOT_SUPPORTED, + "unsupported VkExternalMemoryTypeFlagBitsKHR 0x%x", + external_info->handleType); + goto fail; + } + } + + return VK_SUCCESS; + +fail: + if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) { + /* From the Vulkan 1.0.42 spec: + * + * If the combination of parameters to + * vkGetPhysicalDeviceImageFormatProperties2KHR is not supported by + * the implementation for use in vkCreateImage, then all members of + * imageFormatProperties will be filled with zero. + */ + base_props->imageFormatProperties = (VkImageFormatProperties){ 0 }; + } + + return result; +} + +void +tu_GetPhysicalDeviceSparseImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + uint32_t samples, + VkImageUsageFlags usage, + VkImageTiling tiling, + uint32_t *pNumProperties, + VkSparseImageFormatProperties *pProperties) +{ + /* Sparse images are not yet supported. */ + *pNumProperties = 0; +} + +void +tu_GetPhysicalDeviceSparseImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, + uint32_t *pPropertyCount, + VkSparseImageFormatProperties2KHR *pProperties) +{ + /* Sparse images are not yet supported. */ + *pPropertyCount = 0; +} + +void +tu_GetPhysicalDeviceExternalBufferProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfoKHR *pExternalBufferInfo, + VkExternalBufferPropertiesKHR *pExternalBufferProperties) +{ + VkExternalMemoryFeatureFlagBitsKHR flags = 0; + VkExternalMemoryHandleTypeFlagsKHR export_flags = 0; + VkExternalMemoryHandleTypeFlagsKHR compat_flags = 0; + switch (pExternalBufferInfo->handleType) { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: + flags = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR | + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR; + compat_flags = export_flags = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + break; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + flags = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR; + compat_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; + break; + default: + break; + } + pExternalBufferProperties->externalMemoryProperties = + (VkExternalMemoryPropertiesKHR){ + .externalMemoryFeatures = flags, + .exportFromImportedHandleTypes = export_flags, + .compatibleHandleTypes = compat_flags, + }; +} diff --git a/src/freedreno/vulkan/tu_icd.py b/src/freedreno/vulkan/tu_icd.py new file mode 100644 index 00000000000..1947a969aff --- /dev/null +++ b/src/freedreno/vulkan/tu_icd.py @@ -0,0 +1,47 @@ +# Copyright 2017 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, sub license, 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 NON-INFRINGEMENT. +# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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 json +import os.path + +from tu_extensions import * + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--out', help='Output json file.', required=True) + parser.add_argument('--lib-path', help='Path to libvulkan_freedreno.so') + args = parser.parse_args() + + path = 'libvulkan_freedreno.so' + if args.lib_path: + path = os.path.join(args.lib_path, path) + + json_data = { + 'file_format_version': '1.0.0', + 'ICD': { + 'library_path': path, + 'api_version': str(MAX_API_VERSION), + }, + } + + with open(args.out, 'w') as f: + json.dump(json_data, f, indent = 4, sort_keys=True, separators=(',', ': ')) diff --git a/src/freedreno/vulkan/tu_image.c b/src/freedreno/vulkan/tu_image.c new file mode 100644 index 00000000000..491bf30f2ad --- /dev/null +++ b/src/freedreno/vulkan/tu_image.c @@ -0,0 +1,243 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * based in part on anv driver which is: + * Copyright © 2015 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 "tu_private.h" +#include "util/debug.h" +#include "util/u_atomic.h" +#include "vk_format.h" +#include "vk_util.h" + +VkResult +tu_image_create(VkDevice _device, + const struct tu_image_create_info *create_info, + const VkAllocationCallbacks *alloc, + VkImage *pImage) +{ + TU_FROM_HANDLE(tu_device, device, _device); + const VkImageCreateInfo *pCreateInfo = create_info->vk_info; + struct tu_image *image = NULL; + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO); + + tu_assert(pCreateInfo->mipLevels > 0); + tu_assert(pCreateInfo->arrayLayers > 0); + tu_assert(pCreateInfo->samples > 0); + tu_assert(pCreateInfo->extent.width > 0); + tu_assert(pCreateInfo->extent.height > 0); + tu_assert(pCreateInfo->extent.depth > 0); + + image = vk_zalloc2(&device->alloc, + alloc, + sizeof(*image), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!image) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + image->type = pCreateInfo->imageType; + + image->vk_format = pCreateInfo->format; + image->tiling = pCreateInfo->tiling; + image->usage = pCreateInfo->usage; + image->flags = pCreateInfo->flags; + + image->exclusive = pCreateInfo->sharingMode == VK_SHARING_MODE_EXCLUSIVE; + if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) { + for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; ++i) + if (pCreateInfo->pQueueFamilyIndices[i] == + VK_QUEUE_FAMILY_EXTERNAL_KHR) + image->queue_family_mask |= (1u << TU_MAX_QUEUE_FAMILIES) - 1u; + else + image->queue_family_mask |= 1u + << pCreateInfo->pQueueFamilyIndices[i]; + } + + image->shareable = + vk_find_struct_const(pCreateInfo->pNext, + EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR) != NULL; + + *pImage = tu_image_to_handle(image); + + return VK_SUCCESS; +} + +void +tu_image_view_init(struct tu_image_view *iview, + struct tu_device *device, + const VkImageViewCreateInfo *pCreateInfo) +{ +} + +unsigned +tu_image_queue_family_mask(const struct tu_image *image, + uint32_t family, + uint32_t queue_family) +{ + if (!image->exclusive) + return image->queue_family_mask; + if (family == VK_QUEUE_FAMILY_EXTERNAL_KHR) + return (1u << TU_MAX_QUEUE_FAMILIES) - 1u; + if (family == VK_QUEUE_FAMILY_IGNORED) + return 1u << queue_family; + return 1u << family; +} + +VkResult +tu_CreateImage(VkDevice device, + const VkImageCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkImage *pImage) +{ +#ifdef ANDROID + const VkNativeBufferANDROID *gralloc_info = + vk_find_struct_const(pCreateInfo->pNext, NATIVE_BUFFER_ANDROID); + + if (gralloc_info) + return tu_image_from_gralloc( + device, pCreateInfo, gralloc_info, pAllocator, pImage); +#endif + + return tu_image_create(device, + &(struct tu_image_create_info) { + .vk_info = pCreateInfo, + .scanout = false, + }, + pAllocator, + pImage); +} + +void +tu_DestroyImage(VkDevice _device, + VkImage _image, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_image, image, _image); + + if (!image) + return; + + if (image->owned_memory != VK_NULL_HANDLE) + tu_FreeMemory(_device, image->owned_memory, pAllocator); + + vk_free2(&device->alloc, pAllocator, image); +} + +void +tu_GetImageSubresourceLayout(VkDevice _device, + VkImage _image, + const VkImageSubresource *pSubresource, + VkSubresourceLayout *pLayout) +{ +} + +VkResult +tu_CreateImageView(VkDevice _device, + const VkImageViewCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkImageView *pView) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_image_view *view; + + view = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*view), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (view == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + tu_image_view_init(view, device, pCreateInfo); + + *pView = tu_image_view_to_handle(view); + + return VK_SUCCESS; +} + +void +tu_DestroyImageView(VkDevice _device, + VkImageView _iview, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_image_view, iview, _iview); + + if (!iview) + return; + vk_free2(&device->alloc, pAllocator, iview); +} + +void +tu_buffer_view_init(struct tu_buffer_view *view, + struct tu_device *device, + const VkBufferViewCreateInfo *pCreateInfo) +{ + TU_FROM_HANDLE(tu_buffer, buffer, pCreateInfo->buffer); + + view->range = pCreateInfo->range == VK_WHOLE_SIZE + ? buffer->size - pCreateInfo->offset + : pCreateInfo->range; + view->vk_format = pCreateInfo->format; +} + +VkResult +tu_CreateBufferView(VkDevice _device, + const VkBufferViewCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkBufferView *pView) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_buffer_view *view; + + view = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*view), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!view) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + tu_buffer_view_init(view, device, pCreateInfo); + + *pView = tu_buffer_view_to_handle(view); + + return VK_SUCCESS; +} + +void +tu_DestroyBufferView(VkDevice _device, + VkBufferView bufferView, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_buffer_view, view, bufferView); + + if (!view) + return; + + vk_free2(&device->alloc, pAllocator, view); +} diff --git a/src/freedreno/vulkan/tu_meta_blit.c b/src/freedreno/vulkan/tu_meta_blit.c new file mode 100644 index 00000000000..ea4e48e1cac --- /dev/null +++ b/src/freedreno/vulkan/tu_meta_blit.c @@ -0,0 +1,38 @@ +/* + * Copyright © 2015 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 "tu_private.h" +#include "nir/nir_builder.h" + +void +tu_CmdBlitImage(VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage destImage, + VkImageLayout destImageLayout, + uint32_t regionCount, + const VkImageBlit *pRegions, + VkFilter filter) + +{ +} diff --git a/src/freedreno/vulkan/tu_meta_buffer.c b/src/freedreno/vulkan/tu_meta_buffer.c new file mode 100644 index 00000000000..fd5bb6e5af1 --- /dev/null +++ b/src/freedreno/vulkan/tu_meta_buffer.c @@ -0,0 +1,28 @@ +#include "tu_private.h" + +void +tu_CmdFillBuffer(VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize fillSize, + uint32_t data) +{ +} + +void +tu_CmdCopyBuffer(VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkBuffer destBuffer, + uint32_t regionCount, + const VkBufferCopy *pRegions) +{ +} + +void +tu_CmdUpdateBuffer(VkCommandBuffer commandBuffer, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void *pData) +{ +} diff --git a/src/freedreno/vulkan/tu_meta_clear.c b/src/freedreno/vulkan/tu_meta_clear.c new file mode 100644 index 00000000000..c363668d99a --- /dev/null +++ b/src/freedreno/vulkan/tu_meta_clear.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2015 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 "tu_private.h" + +void +tu_CmdClearColorImage(VkCommandBuffer commandBuffer, + VkImage image_h, + VkImageLayout imageLayout, + const VkClearColorValue *pColor, + uint32_t rangeCount, + const VkImageSubresourceRange *pRanges) +{ +} + +void +tu_CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, + VkImage image_h, + VkImageLayout imageLayout, + const VkClearDepthStencilValue *pDepthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange *pRanges) +{ +} + +void +tu_CmdClearAttachments(VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkClearAttachment *pAttachments, + uint32_t rectCount, + const VkClearRect *pRects) +{ +} diff --git a/src/freedreno/vulkan/tu_meta_copy.c b/src/freedreno/vulkan/tu_meta_copy.c new file mode 100644 index 00000000000..00d7b247cc8 --- /dev/null +++ b/src/freedreno/vulkan/tu_meta_copy.c @@ -0,0 +1,113 @@ +/* + * Copyright © 2016 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 "tu_private.h" + +static void +meta_copy_buffer_to_image(struct tu_cmd_buffer *cmd_buffer, + struct tu_buffer *buffer, + struct tu_image *image, + VkImageLayout layout, + uint32_t regionCount, + const VkBufferImageCopy *pRegions) +{ +} + +void +tu_CmdCopyBufferToImage(VkCommandBuffer commandBuffer, + VkBuffer srcBuffer, + VkImage destImage, + VkImageLayout destImageLayout, + uint32_t regionCount, + const VkBufferImageCopy *pRegions) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + TU_FROM_HANDLE(tu_image, dest_image, destImage); + TU_FROM_HANDLE(tu_buffer, src_buffer, srcBuffer); + + meta_copy_buffer_to_image(cmd_buffer, + src_buffer, + dest_image, + destImageLayout, + regionCount, + pRegions); +} + +static void +meta_copy_image_to_buffer(struct tu_cmd_buffer *cmd_buffer, + struct tu_buffer *buffer, + struct tu_image *image, + VkImageLayout layout, + uint32_t regionCount, + const VkBufferImageCopy *pRegions) +{ +} + +void +tu_CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer destBuffer, + uint32_t regionCount, + const VkBufferImageCopy *pRegions) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + TU_FROM_HANDLE(tu_image, src_image, srcImage); + TU_FROM_HANDLE(tu_buffer, dst_buffer, destBuffer); + + meta_copy_image_to_buffer( + cmd_buffer, dst_buffer, src_image, srcImageLayout, regionCount, pRegions); +} + +static void +meta_copy_image(struct tu_cmd_buffer *cmd_buffer, + struct tu_image *src_image, + VkImageLayout src_image_layout, + struct tu_image *dest_image, + VkImageLayout dest_image_layout, + uint32_t regionCount, + const VkImageCopy *pRegions) +{ +} + +void +tu_CmdCopyImage(VkCommandBuffer commandBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage destImage, + VkImageLayout destImageLayout, + uint32_t regionCount, + const VkImageCopy *pRegions) +{ + TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + TU_FROM_HANDLE(tu_image, src_image, srcImage); + TU_FROM_HANDLE(tu_image, dest_image, destImage); + + meta_copy_image(cmd_buffer, + src_image, + srcImageLayout, + dest_image, + destImageLayout, + regionCount, + pRegions); +} diff --git a/src/freedreno/vulkan/tu_meta_resolve.c b/src/freedreno/vulkan/tu_meta_resolve.c new file mode 100644 index 00000000000..e68d00c9700 --- /dev/null +++ b/src/freedreno/vulkan/tu_meta_resolve.c @@ -0,0 +1,40 @@ +/* + * Copyright © 2016 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 <assert.h> +#include <stdbool.h> + +#include "tu_private.h" +#include "nir/nir_builder.h" +#include "vk_format.h" + +void +tu_CmdResolveImage(VkCommandBuffer cmd_buffer_h, + VkImage src_image_h, + VkImageLayout src_image_layout, + VkImage dest_image_h, + VkImageLayout dest_image_layout, + uint32_t region_count, + const VkImageResolve *regions) +{ +} diff --git a/src/freedreno/vulkan/tu_pass.c b/src/freedreno/vulkan/tu_pass.c new file mode 100644 index 00000000000..e918f2a4470 --- /dev/null +++ b/src/freedreno/vulkan/tu_pass.c @@ -0,0 +1,414 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * based in part on anv driver which is: + * Copyright © 2015 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 "tu_private.h" + +#include "vk_util.h" + +VkResult +tu_CreateRenderPass(VkDevice _device, + const VkRenderPassCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkRenderPass *pRenderPass) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_render_pass *pass; + size_t size; + size_t attachments_offset; + VkRenderPassMultiviewCreateInfoKHR *multiview_info = NULL; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO); + + size = sizeof(*pass); + size += pCreateInfo->subpassCount * sizeof(pass->subpasses[0]); + attachments_offset = size; + size += pCreateInfo->attachmentCount * sizeof(pass->attachments[0]); + + pass = vk_alloc2( + &device->alloc, pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (pass == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + memset(pass, 0, size); + pass->attachment_count = pCreateInfo->attachmentCount; + pass->subpass_count = pCreateInfo->subpassCount; + pass->attachments = (void *)pass + attachments_offset; + + vk_foreach_struct(ext, pCreateInfo->pNext) + { + switch (ext->sType) { + case VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR: + multiview_info = (VkRenderPassMultiviewCreateInfoKHR *)ext; + break; + default: + break; + } + } + + for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { + struct tu_render_pass_attachment *att = &pass->attachments[i]; + + att->format = pCreateInfo->pAttachments[i].format; + att->samples = pCreateInfo->pAttachments[i].samples; + att->load_op = pCreateInfo->pAttachments[i].loadOp; + att->stencil_load_op = pCreateInfo->pAttachments[i].stencilLoadOp; + att->initial_layout = pCreateInfo->pAttachments[i].initialLayout; + att->final_layout = pCreateInfo->pAttachments[i].finalLayout; + // att->store_op = pCreateInfo->pAttachments[i].storeOp; + // att->stencil_store_op = pCreateInfo->pAttachments[i].stencilStoreOp; + } + uint32_t subpass_attachment_count = 0; + struct tu_subpass_attachment *p; + for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { + const VkSubpassDescription *desc = &pCreateInfo->pSubpasses[i]; + + subpass_attachment_count += + desc->inputAttachmentCount + desc->colorAttachmentCount + + (desc->pResolveAttachments ? desc->colorAttachmentCount : 0) + + (desc->pDepthStencilAttachment != NULL); + } + + if (subpass_attachment_count) { + pass->subpass_attachments = vk_alloc2( + &device->alloc, + pAllocator, + subpass_attachment_count * sizeof(struct tu_subpass_attachment), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (pass->subpass_attachments == NULL) { + vk_free2(&device->alloc, pAllocator, pass); + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + } + } else + pass->subpass_attachments = NULL; + + p = pass->subpass_attachments; + for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { + const VkSubpassDescription *desc = &pCreateInfo->pSubpasses[i]; + uint32_t color_sample_count = 1, depth_sample_count = 1; + struct tu_subpass *subpass = &pass->subpasses[i]; + + subpass->input_count = desc->inputAttachmentCount; + subpass->color_count = desc->colorAttachmentCount; + if (multiview_info) + subpass->view_mask = multiview_info->pViewMasks[i]; + + if (desc->inputAttachmentCount > 0) { + subpass->input_attachments = p; + p += desc->inputAttachmentCount; + + for (uint32_t j = 0; j < desc->inputAttachmentCount; j++) { + subpass->input_attachments[j] = (struct tu_subpass_attachment){ + .attachment = desc->pInputAttachments[j].attachment, + .layout = desc->pInputAttachments[j].layout, + }; + if (desc->pInputAttachments[j].attachment != VK_ATTACHMENT_UNUSED) + pass->attachments[desc->pInputAttachments[j].attachment] + .view_mask |= subpass->view_mask; + } + } + + if (desc->colorAttachmentCount > 0) { + subpass->color_attachments = p; + p += desc->colorAttachmentCount; + + for (uint32_t j = 0; j < desc->colorAttachmentCount; j++) { + subpass->color_attachments[j] = (struct tu_subpass_attachment){ + .attachment = desc->pColorAttachments[j].attachment, + .layout = desc->pColorAttachments[j].layout, + }; + if (desc->pColorAttachments[j].attachment != VK_ATTACHMENT_UNUSED) { + pass->attachments[desc->pColorAttachments[j].attachment] + .view_mask |= subpass->view_mask; + color_sample_count = + pCreateInfo + ->pAttachments[desc->pColorAttachments[j].attachment] + .samples; + } + } + } + + subpass->has_resolve = false; + if (desc->pResolveAttachments) { + subpass->resolve_attachments = p; + p += desc->colorAttachmentCount; + + for (uint32_t j = 0; j < desc->colorAttachmentCount; j++) { + uint32_t a = desc->pResolveAttachments[j].attachment; + subpass->resolve_attachments[j] = (struct tu_subpass_attachment){ + .attachment = desc->pResolveAttachments[j].attachment, + .layout = desc->pResolveAttachments[j].layout, + }; + if (a != VK_ATTACHMENT_UNUSED) { + subpass->has_resolve = true; + pass->attachments[desc->pResolveAttachments[j].attachment] + .view_mask |= subpass->view_mask; + } + } + } + + if (desc->pDepthStencilAttachment) { + subpass->depth_stencil_attachment = (struct tu_subpass_attachment){ + .attachment = desc->pDepthStencilAttachment->attachment, + .layout = desc->pDepthStencilAttachment->layout, + }; + if (desc->pDepthStencilAttachment->attachment != + VK_ATTACHMENT_UNUSED) { + pass->attachments[desc->pDepthStencilAttachment->attachment] + .view_mask |= subpass->view_mask; + depth_sample_count = + pCreateInfo + ->pAttachments[desc->pDepthStencilAttachment->attachment] + .samples; + } + } else { + subpass->depth_stencil_attachment.attachment = VK_ATTACHMENT_UNUSED; + } + + subpass->max_sample_count = MAX2(color_sample_count, depth_sample_count); + } + + for (unsigned i = 0; i < pCreateInfo->dependencyCount; ++i) { + uint32_t dst = pCreateInfo->pDependencies[i].dstSubpass; + if (dst == VK_SUBPASS_EXTERNAL) { + pass->end_barrier.src_stage_mask = + pCreateInfo->pDependencies[i].srcStageMask; + pass->end_barrier.src_access_mask = + pCreateInfo->pDependencies[i].srcAccessMask; + pass->end_barrier.dst_access_mask = + pCreateInfo->pDependencies[i].dstAccessMask; + } else { + pass->subpasses[dst].start_barrier.src_stage_mask = + pCreateInfo->pDependencies[i].srcStageMask; + pass->subpasses[dst].start_barrier.src_access_mask = + pCreateInfo->pDependencies[i].srcAccessMask; + pass->subpasses[dst].start_barrier.dst_access_mask = + pCreateInfo->pDependencies[i].dstAccessMask; + } + } + + *pRenderPass = tu_render_pass_to_handle(pass); + + return VK_SUCCESS; +} + +VkResult +tu_CreateRenderPass2KHR(VkDevice _device, + const VkRenderPassCreateInfo2KHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkRenderPass *pRenderPass) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_render_pass *pass; + size_t size; + size_t attachments_offset; + + assert(pCreateInfo->sType == + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR); + + size = sizeof(*pass); + size += pCreateInfo->subpassCount * sizeof(pass->subpasses[0]); + attachments_offset = size; + size += pCreateInfo->attachmentCount * sizeof(pass->attachments[0]); + + pass = vk_alloc2( + &device->alloc, pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (pass == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + memset(pass, 0, size); + pass->attachment_count = pCreateInfo->attachmentCount; + pass->subpass_count = pCreateInfo->subpassCount; + pass->attachments = (void *)pass + attachments_offset; + + for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { + struct tu_render_pass_attachment *att = &pass->attachments[i]; + + att->format = pCreateInfo->pAttachments[i].format; + att->samples = pCreateInfo->pAttachments[i].samples; + att->load_op = pCreateInfo->pAttachments[i].loadOp; + att->stencil_load_op = pCreateInfo->pAttachments[i].stencilLoadOp; + att->initial_layout = pCreateInfo->pAttachments[i].initialLayout; + att->final_layout = pCreateInfo->pAttachments[i].finalLayout; + // att->store_op = pCreateInfo->pAttachments[i].storeOp; + // att->stencil_store_op = pCreateInfo->pAttachments[i].stencilStoreOp; + } + uint32_t subpass_attachment_count = 0; + struct tu_subpass_attachment *p; + for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { + const VkSubpassDescription2KHR *desc = &pCreateInfo->pSubpasses[i]; + + subpass_attachment_count += + desc->inputAttachmentCount + desc->colorAttachmentCount + + (desc->pResolveAttachments ? desc->colorAttachmentCount : 0) + + (desc->pDepthStencilAttachment != NULL); + } + + if (subpass_attachment_count) { + pass->subpass_attachments = vk_alloc2( + &device->alloc, + pAllocator, + subpass_attachment_count * sizeof(struct tu_subpass_attachment), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (pass->subpass_attachments == NULL) { + vk_free2(&device->alloc, pAllocator, pass); + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + } + } else + pass->subpass_attachments = NULL; + + p = pass->subpass_attachments; + for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { + const VkSubpassDescription2KHR *desc = &pCreateInfo->pSubpasses[i]; + uint32_t color_sample_count = 1, depth_sample_count = 1; + struct tu_subpass *subpass = &pass->subpasses[i]; + + subpass->input_count = desc->inputAttachmentCount; + subpass->color_count = desc->colorAttachmentCount; + subpass->view_mask = desc->viewMask; + + if (desc->inputAttachmentCount > 0) { + subpass->input_attachments = p; + p += desc->inputAttachmentCount; + + for (uint32_t j = 0; j < desc->inputAttachmentCount; j++) { + subpass->input_attachments[j] = (struct tu_subpass_attachment){ + .attachment = desc->pInputAttachments[j].attachment, + .layout = desc->pInputAttachments[j].layout, + }; + if (desc->pInputAttachments[j].attachment != VK_ATTACHMENT_UNUSED) + pass->attachments[desc->pInputAttachments[j].attachment] + .view_mask |= subpass->view_mask; + } + } + + if (desc->colorAttachmentCount > 0) { + subpass->color_attachments = p; + p += desc->colorAttachmentCount; + + for (uint32_t j = 0; j < desc->colorAttachmentCount; j++) { + subpass->color_attachments[j] = (struct tu_subpass_attachment){ + .attachment = desc->pColorAttachments[j].attachment, + .layout = desc->pColorAttachments[j].layout, + }; + if (desc->pColorAttachments[j].attachment != VK_ATTACHMENT_UNUSED) { + pass->attachments[desc->pColorAttachments[j].attachment] + .view_mask |= subpass->view_mask; + color_sample_count = + pCreateInfo + ->pAttachments[desc->pColorAttachments[j].attachment] + .samples; + } + } + } + + subpass->has_resolve = false; + if (desc->pResolveAttachments) { + subpass->resolve_attachments = p; + p += desc->colorAttachmentCount; + + for (uint32_t j = 0; j < desc->colorAttachmentCount; j++) { + uint32_t a = desc->pResolveAttachments[j].attachment; + subpass->resolve_attachments[j] = (struct tu_subpass_attachment){ + .attachment = desc->pResolveAttachments[j].attachment, + .layout = desc->pResolveAttachments[j].layout, + }; + if (a != VK_ATTACHMENT_UNUSED) { + subpass->has_resolve = true; + pass->attachments[desc->pResolveAttachments[j].attachment] + .view_mask |= subpass->view_mask; + } + } + } + + if (desc->pDepthStencilAttachment) { + subpass->depth_stencil_attachment = (struct tu_subpass_attachment){ + .attachment = desc->pDepthStencilAttachment->attachment, + .layout = desc->pDepthStencilAttachment->layout, + }; + if (desc->pDepthStencilAttachment->attachment != + VK_ATTACHMENT_UNUSED) { + pass->attachments[desc->pDepthStencilAttachment->attachment] + .view_mask |= subpass->view_mask; + depth_sample_count = + pCreateInfo + ->pAttachments[desc->pDepthStencilAttachment->attachment] + .samples; + } + } else { + subpass->depth_stencil_attachment.attachment = VK_ATTACHMENT_UNUSED; + } + + subpass->max_sample_count = MAX2(color_sample_count, depth_sample_count); + } + + for (unsigned i = 0; i < pCreateInfo->dependencyCount; ++i) { + uint32_t dst = pCreateInfo->pDependencies[i].dstSubpass; + if (dst == VK_SUBPASS_EXTERNAL) { + pass->end_barrier.src_stage_mask = + pCreateInfo->pDependencies[i].srcStageMask; + pass->end_barrier.src_access_mask = + pCreateInfo->pDependencies[i].srcAccessMask; + pass->end_barrier.dst_access_mask = + pCreateInfo->pDependencies[i].dstAccessMask; + } else { + pass->subpasses[dst].start_barrier.src_stage_mask = + pCreateInfo->pDependencies[i].srcStageMask; + pass->subpasses[dst].start_barrier.src_access_mask = + pCreateInfo->pDependencies[i].srcAccessMask; + pass->subpasses[dst].start_barrier.dst_access_mask = + pCreateInfo->pDependencies[i].dstAccessMask; + } + } + + *pRenderPass = tu_render_pass_to_handle(pass); + + return VK_SUCCESS; +} + +void +tu_DestroyRenderPass(VkDevice _device, + VkRenderPass _pass, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_render_pass, pass, _pass); + + if (!_pass) + return; + vk_free2(&device->alloc, pAllocator, pass->subpass_attachments); + vk_free2(&device->alloc, pAllocator, pass); +} + +void +tu_GetRenderAreaGranularity(VkDevice device, + VkRenderPass renderPass, + VkExtent2D *pGranularity) +{ + pGranularity->width = 1; + pGranularity->height = 1; +} diff --git a/src/freedreno/vulkan/tu_pipeline.c b/src/freedreno/vulkan/tu_pipeline.c new file mode 100644 index 00000000000..d6713688ce4 --- /dev/null +++ b/src/freedreno/vulkan/tu_pipeline.c @@ -0,0 +1,113 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * based in part on anv driver which is: + * Copyright © 2015 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 "tu_private.h" +#include "nir/nir.h" +#include "nir/nir_builder.h" +#include "spirv/nir_spirv.h" +#include "util/mesa-sha1.h" +#include "util/u_atomic.h" +#include "vk_util.h" + +#include "main/menums.h" +#include "util/debug.h" +#include "vk_format.h" + +VkResult +tu_graphics_pipeline_create( + VkDevice _device, + VkPipelineCache _cache, + const VkGraphicsPipelineCreateInfo *pCreateInfo, + const struct tu_graphics_pipeline_create_info *extra, + const VkAllocationCallbacks *pAllocator, + VkPipeline *pPipeline) +{ + + return VK_SUCCESS; +} + +VkResult +tu_CreateGraphicsPipelines(VkDevice _device, + VkPipelineCache pipelineCache, + uint32_t count, + const VkGraphicsPipelineCreateInfo *pCreateInfos, + const VkAllocationCallbacks *pAllocator, + VkPipeline *pPipelines) +{ + VkResult result = VK_SUCCESS; + unsigned i = 0; + + for (; i < count; i++) { + VkResult r; + r = tu_graphics_pipeline_create(_device, + pipelineCache, + &pCreateInfos[i], + NULL, + pAllocator, + &pPipelines[i]); + if (r != VK_SUCCESS) { + result = r; + pPipelines[i] = VK_NULL_HANDLE; + } + } + + return result; +} + +static VkResult +tu_compute_pipeline_create(VkDevice _device, + VkPipelineCache _cache, + const VkComputePipelineCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkPipeline *pPipeline) +{ + return VK_SUCCESS; +} + +VkResult +tu_CreateComputePipelines(VkDevice _device, + VkPipelineCache pipelineCache, + uint32_t count, + const VkComputePipelineCreateInfo *pCreateInfos, + const VkAllocationCallbacks *pAllocator, + VkPipeline *pPipelines) +{ + VkResult result = VK_SUCCESS; + + unsigned i = 0; + for (; i < count; i++) { + VkResult r; + r = tu_compute_pipeline_create( + _device, pipelineCache, &pCreateInfos[i], pAllocator, &pPipelines[i]); + if (r != VK_SUCCESS) { + result = r; + pPipelines[i] = VK_NULL_HANDLE; + } + } + + return result; +} diff --git a/src/freedreno/vulkan/tu_pipeline_cache.c b/src/freedreno/vulkan/tu_pipeline_cache.c new file mode 100644 index 00000000000..32470b75aa0 --- /dev/null +++ b/src/freedreno/vulkan/tu_pipeline_cache.c @@ -0,0 +1,424 @@ +/* + * Copyright © 2015 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 "tu_private.h" +#include "util/debug.h" +#include "util/disk_cache.h" +#include "util/mesa-sha1.h" +#include "util/u_atomic.h" + +struct cache_entry_variant_info +{ +}; + +struct cache_entry +{ + union + { + unsigned char sha1[20]; + uint32_t sha1_dw[5]; + }; + uint32_t code_sizes[MESA_SHADER_STAGES]; + struct tu_shader_variant *variants[MESA_SHADER_STAGES]; + char code[0]; +}; + +void +tu_pipeline_cache_init(struct tu_pipeline_cache *cache, + struct tu_device *device) +{ + cache->device = device; + pthread_mutex_init(&cache->mutex, NULL); + + cache->modified = false; + cache->kernel_count = 0; + cache->total_size = 0; + cache->table_size = 1024; + const size_t byte_size = cache->table_size * sizeof(cache->hash_table[0]); + cache->hash_table = malloc(byte_size); + + /* We don't consider allocation failure fatal, we just start with a 0-sized + * cache. Disable caching when we want to keep shader debug info, since + * we don't get the debug info on cached shaders. */ + if (cache->hash_table == NULL) + cache->table_size = 0; + else + memset(cache->hash_table, 0, byte_size); +} + +void +tu_pipeline_cache_finish(struct tu_pipeline_cache *cache) +{ + for (unsigned i = 0; i < cache->table_size; ++i) + if (cache->hash_table[i]) { + vk_free(&cache->alloc, cache->hash_table[i]); + } + pthread_mutex_destroy(&cache->mutex); + free(cache->hash_table); +} + +static uint32_t +entry_size(struct cache_entry *entry) +{ + size_t ret = sizeof(*entry); + for (int i = 0; i < MESA_SHADER_STAGES; ++i) + if (entry->code_sizes[i]) + ret += sizeof(struct cache_entry_variant_info) + entry->code_sizes[i]; + return ret; +} + +void +tu_hash_shaders(unsigned char *hash, + const VkPipelineShaderStageCreateInfo **stages, + const struct tu_pipeline_layout *layout, + const struct tu_pipeline_key *key, + uint32_t flags) +{ + struct mesa_sha1 ctx; + + _mesa_sha1_init(&ctx); + if (key) + _mesa_sha1_update(&ctx, key, sizeof(*key)); + if (layout) + _mesa_sha1_update(&ctx, layout->sha1, sizeof(layout->sha1)); + + for (int i = 0; i < MESA_SHADER_STAGES; ++i) { + if (stages[i]) { + TU_FROM_HANDLE(tu_shader_module, module, stages[i]->module); + const VkSpecializationInfo *spec_info = stages[i]->pSpecializationInfo; + + _mesa_sha1_update(&ctx, module->sha1, sizeof(module->sha1)); + _mesa_sha1_update(&ctx, stages[i]->pName, strlen(stages[i]->pName)); + if (spec_info) { + _mesa_sha1_update(&ctx, + spec_info->pMapEntries, + spec_info->mapEntryCount * + sizeof spec_info->pMapEntries[0]); + _mesa_sha1_update(&ctx, spec_info->pData, spec_info->dataSize); + } + } + } + _mesa_sha1_update(&ctx, &flags, 4); + _mesa_sha1_final(&ctx, hash); +} + +static struct cache_entry * +tu_pipeline_cache_search_unlocked(struct tu_pipeline_cache *cache, + const unsigned char *sha1) +{ + const uint32_t mask = cache->table_size - 1; + const uint32_t start = (*(uint32_t *)sha1); + + if (cache->table_size == 0) + return NULL; + + for (uint32_t i = 0; i < cache->table_size; i++) { + const uint32_t index = (start + i) & mask; + struct cache_entry *entry = cache->hash_table[index]; + + if (!entry) + return NULL; + + if (memcmp(entry->sha1, sha1, sizeof(entry->sha1)) == 0) { + return entry; + } + } + + unreachable("hash table should never be full"); +} + +static struct cache_entry * +tu_pipeline_cache_search(struct tu_pipeline_cache *cache, + const unsigned char *sha1) +{ + struct cache_entry *entry; + + pthread_mutex_lock(&cache->mutex); + + entry = tu_pipeline_cache_search_unlocked(cache, sha1); + + pthread_mutex_unlock(&cache->mutex); + + return entry; +} + +static void +tu_pipeline_cache_set_entry(struct tu_pipeline_cache *cache, + struct cache_entry *entry) +{ + const uint32_t mask = cache->table_size - 1; + const uint32_t start = entry->sha1_dw[0]; + + /* We'll always be able to insert when we get here. */ + assert(cache->kernel_count < cache->table_size / 2); + + for (uint32_t i = 0; i < cache->table_size; i++) { + const uint32_t index = (start + i) & mask; + if (!cache->hash_table[index]) { + cache->hash_table[index] = entry; + break; + } + } + + cache->total_size += entry_size(entry); + cache->kernel_count++; +} + +static VkResult +tu_pipeline_cache_grow(struct tu_pipeline_cache *cache) +{ + const uint32_t table_size = cache->table_size * 2; + const uint32_t old_table_size = cache->table_size; + const size_t byte_size = table_size * sizeof(cache->hash_table[0]); + struct cache_entry **table; + struct cache_entry **old_table = cache->hash_table; + + table = malloc(byte_size); + if (table == NULL) + return vk_error(cache->device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + cache->hash_table = table; + cache->table_size = table_size; + cache->kernel_count = 0; + cache->total_size = 0; + + memset(cache->hash_table, 0, byte_size); + for (uint32_t i = 0; i < old_table_size; i++) { + struct cache_entry *entry = old_table[i]; + if (!entry) + continue; + + tu_pipeline_cache_set_entry(cache, entry); + } + + free(old_table); + + return VK_SUCCESS; +} + +static void +tu_pipeline_cache_add_entry(struct tu_pipeline_cache *cache, + struct cache_entry *entry) +{ + if (cache->kernel_count == cache->table_size / 2) + tu_pipeline_cache_grow(cache); + + /* Failing to grow that hash table isn't fatal, but may mean we don't + * have enough space to add this new kernel. Only add it if there's room. + */ + if (cache->kernel_count < cache->table_size / 2) + tu_pipeline_cache_set_entry(cache, entry); +} + +struct cache_header +{ + uint32_t header_size; + uint32_t header_version; + uint32_t vendor_id; + uint32_t device_id; + uint8_t uuid[VK_UUID_SIZE]; +}; + +void +tu_pipeline_cache_load(struct tu_pipeline_cache *cache, + const void *data, + size_t size) +{ + struct tu_device *device = cache->device; + struct cache_header header; + + if (size < sizeof(header)) + return; + memcpy(&header, data, sizeof(header)); + if (header.header_size < sizeof(header)) + return; + if (header.header_version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE) + return; + if (header.vendor_id != 0 /* TODO */) + return; + if (header.device_id != 0 /* TODO */) + return; + if (memcmp(header.uuid, device->physical_device->cache_uuid, VK_UUID_SIZE) != + 0) + return; + + char *end = (void *)data + size; + char *p = (void *)data + header.header_size; + + while (end - p >= sizeof(struct cache_entry)) { + struct cache_entry *entry = (struct cache_entry *)p; + struct cache_entry *dest_entry; + size_t size = entry_size(entry); + if (end - p < size) + break; + + dest_entry = + vk_alloc(&cache->alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_CACHE); + if (dest_entry) { + memcpy(dest_entry, entry, size); + for (int i = 0; i < MESA_SHADER_STAGES; ++i) + dest_entry->variants[i] = NULL; + tu_pipeline_cache_add_entry(cache, dest_entry); + } + p += size; + } +} + +VkResult +tu_CreatePipelineCache(VkDevice _device, + const VkPipelineCacheCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkPipelineCache *pPipelineCache) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_pipeline_cache *cache; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO); + assert(pCreateInfo->flags == 0); + + cache = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*cache), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (cache == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + if (pAllocator) + cache->alloc = *pAllocator; + else + cache->alloc = device->alloc; + + tu_pipeline_cache_init(cache, device); + + if (pCreateInfo->initialDataSize > 0) { + tu_pipeline_cache_load( + cache, pCreateInfo->pInitialData, pCreateInfo->initialDataSize); + } + + *pPipelineCache = tu_pipeline_cache_to_handle(cache); + + return VK_SUCCESS; +} + +void +tu_DestroyPipelineCache(VkDevice _device, + VkPipelineCache _cache, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_pipeline_cache, cache, _cache); + + if (!cache) + return; + tu_pipeline_cache_finish(cache); + + vk_free2(&device->alloc, pAllocator, cache); +} + +VkResult +tu_GetPipelineCacheData(VkDevice _device, + VkPipelineCache _cache, + size_t *pDataSize, + void *pData) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_pipeline_cache, cache, _cache); + struct cache_header *header; + VkResult result = VK_SUCCESS; + + pthread_mutex_lock(&cache->mutex); + + const size_t size = sizeof(*header) + cache->total_size; + if (pData == NULL) { + pthread_mutex_unlock(&cache->mutex); + *pDataSize = size; + return VK_SUCCESS; + } + if (*pDataSize < sizeof(*header)) { + pthread_mutex_unlock(&cache->mutex); + *pDataSize = 0; + return VK_INCOMPLETE; + } + void *p = pData, *end = pData + *pDataSize; + header = p; + header->header_size = sizeof(*header); + header->header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE; + header->vendor_id = 0 /* TODO */; + header->device_id = 0 /* TODO */; + memcpy(header->uuid, device->physical_device->cache_uuid, VK_UUID_SIZE); + p += header->header_size; + + struct cache_entry *entry; + for (uint32_t i = 0; i < cache->table_size; i++) { + if (!cache->hash_table[i]) + continue; + entry = cache->hash_table[i]; + const uint32_t size = entry_size(entry); + if (end < p + size) { + result = VK_INCOMPLETE; + break; + } + + memcpy(p, entry, size); + for (int j = 0; j < MESA_SHADER_STAGES; ++j) + ((struct cache_entry *)p)->variants[j] = NULL; + p += size; + } + *pDataSize = p - pData; + + pthread_mutex_unlock(&cache->mutex); + return result; +} + +static void +tu_pipeline_cache_merge(struct tu_pipeline_cache *dst, + struct tu_pipeline_cache *src) +{ + for (uint32_t i = 0; i < src->table_size; i++) { + struct cache_entry *entry = src->hash_table[i]; + if (!entry || tu_pipeline_cache_search(dst, entry->sha1)) + continue; + + tu_pipeline_cache_add_entry(dst, entry); + + src->hash_table[i] = NULL; + } +} + +VkResult +tu_MergePipelineCaches(VkDevice _device, + VkPipelineCache destCache, + uint32_t srcCacheCount, + const VkPipelineCache *pSrcCaches) +{ + TU_FROM_HANDLE(tu_pipeline_cache, dst, destCache); + + for (uint32_t i = 0; i < srcCacheCount; i++) { + TU_FROM_HANDLE(tu_pipeline_cache, src, pSrcCaches[i]); + + tu_pipeline_cache_merge(dst, src); + } + + return VK_SUCCESS; +} diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h new file mode 100644 index 00000000000..2f035951956 --- /dev/null +++ b/src/freedreno/vulkan/tu_private.h @@ -0,0 +1,1221 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * based in part on anv driver which is: + * Copyright © 2015 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 TU_PRIVATE_H +#define TU_PRIVATE_H + +#include <assert.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_VALGRIND +#include <memcheck.h> +#include <valgrind.h> +#define VG(x) x +#else +#define VG(x) +#endif + +#include "c11/threads.h" +#include "compiler/shader_enums.h" +#include "main/macros.h" +#include "util/list.h" +#include "util/macros.h" +#include "vk_alloc.h" +#include "vk_debug_report.h" + +#include "tu_descriptor_set.h" +#include "tu_extensions.h" + +/* Pre-declarations needed for WSI entrypoints */ +struct wl_surface; +struct wl_display; +typedef struct xcb_connection_t xcb_connection_t; +typedef uint32_t xcb_visualid_t; +typedef uint32_t xcb_window_t; + +#include <vulkan/vk_android_native_buffer.h> +#include <vulkan/vk_icd.h> +#include <vulkan/vulkan.h> +#include <vulkan/vulkan_intel.h> + +#include "tu_entrypoints.h" + +#define MAX_VBS 32 +#define MAX_VERTEX_ATTRIBS 32 +#define MAX_RTS 8 +#define MAX_VIEWPORTS 16 +#define MAX_SCISSORS 16 +#define MAX_DISCARD_RECTANGLES 4 +#define MAX_PUSH_CONSTANTS_SIZE 128 +#define MAX_PUSH_DESCRIPTORS 32 +#define MAX_DYNAMIC_UNIFORM_BUFFERS 16 +#define MAX_DYNAMIC_STORAGE_BUFFERS 8 +#define MAX_DYNAMIC_BUFFERS \ + (MAX_DYNAMIC_UNIFORM_BUFFERS + MAX_DYNAMIC_STORAGE_BUFFERS) +#define MAX_SAMPLES_LOG2 4 +#define NUM_META_FS_KEYS 13 +#define TU_MAX_DRM_DEVICES 8 +#define MAX_VIEWS 8 + +#define NUM_DEPTH_CLEAR_PIPELINES 3 + +/* + * This is the point we switch from using CP to compute shader + * for certain buffer operations. + */ +#define TU_BUFFER_OPS_CS_THRESHOLD 4096 + +enum tu_mem_heap +{ + TU_MEM_HEAP_VRAM, + TU_MEM_HEAP_VRAM_CPU_ACCESS, + TU_MEM_HEAP_GTT, + TU_MEM_HEAP_COUNT +}; + +enum tu_mem_type +{ + TU_MEM_TYPE_VRAM, + TU_MEM_TYPE_GTT_WRITE_COMBINE, + TU_MEM_TYPE_VRAM_CPU_ACCESS, + TU_MEM_TYPE_GTT_CACHED, + TU_MEM_TYPE_COUNT +}; + +#define tu_printflike(a, b) __attribute__((__format__(__printf__, a, b))) + +static inline uint32_t +align_u32(uint32_t v, uint32_t a) +{ + assert(a != 0 && a == (a & -a)); + return (v + a - 1) & ~(a - 1); +} + +static inline uint32_t +align_u32_npot(uint32_t v, uint32_t a) +{ + return (v + a - 1) / a * a; +} + +static inline uint64_t +align_u64(uint64_t v, uint64_t a) +{ + assert(a != 0 && a == (a & -a)); + return (v + a - 1) & ~(a - 1); +} + +static inline int32_t +align_i32(int32_t v, int32_t a) +{ + assert(a != 0 && a == (a & -a)); + return (v + a - 1) & ~(a - 1); +} + +/** Alignment must be a power of 2. */ +static inline bool +tu_is_aligned(uintmax_t n, uintmax_t a) +{ + assert(a == (a & -a)); + return (n & (a - 1)) == 0; +} + +static inline uint32_t +round_up_u32(uint32_t v, uint32_t a) +{ + return (v + a - 1) / a; +} + +static inline uint64_t +round_up_u64(uint64_t v, uint64_t a) +{ + return (v + a - 1) / a; +} + +static inline uint32_t +tu_minify(uint32_t n, uint32_t levels) +{ + if (unlikely(n == 0)) + return 0; + else + return MAX2(n >> levels, 1); +} +static inline float +tu_clamp_f(float f, float min, float max) +{ + assert(min < max); + + if (f > max) + return max; + else if (f < min) + return min; + else + return f; +} + +static inline bool +tu_clear_mask(uint32_t *inout_mask, uint32_t clear_mask) +{ + if (*inout_mask & clear_mask) { + *inout_mask &= ~clear_mask; + return true; + } else { + return false; + } +} + +#define for_each_bit(b, dword) \ + for (uint32_t __dword = (dword); (b) = __builtin_ffs(__dword) - 1, __dword; \ + __dword &= ~(1 << (b))) + +#define typed_memcpy(dest, src, count) \ + ({ \ + STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \ + memcpy((dest), (src), (count) * sizeof(*(src))); \ + }) + +/* Whenever we generate an error, pass it through this function. Useful for + * debugging, where we can break on it. Only call at error site, not when + * propagating errors. Might be useful to plug in a stack trace here. + */ + +struct tu_instance; + +VkResult +__vk_errorf(struct tu_instance *instance, + VkResult error, + const char *file, + int line, + const char *format, + ...); + +#define vk_error(instance, error) \ + __vk_errorf(instance, error, __FILE__, __LINE__, NULL); +#define vk_errorf(instance, error, format, ...) \ + __vk_errorf(instance, error, __FILE__, __LINE__, format, ##__VA_ARGS__); + +void +__tu_finishme(const char *file, int line, const char *format, ...) + tu_printflike(3, 4); +void +tu_loge(const char *format, ...) tu_printflike(1, 2); +void +tu_loge_v(const char *format, va_list va); +void +tu_logi(const char *format, ...) tu_printflike(1, 2); +void +tu_logi_v(const char *format, va_list va); + +/** + * Print a FINISHME message, including its source location. + */ +#define tu_finishme(format, ...) \ + do { \ + static bool reported = false; \ + if (!reported) { \ + __tu_finishme(__FILE__, __LINE__, format, ##__VA_ARGS__); \ + reported = true; \ + } \ + } while (0) + +/* A non-fatal assert. Useful for debugging. */ +#ifdef DEBUG +#define tu_assert(x) \ + ({ \ + if (unlikely(!(x))) \ + fprintf(stderr, "%s:%d ASSERT: %s\n", __FILE__, __LINE__, #x); \ + }) +#else +#define tu_assert(x) +#endif + +#define stub_return(v) \ + do { \ + tu_finishme("stub %s", __func__); \ + return (v); \ + } while (0) + +#define stub() \ + do { \ + tu_finishme("stub %s", __func__); \ + return; \ + } while (0) + +void * +tu_lookup_entrypoint_unchecked(const char *name); +void * +tu_lookup_entrypoint_checked( + const char *name, + uint32_t core_version, + const struct tu_instance_extension_table *instance, + const struct tu_device_extension_table *device); + +struct tu_physical_device +{ + VK_LOADER_DATA _loader_data; + + struct tu_instance *instance; + + char path[20]; + char name[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; + uint8_t driver_uuid[VK_UUID_SIZE]; + uint8_t device_uuid[VK_UUID_SIZE]; + uint8_t cache_uuid[VK_UUID_SIZE]; + + int local_fd; + int master_fd; + + /* This is the drivers on-disk cache used as a fallback as opposed to + * the pipeline cache defined by apps. + */ + struct disk_cache *disk_cache; + + struct tu_device_extension_table supported_extensions; +}; + +enum tu_debug_flags +{ + TU_DEBUG_STARTUP = 1 << 0, +}; + +struct tu_instance +{ + VK_LOADER_DATA _loader_data; + + VkAllocationCallbacks alloc; + + uint32_t api_version; + int physical_device_count; + struct tu_physical_device physical_devices[TU_MAX_DRM_DEVICES]; + + enum tu_debug_flags debug_flags; + + struct vk_debug_report_instance debug_report_callbacks; + + struct tu_instance_extension_table enabled_extensions; +}; + +bool +tu_instance_extension_supported(const char *name); +uint32_t +tu_physical_device_api_version(struct tu_physical_device *dev); +bool +tu_physical_device_extension_supported(struct tu_physical_device *dev, + const char *name); + +struct cache_entry; + +struct tu_pipeline_cache +{ + struct tu_device *device; + pthread_mutex_t mutex; + + uint32_t total_size; + uint32_t table_size; + uint32_t kernel_count; + struct cache_entry **hash_table; + bool modified; + + VkAllocationCallbacks alloc; +}; + +struct tu_pipeline_key +{ +}; + +void +tu_pipeline_cache_init(struct tu_pipeline_cache *cache, + struct tu_device *device); +void +tu_pipeline_cache_finish(struct tu_pipeline_cache *cache); +void +tu_pipeline_cache_load(struct tu_pipeline_cache *cache, + const void *data, + size_t size); + +struct tu_shader_variant; + +bool +tu_create_shader_variants_from_pipeline_cache( + struct tu_device *device, + struct tu_pipeline_cache *cache, + const unsigned char *sha1, + struct tu_shader_variant **variants); + +void +tu_pipeline_cache_insert_shaders(struct tu_device *device, + struct tu_pipeline_cache *cache, + const unsigned char *sha1, + struct tu_shader_variant **variants, + const void *const *codes, + const unsigned *code_sizes); + +struct tu_meta_state +{ + VkAllocationCallbacks alloc; + + struct tu_pipeline_cache cache; +}; + +/* queue types */ +#define TU_QUEUE_GENERAL 0 + +#define TU_MAX_QUEUE_FAMILIES 1 + +struct tu_queue +{ + VK_LOADER_DATA _loader_data; + struct tu_device *device; + uint32_t queue_family_index; + int queue_idx; + VkDeviceQueueCreateFlags flags; +}; + +struct tu_bo_list +{ + unsigned capacity; + pthread_mutex_t mutex; +}; + +struct tu_device +{ + VK_LOADER_DATA _loader_data; + + VkAllocationCallbacks alloc; + + struct tu_instance *instance; + struct radeon_winsys *ws; + + struct tu_meta_state meta_state; + + struct tu_queue *queues[TU_MAX_QUEUE_FAMILIES]; + int queue_count[TU_MAX_QUEUE_FAMILIES]; + + struct tu_physical_device *physical_device; + + /* Backup in-memory cache to be used if the app doesn't provide one */ + struct tu_pipeline_cache *mem_cache; + + struct list_head shader_slabs; + mtx_t shader_slab_mutex; + + struct tu_device_extension_table enabled_extensions; + + /* Whether the driver uses a global BO list. */ + bool use_global_bo_list; + + struct tu_bo_list bo_list; +}; + +struct tu_device_memory +{ + + /* for dedicated allocations */ + struct tu_image *image; + struct tu_buffer *buffer; + uint32_t type_index; + VkDeviceSize map_size; + void *map; + void *user_ptr; +}; + +struct tu_descriptor_range +{ + uint64_t va; + uint32_t size; +}; + +struct tu_descriptor_set +{ + const struct tu_descriptor_set_layout *layout; + uint32_t size; + + struct radeon_winsys_bo *bo; + uint64_t va; + uint32_t *mapped_ptr; + struct tu_descriptor_range *dynamic_descriptors; +}; + +struct tu_push_descriptor_set +{ + struct tu_descriptor_set set; + uint32_t capacity; +}; + +struct tu_descriptor_pool_entry +{ + uint32_t offset; + uint32_t size; + struct tu_descriptor_set *set; +}; + +struct tu_descriptor_pool +{ + struct radeon_winsys_bo *bo; + uint8_t *mapped_ptr; + uint64_t current_offset; + uint64_t size; + + uint8_t *host_memory_base; + uint8_t *host_memory_ptr; + uint8_t *host_memory_end; + + uint32_t entry_count; + uint32_t max_entry_count; + struct tu_descriptor_pool_entry entries[0]; +}; + +struct tu_descriptor_update_template_entry +{ + VkDescriptorType descriptor_type; + + /* The number of descriptors to update */ + uint32_t descriptor_count; + + /* Into mapped_ptr or dynamic_descriptors, in units of the respective array + */ + uint32_t dst_offset; + + /* In dwords. Not valid/used for dynamic descriptors */ + uint32_t dst_stride; + + uint32_t buffer_offset; + + /* Only valid for combined image samplers and samplers */ + uint16_t has_sampler; + + /* In bytes */ + size_t src_offset; + size_t src_stride; + + /* For push descriptors */ + const uint32_t *immutable_samplers; +}; + +struct tu_descriptor_update_template +{ + uint32_t entry_count; + VkPipelineBindPoint bind_point; + struct tu_descriptor_update_template_entry entry[0]; +}; + +struct tu_buffer +{ + VkDeviceSize size; + + VkBufferUsageFlags usage; + VkBufferCreateFlags flags; +}; + +enum tu_dynamic_state_bits +{ + TU_DYNAMIC_VIEWPORT = 1 << 0, + TU_DYNAMIC_SCISSOR = 1 << 1, + TU_DYNAMIC_LINE_WIDTH = 1 << 2, + TU_DYNAMIC_DEPTH_BIAS = 1 << 3, + TU_DYNAMIC_BLEND_CONSTANTS = 1 << 4, + TU_DYNAMIC_DEPTH_BOUNDS = 1 << 5, + TU_DYNAMIC_STENCIL_COMPARE_MASK = 1 << 6, + TU_DYNAMIC_STENCIL_WRITE_MASK = 1 << 7, + TU_DYNAMIC_STENCIL_REFERENCE = 1 << 8, + TU_DYNAMIC_DISCARD_RECTANGLE = 1 << 9, + TU_DYNAMIC_ALL = (1 << 10) - 1, +}; + +struct tu_vertex_binding +{ + struct tu_buffer *buffer; + VkDeviceSize offset; +}; + +struct tu_viewport_state +{ + uint32_t count; + VkViewport viewports[MAX_VIEWPORTS]; +}; + +struct tu_scissor_state +{ + uint32_t count; + VkRect2D scissors[MAX_SCISSORS]; +}; + +struct tu_discard_rectangle_state +{ + uint32_t count; + VkRect2D rectangles[MAX_DISCARD_RECTANGLES]; +}; + +struct tu_dynamic_state +{ + /** + * Bitmask of (1 << VK_DYNAMIC_STATE_*). + * Defines the set of saved dynamic state. + */ + uint32_t mask; + + struct tu_viewport_state viewport; + + struct tu_scissor_state scissor; + + float line_width; + + struct + { + float bias; + float clamp; + float slope; + } depth_bias; + + float blend_constants[4]; + + struct + { + float min; + float max; + } depth_bounds; + + struct + { + uint32_t front; + uint32_t back; + } stencil_compare_mask; + + struct + { + uint32_t front; + uint32_t back; + } stencil_write_mask; + + struct + { + uint32_t front; + uint32_t back; + } stencil_reference; + + struct tu_discard_rectangle_state discard_rectangle; +}; + +extern const struct tu_dynamic_state default_dynamic_state; + +const char * +tu_get_debug_option_name(int id); + +const char * +tu_get_perftest_option_name(int id); + +/** + * Attachment state when recording a renderpass instance. + * + * The clear value is valid only if there exists a pending clear. + */ +struct tu_attachment_state +{ + VkImageAspectFlags pending_clear_aspects; + uint32_t cleared_views; + VkClearValue clear_value; + VkImageLayout current_layout; +}; + +struct tu_descriptor_state +{ + struct tu_descriptor_set *sets[MAX_SETS]; + uint32_t dirty; + uint32_t valid; + struct tu_push_descriptor_set push_set; + bool push_dirty; + uint32_t dynamic_buffers[4 * MAX_DYNAMIC_BUFFERS]; +}; + +struct tu_cmd_state +{ + /* Vertex descriptors */ + uint64_t vb_va; + unsigned vb_size; + + struct tu_dynamic_state dynamic; + + /* Index buffer */ + struct tu_buffer *index_buffer; + uint64_t index_offset; + uint32_t index_type; + uint32_t max_index_count; + uint64_t index_va; +}; + +struct tu_cmd_pool +{ + VkAllocationCallbacks alloc; + struct list_head cmd_buffers; + struct list_head free_cmd_buffers; + uint32_t queue_family_index; +}; + +struct tu_cmd_buffer_upload +{ + uint8_t *map; + unsigned offset; + uint64_t size; + struct radeon_winsys_bo *upload_bo; + struct list_head list; +}; + +enum tu_cmd_buffer_status +{ + TU_CMD_BUFFER_STATUS_INVALID, + TU_CMD_BUFFER_STATUS_INITIAL, + TU_CMD_BUFFER_STATUS_RECORDING, + TU_CMD_BUFFER_STATUS_EXECUTABLE, + TU_CMD_BUFFER_STATUS_PENDING, +}; + +struct tu_cmd_buffer +{ + VK_LOADER_DATA _loader_data; + + struct tu_device *device; + + struct tu_cmd_pool *pool; + struct list_head pool_link; + + VkCommandBufferUsageFlags usage_flags; + VkCommandBufferLevel level; + enum tu_cmd_buffer_status status; + struct radeon_cmdbuf *cs; + struct tu_cmd_state state; + struct tu_vertex_binding vertex_bindings[MAX_VBS]; + uint32_t queue_family_index; + + uint8_t push_constants[MAX_PUSH_CONSTANTS_SIZE]; + VkShaderStageFlags push_constant_stages; + struct tu_descriptor_set meta_push_descriptors; + + struct tu_descriptor_state descriptors[VK_PIPELINE_BIND_POINT_RANGE_SIZE]; + + struct tu_cmd_buffer_upload upload; + + uint32_t scratch_size_needed; + uint32_t compute_scratch_size_needed; + uint32_t esgs_ring_size_needed; + uint32_t gsvs_ring_size_needed; + bool tess_rings_needed; + bool sample_positions_needed; + + VkResult record_result; + + uint32_t gfx9_fence_offset; + struct radeon_winsys_bo *gfx9_fence_bo; + uint32_t gfx9_fence_idx; + uint64_t gfx9_eop_bug_va; + + /** + * Whether a query pool has been resetted and we have to flush caches. + */ + bool pending_reset_query; +}; + +bool +tu_get_memory_fd(struct tu_device *device, + struct tu_device_memory *memory, + int *pFD); + +/* + * Takes x,y,z as exact numbers of invocations, instead of blocks. + * + * Limitations: Can't call normal dispatch functions without binding or + * rebinding + * the compute pipeline. + */ +void +tu_unaligned_dispatch(struct tu_cmd_buffer *cmd_buffer, + uint32_t x, + uint32_t y, + uint32_t z); + +struct tu_event +{ + struct radeon_winsys_bo *bo; + uint64_t *map; +}; + +struct tu_shader_module; + +#define TU_HASH_SHADER_IS_GEOM_COPY_SHADER (1 << 0) +#define TU_HASH_SHADER_SISCHED (1 << 1) +#define TU_HASH_SHADER_UNSAFE_MATH (1 << 2) +void +tu_hash_shaders(unsigned char *hash, + const VkPipelineShaderStageCreateInfo **stages, + const struct tu_pipeline_layout *layout, + const struct tu_pipeline_key *key, + uint32_t flags); + +static inline gl_shader_stage +vk_to_mesa_shader_stage(VkShaderStageFlagBits vk_stage) +{ + assert(__builtin_popcount(vk_stage) == 1); + return ffs(vk_stage) - 1; +} + +static inline VkShaderStageFlagBits +mesa_to_vk_shader_stage(gl_shader_stage mesa_stage) +{ + return (1 << mesa_stage); +} + +#define TU_STAGE_MASK ((1 << MESA_SHADER_STAGES) - 1) + +#define tu_foreach_stage(stage, stage_bits) \ + for (gl_shader_stage stage, \ + __tmp = (gl_shader_stage)((stage_bits)&TU_STAGE_MASK); \ + stage = __builtin_ffs(__tmp) - 1, __tmp; \ + __tmp &= ~(1 << (stage))) + +struct tu_shader_module +{ + struct nir_shader *nir; + unsigned char sha1[20]; + uint32_t size; + char data[0]; +}; + +struct tu_pipeline +{ + struct tu_device *device; + struct tu_dynamic_state dynamic_state; + + struct tu_pipeline_layout *layout; + + bool need_indirect_descriptor_sets; + VkShaderStageFlags active_stages; +}; + +struct tu_userdata_info * +tu_lookup_user_sgpr(struct tu_pipeline *pipeline, + gl_shader_stage stage, + int idx); + +struct tu_shader_variant * +tu_get_shader(struct tu_pipeline *pipeline, gl_shader_stage stage); + +struct tu_graphics_pipeline_create_info +{ + bool use_rectlist; + bool db_depth_clear; + bool db_stencil_clear; + bool db_depth_disable_expclear; + bool db_stencil_disable_expclear; + bool db_flush_depth_inplace; + bool db_flush_stencil_inplace; + bool db_resummarize; + uint32_t custom_blend_mode; +}; + +VkResult +tu_graphics_pipeline_create( + VkDevice device, + VkPipelineCache cache, + const VkGraphicsPipelineCreateInfo *pCreateInfo, + const struct tu_graphics_pipeline_create_info *extra, + const VkAllocationCallbacks *alloc, + VkPipeline *pPipeline); + +struct vk_format_description; +uint32_t +tu_translate_buffer_dataformat(const struct vk_format_description *desc, + int first_non_void); +uint32_t +tu_translate_buffer_numformat(const struct vk_format_description *desc, + int first_non_void); +uint32_t +tu_translate_colorformat(VkFormat format); +uint32_t +tu_translate_color_numformat(VkFormat format, + const struct vk_format_description *desc, + int first_non_void); +uint32_t +tu_colorformat_endian_swap(uint32_t colorformat); +unsigned +tu_translate_colorswap(VkFormat format, bool do_endian_swap); +uint32_t +tu_translate_dbformat(VkFormat format); +uint32_t +tu_translate_tex_dataformat(VkFormat format, + const struct vk_format_description *desc, + int first_non_void); +uint32_t +tu_translate_tex_numformat(VkFormat format, + const struct vk_format_description *desc, + int first_non_void); +bool +tu_format_pack_clear_color(VkFormat format, + uint32_t clear_vals[2], + VkClearColorValue *value); +bool +tu_is_colorbuffer_format_supported(VkFormat format, bool *blendable); +bool +tu_dcc_formats_compatible(VkFormat format1, VkFormat format2); + +struct tu_image +{ + VkImageType type; + /* The original VkFormat provided by the client. This may not match any + * of the actual surface formats. + */ + VkFormat vk_format; + VkImageAspectFlags aspects; + VkImageUsageFlags usage; /**< Superset of VkImageCreateInfo::usage. */ + VkImageTiling tiling; /** VkImageCreateInfo::tiling */ + VkImageCreateFlags flags; /** VkImageCreateInfo::flags */ + + VkDeviceSize size; + uint32_t alignment; + + unsigned queue_family_mask; + bool exclusive; + bool shareable; + + /* For VK_ANDROID_native_buffer, the WSI image owns the memory, */ + VkDeviceMemory owned_memory; +}; + +unsigned +tu_image_queue_family_mask(const struct tu_image *image, + uint32_t family, + uint32_t queue_family); + +static inline uint32_t +tu_get_layerCount(const struct tu_image *image, + const VkImageSubresourceRange *range) +{ + abort(); +} + +static inline uint32_t +tu_get_levelCount(const struct tu_image *image, + const VkImageSubresourceRange *range) +{ + abort(); +} + +struct tu_image_view +{ + struct tu_image *image; /**< VkImageViewCreateInfo::image */ + + VkImageViewType type; + VkImageAspectFlags aspect_mask; + VkFormat vk_format; + uint32_t base_layer; + uint32_t layer_count; + uint32_t base_mip; + uint32_t level_count; + VkExtent3D extent; /**< Extent of VkImageViewCreateInfo::baseMipLevel. */ + + uint32_t descriptor[16]; + + /* Descriptor for use as a storage image as opposed to a sampled image. + * This has a few differences for cube maps (e.g. type). + */ + uint32_t storage_descriptor[16]; +}; + +struct tu_sampler +{ +}; + +struct tu_image_create_info +{ + const VkImageCreateInfo *vk_info; + bool scanout; + bool no_metadata_planes; +}; + +VkResult +tu_image_create(VkDevice _device, + const struct tu_image_create_info *info, + const VkAllocationCallbacks *alloc, + VkImage *pImage); + +VkResult +tu_image_from_gralloc(VkDevice device_h, + const VkImageCreateInfo *base_info, + const VkNativeBufferANDROID *gralloc_info, + const VkAllocationCallbacks *alloc, + VkImage *out_image_h); + +void +tu_image_view_init(struct tu_image_view *view, + struct tu_device *device, + const VkImageViewCreateInfo *pCreateInfo); + +struct tu_buffer_view +{ + struct radeon_winsys_bo *bo; + VkFormat vk_format; + uint64_t range; /**< VkBufferViewCreateInfo::range */ + uint32_t state[4]; +}; +void +tu_buffer_view_init(struct tu_buffer_view *view, + struct tu_device *device, + const VkBufferViewCreateInfo *pCreateInfo); + +static inline struct VkExtent3D +tu_sanitize_image_extent(const VkImageType imageType, + const struct 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"); + } +} + +static inline struct VkOffset3D +tu_sanitize_image_offset(const VkImageType imageType, + const struct VkOffset3D imageOffset) +{ + switch (imageType) { + case VK_IMAGE_TYPE_1D: + return (VkOffset3D){ imageOffset.x, 0, 0 }; + case VK_IMAGE_TYPE_2D: + return (VkOffset3D){ imageOffset.x, imageOffset.y, 0 }; + case VK_IMAGE_TYPE_3D: + return imageOffset; + default: + unreachable("invalid image type"); + } +} + +struct tu_attachment_info +{ + struct tu_image_view *attachment; +}; + +struct tu_framebuffer +{ + uint32_t width; + uint32_t height; + uint32_t layers; + + uint32_t attachment_count; + struct tu_attachment_info attachments[0]; +}; + +struct tu_subpass_barrier +{ + VkPipelineStageFlags src_stage_mask; + VkAccessFlags src_access_mask; + VkAccessFlags dst_access_mask; +}; + +void +tu_subpass_barrier(struct tu_cmd_buffer *cmd_buffer, + const struct tu_subpass_barrier *barrier); + +struct tu_subpass_attachment +{ + uint32_t attachment; + VkImageLayout layout; +}; + +struct tu_subpass +{ + uint32_t input_count; + uint32_t color_count; + struct tu_subpass_attachment *input_attachments; + struct tu_subpass_attachment *color_attachments; + struct tu_subpass_attachment *resolve_attachments; + struct tu_subpass_attachment depth_stencil_attachment; + + /** Subpass has at least one resolve attachment */ + bool has_resolve; + + struct tu_subpass_barrier start_barrier; + + uint32_t view_mask; + VkSampleCountFlagBits max_sample_count; +}; + +struct tu_render_pass_attachment +{ + VkFormat format; + uint32_t samples; + VkAttachmentLoadOp load_op; + VkAttachmentLoadOp stencil_load_op; + VkImageLayout initial_layout; + VkImageLayout final_layout; + uint32_t view_mask; +}; + +struct tu_render_pass +{ + uint32_t attachment_count; + uint32_t subpass_count; + struct tu_subpass_attachment *subpass_attachments; + struct tu_render_pass_attachment *attachments; + struct tu_subpass_barrier end_barrier; + struct tu_subpass subpasses[0]; +}; + +VkResult +tu_device_init_meta(struct tu_device *device); +void +tu_device_finish_meta(struct tu_device *device); + +struct tu_query_pool +{ + struct radeon_winsys_bo *bo; + uint32_t stride; + uint32_t availability_offset; + uint64_t size; + char *ptr; + VkQueryType type; + uint32_t pipeline_stats_mask; +}; + +struct tu_semaphore +{ + /* use a winsys sem for non-exportable */ + struct radeon_winsys_sem *sem; + uint32_t syncobj; + uint32_t temp_syncobj; +}; + +void +tu_set_descriptor_set(struct tu_cmd_buffer *cmd_buffer, + VkPipelineBindPoint bind_point, + struct tu_descriptor_set *set, + unsigned idx); + +void +tu_update_descriptor_sets(struct tu_device *device, + struct tu_cmd_buffer *cmd_buffer, + VkDescriptorSet overrideSet, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites, + uint32_t descriptorCopyCount, + const VkCopyDescriptorSet *pDescriptorCopies); + +void +tu_update_descriptor_set_with_template( + struct tu_device *device, + struct tu_cmd_buffer *cmd_buffer, + struct tu_descriptor_set *set, + VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, + const void *pData); + +void +tu_meta_push_descriptor_set(struct tu_cmd_buffer *cmd_buffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout _layout, + uint32_t set, + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet *pDescriptorWrites); + +struct tu_fence +{ + struct radeon_winsys_fence *fence; + bool submitted; + bool signalled; + + uint32_t syncobj; + uint32_t temp_syncobj; +}; + +/* tu_nir_to_llvm.c */ +struct tu_shader_variant_info; +struct tu_nir_compiler_options; + +struct radeon_winsys_sem; + +#define TU_DEFINE_HANDLE_CASTS(__tu_type, __VkType) \ + \ + static inline struct __tu_type *__tu_type##_from_handle(__VkType _handle) \ + { \ + return (struct __tu_type *)_handle; \ + } \ + \ + static inline __VkType __tu_type##_to_handle(struct __tu_type *_obj) \ + { \ + return (__VkType)_obj; \ + } + +#define TU_DEFINE_NONDISP_HANDLE_CASTS(__tu_type, __VkType) \ + \ + static inline struct __tu_type *__tu_type##_from_handle(__VkType _handle) \ + { \ + return (struct __tu_type *)(uintptr_t)_handle; \ + } \ + \ + static inline __VkType __tu_type##_to_handle(struct __tu_type *_obj) \ + { \ + return (__VkType)(uintptr_t)_obj; \ + } + +#define TU_FROM_HANDLE(__tu_type, __name, __handle) \ + struct __tu_type *__name = __tu_type##_from_handle(__handle) + +TU_DEFINE_HANDLE_CASTS(tu_cmd_buffer, VkCommandBuffer) +TU_DEFINE_HANDLE_CASTS(tu_device, VkDevice) +TU_DEFINE_HANDLE_CASTS(tu_instance, VkInstance) +TU_DEFINE_HANDLE_CASTS(tu_physical_device, VkPhysicalDevice) +TU_DEFINE_HANDLE_CASTS(tu_queue, VkQueue) + +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_cmd_pool, VkCommandPool) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_buffer, VkBuffer) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_buffer_view, VkBufferView) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_descriptor_pool, VkDescriptorPool) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_descriptor_set, VkDescriptorSet) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_descriptor_set_layout, + VkDescriptorSetLayout) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_descriptor_update_template, + VkDescriptorUpdateTemplateKHR) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_device_memory, VkDeviceMemory) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_fence, VkFence) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_event, VkEvent) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_framebuffer, VkFramebuffer) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_image, VkImage) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_image_view, VkImageView); +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_pipeline_cache, VkPipelineCache) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_pipeline, VkPipeline) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_pipeline_layout, VkPipelineLayout) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_query_pool, VkQueryPool) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_render_pass, VkRenderPass) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_sampler, VkSampler) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_shader_module, VkShaderModule) +TU_DEFINE_NONDISP_HANDLE_CASTS(tu_semaphore, VkSemaphore) + +#endif /* TU_PRIVATE_H */ diff --git a/src/freedreno/vulkan/tu_query.c b/src/freedreno/vulkan/tu_query.c new file mode 100644 index 00000000000..30f47c8ca9d --- /dev/null +++ b/src/freedreno/vulkan/tu_query.c @@ -0,0 +1,123 @@ +/* + * Copyrigh 2016 Red Hat Inc. + * Based on anv: + * Copyright © 2015 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 <assert.h> +#include <fcntl.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> + +#include "tu_private.h" +#include "nir/nir_builder.h" + +VkResult +tu_CreateQueryPool(VkDevice _device, + const VkQueryPoolCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkQueryPool *pQueryPool) +{ + TU_FROM_HANDLE(tu_device, device, _device); + struct tu_query_pool *pool = vk_alloc2(&device->alloc, + pAllocator, + sizeof(*pool), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!pool) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + *pQueryPool = tu_query_pool_to_handle(pool); + return VK_SUCCESS; +} + +void +tu_DestroyQueryPool(VkDevice _device, + VkQueryPool _pool, + const VkAllocationCallbacks *pAllocator) +{ + TU_FROM_HANDLE(tu_device, device, _device); + TU_FROM_HANDLE(tu_query_pool, pool, _pool); + + if (!pool) + return; + + vk_free2(&device->alloc, pAllocator, pool); +} + +VkResult +tu_GetQueryPoolResults(VkDevice _device, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + size_t dataSize, + void *pData, + VkDeviceSize stride, + VkQueryResultFlags flags) +{ + return VK_SUCCESS; +} + +void +tu_CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize stride, + VkQueryResultFlags flags) +{ +} + +void +tu_CmdResetQueryPool(VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount) +{ +} + +void +tu_CmdBeginQuery(VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags) +{ +} + +void +tu_CmdEndQuery(VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query) +{ +} + +void +tu_CmdWriteTimestamp(VkCommandBuffer commandBuffer, + VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query) +{ +} diff --git a/src/freedreno/vulkan/tu_util.c b/src/freedreno/vulkan/tu_util.c new file mode 100644 index 00000000000..311c3a1b141 --- /dev/null +++ b/src/freedreno/vulkan/tu_util.c @@ -0,0 +1,115 @@ +/* + * Copyright © 2015 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 <assert.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "tu_private.h" +#include "vk_enum_to_str.h" + +#include "util/u_math.h" + +/** Log an error message. */ +void tu_printflike(1, 2) tu_loge(const char *format, ...) +{ + va_list va; + + va_start(va, format); + tu_loge_v(format, va); + va_end(va); +} + +/** \see tu_loge() */ +void +tu_loge_v(const char *format, va_list va) +{ + fprintf(stderr, "vk: error: "); + vfprintf(stderr, format, va); + fprintf(stderr, "\n"); +} + +/** Log an error message. */ +void tu_printflike(1, 2) tu_logi(const char *format, ...) +{ + va_list va; + + va_start(va, format); + tu_logi_v(format, va); + va_end(va); +} + +/** \see tu_logi() */ +void +tu_logi_v(const char *format, va_list va) +{ + fprintf(stderr, "tu: info: "); + vfprintf(stderr, format, va); + fprintf(stderr, "\n"); +} + +void tu_printflike(3, 4) + __tu_finishme(const char *file, int line, const char *format, ...) +{ + va_list ap; + char buffer[256]; + + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + fprintf(stderr, "%s:%d: FINISHME: %s\n", file, line, buffer); +} + +VkResult +__vk_errorf(struct tu_instance *instance, + VkResult error, + const char *file, + int line, + const char *format, + ...) +{ + va_list ap; + char buffer[256]; + + const char *error_str = vk_Result_to_str(error); + +#ifndef DEBUG + return error; +#endif + + if (format) { + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + fprintf(stderr, "%s:%d: %s (%s)\n", file, line, buffer, error_str); + } else { + fprintf(stderr, "%s:%d: %s\n", file, line, error_str); + } + + return error; +} diff --git a/src/freedreno/vulkan/tu_util.h b/src/freedreno/vulkan/tu_util.h new file mode 100644 index 00000000000..b013079d518 --- /dev/null +++ b/src/freedreno/vulkan/tu_util.h @@ -0,0 +1,11 @@ +#ifndef TU_UTIL_H +#define TU_UTIL_H + +#ifdef HAVE___BUILTIN_POPCOUNT +#define util_bitcount(i) __builtin_popcount(i) +#else +extern unsigned int +util_bitcount(unsigned int n); +#endif + +#endif /* TU_UTIL_H */ diff --git a/src/freedreno/vulkan/vk_format.h b/src/freedreno/vulkan/vk_format.h new file mode 100644 index 00000000000..bab0eda2076 --- /dev/null +++ b/src/freedreno/vulkan/vk_format.h @@ -0,0 +1,545 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * Based on u_format.h which is: + * Copyright 2009-2010 Vmware, Inc. + * 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_FORMAT_H +#define VK_FORMAT_H + +#include <assert.h> +#include <util/macros.h> +#include <vulkan/vulkan.h> + +enum vk_format_layout +{ + /** + * Formats with vk_format_block::width == vk_format_block::height == 1 + * that can be described as an ordinary data structure. + */ + VK_FORMAT_LAYOUT_PLAIN = 0, + + /** + * Formats with sub-sampled channels. + * + * This is for formats like YVYU where there is less than one sample per + * pixel. + */ + VK_FORMAT_LAYOUT_SUBSAMPLED = 3, + + /** + * S3 Texture Compression formats. + */ + VK_FORMAT_LAYOUT_S3TC = 4, + + /** + * Red-Green Texture Compression formats. + */ + VK_FORMAT_LAYOUT_RGTC = 5, + + /** + * Ericsson Texture Compression + */ + VK_FORMAT_LAYOUT_ETC = 6, + + /** + * BC6/7 Texture Compression + */ + VK_FORMAT_LAYOUT_BPTC = 7, + + /** + * ASTC + */ + VK_FORMAT_LAYOUT_ASTC = 8, + + /** + * Everything else that doesn't fit in any of the above layouts. + */ + VK_FORMAT_LAYOUT_OTHER = 9 +}; + +struct vk_format_block +{ + /** Block width in pixels */ + unsigned width; + + /** Block height in pixels */ + unsigned height; + + /** Block size in bits */ + unsigned bits; +}; + +enum vk_format_type +{ + VK_FORMAT_TYPE_VOID = 0, + VK_FORMAT_TYPE_UNSIGNED = 1, + VK_FORMAT_TYPE_SIGNED = 2, + VK_FORMAT_TYPE_FIXED = 3, + VK_FORMAT_TYPE_FLOAT = 4 +}; + +enum vk_format_colorspace +{ + VK_FORMAT_COLORSPACE_RGB = 0, + VK_FORMAT_COLORSPACE_SRGB = 1, + VK_FORMAT_COLORSPACE_YUV = 2, + VK_FORMAT_COLORSPACE_ZS = 3 +}; + +struct vk_format_channel_description +{ + unsigned type : 5; + unsigned normalized : 1; + unsigned pure_integer : 1; + unsigned scaled : 1; + unsigned size : 8; + unsigned shift : 16; +}; + +struct vk_format_description +{ + VkFormat format; + const char *name; + const char *short_name; + + struct vk_format_block block; + enum vk_format_layout layout; + + unsigned nr_channels : 3; + unsigned is_array : 1; + unsigned is_bitmask : 1; + unsigned is_mixed : 1; + + struct vk_format_channel_description channel[4]; + + unsigned char swizzle[4]; + + enum vk_format_colorspace colorspace; +}; + +extern const struct vk_format_description vk_format_description_table[]; + +const struct vk_format_description * +vk_format_description(VkFormat format); + +/** + * Return total bits needed for the pixel format per block. + */ +static inline unsigned +vk_format_get_blocksizebits(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + + assert(desc); + if (!desc) { + return 0; + } + + return desc->block.bits; +} + +/** + * Return bytes per block (not pixel) for the given format. + */ +static inline unsigned +vk_format_get_blocksize(VkFormat format) +{ + unsigned bits = vk_format_get_blocksizebits(format); + unsigned bytes = bits / 8; + + assert(bits % 8 == 0); + assert(bytes > 0); + if (bytes == 0) { + bytes = 1; + } + + return bytes; +} + +static inline unsigned +vk_format_get_blockwidth(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + + assert(desc); + if (!desc) { + return 1; + } + + return desc->block.width; +} + +static inline unsigned +vk_format_get_blockheight(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + + assert(desc); + if (!desc) { + return 1; + } + + return desc->block.height; +} + +/** + * Return the index of the first non-void channel + * -1 if no non-void channels + */ +static inline int +vk_format_get_first_non_void_channel(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + int i; + + for (i = 0; i < 4; i++) + if (desc->channel[i].type != VK_FORMAT_TYPE_VOID) + break; + + if (i == 4) + return -1; + + return i; +} + +enum vk_swizzle +{ + VK_SWIZZLE_X, + VK_SWIZZLE_Y, + VK_SWIZZLE_Z, + VK_SWIZZLE_W, + VK_SWIZZLE_0, + VK_SWIZZLE_1, + VK_SWIZZLE_NONE, + VK_SWIZZLE_MAX, /**< Number of enums counter (must be last) */ +}; + +static inline VkImageAspectFlags +vk_format_aspects(VkFormat format) +{ + switch (format) { + case VK_FORMAT_UNDEFINED: + return 0; + + case VK_FORMAT_S8_UINT: + return VK_IMAGE_ASPECT_STENCIL_BIT; + + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + return VK_IMAGE_ASPECT_DEPTH_BIT; + + default: + return VK_IMAGE_ASPECT_COLOR_BIT; + } +} + +static inline enum vk_swizzle +tu_swizzle_conv(VkComponentSwizzle component, + const unsigned char chan[4], + VkComponentSwizzle vk_swiz) +{ + int x; + + if (vk_swiz == VK_COMPONENT_SWIZZLE_IDENTITY) + vk_swiz = component; + switch (vk_swiz) { + case VK_COMPONENT_SWIZZLE_ZERO: + return VK_SWIZZLE_0; + case VK_COMPONENT_SWIZZLE_ONE: + return VK_SWIZZLE_1; + case VK_COMPONENT_SWIZZLE_R: + for (x = 0; x < 4; x++) + if (chan[x] == 0) + return x; + return VK_SWIZZLE_0; + case VK_COMPONENT_SWIZZLE_G: + for (x = 0; x < 4; x++) + if (chan[x] == 1) + return x; + return VK_SWIZZLE_0; + case VK_COMPONENT_SWIZZLE_B: + for (x = 0; x < 4; x++) + if (chan[x] == 2) + return x; + return VK_SWIZZLE_0; + case VK_COMPONENT_SWIZZLE_A: + for (x = 0; x < 4; x++) + if (chan[x] == 3) + return x; + return VK_SWIZZLE_1; + default: + unreachable("Illegal swizzle"); + } +} + +static inline void +vk_format_compose_swizzles(const VkComponentMapping *mapping, + const unsigned char swz[4], + enum vk_swizzle dst[4]) +{ + dst[0] = tu_swizzle_conv(VK_COMPONENT_SWIZZLE_R, swz, mapping->r); + dst[1] = tu_swizzle_conv(VK_COMPONENT_SWIZZLE_G, swz, mapping->g); + dst[2] = tu_swizzle_conv(VK_COMPONENT_SWIZZLE_B, swz, mapping->b); + dst[3] = tu_swizzle_conv(VK_COMPONENT_SWIZZLE_A, swz, mapping->a); +} + +static inline bool +vk_format_is_compressed(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + + assert(desc); + if (!desc) { + return false; + } + + switch (desc->layout) { + case VK_FORMAT_LAYOUT_S3TC: + case VK_FORMAT_LAYOUT_RGTC: + case VK_FORMAT_LAYOUT_ETC: + case VK_FORMAT_LAYOUT_BPTC: + case VK_FORMAT_LAYOUT_ASTC: + /* XXX add other formats in the future */ + return true; + default: + return false; + } +} + +static inline bool +vk_format_has_depth(const struct vk_format_description *desc) +{ + return desc->colorspace == VK_FORMAT_COLORSPACE_ZS && + desc->swizzle[0] != VK_SWIZZLE_NONE; +} + +static inline bool +vk_format_has_stencil(const struct vk_format_description *desc) +{ + return desc->colorspace == VK_FORMAT_COLORSPACE_ZS && + desc->swizzle[1] != VK_SWIZZLE_NONE; +} + +static inline bool +vk_format_is_depth_or_stencil(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + + assert(desc); + if (!desc) { + return false; + } + + return vk_format_has_depth(desc) || vk_format_has_stencil(desc); +} + +static inline bool +vk_format_is_depth(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + + assert(desc); + if (!desc) { + return false; + } + + return vk_format_has_depth(desc); +} + +static inline bool +vk_format_is_stencil(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + + assert(desc); + if (!desc) { + return false; + } + + return vk_format_has_stencil(desc); +} + +static inline bool +vk_format_is_color(VkFormat format) +{ + return !vk_format_is_depth_or_stencil(format); +} + +static inline VkFormat +vk_format_depth_only(VkFormat 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 bool +vk_format_is_int(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + int channel = vk_format_get_first_non_void_channel(format); + + return channel >= 0 && desc->channel[channel].pure_integer; +} + +static inline bool +vk_format_is_srgb(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + return desc->colorspace == VK_FORMAT_COLORSPACE_SRGB; +} + +static inline VkFormat +vk_format_no_srgb(VkFormat format) +{ + switch (format) { + case VK_FORMAT_R8_SRGB: + return VK_FORMAT_R8_UNORM; + case VK_FORMAT_R8G8_SRGB: + return VK_FORMAT_R8G8_UNORM; + case VK_FORMAT_R8G8B8_SRGB: + return VK_FORMAT_R8G8B8_UNORM; + case VK_FORMAT_B8G8R8_SRGB: + return VK_FORMAT_B8G8R8_UNORM; + case VK_FORMAT_R8G8B8A8_SRGB: + return VK_FORMAT_R8G8B8A8_UNORM; + case VK_FORMAT_B8G8R8A8_SRGB: + return VK_FORMAT_B8G8R8A8_UNORM; + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: + return VK_FORMAT_A8B8G8R8_UNORM_PACK32; + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: + return VK_FORMAT_BC1_RGB_UNORM_BLOCK; + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + case VK_FORMAT_BC2_SRGB_BLOCK: + return VK_FORMAT_BC2_UNORM_BLOCK; + case VK_FORMAT_BC3_SRGB_BLOCK: + return VK_FORMAT_BC3_UNORM_BLOCK; + case VK_FORMAT_BC7_SRGB_BLOCK: + return VK_FORMAT_BC7_UNORM_BLOCK; + case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; + case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: + return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + default: + assert(!vk_format_is_srgb(format)); + return format; + } +} + +static inline VkFormat +vk_format_stencil_only(VkFormat format) +{ + return VK_FORMAT_S8_UINT; +} + +static inline unsigned +vk_format_get_component_bits(VkFormat format, + enum vk_format_colorspace colorspace, + unsigned component) +{ + const struct vk_format_description *desc = vk_format_description(format); + enum vk_format_colorspace desc_colorspace; + + assert(format); + if (!format) { + return 0; + } + + assert(component < 4); + + /* Treat RGB and SRGB as equivalent. */ + if (colorspace == VK_FORMAT_COLORSPACE_SRGB) { + colorspace = VK_FORMAT_COLORSPACE_RGB; + } + if (desc->colorspace == VK_FORMAT_COLORSPACE_SRGB) { + desc_colorspace = VK_FORMAT_COLORSPACE_RGB; + } else { + desc_colorspace = desc->colorspace; + } + + if (desc_colorspace != colorspace) { + return 0; + } + + switch (desc->swizzle[component]) { + case VK_SWIZZLE_X: + return desc->channel[0].size; + case VK_SWIZZLE_Y: + return desc->channel[1].size; + case VK_SWIZZLE_Z: + return desc->channel[2].size; + case VK_SWIZZLE_W: + return desc->channel[3].size; + default: + return 0; + } +} + +static inline VkFormat +vk_to_non_srgb_format(VkFormat format) +{ + switch (format) { + case VK_FORMAT_R8_SRGB: + return VK_FORMAT_R8_UNORM; + case VK_FORMAT_R8G8_SRGB: + return VK_FORMAT_R8G8_UNORM; + case VK_FORMAT_R8G8B8_SRGB: + return VK_FORMAT_R8G8B8_UNORM; + case VK_FORMAT_B8G8R8_SRGB: + return VK_FORMAT_B8G8R8_UNORM; + case VK_FORMAT_R8G8B8A8_SRGB: + return VK_FORMAT_R8G8B8A8_UNORM; + case VK_FORMAT_B8G8R8A8_SRGB: + return VK_FORMAT_B8G8R8A8_UNORM; + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: + return VK_FORMAT_A8B8G8R8_UNORM_PACK32; + default: + return format; + } +} + +static inline unsigned +vk_format_get_nr_components(VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + return desc->nr_channels; +} + +#endif /* VK_FORMAT_H */ diff --git a/src/freedreno/vulkan/vk_format_layout.csv b/src/freedreno/vulkan/vk_format_layout.csv new file mode 100644 index 00000000000..f9c2e6f7c35 --- /dev/null +++ b/src/freedreno/vulkan/vk_format_layout.csv @@ -0,0 +1,188 @@ +/* this is pretty much taken from the gallium one. */ + + +VK_FORMAT_UNDEFINED , plain, 1, 1, u8 , , , , x001, rgb +VK_FORMAT_R4G4_UNORM_PACK8 , plain, 1, 1, un4 , un4 , , , xy01, rgb +VK_FORMAT_R4G4B4A4_UNORM_PACK16 , plain, 1, 1, un4 , un4 , un4 , un4 , wzyx, rgb +VK_FORMAT_B4G4R4A4_UNORM_PACK16 , plain, 1, 1, un4 , un4 , un4 , un4 , wxyz, rgb +VK_FORMAT_R5G6B5_UNORM_PACK16 , plain, 1, 1, un5 , un6 , un5 , , zyx1, rgb +VK_FORMAT_B5G6R5_UNORM_PACK16 , plain, 1, 1, un5 , un6 , un5 , , xyz1, rgb +VK_FORMAT_R5G5B5A1_UNORM_PACK16 , plain, 1, 1, un1 , un5 , un5 , un5 , wzyx, rgb +VK_FORMAT_B5G5R5A1_UNORM_PACK16 , plain, 1, 1, un1 , un5 , un5 , un5 , wxyz, rgb +VK_FORMAT_A1R5G5B5_UNORM_PACK16 , plain, 1, 1, un5 , un5 , un5 , un1 , zyxw, rgb +VK_FORMAT_R8_UNORM , plain, 1, 1, un8 , , , , x001, rgb +VK_FORMAT_R8_SNORM , plain, 1, 1, sn8 , , , , x001, rgb +VK_FORMAT_R8_USCALED , plain, 1, 1, us8 , , , , x001, rgb +VK_FORMAT_R8_SSCALED , plain, 1, 1, ss8 , , , , x001, rgb +VK_FORMAT_R8_UINT , plain, 1, 1, up8 , , , , x001, rgb +VK_FORMAT_R8_SINT , plain, 1, 1, sp8 , , , , x001, rgb +VK_FORMAT_R8_SRGB , plain, 1, 1, un8 , , , , x001, srgb +VK_FORMAT_R8G8_UNORM , plain, 1, 1, un8 , un8 , , , xy01, rgb +VK_FORMAT_R8G8_SNORM , plain, 1, 1, sn8 , sn8 , , , xy01, rgb +VK_FORMAT_R8G8_USCALED , plain, 1, 1, us8 , us8 , , , xy01, rgb +VK_FORMAT_R8G8_SSCALED , plain, 1, 1, ss8 , ss8 , , , xy01, rgb +VK_FORMAT_R8G8_UINT , plain, 1, 1, up8 , up8 , , , xy01, rgb +VK_FORMAT_R8G8_SINT , plain, 1, 1, sp8 , sp8 , , , xy01, rgb +VK_FORMAT_R8G8_SRGB , plain, 1, 1, un8 , un8 , , , xy01, srgb +VK_FORMAT_R8G8B8_UNORM , plain, 1, 1, un8 , un8 , un8 , , xyz1, rgb +VK_FORMAT_R8G8B8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , , xyz1, rgb +VK_FORMAT_R8G8B8_USCALED , plain, 1, 1, us8 , us8 , us8 , , xyz1, rgb +VK_FORMAT_R8G8B8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , , xyz1, rgb +VK_FORMAT_R8G8B8_UINT , plain, 1, 1, up8 , up8 , up8 , , xyz1, rgb +VK_FORMAT_R8G8B8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , , xyz1, rgb +VK_FORMAT_R8G8B8_SRGB , plain, 1, 1, un8 , un8 , un8 , , xyz1, srgb +VK_FORMAT_B8G8R8_UNORM , plain, 1, 1, un8 , un8 , un8 , , zyx1, rgb +VK_FORMAT_B8G8R8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , , zyx1, rgb +VK_FORMAT_B8G8R8_USCALED , plain, 1, 1, us8 , us8 , us8 , , zyx1, rgb +VK_FORMAT_B8G8R8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , , zyx1, rgb +VK_FORMAT_B8G8R8_UINT , plain, 1, 1, up8 , up8 , up8 , , zyx1, rgb +VK_FORMAT_B8G8R8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , , zyx1, rgb +VK_FORMAT_B8G8R8_SRGB , plain, 1, 1, un8 , un8 , un8 , , zyx1, srgb +VK_FORMAT_R8G8B8A8_UNORM , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, rgb +VK_FORMAT_R8G8B8A8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , sn8 , xyzw, rgb +VK_FORMAT_R8G8B8A8_USCALED , plain, 1, 1, us8 , us8 , us8 , us8 , xyzw, rgb +VK_FORMAT_R8G8B8A8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , ss8 , xyzw, rgb +VK_FORMAT_R8G8B8A8_UINT , plain, 1, 1, up8 , up8 , up8 , up8 , xyzw, rgb +VK_FORMAT_R8G8B8A8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , sp8 , xyzw, rgb +VK_FORMAT_R8G8B8A8_SRGB , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, srgb +VK_FORMAT_B8G8R8A8_UNORM , plain, 1, 1, un8 , un8 , un8 , un8 , zyxw, rgb +VK_FORMAT_B8G8R8A8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , sn8 , zyxw, rgb +VK_FORMAT_B8G8R8A8_USCALED , plain, 1, 1, us8 , us8 , us8 , us8 , zyxw, rgb +VK_FORMAT_B8G8R8A8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , ss8 , zyxw, rgb +VK_FORMAT_B8G8R8A8_UINT , plain, 1, 1, up8 , up8 , up8 , up8 , zyxw, rgb +VK_FORMAT_B8G8R8A8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , sp8 , zyxw, rgb +VK_FORMAT_B8G8R8A8_SRGB , plain, 1, 1, un8 , un8 , un8 , un8 , zyxw, srgb +VK_FORMAT_A8B8G8R8_UNORM_PACK32 , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, rgb +VK_FORMAT_A8B8G8R8_SNORM_PACK32 , plain, 1, 1, sn8 , sn8 , sn8 , sn8 , xyzw, rgb +VK_FORMAT_A8B8G8R8_USCALED_PACK32 , plain, 1, 1, us8 , us8 , us8 , us8 , xyzw, rgb +VK_FORMAT_A8B8G8R8_SSCALED_PACK32 , plain, 1, 1, ss8 , ss8 , ss8 , ss8 , xyzw, rgb +VK_FORMAT_A8B8G8R8_UINT_PACK32 , plain, 1, 1, up8 , up8 , up8 , up8 , xyzw, rgb +VK_FORMAT_A8B8G8R8_SINT_PACK32 , plain, 1, 1, sp8 , sp8 , sp8 , sp8 , xyzw, rgb +VK_FORMAT_A8B8G8R8_SRGB_PACK32 , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, srgb +VK_FORMAT_A2R10G10B10_UNORM_PACK32 , plain, 1, 1, un10, un10, un10, un2 , zyxw, rgb +VK_FORMAT_A2R10G10B10_SNORM_PACK32 , plain, 1, 1, sn10, sn10, sn10, sn2 , zyxw, rgb +VK_FORMAT_A2R10G10B10_USCALED_PACK32 , plain, 1, 1, us10, us10, us10, us2 , zyxw, rgb +VK_FORMAT_A2R10G10B10_SSCALED_PACK32 , plain, 1, 1, ss10, ss10, ss10, ss2 , zyxw, rgb +VK_FORMAT_A2R10G10B10_UINT_PACK32 , plain, 1, 1, up10, up10, up10, up2 , zyxw, rgb +VK_FORMAT_A2R10G10B10_SINT_PACK32 , plain, 1, 1, sp10, sp10, sp10, sp2 , zyxw, rgb +VK_FORMAT_A2B10G10R10_UNORM_PACK32 , plain, 1, 1, un10, un10, un10, un2 , xyzw, rgb +VK_FORMAT_A2B10G10R10_SNORM_PACK32 , plain, 1, 1, sn10, sn10, sn10, sn2 , xyzw, rgb +VK_FORMAT_A2B10G10R10_USCALED_PACK32 , plain, 1, 1, us10, us10, us10, us2 , xyzw, rgb +VK_FORMAT_A2B10G10R10_SSCALED_PACK32 , plain, 1, 1, ss10, ss10, ss10, ss2 , xyzw, rgb +VK_FORMAT_A2B10G10R10_UINT_PACK32 , plain, 1, 1, up10, up10, up10, up2 , xyzw, rgb +VK_FORMAT_A2B10G10R10_SINT_PACK32 , plain, 1, 1, sp10, sp10, sp10, sp2 , xyzw, rgb +VK_FORMAT_R16_UNORM , plain, 1, 1, un16, , , , x001, rgb +VK_FORMAT_R16_SNORM , plain, 1, 1, sn16, , , , x001, rgb +VK_FORMAT_R16_USCALED , plain, 1, 1, us16, , , , x001, rgb +VK_FORMAT_R16_SSCALED , plain, 1, 1, ss16, , , , x001, rgb +VK_FORMAT_R16_UINT , plain, 1, 1, up16, , , , x001, rgb +VK_FORMAT_R16_SINT , plain, 1, 1, sp16, , , , x001, rgb +VK_FORMAT_R16_SFLOAT , plain, 1, 1, f16 , , , , x001, rgb +VK_FORMAT_R16G16_UNORM , plain, 1, 1, un16, un16, , , xy01, rgb +VK_FORMAT_R16G16_SNORM , plain, 1, 1, sn16, sn16, , , xy01, rgb +VK_FORMAT_R16G16_USCALED , plain, 1, 1, us16, us16, , , xy01, rgb +VK_FORMAT_R16G16_SSCALED , plain, 1, 1, ss16, ss16, , , xy01, rgb +VK_FORMAT_R16G16_UINT , plain, 1, 1, up16, up16, , , xy01, rgb +VK_FORMAT_R16G16_SINT , plain, 1, 1, sp16, sp16, , , xy01, rgb +VK_FORMAT_R16G16_SFLOAT , plain, 1, 1, f16 , f16 , , , xy01, rgb +VK_FORMAT_R16G16B16_UNORM , plain, 1, 1, un16, un16, un16, , xyz1, rgb +VK_FORMAT_R16G16B16_SNORM , plain, 1, 1, sn16, sn16, sn16, , xyz1, rgb +VK_FORMAT_R16G16B16_USCALED , plain, 1, 1, us16, us16, us16, , xyz1, rgb +VK_FORMAT_R16G16B16_SSCALED , plain, 1, 1, ss16, ss16, ss16, , xyz1, rgb +VK_FORMAT_R16G16B16_UINT , plain, 1, 1, up16, up16, up16, , xyz1, rgb +VK_FORMAT_R16G16B16_SINT , plain, 1, 1, sp16, sp16, sp16, , xyz1, rgb +VK_FORMAT_R16G16B16_SFLOAT , plain, 1, 1, f16 , f16 , f16 , , xyz1, rgb +VK_FORMAT_R16G16B16A16_UNORM , plain, 1, 1, un16, un16, un16, un16, xyzw, rgb +VK_FORMAT_R16G16B16A16_SNORM , plain, 1, 1, sn16, sn16, sn16, sn16, xyzw, rgb +VK_FORMAT_R16G16B16A16_USCALED , plain, 1, 1, us16, us16, us16, us16, xyzw, rgb +VK_FORMAT_R16G16B16A16_SSCALED , plain, 1, 1, ss16, ss16, ss16, ss16, xyzw, rgb +VK_FORMAT_R16G16B16A16_UINT , plain, 1, 1, up16, up16, up16, up16, xyzw, rgb +VK_FORMAT_R16G16B16A16_SINT , plain, 1, 1, sp16, sp16, sp16, sp16, xyzw, rgb +VK_FORMAT_R16G16B16A16_SFLOAT , plain, 1, 1, f16 , f16 , f16 , f16 , xyzw, rgb +VK_FORMAT_R32_UINT , plain, 1, 1, up32, , , , x001, rgb +VK_FORMAT_R32_SINT , plain, 1, 1, sp32, , , , x001, rgb +VK_FORMAT_R32_SFLOAT , plain, 1, 1, f32 , , , , x001, rgb +VK_FORMAT_R32G32_UINT , plain, 1, 1, up32, up32, , , xy01, rgb +VK_FORMAT_R32G32_SINT , plain, 1, 1, sp32, sp32, , , xy01, rgb +VK_FORMAT_R32G32_SFLOAT , plain, 1, 1, f32 , f32 , , , xy01, rgb +VK_FORMAT_R32G32B32_UINT , plain, 1, 1, up32, up32, up32, , xyz1, rgb +VK_FORMAT_R32G32B32_SINT , plain, 1, 1, sp32, sp32, sp32, , xyz1, rgb +VK_FORMAT_R32G32B32_SFLOAT , plain, 1, 1, f32 , f32 , f32 , , xyz1, rgb +VK_FORMAT_R32G32B32A32_UINT , plain, 1, 1, up32, up32, up32, up32, xyzw, rgb +VK_FORMAT_R32G32B32A32_SINT , plain, 1, 1, sp32, sp32, sp32, sp32, xyzw, rgb +VK_FORMAT_R32G32B32A32_SFLOAT , plain, 1, 1, f32 , f32 , f32 , f32 , xyzw, rgb +VK_FORMAT_R64_UINT , plain, 1, 1, up64, , , , x001, rgb +VK_FORMAT_R64_SINT , plain, 1, 1, sp64, , , , x001, rgb +VK_FORMAT_R64_SFLOAT , plain, 1, 1, f64 , , , , x001, rgb +VK_FORMAT_R64G64_UINT , plain, 1, 1, up64, up64, , , xy01, rgb +VK_FORMAT_R64G64_SINT , plain, 1, 1, sp64, sp64, , , xy01, rgb +VK_FORMAT_R64G64_SFLOAT , plain, 1, 1, f64 , f64 , , , xy01, rgb +VK_FORMAT_R64G64B64_UINT , plain, 1, 1, up64, up64, up64, , xyz1, rgb +VK_FORMAT_R64G64B64_SINT , plain, 1, 1, sp64, sp64, sp64, , xyz1, rgb +VK_FORMAT_R64G64B64_SFLOAT , plain, 1, 1, f64 , f64 , f64 , , xyz1, rgb +VK_FORMAT_R64G64B64A64_UINT , plain, 1, 1, up64, up64, up64, up64, xyzw, rgb +VK_FORMAT_R64G64B64A64_SINT , plain, 1, 1, sp64, sp64, sp64, sp64, xyzw, rgb +VK_FORMAT_R64G64B64A64_SFLOAT , plain, 1, 1, f64 , f64 , f64 , f64 , xyzw, rgb +VK_FORMAT_B10G11R11_UFLOAT_PACK32 , other, 1, 1, x32 , , , , xyz1, rgb +VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 , other, 1, 1, x32 , , , , xyz1, rgb +VK_FORMAT_D16_UNORM , plain, 1, 1, un16, , , , x___, zs +VK_FORMAT_X8_D24_UNORM_PACK32 , plain, 1, 1, un24, x8 , , , x___, zs +VK_FORMAT_D32_SFLOAT , plain, 1, 1, f32 , , , , x___, zs +VK_FORMAT_S8_UINT , plain, 1, 1, up8 , , , , _x__, zs +VK_FORMAT_D16_UNORM_S8_UINT , plain, 1, 1, un16, up8 , , , xy__, zs +VK_FORMAT_D24_UNORM_S8_UINT , plain, 1, 1, un24, up8 , , , xy__, zs +VK_FORMAT_D32_SFLOAT_S8_UINT , plain, 1, 1, f32 , up8 , , , xy__, zs +VK_FORMAT_BC1_RGB_UNORM_BLOCK , s3tc, 4, 4, x64 , , , , xyz1, rgb +VK_FORMAT_BC1_RGB_SRGB_BLOCK , s3tc, 4, 4, x64 , , , , xyz1, srgb +VK_FORMAT_BC1_RGBA_UNORM_BLOCK , s3tc, 4, 4, x64 , , , , xyzw, rgb +VK_FORMAT_BC1_RGBA_SRGB_BLOCK , s3tc, 4, 4, x64 , , , , xyzw, srgb +VK_FORMAT_BC2_UNORM_BLOCK , s3tc, 4, 4, x128, , , , xyzw, rgb +VK_FORMAT_BC2_SRGB_BLOCK , s3tc, 4, 4, x128, , , , xyzw, srgb +VK_FORMAT_BC3_UNORM_BLOCK , s3tc, 4, 4, x128, , , , xyzw, rgb +VK_FORMAT_BC3_SRGB_BLOCK , s3tc, 4, 4, x128, , , , xyzw, srgb +VK_FORMAT_BC4_UNORM_BLOCK , rgtc, 4, 4, x64, , , , x001, rgb +VK_FORMAT_BC4_SNORM_BLOCK , rgtc, 4, 4, x64, , , , x001, rgb +VK_FORMAT_BC5_UNORM_BLOCK , rgtc, 4, 4, x128, , , , xy01, rgb +VK_FORMAT_BC5_SNORM_BLOCK , rgtc, 4, 4, x128, , , , xy01, rgb +VK_FORMAT_BC6H_UFLOAT_BLOCK , bptc, 4, 4, x128, , , , xyz1, rgb +VK_FORMAT_BC6H_SFLOAT_BLOCK , bptc, 4, 4, x128, , , , xyz1, rgb +VK_FORMAT_BC7_UNORM_BLOCK , bptc, 4, 4, x128, , , , xyzw, rgb +VK_FORMAT_BC7_SRGB_BLOCK , bptc, 4, 4, x128, , , , xyzw, srgb +VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK , etc, 4, 4, x64, , , , xyz1, rgb +VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK , etc, 4, 4, x64, , , , xyz1, srgb +VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK , etc, 4, 4, x64, , , , xyzw, rgb +VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK , etc, 4, 4, x64, , , , xyzw, srgb +VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK , etc, 4, 4, x128, , , , xyzw, rgb +VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK , etc, 4, 4, x128, , , , xyzw, srgb +VK_FORMAT_EAC_R11_UNORM_BLOCK , etc, 4, 4, x64, , , , x001, rgb +VK_FORMAT_EAC_R11_SNORM_BLOCK , etc, 4, 4, x64, , , , x001, rgb +VK_FORMAT_EAC_R11G11_UNORM_BLOCK , etc, 4, 4, x128, , , , xy01, rgb +VK_FORMAT_EAC_R11G11_SNORM_BLOCK , etc, 4, 4, x128, , , , xy01, rgb +VK_FORMAT_ASTC_4x4_UNORM_BLOCK, +VK_FORMAT_ASTC_4x4_SRGB_BLOCK, +VK_FORMAT_ASTC_5x4_UNORM_BLOCK, +VK_FORMAT_ASTC_5x4_SRGB_BLOCK, +VK_FORMAT_ASTC_5x5_UNORM_BLOCK, +VK_FORMAT_ASTC_5x5_SRGB_BLOCK, +VK_FORMAT_ASTC_6x5_UNORM_BLOCK, +VK_FORMAT_ASTC_6x5_SRGB_BLOCK, +VK_FORMAT_ASTC_6x6_UNORM_BLOCK, +VK_FORMAT_ASTC_6x6_SRGB_BLOCK, +VK_FORMAT_ASTC_8x5_UNORM_BLOCK, +VK_FORMAT_ASTC_8x5_SRGB_BLOCK, +VK_FORMAT_ASTC_8x6_UNORM_BLOCK, +VK_FORMAT_ASTC_8x6_SRGB_BLOCK, +VK_FORMAT_ASTC_8x8_UNORM_BLOCK, +VK_FORMAT_ASTC_8x8_SRGB_BLOCK, +VK_FORMAT_ASTC_10x5_UNORM_BLOCK, +VK_FORMAT_ASTC_10x5_SRGB_BLOCK, +VK_FORMAT_ASTC_10x6_UNORM_BLOCK, +VK_FORMAT_ASTC_10x6_SRGB_BLOCK, +VK_FORMAT_ASTC_10x8_UNORM_BLOCK, +VK_FORMAT_ASTC_10x8_SRGB_BLOCK, +VK_FORMAT_ASTC_10x10_UNORM_BLOCK, +VK_FORMAT_ASTC_10x10_SRGB_BLOCK, +VK_FORMAT_ASTC_12x10_UNORM_BLOCK, +VK_FORMAT_ASTC_12x10_SRGB_BLOCK, +VK_FORMAT_ASTC_12x12_UNORM_BLOCK, +VK_FORMAT_ASTC_12x12_SRGB_BLOCK, diff --git a/src/freedreno/vulkan/vk_format_parse.py b/src/freedreno/vulkan/vk_format_parse.py new file mode 100644 index 00000000000..8f3823c806f --- /dev/null +++ b/src/freedreno/vulkan/vk_format_parse.py @@ -0,0 +1,388 @@ + +''' +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ +''' + + +VOID, UNSIGNED, SIGNED, FIXED, FLOAT = range(5) + +SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_0, SWIZZLE_1, SWIZZLE_NONE, = range(7) + +PLAIN = 'plain' +SCALED = 'scaled' + +RGB = 'rgb' +SRGB = 'srgb' +YUV = 'yuv' +ZS = 'zs' + + +def is_pot(x): + return (x & (x - 1)) == 0 + + +VERY_LARGE = 99999999999999999999999 + + +class Channel: + '''Describe the channel of a color channel.''' + + def __init__(self, type, norm, pure, scaled, size, name = ''): + self.type = type + self.norm = norm + self.pure = pure + self.size = size + self.scaled = scaled + self.sign = type in (SIGNED, FIXED, FLOAT) + self.name = name + + def __str__(self): + s = str(self.type) + if self.norm: + s += 'n' + if self.pure: + s += 'p' + if self.scaled: + s += 's' + s += str(self.size) + return s + + def __eq__(self, other): + return (other is not None and + self.type == other.type and + self.norm == other.norm and + self.pure == other.pure and + self.size == other.size and + self.scaled == other.scaled) + + def max(self): + '''Maximum representable number.''' + if self.type == FLOAT: + return VERY_LARGE + if self.type == FIXED: + return (1 << (self.size/2)) - 1 + if self.norm: + return 1 + if self.type == UNSIGNED: + return (1 << self.size) - 1 + if self.type == SIGNED: + return (1 << (self.size - 1)) - 1 + assert False + + def min(self): + '''Minimum representable number.''' + if self.type == FLOAT: + return -VERY_LARGE + if self.type == FIXED: + return -(1 << (self.size/2)) + if self.type == UNSIGNED: + return 0 + if self.norm: + return -1 + if self.type == SIGNED: + return -(1 << (self.size - 1)) + assert False + + +class Format: + '''Describe a pixel format.''' + + def __init__(self, name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace): + self.name = name + self.layout = layout + self.block_width = block_width + self.block_height = block_height + self.le_channels = le_channels + self.le_swizzles = le_swizzles + self.be_channels = be_channels + self.be_swizzles = be_swizzles + self.name = name + self.colorspace = colorspace + + def __str__(self): + return self.name + + def short_name(self): + '''Make up a short norm for a format, suitable to be used as suffix in + function names.''' + + name = self.name + if name.startswith('VK_FORMAT_'): + name = name[len('VK_FORMAT_'):] + name = name.lower() + return name + + def block_size(self): + size = 0 + for channel in self.le_channels: + size += channel.size + return size + + def nr_channels(self): + nr_channels = 0 + for channel in self.le_channels: + if channel.size: + nr_channels += 1 + return nr_channels + + def array_element(self): + if self.layout != PLAIN: + return None + ref_channel = self.le_channels[0] + if ref_channel.type == VOID: + ref_channel = self.le_channels[1] + for channel in self.le_channels: + if channel.size and (channel.size != ref_channel.size or channel.size % 8): + return None + if channel.type != VOID: + if channel.type != ref_channel.type: + return None + if channel.norm != ref_channel.norm: + return None + if channel.pure != ref_channel.pure: + return None + if channel.scaled != ref_channel.scaled: + return None + return ref_channel + + def is_array(self): + return self.array_element() != None + + def is_mixed(self): + if self.layout != PLAIN: + return False + ref_channel = self.le_channels[0] + if ref_channel.type == VOID: + ref_channel = self.le_channels[1] + for channel in self.le_channels[1:]: + if channel.type != VOID: + if channel.type != ref_channel.type: + return True + if channel.norm != ref_channel.norm: + return True + if channel.pure != ref_channel.pure: + return True + if channel.scaled != ref_channel.scaled: + return True + return False + + def is_pot(self): + return is_pot(self.block_size()) + + def is_int(self): + if self.layout != PLAIN: + return False + for channel in self.le_channels: + if channel.type not in (VOID, UNSIGNED, SIGNED): + return False + return True + + def is_float(self): + if self.layout != PLAIN: + return False + for channel in self.le_channels: + if channel.type not in (VOID, FLOAT): + return False + return True + + def is_bitmask(self): + if self.layout != PLAIN: + return False + if self.block_size() not in (8, 16, 32): + return False + for channel in self.le_channels: + if channel.type not in (VOID, UNSIGNED, SIGNED): + return False + return True + + def is_pure_color(self): + if self.layout != PLAIN or self.colorspace == ZS: + return False + pures = [channel.pure + for channel in self.le_channels + if channel.type != VOID] + for x in pures: + assert x == pures[0] + return pures[0] + + def channel_type(self): + types = [channel.type + for channel in self.le_channels + if channel.type != VOID] + for x in types: + assert x == types[0] + return types[0] + + def is_pure_signed(self): + return self.is_pure_color() and self.channel_type() == SIGNED + + def is_pure_unsigned(self): + return self.is_pure_color() and self.channel_type() == UNSIGNED + + def has_channel(self, id): + return self.le_swizzles[id] != SWIZZLE_NONE + + def has_depth(self): + return self.colorspace == ZS and self.has_channel(0) + + def has_stencil(self): + return self.colorspace == ZS and self.has_channel(1) + + def stride(self): + return self.block_size()/8 + + +_type_parse_map = { + '': VOID, + 'x': VOID, + 'u': UNSIGNED, + 's': SIGNED, + 'h': FIXED, + 'f': FLOAT, +} + +_swizzle_parse_map = { + 'x': SWIZZLE_X, + 'y': SWIZZLE_Y, + 'z': SWIZZLE_Z, + 'w': SWIZZLE_W, + '0': SWIZZLE_0, + '1': SWIZZLE_1, + '_': SWIZZLE_NONE, +} + +def _parse_channels(fields, layout, colorspace, swizzles): + if layout == PLAIN: + names = ['']*4 + if colorspace in (RGB, SRGB): + for i in range(4): + swizzle = swizzles[i] + if swizzle < 4: + names[swizzle] += 'rgba'[i] + elif colorspace == ZS: + for i in range(4): + swizzle = swizzles[i] + if swizzle < 4: + names[swizzle] += 'zs'[i] + else: + assert False + for i in range(4): + if names[i] == '': + names[i] = 'x' + else: + names = ['x', 'y', 'z', 'w'] + + channels = [] + for i in range(0, 4): + field = fields[i] + if field: + type = _type_parse_map[field[0]] + if field[1] == 'n': + norm = True + pure = False + scaled = False + size = int(field[2:]) + elif field[1] == 'p': + pure = True + norm = False + scaled = False + size = int(field[2:]) + elif field[1] == 's': + pure = False + norm = False + scaled = True + size = int(field[2:]) + else: + norm = False + pure = False + scaled = False + size = int(field[1:]) + else: + type = VOID + norm = False + pure = False + scaled = False + size = 0 + channel = Channel(type, norm, pure, scaled, size, names[i]) + channels.append(channel) + + return channels + +def parse(filename): + '''Parse the format description in CSV format in terms of the + Channel and Format classes above.''' + + stream = open(filename) + formats = [] + for line in stream: + try: + comment = line.index('#') + except ValueError: + pass + else: + line = line[:comment] + line = line.strip() + if not line: + continue + + fields = [field.strip() for field in line.split(',')] + if len (fields) < 10: + continue + if len (fields) == 10: + fields += fields[4:9] + assert len (fields) == 15 + + name = fields[0] + layout = fields[1] + block_width, block_height = map(int, fields[2:4]) + colorspace = fields[9] + + le_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]] + le_channels = _parse_channels(fields[4:8], layout, colorspace, le_swizzles) + + be_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[14]] + be_channels = _parse_channels(fields[10:14], layout, colorspace, be_swizzles) + + le_shift = 0 + for channel in le_channels: + channel.shift = le_shift + le_shift += channel.size + + be_shift = 0 + for channel in be_channels[3::-1]: + channel.shift = be_shift + be_shift += channel.size + + assert le_shift == be_shift + for i in range(4): + assert (le_swizzles[i] != SWIZZLE_NONE) == (be_swizzles[i] != SWIZZLE_NONE) + + format = Format(name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace) + formats.append(format) + return formats + diff --git a/src/freedreno/vulkan/vk_format_table.py b/src/freedreno/vulkan/vk_format_table.py new file mode 100644 index 00000000000..604aac8fa75 --- /dev/null +++ b/src/freedreno/vulkan/vk_format_table.py @@ -0,0 +1,173 @@ +from __future__ import print_function + +CopyRight = ''' +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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 sys + +from vk_format_parse import * + +def layout_map(layout): + return 'VK_FORMAT_LAYOUT_' + str(layout).upper() + + +def colorspace_map(colorspace): + return 'VK_FORMAT_COLORSPACE_' + str(colorspace).upper() + + +colorspace_channels_map = { + 'rgb': ['r', 'g', 'b', 'a'], + 'srgb': ['sr', 'sg', 'sb', 'a'], + 'zs': ['z', 's'], + 'yuv': ['y', 'u', 'v'], +} + + +type_map = { + VOID: "VK_FORMAT_TYPE_VOID", + UNSIGNED: "VK_FORMAT_TYPE_UNSIGNED", + SIGNED: "VK_FORMAT_TYPE_SIGNED", + FIXED: "VK_FORMAT_TYPE_FIXED", + FLOAT: "VK_FORMAT_TYPE_FLOAT", +} + + +def bool_map(value): + if value: + return "true" + else: + return "false" + + +swizzle_map = { + SWIZZLE_X: "VK_SWIZZLE_X", + SWIZZLE_Y: "VK_SWIZZLE_Y", + SWIZZLE_Z: "VK_SWIZZLE_Z", + SWIZZLE_W: "VK_SWIZZLE_W", + SWIZZLE_0: "VK_SWIZZLE_0", + SWIZZLE_1: "VK_SWIZZLE_1", + SWIZZLE_NONE: "VK_SWIZZLE_NONE", +} + +def print_channels(format, func): + if format.nr_channels() <= 1: + func(format.le_channels, format.le_swizzles) + else: + print('#ifdef PIPE_ARCH_BIG_ENDIAN') + func(format.be_channels, format.be_swizzles) + print('#else') + func(format.le_channels, format.le_swizzles) + print('#endif') + +def write_format_table(formats): + print('/* This file is autogenerated by vk_format_table.py from vk_format_layout.csv. Do not edit directly. */') + print() + # This will print the copyright message on the top of this file + print(CopyRight.strip()) + print() + print('#include "stdbool.h"') + print('#include "vk_format.h"') + print() + + def do_channel_array(channels, swizzles): + print(" {") + for i in range(4): + channel = channels[i] + if i < 3: + sep = "," + else: + sep = "" + if channel.size: + print(" {%s, %s, %s, %s, %u, %u}%s\t/* %s = %s */" % (type_map[channel.type], bool_map(channel.norm), bool_map(channel.pure), bool_map(channel.scaled), channel.size, channel.shift, sep, "xyzw"[i], channel.name)) + else: + print(" {0, 0, 0, 0, 0}%s" % (sep,)) + print(" },") + + def do_swizzle_array(channels, swizzles): + print(" {") + for i in range(4): + swizzle = swizzles[i] + if i < 3: + sep = "," + else: + sep = "" + try: + comment = colorspace_channels_map[format.colorspace][i] + except (KeyError, IndexError): + comment = 'ignored' + print(" %s%s\t/* %s */" % (swizzle_map[swizzle], sep, comment)) + print(" },") + + for format in formats: + print('static const struct vk_format_description') + print('vk_format_%s_description = {' % (format.short_name(),)) + print(" %s," % (format.name,)) + print(" \"%s\"," % (format.name,)) + print(" \"%s\"," % (format.short_name(),)) + print(" {%u, %u, %u},\t/* block */" % (format.block_width, format.block_height, format.block_size())) + print(" %s," % (layout_map(format.layout),)) + print(" %u,\t/* nr_channels */" % (format.nr_channels(),)) + print(" %s,\t/* is_array */" % (bool_map(format.is_array()),)) + print(" %s,\t/* is_bitmask */" % (bool_map(format.is_bitmask()),)) + print(" %s,\t/* is_mixed */" % (bool_map(format.is_mixed()),)) + print_channels(format, do_channel_array) + print_channels(format, do_swizzle_array) + print(" %s," % (colorspace_map(format.colorspace),)) + print("};") + print() + + print("const struct vk_format_description *") + print("vk_format_description(VkFormat format)") + print("{") + print(" if (format > VK_FORMAT_END_RANGE) {") + print(" return NULL;") + print(" }") + print() + print(" switch (format) {") + for format in formats: + print(" case %s:" % format.name) + print(" return &vk_format_%s_description;" % (format.short_name(),)) + print(" default:") + print(" return NULL;") + print(" }") + print("}") + print() + + +def main(): + + formats = [] + for arg in sys.argv[1:]: + formats.extend(parse(arg)) + write_format_table(formats) + + +if __name__ == '__main__': + main() diff --git a/src/meson.build b/src/meson.build index 7f537b7094f..6d04b5fc3b2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -64,7 +64,7 @@ endif if with_gallium_vc4 or with_gallium_v3d subdir('broadcom') endif -if with_gallium_freedreno +if with_gallium_freedreno or with_freedreno_vk subdir('freedreno') endif if with_dri_i965 or with_intel_vk or with_gallium_iris |