tu: Implement multiview pipeline state
[mesa.git] / src / freedreno / vulkan / tu_device.c
index 235aa44dbd70da4071d22d03993fa13fa835f282..9a6085f96d36d42a184c5191f866b6485c03472e 100644 (file)
  * 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.
+ * 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 <libsync.h>
 #include <stdbool.h>
 #include <string.h>
 #include <sys/sysinfo.h>
 #include <unistd.h>
-#include <xf86drm.h>
+
+#include "compiler/glsl_types.h"
+#include "util/debug.h"
+#include "util/disk_cache.h"
+#include "util/u_atomic.h"
+#include "vk_format.h"
+#include "vk_util.h"
+
+/* for fd_get_driver/device_uuid() */
+#include "freedreno/common/freedreno_uuid.h"
 
 static int
 tu_device_get_cache_uuid(uint16_t family, void *uuid)
@@ -49,136 +55,56 @@ tu_device_get_cache_uuid(uint16_t family, void *uuid)
       return -1;
 
    memcpy(uuid, &mesa_timestamp, 4);
-   memcpy((char *)uuid + 4, &f, 2);
-   snprintf((char *)uuid + 6, VK_UUID_SIZE - 10, "tu");
+   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
+VkResult
 tu_physical_device_init(struct tu_physical_device *device,
-                         struct tu_instance *instance,
-                         drmDevicePtr drm_device)
+                        struct tu_instance *instance)
 {
-   const char *path = drm_device->nodes[DRM_NODE_RENDER];
-   VkResult result;
-   drmVersionPtr version;
-   int fd;
-   int master_fd = -1;
-   struct fd_pipe *tmp_pipe = NULL;
-   uint64_t val;
-
-   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, "msm")) {
-      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 msm 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? */
-      }
-   }
-
-   device->master_fd = master_fd;
-   device->local_fd = fd;
-
-   device->drm_device = fd_device_new_dup(fd);
-   if (!device->drm_device) {
-      result = vk_errorf(
-        instance, VK_ERROR_INITIALIZATION_FAILED, "could not create the libdrm device");
-       goto fail;
-   }
-
-   tmp_pipe = fd_pipe_new(device->drm_device, FD_PIPE_3D);
-   if (!tmp_pipe) {
-      result = vk_errorf(
-        instance, VK_ERROR_INITIALIZATION_FAILED, "could not open the 3D pipe");
-      goto fail;
-   }
-
-   if (fd_pipe_get_param(tmp_pipe, FD_GPU_ID, &val)) {
-      result = vk_errorf(
-        instance, VK_ERROR_INITIALIZATION_FAILED, "could not get GPU ID");
-      goto fail;
-   }
-   device->gpu_id = val;
-
-   if (fd_pipe_get_param(tmp_pipe, FD_GMEM_SIZE, &val)) {
-      result = vk_errorf(
-        instance, VK_ERROR_INITIALIZATION_FAILED, "could not get GMEM size");
-      goto fail;
-   }
-   device->gmem_size = val;
-
-   fd_pipe_del(tmp_pipe);
-   tmp_pipe = NULL;
+   VkResult result = VK_SUCCESS;
 
    memset(device->name, 0, sizeof(device->name));
    sprintf(device->name, "FD%d", device->gpu_id);
 
-   switch(device->gpu_id) {
-   case 530:
+   device->limited_z24s8 = (device->gpu_id == 630);
+
+   switch (device->gpu_id) {
+   case 618:
+      device->ccu_offset_gmem = 0x7c000; /* 0x7e000 in some cases? */
+      device->ccu_offset_bypass = 0x10000;
+      device->tile_align_w = 32;
+      device->magic.PC_UNKNOWN_9805 = 0x0;
+      device->magic.SP_UNKNOWN_A0F8 = 0x0;
+      device->supports_multiview_mask = false; /* TODO */
+      break;
+   case 630:
+   case 640:
+      device->ccu_offset_gmem = 0xf8000;
+      device->ccu_offset_bypass = 0x20000;
+      device->tile_align_w = 32;
+      device->magic.PC_UNKNOWN_9805 = 0x1;
+      device->magic.SP_UNKNOWN_A0F8 = 0x1;
+      device->supports_multiview_mask = device->gpu_id != 630;
+      break;
+   case 650:
+      device->ccu_offset_gmem = 0x114000;
+      device->ccu_offset_bypass = 0x30000;
+      device->tile_align_w = 96;
+      device->magic.PC_UNKNOWN_9805 = 0x2;
+      device->magic.SP_UNKNOWN_A0F8 = 0x2;
+      device->supports_multiview_mask = true;
       break;
    default:
-      if (instance->debug_flags & TU_DEBUG_STARTUP)
-         tu_logi("Device '%s' is not supported.", device->name);
-      result = vk_errorf(
-        instance, VK_ERROR_INITIALIZATION_FAILED, "unsupported device");
+      result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
+                         "device %s is unsupported", device->name);
       goto fail;
    }
    if (tu_device_get_cache_uuid(device->gpu_id, device->cache_uuid)) {
-      result = vk_errorf(
-        instance, VK_ERROR_INITIALIZATION_FAILED, "cannot generate UUID");
+      result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
+                         "cannot generate UUID");
       goto fail;
    }
 
@@ -189,43 +115,48 @@ tu_physical_device_init(struct tu_physical_device *device,
    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");
+   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);
+   fd_get_driver_uuid(device->driver_uuid);
+   fd_get_device_uuid(device->device_uuid, device->gpu_id);
 
-   tu_fill_device_extension_table(device, &device->supported_extensions);
+   tu_physical_device_get_supported_extensions(device, &device->supported_extensions);
 
    if (result != VK_SUCCESS) {
       vk_error(instance, result);
       goto fail;
    }
 
+   result = tu_wsi_init(device);
+   if (result != VK_SUCCESS) {
+      vk_error(instance, result);
+      goto fail;
+   }
+
    return VK_SUCCESS;
 
 fail:
-   if (tmp_pipe)
-      fd_pipe_del(tmp_pipe);
-   if (device->drm_device)
-      fd_device_del(device->drm_device);
-   close(fd);
-   if (master_fd != -1)
-      close(master_fd);
+   close(device->local_fd);
+   if (device->master_fd != -1)
+      close(device->master_fd);
    return result;
 }
 
 static void
 tu_physical_device_finish(struct tu_physical_device *device)
 {
+   tu_wsi_finish(device);
+
    disk_cache_destroy(device->disk_cache);
    close(device->local_fd);
    if (device->master_fd != -1)
       close(device->master_fd);
+
+   vk_object_base_finish(&device->base);
 }
 
-static void *
+static VKAPI_ATTR void *
 default_alloc_func(void *pUserData,
                    size_t size,
                    size_t align,
@@ -234,7 +165,7 @@ default_alloc_func(void *pUserData,
    return malloc(size);
 }
 
-static void *
+static VKAPI_ATTR void *
 default_realloc_func(void *pUserData,
                      void *pOriginal,
                      size_t size,
@@ -244,7 +175,7 @@ default_realloc_func(void *pUserData,
    return realloc(pOriginal, size);
 }
 
-static void
+static VKAPI_ATTR void
 default_free_func(void *pUserData, void *pMemory)
 {
    free(pMemory);
@@ -257,9 +188,16 @@ static const VkAllocationCallbacks default_alloc = {
    .pfnFree = default_free_func,
 };
 
-static const struct debug_control tu_debug_options[] = { { "startup",
-                                                            TU_DEBUG_STARTUP },
-                                                          { NULL, 0 } };
+static const struct debug_control tu_debug_options[] = {
+   { "startup", TU_DEBUG_STARTUP },
+   { "nir", TU_DEBUG_NIR },
+   { "ir3", TU_DEBUG_IR3 },
+   { "nobin", TU_DEBUG_NOBIN },
+   { "sysmem", TU_DEBUG_SYSMEM },
+   { "forcebin", TU_DEBUG_FORCEBIN },
+   { "noubwc", TU_DEBUG_NOUBWC },
+   { NULL, 0 }
+};
 
 const char *
 tu_get_debug_option_name(int id)
@@ -280,8 +218,8 @@ tu_get_instance_extension_index(const char *name)
 
 VkResult
 tu_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
-                   const VkAllocationCallbacks *pAllocator,
-                   VkInstance *pInstance)
+                  const VkAllocationCallbacks *pAllocator,
+                  VkInstance *pInstance)
 {
    struct tu_instance *instance;
    VkResult result;
@@ -296,15 +234,13 @@ tu_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
       tu_EnumerateInstanceVersion(&client_version);
    }
 
-   instance = vk_zalloc2(&default_alloc,
-                         pAllocator,
-                         sizeof(*instance),
-                         8,
+   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;
+   vk_object_base_init(NULL, &instance->base, VK_OBJECT_TYPE_INSTANCE);
 
    if (pAllocator)
       instance->alloc = *pAllocator;
@@ -315,7 +251,7 @@ tu_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
    instance->physical_device_count = -1;
 
    instance->debug_flags =
-     parse_debug_string(getenv("TU_DEBUG"), tu_debug_options);
+      parse_debug_string(getenv("TU_DEBUG"), tu_debug_options);
 
    if (instance->debug_flags & TU_DEBUG_STARTUP)
       tu_logi("Created an instance");
@@ -324,7 +260,8 @@ tu_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
       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]) {
+      if (index < 0 || !tu_instance_extensions_supported.extensions[index]) {
+         vk_object_base_finish(&instance->base);
          vk_free2(&default_alloc, pAllocator, instance);
          return vk_error(instance, VK_ERROR_EXTENSION_NOT_PRESENT);
       }
@@ -334,11 +271,12 @@ tu_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
 
    result = vk_debug_report_instance_init(&instance->debug_report_callbacks);
    if (result != VK_SUCCESS) {
+      vk_object_base_finish(&instance->base);
       vk_free2(&default_alloc, pAllocator, instance);
       return vk_error(instance, result);
    }
 
-   _mesa_locale_init();
+   glsl_type_singleton_init_or_ref();
 
    VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
 
@@ -349,7 +287,7 @@ tu_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
 
 void
 tu_DestroyInstance(VkInstance _instance,
-                    const VkAllocationCallbacks *pAllocator)
+                   const VkAllocationCallbacks *pAllocator)
 {
    TU_FROM_HANDLE(tu_instance, instance, _instance);
 
@@ -362,56 +300,22 @@ tu_DestroyInstance(VkInstance _instance,
 
    VG(VALGRIND_DESTROY_MEMPOOL(instance));
 
-   _mesa_locale_fini();
+   glsl_type_singleton_decref();
 
    vk_debug_report_instance_destroy(&instance->debug_report_callbacks);
 
+   vk_object_base_finish(&instance->base);
    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_PLATFORM) {
-
-         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)
+                            uint32_t *pPhysicalDeviceCount,
+                            VkPhysicalDevice *pPhysicalDevices)
 {
    TU_FROM_HANDLE(tu_instance, instance, _instance);
+   VK_OUTARRAY_MAKE(out, pPhysicalDevices, pPhysicalDeviceCount);
+
    VkResult result;
 
    if (instance->physical_device_count < 0) {
@@ -420,28 +324,25 @@ tu_EnumeratePhysicalDevices(VkInstance _instance,
          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);
+   for (uint32_t i = 0; i < instance->physical_device_count; ++i) {
+      vk_outarray_append(&out, p)
+      {
+         *p = tu_physical_device_to_handle(instance->physical_devices + i);
+      }
    }
 
-   return *pPhysicalDeviceCount < instance->physical_device_count
-            ? VK_INCOMPLETE
-            : VK_SUCCESS;
+   return vk_outarray_status(&out);
 }
 
 VkResult
 tu_EnumeratePhysicalDeviceGroups(
-  VkInstance _instance,
-  uint32_t *pPhysicalDeviceGroupCount,
-  VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties)
+   VkInstance _instance,
+   uint32_t *pPhysicalDeviceGroupCount,
+   VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties)
 {
    TU_FROM_HANDLE(tu_instance, instance, _instance);
+   VK_OUTARRAY_MAKE(out, pPhysicalDeviceGroupProperties,
+                    pPhysicalDeviceGroupCount);
    VkResult result;
 
    if (instance->physical_device_count < 0) {
@@ -450,65 +351,61 @@ tu_EnumeratePhysicalDeviceGroups(
          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;
+   for (uint32_t i = 0; i < instance->physical_device_count; ++i) {
+      vk_outarray_append(&out, p)
+      {
+         p->physicalDeviceCount = 1;
+         p->physicalDevices[0] =
+            tu_physical_device_to_handle(instance->physical_devices + i);
+         p->subsetAllocation = false;
       }
    }
-   return *pPhysicalDeviceGroupCount < instance->physical_device_count
-            ? VK_INCOMPLETE
-            : VK_SUCCESS;
+
+   return vk_outarray_status(&out);
 }
 
 void
 tu_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
-                              VkPhysicalDeviceFeatures *pFeatures)
+                             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,
+   *pFeatures = (VkPhysicalDeviceFeatures) {
+      .robustBufferAccess = true,
+      .fullDrawIndexUint32 = true,
+      .imageCubeArray = true,
+      .independentBlend = true,
+      .geometryShader = true,
+      .tessellationShader = true,
+      .sampleRateShading = true,
+      .dualSrcBlend = true,
+      .logicOp = true,
+      .multiDrawIndirect = true,
+      .drawIndirectFirstInstance = true,
+      .depthClamp = true,
+      .depthBiasClamp = true,
+      .fillModeNonSolid = true,
+      .depthBounds = true,
       .wideLines = false,
-      .largePoints = false,
-      .alphaToOne = false,
+      .largePoints = true,
+      .alphaToOne = true,
       .multiViewport = false,
-      .samplerAnisotropy = false,
-      .textureCompressionETC2 = false,
-      .textureCompressionASTC_LDR = false,
-      .textureCompressionBC = false,
-      .occlusionQueryPrecise = false,
+      .samplerAnisotropy = true,
+      .textureCompressionETC2 = true,
+      .textureCompressionASTC_LDR = true,
+      .textureCompressionBC = true,
+      .occlusionQueryPrecise = true,
       .pipelineStatisticsQuery = false,
-      .vertexPipelineStoresAndAtomics = false,
-      .fragmentStoresAndAtomics = false,
+      .vertexPipelineStoresAndAtomics = true,
+      .fragmentStoresAndAtomics = true,
       .shaderTessellationAndGeometryPointSize = false,
       .shaderImageGatherExtended = false,
       .shaderStorageImageExtendedFormats = false,
       .shaderStorageImageMultisample = false,
-      .shaderUniformBufferArrayDynamicIndexing = false,
-      .shaderSampledImageArrayDynamicIndexing = false,
-      .shaderStorageBufferArrayDynamicIndexing = false,
-      .shaderStorageImageArrayDynamicIndexing = false,
+      .shaderUniformBufferArrayDynamicIndexing = true,
+      .shaderSampledImageArrayDynamicIndexing = true,
+      .shaderStorageBufferArrayDynamicIndexing = true,
+      .shaderStorageImageArrayDynamicIndexing = true,
       .shaderStorageImageReadWithoutFormat = false,
       .shaderStorageImageWriteWithoutFormat = false,
       .shaderClipDistance = false,
@@ -524,86 +421,199 @@ tu_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
 
 void
 tu_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
-                               VkPhysicalDeviceFeatures2KHR *pFeatures)
+                              VkPhysicalDeviceFeatures2 *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;
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: {
+         VkPhysicalDeviceVulkan11Features *features = (void *) ext;
+         features->storageBuffer16BitAccess            = false;
+         features->uniformAndStorageBuffer16BitAccess  = false;
+         features->storagePushConstant16               = false;
+         features->storageInputOutput16                = false;
+         features->multiview                           = false;
+         features->multiviewGeometryShader             = false;
+         features->multiviewTessellationShader         = false;
+         features->variablePointersStorageBuffer       = true;
+         features->variablePointers                    = true;
+         features->protectedMemory                     = false;
+         features->samplerYcbcrConversion              = true;
+         features->shaderDrawParameters                = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: {
+         VkPhysicalDeviceVulkan12Features *features = (void *) ext;
+         features->samplerMirrorClampToEdge            = true;
+         features->drawIndirectCount                   = true;
+         features->storageBuffer8BitAccess             = false;
+         features->uniformAndStorageBuffer8BitAccess   = false;
+         features->storagePushConstant8                = false;
+         features->shaderBufferInt64Atomics            = false;
+         features->shaderSharedInt64Atomics            = false;
+         features->shaderFloat16                       = false;
+         features->shaderInt8                          = false;
+
+         features->descriptorIndexing                                 = false;
+         features->shaderInputAttachmentArrayDynamicIndexing          = false;
+         features->shaderUniformTexelBufferArrayDynamicIndexing       = false;
+         features->shaderStorageTexelBufferArrayDynamicIndexing       = false;
+         features->shaderUniformBufferArrayNonUniformIndexing         = false;
+         features->shaderSampledImageArrayNonUniformIndexing          = false;
+         features->shaderStorageBufferArrayNonUniformIndexing         = false;
+         features->shaderStorageImageArrayNonUniformIndexing          = false;
+         features->shaderInputAttachmentArrayNonUniformIndexing       = false;
+         features->shaderUniformTexelBufferArrayNonUniformIndexing    = false;
+         features->shaderStorageTexelBufferArrayNonUniformIndexing    = false;
+         features->descriptorBindingUniformBufferUpdateAfterBind      = false;
+         features->descriptorBindingSampledImageUpdateAfterBind       = false;
+         features->descriptorBindingStorageImageUpdateAfterBind       = false;
+         features->descriptorBindingStorageBufferUpdateAfterBind      = false;
+         features->descriptorBindingUniformTexelBufferUpdateAfterBind = false;
+         features->descriptorBindingStorageTexelBufferUpdateAfterBind = false;
+         features->descriptorBindingUpdateUnusedWhilePending          = false;
+         features->descriptorBindingPartiallyBound                    = false;
+         features->descriptorBindingVariableDescriptorCount           = false;
+         features->runtimeDescriptorArray                             = false;
+
+         features->samplerFilterMinmax                 = true;
+         features->scalarBlockLayout                   = false;
+         features->imagelessFramebuffer                = false;
+         features->uniformBufferStandardLayout         = false;
+         features->shaderSubgroupExtendedTypes         = false;
+         features->separateDepthStencilLayouts         = false;
+         features->hostQueryReset                      = false;
+         features->timelineSemaphore                   = false;
+         features->bufferDeviceAddress                 = false;
+         features->bufferDeviceAddressCaptureReplay    = false;
+         features->bufferDeviceAddressMultiDevice      = false;
+         features->vulkanMemoryModel                   = false;
+         features->vulkanMemoryModelDeviceScope        = false;
+         features->vulkanMemoryModelAvailabilityVisibilityChains = false;
+         features->shaderOutputViewportIndex           = false;
+         features->shaderOutputLayer                   = false;
+         features->subgroupBroadcastDynamicId          = false;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: {
+         VkPhysicalDeviceVariablePointersFeatures *features = (void *) ext;
+         features->variablePointersStorageBuffer = true;
+         features->variablePointers = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: {
+         VkPhysicalDeviceMultiviewFeatures *features =
+            (VkPhysicalDeviceMultiviewFeatures *) ext;
+         features->multiview = false;
+         features->multiviewGeometryShader = false;
+         features->multiviewTessellationShader = false;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: {
+         VkPhysicalDeviceShaderDrawParametersFeatures *features =
+            (VkPhysicalDeviceShaderDrawParametersFeatures *) 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 = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT: {
+         VkPhysicalDeviceDescriptorIndexingFeaturesEXT *features =
+            (VkPhysicalDeviceDescriptorIndexingFeaturesEXT *) ext;
+         features->shaderInputAttachmentArrayDynamicIndexing = false;
+         features->shaderUniformTexelBufferArrayDynamicIndexing = false;
+         features->shaderStorageTexelBufferArrayDynamicIndexing = false;
+         features->shaderUniformBufferArrayNonUniformIndexing = false;
+         features->shaderSampledImageArrayNonUniformIndexing = false;
+         features->shaderStorageBufferArrayNonUniformIndexing = false;
+         features->shaderStorageImageArrayNonUniformIndexing = false;
+         features->shaderInputAttachmentArrayNonUniformIndexing = false;
+         features->shaderUniformTexelBufferArrayNonUniformIndexing = false;
+         features->shaderStorageTexelBufferArrayNonUniformIndexing = false;
+         features->descriptorBindingUniformBufferUpdateAfterBind = false;
+         features->descriptorBindingSampledImageUpdateAfterBind = false;
+         features->descriptorBindingStorageImageUpdateAfterBind = false;
+         features->descriptorBindingStorageBufferUpdateAfterBind = false;
+         features->descriptorBindingUniformTexelBufferUpdateAfterBind = false;
+         features->descriptorBindingStorageTexelBufferUpdateAfterBind = false;
+         features->descriptorBindingUpdateUnusedWhilePending = false;
+         features->descriptorBindingPartiallyBound = false;
+         features->descriptorBindingVariableDescriptorCount = false;
+         features->runtimeDescriptorArray = false;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT: {
+         VkPhysicalDeviceConditionalRenderingFeaturesEXT *features =
+            (VkPhysicalDeviceConditionalRenderingFeaturesEXT *) ext;
+         features->conditionalRendering = true;
+         features->inheritedConditionalRendering = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT: {
+         VkPhysicalDeviceTransformFeedbackFeaturesEXT *features =
+            (VkPhysicalDeviceTransformFeedbackFeaturesEXT *) ext;
+         features->transformFeedback = true;
+         features->geometryStreams = false;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: {
+         VkPhysicalDeviceIndexTypeUint8FeaturesEXT *features =
+            (VkPhysicalDeviceIndexTypeUint8FeaturesEXT *)ext;
+         features->indexTypeUint8 = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: {
+         VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *features =
+            (VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *)ext;
+         features->vertexAttributeInstanceRateDivisor = true;
+         features->vertexAttributeInstanceRateZeroDivisor = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT: {
+         VkPhysicalDevicePrivateDataFeaturesEXT *features =
+            (VkPhysicalDevicePrivateDataFeaturesEXT *)ext;
+         features->privateData = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT: {
+         VkPhysicalDeviceDepthClipEnableFeaturesEXT *features =
+            (VkPhysicalDeviceDepthClipEnableFeaturesEXT *)ext;
+         features->depthClipEnable = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: {
+         VkPhysicalDevice4444FormatsFeaturesEXT *features = (void *)ext;
+         features->formatA4R4G4B4 = true;
+         features->formatA4B4G4R4 = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: {
+         VkPhysicalDeviceCustomBorderColorFeaturesEXT *features = (void *) ext;
+         features->customBorderColors = true;
+         features->customBorderColorWithoutFormat = true;
+         break;
+      }
+      default:
+         break;
       }
    }
    return tu_GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);
@@ -611,23 +621,19 @@ tu_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
 
 void
 tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
-                                VkPhysicalDeviceProperties *pProperties)
+                               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 */);
+   VkSampleCountFlags sample_counts =
+      VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT;
+
+   /* I have no idea what the maximum size is, but the hardware supports very
+    * large numbers of descriptors (at least 2^16). This limit is based on
+    * CP_LOAD_STATE6, which has a 28-bit field for the DWORD offset, so that
+    * we don't have to think about what to do if that overflows, but really
+    * nothing is likely to get close to this.
+    */
+   const size_t max_descriptor_set_size = (1 << 28) / A6XX_TEX_CONST_DWORDS;
 
    VkPhysicalDeviceLimits limits = {
       .maxImageDimension1D = (1 << 14),
@@ -636,8 +642,8 @@ tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
       .maxImageDimensionCube = (1 << 14),
       .maxImageArrayLayers = (1 << 11),
       .maxTexelBufferElements = 128 * 1024 * 1024,
-      .maxUniformBufferRange = UINT32_MAX,
-      .maxStorageBufferRange = UINT32_MAX,
+      .maxUniformBufferRange = MAX_UNIFORM_BUFFER_RANGE,
+      .maxStorageBufferRange = MAX_STORAGE_BUFFER_RANGE,
       .maxPushConstantsSize = MAX_PUSH_CONSTANTS_SIZE,
       .maxMemoryAllocationCount = UINT32_MAX,
       .maxSamplerAllocationCount = 64 * 1024,
@@ -649,7 +655,7 @@ tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
       .maxPerStageDescriptorStorageBuffers = max_descriptor_set_size,
       .maxPerStageDescriptorSampledImages = max_descriptor_set_size,
       .maxPerStageDescriptorStorageImages = max_descriptor_set_size,
-      .maxPerStageDescriptorInputAttachments = max_descriptor_set_size,
+      .maxPerStageDescriptorInputAttachments = MAX_RTS,
       .maxPerStageResources = max_descriptor_set_size,
       .maxDescriptorSetSamplers = max_descriptor_set_size,
       .maxDescriptorSetUniformBuffers = max_descriptor_set_size,
@@ -658,10 +664,10 @@ tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
       .maxDescriptorSetStorageBuffersDynamic = MAX_DYNAMIC_STORAGE_BUFFERS,
       .maxDescriptorSetSampledImages = max_descriptor_set_size,
       .maxDescriptorSetStorageImages = max_descriptor_set_size,
-      .maxDescriptorSetInputAttachments = max_descriptor_set_size,
+      .maxDescriptorSetInputAttachments = MAX_RTS,
       .maxVertexInputAttributes = 32,
       .maxVertexInputBindings = 32,
-      .maxVertexInputAttributeOffset = 2047,
+      .maxVertexInputAttributeOffset = 4095,
       .maxVertexInputBindingStride = 2048,
       .maxVertexOutputComponents = 128,
       .maxTessellationGenerationLevel = 64,
@@ -672,12 +678,12 @@ tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
       .maxTessellationControlTotalOutputComponents = 4096,
       .maxTessellationEvaluationInputComponents = 128,
       .maxTessellationEvaluationOutputComponents = 128,
-      .maxGeometryShaderInvocations = 127,
+      .maxGeometryShaderInvocations = 32,
       .maxGeometryInputComponents = 64,
       .maxGeometryOutputComponents = 128,
       .maxGeometryOutputVertices = 256,
       .maxGeometryTotalOutputComponents = 1024,
-      .maxFragmentInputComponents = 128,
+      .maxFragmentInputComponents = 124,
       .maxFragmentOutputAttachments = 8,
       .maxFragmentDualSrcAttachments = 1,
       .maxFragmentCombinedOutputResources = 8,
@@ -685,28 +691,28 @@ tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
       .maxComputeWorkGroupCount = { 65535, 65535, 65535 },
       .maxComputeWorkGroupInvocations = 2048,
       .maxComputeWorkGroupSize = { 2048, 2048, 2048 },
-      .subPixelPrecisionBits = 4 /* FIXME */,
-      .subTexelPrecisionBits = 4 /* FIXME */,
-      .mipmapPrecisionBits = 4 /* FIXME */,
+      .subPixelPrecisionBits = 8,
+      .subTexelPrecisionBits = 8,
+      .mipmapPrecisionBits = 8,
       .maxDrawIndexedIndexValue = UINT32_MAX,
       .maxDrawIndirectCount = UINT32_MAX,
-      .maxSamplerLodBias = 16,
+      .maxSamplerLodBias = 4095.0 / 256.0, /* [-16, 15.99609375] */
       .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,
+      .minTexelBufferOffsetAlignment = 64,
+      .minUniformBufferOffsetAlignment = 64,
+      .minStorageBufferOffsetAlignment = 64,
+      .minTexelOffset = -16,
+      .maxTexelOffset = 15,
       .minTexelGatherOffset = -32,
       .maxTexelGatherOffset = 31,
-      .minInterpolationOffset = -2,
-      .maxInterpolationOffset = 2,
-      .subPixelInterpolationOffsetBits = 8,
+      .minInterpolationOffset = -0.5,
+      .maxInterpolationOffset = 0.4375,
+      .subPixelInterpolationOffsetBits = 4,
       .maxFramebufferWidth = (1 << 14),
       .maxFramebufferHeight = (1 << 14),
       .maxFramebufferLayers = (1 << 10),
@@ -722,14 +728,14 @@ tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
       .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT,
       .maxSampleMaskWords = 1,
       .timestampComputeAndGraphics = true,
-      .timestampPeriod = 1,
+      .timestampPeriod = 1000000000.0 / 19200000.0, /* CP_ALWAYS_ON_COUNTER is fixed 19.2MHz */
       .maxClipDistances = 8,
       .maxCullDistances = 8,
       .maxCombinedClipAndCullDistances = 8,
       .discreteQueuePriorities = 1,
-      .pointSizeRange = { 0.125, 255.875 },
+      .pointSizeRange = { 1, 4092 },
       .lineWidthRange = { 0.0, 7.9921875 },
-      .pointSizeGranularity = (1.0 / 8.0),
+      .pointSizeGranularity =  0.0625,
       .lineWidthGranularity = (1.0 / 128.0),
       .strictLines = false, /* FINISHME */
       .standardSampleLocations = true,
@@ -738,7 +744,7 @@ tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
       .nonCoherentAtomSize = 64,
    };
 
-   *pProperties = (VkPhysicalDeviceProperties){
+   *pProperties = (VkPhysicalDeviceProperties) {
       .apiVersion = tu_physical_device_api_version(pdevice),
       .driverVersion = vk_get_driver_version(),
       .vendorID = 0, /* TODO */
@@ -754,7 +760,7 @@ tu_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
 
 void
 tu_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
-                                 VkPhysicalDeviceProperties2KHR *pProperties)
+                                VkPhysicalDeviceProperties2 *pProperties)
 {
    TU_FROM_HANDLE(tu_physical_device, pdevice, physicalDevice);
    tu_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);
@@ -762,117 +768,140 @@ tu_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
    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;
+      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: {
+         VkPhysicalDeviceIDProperties *properties =
+            (VkPhysicalDeviceIDProperties *) 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: {
+         VkPhysicalDeviceMultiviewProperties *properties =
+            (VkPhysicalDeviceMultiviewProperties *) ext;
+         properties->maxMultiviewViewCount = MAX_VIEWS;
+         properties->maxMultiviewInstanceIndex = INT_MAX;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
+         VkPhysicalDevicePointClippingProperties *properties =
+            (VkPhysicalDevicePointClippingProperties *) ext;
+         properties->pointClippingBehavior =
+            VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
+         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;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT: {
+         VkPhysicalDeviceTransformFeedbackPropertiesEXT *properties =
+            (VkPhysicalDeviceTransformFeedbackPropertiesEXT *)ext;
+
+         properties->maxTransformFeedbackStreams = IR3_MAX_SO_STREAMS;
+         properties->maxTransformFeedbackBuffers = IR3_MAX_SO_BUFFERS;
+         properties->maxTransformFeedbackBufferSize = UINT32_MAX;
+         properties->maxTransformFeedbackStreamDataSize = 512;
+         properties->maxTransformFeedbackBufferDataSize = 512;
+         properties->maxTransformFeedbackBufferDataStride = 512;
+         properties->transformFeedbackQueries = true;
+         properties->transformFeedbackStreamsLinesTriangles = false;
+         properties->transformFeedbackRasterizationStreamSelect = false;
+         properties->transformFeedbackDraw = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT: {
+         VkPhysicalDeviceSampleLocationsPropertiesEXT *properties =
+            (VkPhysicalDeviceSampleLocationsPropertiesEXT *)ext;
+         properties->sampleLocationSampleCounts = 0;
+         if (pdevice->supported_extensions.EXT_sample_locations) {
+            properties->sampleLocationSampleCounts =
+               VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT;
          }
-         default:
-            break;
+         properties->maxSampleLocationGridSize = (VkExtent2D) { 1 , 1 };
+         properties->sampleLocationCoordinateRange[0] = 0.0f;
+         properties->sampleLocationCoordinateRange[1] = 0.9375f;
+         properties->sampleLocationSubPixelBits = 4;
+         properties->variableSampleLocations = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES: {
+         VkPhysicalDeviceSamplerFilterMinmaxProperties *properties =
+            (VkPhysicalDeviceSamplerFilterMinmaxProperties *)ext;
+         properties->filterMinmaxImageComponentMapping = true;
+         properties->filterMinmaxSingleComponentFormats = true;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES: {
+         VkPhysicalDeviceSubgroupProperties *properties =
+            (VkPhysicalDeviceSubgroupProperties *)ext;
+         properties->subgroupSize = 64;
+         properties->supportedStages = VK_SHADER_STAGE_COMPUTE_BIT;
+         properties->supportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT |
+                                           VK_SUBGROUP_FEATURE_VOTE_BIT;
+         properties->quadOperationsInAllStages = false;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
+         VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *props =
+            (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)ext;
+         props->maxVertexAttribDivisor = UINT32_MAX;
+         break;
+      }
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT: {
+         VkPhysicalDeviceCustomBorderColorPropertiesEXT *props = (void *)ext;
+         props->maxCustomBorderColorSamplers = TU_BORDER_COLOR_COUNT;
+         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;
-}
+static const VkQueueFamilyProperties tu_queue_family_properties = {
+   .queueFlags =
+      VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT,
+   .queueCount = 1,
+   .timestampValidBits = 48,
+   .minImageTransferGranularity = { 1, 1, 1 },
+};
 
 void
 tu_GetPhysicalDeviceQueueFamilyProperties(
-  VkPhysicalDevice physicalDevice,
-  uint32_t *pCount,
-  VkQueueFamilyProperties *pQueueFamilyProperties)
+   VkPhysicalDevice physicalDevice,
+   uint32_t *pQueueFamilyPropertyCount,
+   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);
+   VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pQueueFamilyPropertyCount);
+
+   vk_outarray_append(&out, p) { *p = tu_queue_family_properties; }
 }
 
 void
 tu_GetPhysicalDeviceQueueFamilyProperties2(
-  VkPhysicalDevice physicalDevice,
-  uint32_t *pCount,
-  VkQueueFamilyProperties2KHR *pQueueFamilyProperties)
+   VkPhysicalDevice physicalDevice,
+   uint32_t *pQueueFamilyPropertyCount,
+   VkQueueFamilyProperties2 *pQueueFamilyProperties)
 {
-   TU_FROM_HANDLE(tu_physical_device, pdevice, physicalDevice);
-   if (!pQueueFamilyProperties) {
-      return tu_get_physical_device_queue_family_properties(
-        pdevice, pCount, NULL);
-      return;
+   VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pQueueFamilyPropertyCount);
+
+   vk_outarray_append(&out, p)
+   {
+      p->queueFamilyProperties = tu_queue_family_properties;
    }
-   VkQueueFamilyProperties *properties[] = {
-      &pQueueFamilyProperties[0].queueFamilyProperties,
-   };
-   tu_get_physical_device_queue_family_properties(pdevice, pCount, properties);
-   assert(*pCount <= 1);
 }
 
 static uint64_t
@@ -881,7 +910,7 @@ tu_get_system_heap_size()
    struct sysinfo info;
    sysinfo(&info);
 
-   uint64_t total_ram = (uint64_t)info.totalram * (uint64_t)info.mem_unit;
+   uint64_t total_ram = (uint64_t) info.totalram * (uint64_t) info.mem_unit;
 
    /* We don't want to burn too much ram with the GPU.  If the user has 4GiB
     * or less, we use at most half.  If they have more than 4GiB, we use 3/4.
@@ -897,48 +926,58 @@ tu_get_system_heap_size()
 
 void
 tu_GetPhysicalDeviceMemoryProperties(
-  VkPhysicalDevice physicalDevice,
-  VkPhysicalDeviceMemoryProperties *pMemoryProperties)
+   VkPhysicalDevice physicalDevice,
+   VkPhysicalDeviceMemoryProperties *pMemoryProperties)
 {
    pMemoryProperties->memoryHeapCount = 1;
    pMemoryProperties->memoryHeaps[0].size = tu_get_system_heap_size();
    pMemoryProperties->memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
 
    pMemoryProperties->memoryTypeCount = 1;
-   pMemoryProperties->memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
-                                                     VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
-                                                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+   pMemoryProperties->memoryTypes[0].propertyFlags =
+      VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
+      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+      VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    pMemoryProperties->memoryTypes[0].heapIndex = 0;
 }
 
 void
 tu_GetPhysicalDeviceMemoryProperties2(
-  VkPhysicalDevice physicalDevice,
-  VkPhysicalDeviceMemoryProperties2KHR *pMemoryProperties)
+   VkPhysicalDevice physicalDevice,
+   VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
 {
    return tu_GetPhysicalDeviceMemoryProperties(
-     physicalDevice, &pMemoryProperties->memoryProperties);
+      physicalDevice, &pMemoryProperties->memoryProperties);
 }
 
-static int
+static VkResult
 tu_queue_init(struct tu_device *device,
-               struct tu_queue *queue,
-               uint32_t queue_family_index,
-               int idx,
-               VkDeviceQueueCreateFlags flags)
+              struct tu_queue *queue,
+              uint32_t queue_family_index,
+              int idx,
+              VkDeviceQueueCreateFlags flags)
 {
-   queue->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
+   vk_object_base_init(&device->vk, &queue->base, VK_OBJECT_TYPE_QUEUE);
+
    queue->device = device;
    queue->queue_family_index = queue_family_index;
    queue->queue_idx = idx;
    queue->flags = flags;
 
+   int ret = tu_drm_submitqueue_new(device, 0, &queue->msm_queue_id);
+   if (ret)
+      return VK_ERROR_INITIALIZATION_FAILED;
+
+   tu_fence_init(&queue->submit_fence, false);
+
    return VK_SUCCESS;
 }
 
 static void
 tu_queue_finish(struct tu_queue *queue)
 {
+   tu_fence_finish(&queue->submit_fence);
+   tu_drm_submitqueue_close(queue->device, queue->msm_queue_id);
 }
 
 static int
@@ -953,22 +992,23 @@ tu_get_device_extension_index(const char *name)
 
 VkResult
 tu_CreateDevice(VkPhysicalDevice physicalDevice,
-                 const VkDeviceCreateInfo *pCreateInfo,
-                 const VkAllocationCallbacks *pAllocator,
-                 VkDevice *pDevice)
+                const VkDeviceCreateInfo *pCreateInfo,
+                const VkAllocationCallbacks *pAllocator,
+                VkDevice *pDevice)
 {
    TU_FROM_HANDLE(tu_physical_device, physical_device, physicalDevice);
    VkResult result;
    struct tu_device *device;
+   bool custom_border_colors = false;
 
    /* 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;
+      VkBool32 *supported_feature = (VkBool32 *) &supported_features;
+      VkBool32 *enabled_feature = (VkBool32 *) pCreateInfo->pEnabledFeatures;
       unsigned num_features =
-        sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
+         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,
@@ -976,29 +1016,36 @@ tu_CreateDevice(VkPhysicalDevice physicalDevice,
       }
    }
 
-   device = vk_zalloc2(&physical_device->instance->alloc,
-                       pAllocator,
-                       sizeof(*device),
-                       8,
-                       VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
+   vk_foreach_struct_const(ext, pCreateInfo->pNext) {
+      switch (ext->sType) {
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: {
+         const VkPhysicalDeviceCustomBorderColorFeaturesEXT *border_color_features = (const void *)ext;
+         custom_border_colors = border_color_features->customBorderColors;
+         break;
+      }
+      default:
+         break;
+      }
+   }
+
+   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;
+   vk_device_init(&device->vk, pCreateInfo,
+         &physical_device->instance->alloc, pAllocator);
+
    device->instance = physical_device->instance;
    device->physical_device = physical_device;
-
-   if (pAllocator)
-      device->alloc = *pAllocator;
-   else
-      device->alloc = physical_device->instance->alloc;
+   device->_lost = false;
 
    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);
+         vk_free(&device->vk.alloc, device);
          return vk_error(physical_device->instance,
                          VK_ERROR_EXTENSION_NOT_PRESENT);
       }
@@ -1008,32 +1055,68 @@ tu_CreateDevice(VkPhysicalDevice physicalDevice,
 
    for (unsigned i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
       const VkDeviceQueueCreateInfo *queue_create =
-        &pCreateInfo->pQueueCreateInfos[i];
+         &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);
+      device->queues[qfi] = vk_alloc(
+         &device->vk.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;
+         goto fail_queues;
       }
 
-      memset(device->queues[qfi],
-             0,
+      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);
+         result = tu_queue_init(device, &device->queues[qfi][q], qfi, q,
+                                queue_create->flags);
          if (result != VK_SUCCESS)
-            goto fail;
+            goto fail_queues;
       }
    }
 
+   device->compiler = ir3_compiler_create(NULL, physical_device->gpu_id);
+   if (!device->compiler)
+      goto fail_queues;
+
+   /* initial sizes, these will increase if there is overflow */
+   device->vsc_draw_strm_pitch = 0x1000 + VSC_PAD;
+   device->vsc_prim_strm_pitch = 0x4000 + VSC_PAD;
+
+   uint32_t global_size = sizeof(struct tu6_global);
+   if (custom_border_colors)
+      global_size += TU_BORDER_COLOR_COUNT * sizeof(struct bcolor_entry);
+
+   result = tu_bo_init_new(device, &device->global_bo, global_size);
+   if (result != VK_SUCCESS)
+      goto fail_global_bo;
+
+   result = tu_bo_map(device, &device->global_bo);
+   if (result != VK_SUCCESS)
+      goto fail_global_bo_map;
+
+   struct tu6_global *global = device->global_bo.map;
+   tu_init_clear_blit_shaders(device->global_bo.map);
+   global->predicate = 0;
+   tu6_pack_border_color(&global->bcolor_builtin[VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK],
+                         &(VkClearColorValue) {}, false);
+   tu6_pack_border_color(&global->bcolor_builtin[VK_BORDER_COLOR_INT_TRANSPARENT_BLACK],
+                         &(VkClearColorValue) {}, true);
+   tu6_pack_border_color(&global->bcolor_builtin[VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK],
+                         &(VkClearColorValue) { .float32[3] = 1.0f }, false);
+   tu6_pack_border_color(&global->bcolor_builtin[VK_BORDER_COLOR_INT_OPAQUE_BLACK],
+                         &(VkClearColorValue) { .int32[3] = 1 }, true);
+   tu6_pack_border_color(&global->bcolor_builtin[VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE],
+                         &(VkClearColorValue) { .float32[0 ... 3] = 1.0f }, false);
+   tu6_pack_border_color(&global->bcolor_builtin[VK_BORDER_COLOR_INT_OPAQUE_WHITE],
+                         &(VkClearColorValue) { .int32[0 ... 3] = 1 }, true);
+
+   /* initialize to ones so ffs can be used to find unused slots */
+   BITSET_ONES(device->custom_border_color);
+
    VkPipelineCacheCreateInfo ci;
    ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
    ci.pNext = NULL;
@@ -1042,24 +1125,36 @@ tu_CreateDevice(VkPhysicalDevice physicalDevice,
    ci.initialDataSize = 0;
    VkPipelineCache pc;
    result =
-     tu_CreatePipelineCache(tu_device_to_handle(device), &ci, NULL, &pc);
+      tu_CreatePipelineCache(tu_device_to_handle(device), &ci, NULL, &pc);
    if (result != VK_SUCCESS)
-      goto fail;
+      goto fail_pipeline_cache;
 
    device->mem_cache = tu_pipeline_cache_from_handle(pc);
 
+   for (unsigned i = 0; i < ARRAY_SIZE(device->scratch_bos); i++)
+      mtx_init(&device->scratch_bos[i].construct_mtx, mtx_plain);
+
+   mtx_init(&device->mutex, mtx_plain);
+
    *pDevice = tu_device_to_handle(device);
    return VK_SUCCESS;
 
-fail:
+fail_pipeline_cache:
+fail_global_bo_map:
+   tu_bo_finish(device, &device->global_bo);
+
+fail_global_bo:
+   ralloc_free(device->compiler);
+
+fail_queues:
    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_object_free(&device->vk, NULL, device->queues[i]);
    }
 
-   vk_free(&device->alloc, device);
+   vk_free(&device->vk.alloc, device);
    return result;
 }
 
@@ -1075,52 +1170,117 @@ tu_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator)
       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_object_free(&device->vk, NULL, device->queues[i]);
    }
 
+   for (unsigned i = 0; i < ARRAY_SIZE(device->scratch_bos); i++) {
+      if (device->scratch_bos[i].initialized)
+         tu_bo_finish(device, &device->scratch_bos[i].bo);
+   }
+
+   ir3_compiler_destroy(device->compiler);
+
    VkPipelineCache pc = tu_pipeline_cache_to_handle(device->mem_cache);
    tu_DestroyPipelineCache(tu_device_to_handle(device), pc, NULL);
 
-   vk_free(&device->alloc, device);
+   vk_free(&device->vk.alloc, device);
 }
 
 VkResult
-tu_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
-                                     VkLayerProperties *pProperties)
+_tu_device_set_lost(struct tu_device *device,
+                    const char *file, int line,
+                    const char *msg, ...)
 {
-   if (pProperties == NULL) {
-      *pPropertyCount = 0;
-      return VK_SUCCESS;
-   }
+   /* Set the flag indicating that waits should return in finite time even
+    * after device loss.
+    */
+   p_atomic_inc(&device->_lost);
 
-   /* None supported at this time */
-   return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
+   /* TODO: Report the log message through VkDebugReportCallbackEXT instead */
+   fprintf(stderr, "%s:%d: ", file, line);
+   va_list ap;
+   va_start(ap, msg);
+   vfprintf(stderr, msg, ap);
+   va_end(ap);
+
+   if (env_var_as_boolean("TU_ABORT_ON_DEVICE_LOSS", false))
+      abort();
+
+   return VK_ERROR_DEVICE_LOST;
 }
 
 VkResult
-tu_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
-                                   uint32_t *pPropertyCount,
-                                   VkLayerProperties *pProperties)
+tu_get_scratch_bo(struct tu_device *dev, uint64_t size, struct tu_bo **bo)
 {
-   if (pProperties == NULL) {
-      *pPropertyCount = 0;
+   unsigned size_log2 = MAX2(util_logbase2_ceil64(size), MIN_SCRATCH_BO_SIZE_LOG2);
+   unsigned index = size_log2 - MIN_SCRATCH_BO_SIZE_LOG2;
+   assert(index < ARRAY_SIZE(dev->scratch_bos));
+
+   for (unsigned i = index; i < ARRAY_SIZE(dev->scratch_bos); i++) {
+      if (p_atomic_read(&dev->scratch_bos[i].initialized)) {
+         /* Fast path: just return the already-allocated BO. */
+         *bo = &dev->scratch_bos[i].bo;
+         return VK_SUCCESS;
+      }
+   }
+
+   /* Slow path: actually allocate the BO. We take a lock because the process
+    * of allocating it is slow, and we don't want to block the CPU while it
+    * finishes.
+   */
+   mtx_lock(&dev->scratch_bos[index].construct_mtx);
+
+   /* Another thread may have allocated it already while we were waiting on
+    * the lock. We need to check this in order to avoid double-allocating.
+    */
+   if (dev->scratch_bos[index].initialized) {
+      mtx_unlock(&dev->scratch_bos[index].construct_mtx);
+      *bo = &dev->scratch_bos[index].bo;
       return VK_SUCCESS;
    }
 
-   /* None supported at this time */
-   return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
+   unsigned bo_size = 1ull << size_log2;
+   VkResult result = tu_bo_init_new(dev, &dev->scratch_bos[index].bo, bo_size);
+   if (result != VK_SUCCESS) {
+      mtx_unlock(&dev->scratch_bos[index].construct_mtx);
+      return result;
+   }
+
+   p_atomic_set(&dev->scratch_bos[index].initialized, true);
+
+   mtx_unlock(&dev->scratch_bos[index].construct_mtx);
+
+   *bo = &dev->scratch_bos[index].bo;
+   return VK_SUCCESS;
+}
+
+VkResult
+tu_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
+                                    VkLayerProperties *pProperties)
+{
+   *pPropertyCount = 0;
+   return VK_SUCCESS;
+}
+
+VkResult
+tu_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
+                                  uint32_t *pPropertyCount,
+                                  VkLayerProperties *pProperties)
+{
+   *pPropertyCount = 0;
+   return VK_SUCCESS;
 }
 
 void
 tu_GetDeviceQueue2(VkDevice _device,
-                    const VkDeviceQueueInfo2 *pQueueInfo,
-                    VkQueue *pQueue)
+                   const VkDeviceQueueInfo2 *pQueueInfo,
+                   VkQueue *pQueue)
 {
    TU_FROM_HANDLE(tu_device, device, _device);
    struct tu_queue *queue;
 
    queue =
-     &device->queues[pQueueInfo->queueFamilyIndex][pQueueInfo->queueIndex];
+      &device->queues[pQueueInfo->queueFamilyIndex][pQueueInfo->queueIndex];
    if (pQueueInfo->flags != queue->flags) {
       /* From the Vulkan 1.1.70 spec:
        *
@@ -1139,30 +1299,28 @@ tu_GetDeviceQueue2(VkDevice _device,
 
 void
 tu_GetDeviceQueue(VkDevice _device,
-                   uint32_t queueFamilyIndex,
-                   uint32_t queueIndex,
-                   VkQueue *pQueue)
+                  uint32_t queueFamilyIndex,
+                  uint32_t queueIndex,
+                  VkQueue *pQueue)
 {
    const VkDeviceQueueInfo2 info =
-     (VkDeviceQueueInfo2){.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2,
-                          .queueFamilyIndex = queueFamilyIndex,
-                          .queueIndex = queueIndex };
+      (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)
 {
+   TU_FROM_HANDLE(tu_queue, queue, _queue);
+
+   if (tu_device_is_lost(queue->device))
+      return VK_ERROR_DEVICE_LOST;
+
+   tu_fence_wait_idle(&queue->submit_fence);
+
    return VK_SUCCESS;
 }
 
@@ -1171,6 +1329,9 @@ tu_DeviceWaitIdle(VkDevice _device)
 {
    TU_FROM_HANDLE(tu_device, device, _device);
 
+   if (tu_device_is_lost(device))
+      return VK_ERROR_DEVICE_LOST;
+
    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]));
@@ -1181,13 +1342,17 @@ tu_DeviceWaitIdle(VkDevice _device)
 
 VkResult
 tu_EnumerateInstanceExtensionProperties(const char *pLayerName,
-                                         uint32_t *pPropertyCount,
-                                         VkExtensionProperties *pProperties)
+                                        uint32_t *pPropertyCount,
+                                        VkExtensionProperties *pProperties)
 {
    VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
 
+   /* We spport no lyaers */
+   if (pLayerName)
+      return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
+
    for (int i = 0; i < TU_INSTANCE_EXTENSION_COUNT; i++) {
-      if (tu_supported_instance_extensions.extensions[i]) {
+      if (tu_instance_extensions_supported.extensions[i]) {
          vk_outarray_append(&out, prop) { *prop = tu_instance_extensions[i]; }
       }
    }
@@ -1197,13 +1362,18 @@ tu_EnumerateInstanceExtensionProperties(const char *pLayerName,
 
 VkResult
 tu_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
-                                       const char *pLayerName,
-                                       uint32_t *pPropertyCount,
-                                       VkExtensionProperties *pProperties)
+                                      const char *pLayerName,
+                                      uint32_t *pPropertyCount,
+                                      VkExtensionProperties *pProperties)
 {
+   /* We spport no lyaers */
    TU_FROM_HANDLE(tu_physical_device, device, physicalDevice);
    VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
 
+   /* We spport no lyaers */
+   if (pLayerName)
+      return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
+
    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]; }
@@ -1218,11 +1388,9 @@ 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);
+   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
@@ -1244,19 +1412,19 @@ 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);
+   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)
+                const VkMemoryAllocateInfo *pAllocateInfo,
+                const VkAllocationCallbacks *pAllocator,
+                VkDeviceMemory *pMem)
 {
    struct tu_device_memory *mem;
+   VkResult result;
 
    assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);
 
@@ -1266,21 +1434,43 @@ tu_alloc_memory(struct tu_device *device,
       return VK_SUCCESS;
    }
 
-   mem = vk_alloc2(&device->alloc,
-                   pAllocator,
-                   sizeof(*mem),
-                   8,
-                   VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   mem = vk_object_alloc(&device->vk, pAllocator, sizeof(*mem),
+                         VK_OBJECT_TYPE_DEVICE_MEMORY);
    if (mem == NULL)
       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
 
-   mem->bo = fd_bo_new(device->physical_device->drm_device, pAllocateInfo->allocationSize,
-                       DRM_FREEDRENO_GEM_CACHE_WCOMBINE |
-                       DRM_FREEDRENO_GEM_TYPE_KMEM);
-   if (!mem->bo) {
-      vk_free2(&device->alloc, pAllocator, mem);
-      return vk_error(device->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY);
+   const VkImportMemoryFdInfoKHR *fd_info =
+      vk_find_struct_const(pAllocateInfo->pNext, IMPORT_MEMORY_FD_INFO_KHR);
+   if (fd_info && !fd_info->handleType)
+      fd_info = NULL;
+
+   if (fd_info) {
+      assert(fd_info->handleType ==
+                VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
+             fd_info->handleType ==
+                VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
+
+      /*
+       * TODO Importing the same fd twice gives us the same handle without
+       * reference counting.  We need to maintain a per-instance handle-to-bo
+       * table and add reference count to tu_bo.
+       */
+      result = tu_bo_init_dmabuf(device, &mem->bo,
+                                 pAllocateInfo->allocationSize, fd_info->fd);
+      if (result == VK_SUCCESS) {
+         /* take ownership and close the fd */
+         close(fd_info->fd);
+      }
+   } else {
+      result =
+         tu_bo_init_new(device, &mem->bo, pAllocateInfo->allocationSize);
+   }
+
+   if (result != VK_SUCCESS) {
+      vk_object_free(&device->vk, pAllocator, mem);
+      return result;
    }
+
    mem->size = pAllocateInfo->allocationSize;
    mem->type_index = pAllocateInfo->memoryTypeIndex;
 
@@ -1294,9 +1484,9 @@ tu_alloc_memory(struct tu_device *device,
 
 VkResult
 tu_AllocateMemory(VkDevice _device,
-                   const VkMemoryAllocateInfo *pAllocateInfo,
-                   const VkAllocationCallbacks *pAllocator,
-                   VkDeviceMemory *pMem)
+                  const VkMemoryAllocateInfo *pAllocateInfo,
+                  const VkAllocationCallbacks *pAllocator,
+                  VkDeviceMemory *pMem)
 {
    TU_FROM_HANDLE(tu_device, device, _device);
    return tu_alloc_memory(device, pAllocateInfo, pAllocator, pMem);
@@ -1304,8 +1494,8 @@ tu_AllocateMemory(VkDevice _device,
 
 void
 tu_FreeMemory(VkDevice _device,
-               VkDeviceMemory _mem,
-               const VkAllocationCallbacks *pAllocator)
+              VkDeviceMemory _mem,
+              const VkAllocationCallbacks *pAllocator)
 {
    TU_FROM_HANDLE(tu_device, device, _device);
    TU_FROM_HANDLE(tu_device_memory, mem, _mem);
@@ -1313,22 +1503,21 @@ tu_FreeMemory(VkDevice _device,
    if (mem == NULL)
       return;
 
-   if (mem->bo)
-      fd_bo_del(mem->bo);
-
-   vk_free2(&device->alloc, pAllocator, mem);
+   tu_bo_finish(device, &mem->bo);
+   vk_object_free(&device->vk, pAllocator, mem);
 }
 
 VkResult
 tu_MapMemory(VkDevice _device,
-              VkDeviceMemory _memory,
-              VkDeviceSize offset,
-              VkDeviceSize size,
-              VkMemoryMapFlags flags,
-              void **ppData)
+             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);
+   VkResult result;
 
    if (mem == NULL) {
       *ppData = NULL;
@@ -1337,8 +1526,11 @@ tu_MapMemory(VkDevice _device,
 
    if (mem->user_ptr) {
       *ppData = mem->user_ptr;
-   } else  if (!mem->map){
-      *ppData = mem->map = fd_bo_map(mem->bo);
+   } else if (!mem->map) {
+      result = tu_bo_map(device, &mem->bo);
+      if (result != VK_SUCCESS)
+         return result;
+      *ppData = mem->map = mem->bo.map;
    } else
       *ppData = mem->map;
 
@@ -1358,108 +1550,119 @@ tu_UnmapMemory(VkDevice _device, VkDeviceMemory _memory)
 
 VkResult
 tu_FlushMappedMemoryRanges(VkDevice _device,
-                            uint32_t memoryRangeCount,
-                            const VkMappedMemoryRange *pMemoryRanges)
+                           uint32_t memoryRangeCount,
+                           const VkMappedMemoryRange *pMemoryRanges)
 {
    return VK_SUCCESS;
 }
 
 VkResult
 tu_InvalidateMappedMemoryRanges(VkDevice _device,
-                                 uint32_t memoryRangeCount,
-                                 const VkMappedMemoryRange *pMemoryRanges)
+                                uint32_t memoryRangeCount,
+                                const VkMappedMemoryRange *pMemoryRanges)
 {
    return VK_SUCCESS;
 }
 
 void
 tu_GetBufferMemoryRequirements(VkDevice _device,
-                                VkBuffer _buffer,
-                                VkMemoryRequirements *pMemoryRequirements)
+                               VkBuffer _buffer,
+                               VkMemoryRequirements *pMemoryRequirements)
 {
    TU_FROM_HANDLE(tu_buffer, buffer, _buffer);
 
    pMemoryRequirements->memoryTypeBits = 1;
-   pMemoryRequirements->alignment = 16;
+   pMemoryRequirements->alignment = 64;
    pMemoryRequirements->size =
-     align64(buffer->size, pMemoryRequirements->alignment);
+      align64(buffer->size, pMemoryRequirements->alignment);
 }
 
 void
 tu_GetBufferMemoryRequirements2(
-  VkDevice device,
-  const VkBufferMemoryRequirementsInfo2KHR *pInfo,
-  VkMemoryRequirements2KHR *pMemoryRequirements)
+   VkDevice device,
+   const VkBufferMemoryRequirementsInfo2 *pInfo,
+   VkMemoryRequirements2 *pMemoryRequirements)
 {
-   tu_GetBufferMemoryRequirements(
-     device, pInfo->buffer, &pMemoryRequirements->memoryRequirements);
+   tu_GetBufferMemoryRequirements(device, pInfo->buffer,
+                                  &pMemoryRequirements->memoryRequirements);
 }
 
 void
 tu_GetImageMemoryRequirements(VkDevice _device,
-                               VkImage _image,
-                               VkMemoryRequirements *pMemoryRequirements)
+                              VkImage _image,
+                              VkMemoryRequirements *pMemoryRequirements)
 {
    TU_FROM_HANDLE(tu_image, image, _image);
 
    pMemoryRequirements->memoryTypeBits = 1;
-   pMemoryRequirements->size = image->size;
-   pMemoryRequirements->alignment = image->alignment;
+   pMemoryRequirements->size = image->total_size;
+   pMemoryRequirements->alignment = image->layout[0].base_align;
 }
 
 void
 tu_GetImageMemoryRequirements2(VkDevice device,
-                                const VkImageMemoryRequirementsInfo2KHR *pInfo,
-                                VkMemoryRequirements2KHR *pMemoryRequirements)
+                               const VkImageMemoryRequirementsInfo2 *pInfo,
+                               VkMemoryRequirements2 *pMemoryRequirements)
 {
-   tu_GetImageMemoryRequirements(
-     device, pInfo->image, &pMemoryRequirements->memoryRequirements);
+   tu_GetImageMemoryRequirements(device, pInfo->image,
+                                 &pMemoryRequirements->memoryRequirements);
 }
 
 void
 tu_GetImageSparseMemoryRequirements(
-  VkDevice device,
-  VkImage image,
-  uint32_t *pSparseMemoryRequirementCount,
-  VkSparseImageMemoryRequirements *pSparseMemoryRequirements)
+   VkDevice device,
+   VkImage image,
+   uint32_t *pSparseMemoryRequirementCount,
+   VkSparseImageMemoryRequirements *pSparseMemoryRequirements)
 {
-   stub();
+   tu_stub();
 }
 
 void
 tu_GetImageSparseMemoryRequirements2(
-  VkDevice device,
-  const VkImageSparseMemoryRequirementsInfo2KHR *pInfo,
-  uint32_t *pSparseMemoryRequirementCount,
-  VkSparseImageMemoryRequirements2KHR *pSparseMemoryRequirements)
+   VkDevice device,
+   const VkImageSparseMemoryRequirementsInfo2 *pInfo,
+   uint32_t *pSparseMemoryRequirementCount,
+   VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
 {
-   stub();
+   tu_stub();
 }
 
 void
 tu_GetDeviceMemoryCommitment(VkDevice device,
-                              VkDeviceMemory memory,
-                              VkDeviceSize *pCommittedMemoryInBytes)
+                             VkDeviceMemory memory,
+                             VkDeviceSize *pCommittedMemoryInBytes)
 {
    *pCommittedMemoryInBytes = 0;
 }
 
 VkResult
 tu_BindBufferMemory2(VkDevice device,
-                      uint32_t bindInfoCount,
-                      const VkBindBufferMemoryInfoKHR *pBindInfos)
+                     uint32_t bindInfoCount,
+                     const VkBindBufferMemoryInfo *pBindInfos)
 {
+   for (uint32_t i = 0; i < bindInfoCount; ++i) {
+      TU_FROM_HANDLE(tu_device_memory, mem, pBindInfos[i].memory);
+      TU_FROM_HANDLE(tu_buffer, buffer, pBindInfos[i].buffer);
+
+      if (mem) {
+         buffer->bo = &mem->bo;
+         buffer->bo_offset = pBindInfos[i].memoryOffset;
+      } else {
+         buffer->bo = NULL;
+      }
+   }
    return VK_SUCCESS;
 }
 
 VkResult
 tu_BindBufferMemory(VkDevice device,
-                     VkBuffer buffer,
-                     VkDeviceMemory memory,
-                     VkDeviceSize memoryOffset)
+                    VkBuffer buffer,
+                    VkDeviceMemory memory,
+                    VkDeviceSize memoryOffset)
 {
-   const VkBindBufferMemoryInfoKHR info = {
-      .sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR,
+   const VkBindBufferMemoryInfo info = {
+      .sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO,
       .buffer = buffer,
       .memory = memory,
       .memoryOffset = memoryOffset
@@ -1470,20 +1673,33 @@ tu_BindBufferMemory(VkDevice device,
 
 VkResult
 tu_BindImageMemory2(VkDevice device,
-                     uint32_t bindInfoCount,
-                     const VkBindImageMemoryInfoKHR *pBindInfos)
-{
+                    uint32_t bindInfoCount,
+                    const VkBindImageMemoryInfo *pBindInfos)
+{
+   for (uint32_t i = 0; i < bindInfoCount; ++i) {
+      TU_FROM_HANDLE(tu_image, image, pBindInfos[i].image);
+      TU_FROM_HANDLE(tu_device_memory, mem, pBindInfos[i].memory);
+
+      if (mem) {
+         image->bo = &mem->bo;
+         image->bo_offset = pBindInfos[i].memoryOffset;
+      } else {
+         image->bo = NULL;
+         image->bo_offset = 0;
+      }
+   }
+
    return VK_SUCCESS;
 }
 
 VkResult
 tu_BindImageMemory(VkDevice device,
-                    VkImage image,
-                    VkDeviceMemory memory,
-                    VkDeviceSize memoryOffset)
+                   VkImage image,
+                   VkDeviceMemory memory,
+                   VkDeviceSize memoryOffset)
 {
-   const VkBindImageMemoryInfoKHR info = {
-      .sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR,
+   const VkBindImageMemoryInfo info = {
+      .sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO,
       .image = image,
       .memory = memory,
       .memoryOffset = memoryOffset
@@ -1494,138 +1710,60 @@ tu_BindImageMemory(VkDevice device,
 
 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)
+                   uint32_t bindInfoCount,
+                   const VkBindSparseInfo *pBindInfo,
+                   VkFence _fence)
 {
-   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)
+               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);
 
+   struct tu_event *event =
+         vk_object_alloc(&device->vk, pAllocator, sizeof(*event),
+                         VK_OBJECT_TYPE_EVENT);
    if (!event)
       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
 
+   VkResult result = tu_bo_init_new(device, &event->bo, 0x1000);
+   if (result != VK_SUCCESS)
+      goto fail_alloc;
+
+   result = tu_bo_map(device, &event->bo);
+   if (result != VK_SUCCESS)
+      goto fail_map;
+
    *pEvent = tu_event_to_handle(event);
 
    return VK_SUCCESS;
+
+fail_map:
+   tu_bo_finish(device, &event->bo);
+fail_alloc:
+   vk_object_free(&device->vk, pAllocator, event);
+   return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
 }
 
 void
 tu_DestroyEvent(VkDevice _device,
-                 VkEvent _event,
-                 const VkAllocationCallbacks *pAllocator)
+                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);
+
+   tu_bo_finish(device, &event->bo);
+   vk_object_free(&device->vk, pAllocator, event);
 }
 
 VkResult
@@ -1633,7 +1771,7 @@ tu_GetEventStatus(VkDevice _device, VkEvent _event)
 {
    TU_FROM_HANDLE(tu_event, event, _event);
 
-   if (*event->map == 1)
+   if (*(uint64_t*) event->bo.map == 1)
       return VK_EVENT_SET;
    return VK_EVENT_RESET;
 }
@@ -1642,7 +1780,7 @@ VkResult
 tu_SetEvent(VkDevice _device, VkEvent _event)
 {
    TU_FROM_HANDLE(tu_event, event, _event);
-   *event->map = 1;
+   *(uint64_t*) event->bo.map = 1;
 
    return VK_SUCCESS;
 }
@@ -1651,27 +1789,24 @@ VkResult
 tu_ResetEvent(VkDevice _device, VkEvent _event)
 {
    TU_FROM_HANDLE(tu_event, event, _event);
-   *event->map = 0;
+   *(uint64_t*) event->bo.map = 0;
 
    return VK_SUCCESS;
 }
 
 VkResult
 tu_CreateBuffer(VkDevice _device,
-                 const VkBufferCreateInfo *pCreateInfo,
-                 const VkAllocationCallbacks *pAllocator,
-                 VkBuffer *pBuffer)
+                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);
+   buffer = vk_object_alloc(&device->vk, pAllocator, sizeof(*buffer),
+                            VK_OBJECT_TYPE_BUFFER);
    if (buffer == NULL)
       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
 
@@ -1686,8 +1821,8 @@ tu_CreateBuffer(VkDevice _device,
 
 void
 tu_DestroyBuffer(VkDevice _device,
-                  VkBuffer _buffer,
-                  const VkAllocationCallbacks *pAllocator)
+                 VkBuffer _buffer,
+                 const VkAllocationCallbacks *pAllocator)
 {
    TU_FROM_HANDLE(tu_device, device, _device);
    TU_FROM_HANDLE(tu_buffer, buffer, _buffer);
@@ -1695,33 +1830,25 @@ tu_DestroyBuffer(VkDevice _device,
    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);
+   vk_object_free(&device->vk, pAllocator, buffer);
 }
 
 VkResult
 tu_CreateFramebuffer(VkDevice _device,
-                      const VkFramebufferCreateInfo *pCreateInfo,
-                      const VkAllocationCallbacks *pAllocator,
-                      VkFramebuffer *pFramebuffer)
+                     const VkFramebufferCreateInfo *pCreateInfo,
+                     const VkAllocationCallbacks *pAllocator,
+                     VkFramebuffer *pFramebuffer)
 {
    TU_FROM_HANDLE(tu_device, device, _device);
+   TU_FROM_HANDLE(tu_render_pass, pass, pCreateInfo->renderPass);
    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);
+   size_t size = sizeof(*framebuffer) + sizeof(struct tu_attachment_info) *
+                                           pCreateInfo->attachmentCount;
+   framebuffer = vk_object_alloc(&device->vk, pAllocator, size,
+                                 VK_OBJECT_TYPE_FRAMEBUFFER);
    if (framebuffer == NULL)
       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
 
@@ -1733,53 +1860,112 @@ tu_CreateFramebuffer(VkDevice _device,
       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));
    }
 
+   tu_framebuffer_tiling_config(framebuffer, device, pass);
+
    *pFramebuffer = tu_framebuffer_to_handle(framebuffer);
    return VK_SUCCESS;
 }
 
 void
 tu_DestroyFramebuffer(VkDevice _device,
-                       VkFramebuffer _fb,
-                       const VkAllocationCallbacks *pAllocator)
+                      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);
+
+   vk_object_free(&device->vk, pAllocator, fb);
 }
 
 static void
 tu_init_sampler(struct tu_device *device,
-                 struct tu_sampler *sampler,
-                 const VkSamplerCreateInfo *pCreateInfo)
-{
+                struct tu_sampler *sampler,
+                const VkSamplerCreateInfo *pCreateInfo)
+{
+   const struct VkSamplerReductionModeCreateInfo *reduction =
+      vk_find_struct_const(pCreateInfo->pNext, SAMPLER_REDUCTION_MODE_CREATE_INFO);
+   const struct VkSamplerYcbcrConversionInfo *ycbcr_conversion =
+      vk_find_struct_const(pCreateInfo->pNext,  SAMPLER_YCBCR_CONVERSION_INFO);
+   const VkSamplerCustomBorderColorCreateInfoEXT *custom_border_color =
+      vk_find_struct_const(pCreateInfo->pNext, SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT);
+   /* for non-custom border colors, the VK enum is translated directly to an offset in
+    * the border color buffer. custom border colors are located immediately after the
+    * builtin colors, and thus an offset of TU_BORDER_COLOR_BUILTIN is added.
+    */
+   uint32_t border_color = (unsigned) pCreateInfo->borderColor;
+   if (pCreateInfo->borderColor == VK_BORDER_COLOR_FLOAT_CUSTOM_EXT ||
+       pCreateInfo->borderColor == VK_BORDER_COLOR_INT_CUSTOM_EXT) {
+      mtx_lock(&device->mutex);
+      border_color = BITSET_FFS(device->custom_border_color);
+      BITSET_CLEAR(device->custom_border_color, border_color);
+      mtx_unlock(&device->mutex);
+      tu6_pack_border_color(device->global_bo.map + gb_offset(bcolor[border_color]),
+                            &custom_border_color->customBorderColor,
+                            pCreateInfo->borderColor == VK_BORDER_COLOR_INT_CUSTOM_EXT);
+      border_color += TU_BORDER_COLOR_BUILTIN;
+   }
+
+   unsigned aniso = pCreateInfo->anisotropyEnable ?
+      util_last_bit(MIN2((uint32_t)pCreateInfo->maxAnisotropy >> 1, 8)) : 0;
+   bool miplinear = (pCreateInfo->mipmapMode == VK_SAMPLER_MIPMAP_MODE_LINEAR);
+   float min_lod = CLAMP(pCreateInfo->minLod, 0.0f, 4095.0f / 256.0f);
+   float max_lod = CLAMP(pCreateInfo->maxLod, 0.0f, 4095.0f / 256.0f);
+
+   sampler->descriptor[0] =
+      COND(miplinear, A6XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR) |
+      A6XX_TEX_SAMP_0_XY_MAG(tu6_tex_filter(pCreateInfo->magFilter, aniso)) |
+      A6XX_TEX_SAMP_0_XY_MIN(tu6_tex_filter(pCreateInfo->minFilter, aniso)) |
+      A6XX_TEX_SAMP_0_ANISO(aniso) |
+      A6XX_TEX_SAMP_0_WRAP_S(tu6_tex_wrap(pCreateInfo->addressModeU)) |
+      A6XX_TEX_SAMP_0_WRAP_T(tu6_tex_wrap(pCreateInfo->addressModeV)) |
+      A6XX_TEX_SAMP_0_WRAP_R(tu6_tex_wrap(pCreateInfo->addressModeW)) |
+      A6XX_TEX_SAMP_0_LOD_BIAS(pCreateInfo->mipLodBias);
+   sampler->descriptor[1] =
+      /* COND(!cso->seamless_cube_map, A6XX_TEX_SAMP_1_CUBEMAPSEAMLESSFILTOFF) | */
+      COND(pCreateInfo->unnormalizedCoordinates, A6XX_TEX_SAMP_1_UNNORM_COORDS) |
+      A6XX_TEX_SAMP_1_MIN_LOD(min_lod) |
+      A6XX_TEX_SAMP_1_MAX_LOD(max_lod) |
+      COND(pCreateInfo->compareEnable,
+           A6XX_TEX_SAMP_1_COMPARE_FUNC(tu6_compare_func(pCreateInfo->compareOp)));
+   sampler->descriptor[2] = A6XX_TEX_SAMP_2_BCOLOR(border_color);
+   sampler->descriptor[3] = 0;
+
+   if (reduction) {
+      sampler->descriptor[2] |= A6XX_TEX_SAMP_2_REDUCTION_MODE(
+         tu6_reduction_mode(reduction->reductionMode));
+   }
+
+   sampler->ycbcr_sampler = ycbcr_conversion ?
+      tu_sampler_ycbcr_conversion_from_handle(ycbcr_conversion->conversion) : NULL;
+
+   if (sampler->ycbcr_sampler &&
+       sampler->ycbcr_sampler->chroma_filter == VK_FILTER_LINEAR) {
+      sampler->descriptor[2] |= A6XX_TEX_SAMP_2_CHROMA_LINEAR;
+   }
+
+   /* TODO:
+    * A6XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR disables mipmapping, but vk has no NONE mipfilter?
+    */
 }
 
 VkResult
 tu_CreateSampler(VkDevice _device,
-                  const VkSamplerCreateInfo *pCreateInfo,
-                  const VkAllocationCallbacks *pAllocator,
-                  VkSampler *pSampler)
+                 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);
+   sampler = vk_object_alloc(&device->vk, pAllocator, sizeof(*sampler),
+                             VK_OBJECT_TYPE_SAMPLER);
    if (!sampler)
       return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
 
@@ -1791,15 +1977,27 @@ tu_CreateSampler(VkDevice _device,
 
 void
 tu_DestroySampler(VkDevice _device,
-                   VkSampler _sampler,
-                   const VkAllocationCallbacks *pAllocator)
+                  VkSampler _sampler,
+                  const VkAllocationCallbacks *pAllocator)
 {
    TU_FROM_HANDLE(tu_device, device, _device);
    TU_FROM_HANDLE(tu_sampler, sampler, _sampler);
+   uint32_t border_color;
 
    if (!sampler)
       return;
-   vk_free2(&device->alloc, pAllocator, sampler);
+
+   border_color = (sampler->descriptor[2] & A6XX_TEX_SAMP_2_BCOLOR__MASK) >> A6XX_TEX_SAMP_2_BCOLOR__SHIFT;
+   if (border_color >= TU_BORDER_COLOR_BUILTIN) {
+      border_color -= TU_BORDER_COLOR_BUILTIN;
+      /* if the sampler had a custom border color, free it. TODO: no lock */
+      mtx_lock(&device->mutex);
+      assert(!BITSET_TEST(device->custom_border_color, border_color));
+      BITSET_SET(device->custom_border_color, border_color);
+      mtx_unlock(&device->mutex);
+   }
+
+   vk_object_free(&device->vk, pAllocator, sampler);
 }
 
 /* vk_icd.h does not declare this function, so we declare it here to
@@ -1812,56 +2010,100 @@ 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.
-   */
+    * <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)
+VkResult
+tu_GetMemoryFdKHR(VkDevice _device,
+                  const VkMemoryGetFdInfoKHR *pGetFdInfo,
+                  int *pFd)
+{
+   TU_FROM_HANDLE(tu_device, device, _device);
+   TU_FROM_HANDLE(tu_device_memory, memory, pGetFdInfo->memory);
+
+   assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR);
+
+   /* At the moment, we support only the below handle types. */
+   assert(pGetFdInfo->handleType ==
+             VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
+          pGetFdInfo->handleType ==
+             VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
+
+   int prime_fd = tu_bo_export_dmabuf(device, &memory->bo);
+   if (prime_fd < 0)
+      return vk_error(device->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY);
+
+   *pFd = prime_fd;
+   return VK_SUCCESS;
+}
+
+VkResult
+tu_GetMemoryFdPropertiesKHR(VkDevice _device,
+                            VkExternalMemoryHandleTypeFlagBits handleType,
+                            int fd,
+                            VkMemoryFdPropertiesKHR *pMemoryFdProperties)
 {
-   pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
-   pExternalSemaphoreProperties->compatibleHandleTypes = 0;
-   pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
+   assert(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
+   pMemoryFdProperties->memoryTypeBits = 1;
+   return VK_SUCCESS;
+}
+
+VkResult
+tu_ImportFenceFdKHR(VkDevice _device,
+                    const VkImportFenceFdInfoKHR *pImportFenceFdInfo)
+{
+   tu_stub();
+
+   return VK_SUCCESS;
+}
+
+VkResult
+tu_GetFenceFdKHR(VkDevice _device,
+                 const VkFenceGetFdInfoKHR *pGetFdInfo,
+                 int *pFd)
+{
+   tu_stub();
+
+   return VK_SUCCESS;
 }
 
 void
 tu_GetPhysicalDeviceExternalFenceProperties(
-  VkPhysicalDevice physicalDevice,
-  const VkPhysicalDeviceExternalFenceInfoKHR *pExternalFenceInfo,
-  VkExternalFencePropertiesKHR *pExternalFenceProperties)
+   VkPhysicalDevice physicalDevice,
+   const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo,
+   VkExternalFenceProperties *pExternalFenceProperties)
 {
    pExternalFenceProperties->exportFromImportedHandleTypes = 0;
    pExternalFenceProperties->compatibleHandleTypes = 0;
@@ -1870,59 +2112,49 @@ tu_GetPhysicalDeviceExternalFenceProperties(
 
 VkResult
 tu_CreateDebugReportCallbackEXT(
-  VkInstance _instance,
-  const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-  const VkAllocationCallbacks *pAllocator,
-  VkDebugReportCallbackEXT *pCallback)
+   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);
+                                          pCreateInfo, pAllocator,
+                                          &instance->alloc, pCallback);
 }
 
 void
 tu_DestroyDebugReportCallbackEXT(VkInstance _instance,
-                                  VkDebugReportCallbackEXT _callback,
-                                  const VkAllocationCallbacks *pAllocator)
+                                 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);
+                                    _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)
+                         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);
+   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)
+   VkDevice device,
+   uint32_t heapIndex,
+   uint32_t localDeviceIndex,
+   uint32_t remoteDeviceIndex,
+   VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)
 {
    assert(localDeviceIndex == remoteDeviceIndex);
 
@@ -1931,3 +2163,69 @@ tu_GetDeviceGroupPeerMemoryFeatures(
                           VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT |
                           VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT;
 }
+
+void tu_GetPhysicalDeviceMultisamplePropertiesEXT(
+   VkPhysicalDevice                            physicalDevice,
+   VkSampleCountFlagBits                       samples,
+   VkMultisamplePropertiesEXT*                 pMultisampleProperties)
+{
+   TU_FROM_HANDLE(tu_physical_device, pdevice, physicalDevice);
+
+   if (samples <= VK_SAMPLE_COUNT_4_BIT && pdevice->supported_extensions.EXT_sample_locations)
+      pMultisampleProperties->maxSampleLocationGridSize = (VkExtent2D){ 1, 1 };
+   else
+      pMultisampleProperties->maxSampleLocationGridSize = (VkExtent2D){ 0, 0 };
+}
+
+
+VkResult
+tu_CreatePrivateDataSlotEXT(VkDevice _device,
+                            const VkPrivateDataSlotCreateInfoEXT* pCreateInfo,
+                            const VkAllocationCallbacks* pAllocator,
+                            VkPrivateDataSlotEXT* pPrivateDataSlot)
+{
+   TU_FROM_HANDLE(tu_device, device, _device);
+   return vk_private_data_slot_create(&device->vk,
+                                      pCreateInfo,
+                                      pAllocator,
+                                      pPrivateDataSlot);
+}
+
+void
+tu_DestroyPrivateDataSlotEXT(VkDevice _device,
+                             VkPrivateDataSlotEXT privateDataSlot,
+                             const VkAllocationCallbacks* pAllocator)
+{
+   TU_FROM_HANDLE(tu_device, device, _device);
+   vk_private_data_slot_destroy(&device->vk, privateDataSlot, pAllocator);
+}
+
+VkResult
+tu_SetPrivateDataEXT(VkDevice _device,
+                     VkObjectType objectType,
+                     uint64_t objectHandle,
+                     VkPrivateDataSlotEXT privateDataSlot,
+                     uint64_t data)
+{
+   TU_FROM_HANDLE(tu_device, device, _device);
+   return vk_object_base_set_private_data(&device->vk,
+                                          objectType,
+                                          objectHandle,
+                                          privateDataSlot,
+                                          data);
+}
+
+void
+tu_GetPrivateDataEXT(VkDevice _device,
+                     VkObjectType objectType,
+                     uint64_t objectHandle,
+                     VkPrivateDataSlotEXT privateDataSlot,
+                     uint64_t* pData)
+{
+   TU_FROM_HANDLE(tu_device, device, _device);
+   vk_object_base_get_private_data(&device->vk,
+                                   objectType,
+                                   objectHandle,
+                                   privateDataSlot,
+                                   pData);
+}