diff --git a/include/vkd3d_d3d12.idl b/include/vkd3d_d3d12.idl
index 06287f5a8e4ef9faeb985f42013906a0d9dca368..9af75f40291a7e2a79968cdbcd13ae99c9c157cc 100644
--- a/include/vkd3d_d3d12.idl
+++ b/include/vkd3d_d3d12.idl
@@ -72,6 +72,7 @@ const UINT D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT = 4096;
 const UINT D3D12_STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE = 4;
 const UINT D3D12_TEXTURE_DATA_PITCH_ALIGNMENT = 256;
 const UINT D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT = 512;
+const UINT D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES = 65536;
 const UINT D3D12_UAV_COUNTER_PLACEMENT_ALIGNMENT = 4096;
 const UINT D3D12_VS_INPUT_REGISTER_COUNT = 32;
 const UINT D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE = 16;
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
index 025a60fcef10a59b088f18fd5eabd68b74c760bc..a8cfffcd7a4ac9fc8497d0eccda34d784605f84c 100644
--- a/libs/vkd3d/device.c
+++ b/libs/vkd3d/device.c
@@ -3893,12 +3893,18 @@ static void STDMETHODCALLTYPE d3d12_device_GetResourceTiling(ID3D12Device *iface
         UINT *sub_resource_tiling_count, UINT first_sub_resource_tiling,
         D3D12_SUBRESOURCE_TILING *sub_resource_tilings)
 {
-    FIXME("iface %p, resource %p, total_tile_count %p, packed_mip_info %p, "
+    const struct d3d12_resource *resource_impl = impl_from_ID3D12Resource(resource);
+    struct d3d12_device *device = impl_from_ID3D12Device(iface);
+
+    TRACE("iface %p, resource %p, total_tile_count %p, packed_mip_info %p, "
             "standard_title_shape %p, sub_resource_tiling_count %p, "
-            "first_sub_resource_tiling %u, sub_resource_tilings %p stub!\n",
+            "first_sub_resource_tiling %u, sub_resource_tilings %p.\n",
             iface, resource, total_tile_count, packed_mip_info, standard_tile_shape,
             sub_resource_tiling_count, first_sub_resource_tiling,
             sub_resource_tilings);
+
+    d3d12_resource_get_tiling(device, resource_impl, total_tile_count, packed_mip_info, standard_tile_shape,
+            sub_resource_tiling_count, first_sub_resource_tiling, sub_resource_tilings);
 }
 
 static LUID * STDMETHODCALLTYPE d3d12_device_GetAdapterLuid(ID3D12Device *iface, LUID *luid)
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c
index f2fe12502acaec90286e71e287e0c1aa4e4590d4..7550e21ffadbdeeef4073c10feb62719210fd9bb 100644
--- a/libs/vkd3d/resource.c
+++ b/libs/vkd3d/resource.c
@@ -971,6 +971,11 @@ HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device,
     return hr;
 }
 
+static void d3d12_resource_tile_info_cleanup(struct d3d12_resource *resource)
+{
+    vkd3d_free(resource->tiles.subresources);
+}
+
 static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12_device *device)
 {
     const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
@@ -986,6 +991,8 @@ static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12
     else
         VK_CALL(vkDestroyImage(device->vk_device, resource->u.vk_image, NULL));
 
+    d3d12_resource_tile_info_cleanup(resource);
+
     if (resource->heap)
         d3d12_heap_resource_destroyed(resource->heap);
 }
@@ -1057,9 +1064,101 @@ static void d3d12_resource_get_level_box(const struct d3d12_resource *resource,
     box->back = d3d12_resource_desc_get_depth(&resource->desc, level);
 }
 
-static void d3d12_resource_init_tiles(struct d3d12_resource *resource)
+void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_resource *resource,
+        UINT *total_tile_count, D3D12_PACKED_MIP_INFO *packed_mip_info, D3D12_TILE_SHAPE *standard_tile_shape,
+        UINT *subresource_tiling_count, UINT first_subresource_tiling,
+        D3D12_SUBRESOURCE_TILING *subresource_tilings)
 {
-    resource->tiles.subresource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc);
+    unsigned int i, subresource, subresource_count, count;
+    const struct vkd3d_subresource_tile_info *tile_info;
+    const VkExtent3D *tile_extent;
+
+    if (d3d12_resource_is_texture(resource))
+    {
+        FIXME("Not implemented for textures.\n");
+        return;
+    }
+
+    tile_extent = &resource->tiles.tile_extent;
+
+    if (packed_mip_info)
+    {
+        packed_mip_info->NumStandardMips = resource->tiles.standard_mip_count;
+        packed_mip_info->NumPackedMips = 0;
+        packed_mip_info->NumTilesForPackedMips = 0;
+        packed_mip_info->StartTileIndexInOverallResource = 0;
+    }
+
+    if (standard_tile_shape)
+    {
+        /* D3D12 docs say tile shape is cleared to zero if there is no standard mip, but drivers don't to do this. */
+        standard_tile_shape->WidthInTexels = tile_extent->width;
+        standard_tile_shape->HeightInTexels = tile_extent->height;
+        standard_tile_shape->DepthInTexels = tile_extent->depth;
+    }
+
+    if (total_tile_count)
+        *total_tile_count = resource->tiles.total_count;
+
+    if (!subresource_tiling_count)
+        return;
+
+    subresource_count = resource->tiles.subresource_count;
+
+    count = subresource_count - min(first_subresource_tiling, subresource_count);
+    count = min(count, *subresource_tiling_count);
+
+    for (i = 0; i < count; ++i)
+    {
+        subresource = i + first_subresource_tiling;
+        tile_info = &resource->tiles.subresources[subresource];
+        subresource_tilings[i].StartTileIndexInOverallResource = tile_info->offset;
+        subresource_tilings[i].WidthInTiles = tile_info->extent.width;
+        subresource_tilings[i].HeightInTiles = tile_info->extent.height;
+        subresource_tilings[i].DepthInTiles = tile_info->extent.depth;
+    }
+    *subresource_tiling_count = i;
+}
+
+static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3d12_device *device)
+{
+    const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+    struct vkd3d_subresource_tile_info *tile_info;
+    VkMemoryRequirements requirements;
+    unsigned int subresource_count;
+
+    subresource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc);
+
+    if (d3d12_resource_is_buffer(resource))
+    {
+        assert(subresource_count == 1);
+        if (!(resource->tiles.subresources = vkd3d_calloc(subresource_count, sizeof(*resource->tiles.subresources))))
+        {
+            ERR("Failed to allocate subresource info array.\n");
+            return false;
+        }
+
+        VK_CALL(vkGetBufferMemoryRequirements(device->vk_device, resource->u.vk_buffer, &requirements));
+        if (requirements.alignment > D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES)
+            FIXME("Vulkan device tile size is greater than the standard D3D12 tile size.\n");
+
+        tile_info = &resource->tiles.subresources[0];
+        tile_info->offset = 0;
+        tile_info->extent.width = align(resource->desc.Width, D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES)
+                / D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES;
+        tile_info->extent.height = 1;
+        tile_info->extent.depth = 1;
+        tile_info->count = tile_info->extent.width;
+
+        resource->tiles.tile_extent.width = D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES;
+        resource->tiles.tile_extent.height = 1;
+        resource->tiles.tile_extent.depth = 1;
+        resource->tiles.total_count = tile_info->extent.width;
+        resource->tiles.subresource_count = 1;
+        resource->tiles.standard_mip_count = 1;
+    }
+
+    return true;
 }
 
 /* ID3D12Resource */
@@ -2013,7 +2112,11 @@ HRESULT d3d12_reserved_resource_create(struct d3d12_device *device,
             desc, initial_state, optimized_clear_value, &object)))
         return hr;
 
-    d3d12_resource_init_tiles(object);
+    if (!d3d12_resource_init_tiles(object, device))
+    {
+        d3d12_resource_Release(&object->ID3D12Resource_iface);
+        return E_OUTOFMEMORY;
+    }
 
     TRACE("Created reserved resource %p.\n", object);
 
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index a5eed59a96028ea2f9522148b1a79db98232c97d..4f9177d21f1bff604ec33e2760e738c80b792b01 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -687,9 +687,27 @@ struct d3d12_heap *unsafe_impl_from_ID3D12Heap(ID3D12Heap *iface);
 #define VKD3D_RESOURCE_DEDICATED_HEAP 0x00000008
 #define VKD3D_RESOURCE_LINEAR_TILING  0x00000010
 
+struct vkd3d_tiled_region_extent
+{
+    unsigned int width;
+    unsigned int height;
+    unsigned int depth;
+};
+
+struct vkd3d_subresource_tile_info
+{
+    unsigned int offset;
+    unsigned int count;
+    struct vkd3d_tiled_region_extent extent;
+};
+
 struct d3d12_resource_tile_info
 {
+    VkExtent3D tile_extent;
+    unsigned int total_count;
+    unsigned int standard_mip_count;
     unsigned int subresource_count;
+    struct vkd3d_subresource_tile_info *subresources;
 };
 
 /* ID3D12Resource */
@@ -742,6 +760,10 @@ static inline bool d3d12_resource_is_texture(const struct d3d12_resource *resour
 
 bool d3d12_resource_is_cpu_accessible(const struct d3d12_resource *resource);
 HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC *desc, struct d3d12_device *device);
+void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_resource *resource,
+        UINT *total_tile_count, D3D12_PACKED_MIP_INFO *packed_mip_info, D3D12_TILE_SHAPE *standard_tile_shape,
+        UINT *sub_resource_tiling_count, UINT first_sub_resource_tiling,
+        D3D12_SUBRESOURCE_TILING *sub_resource_tilings);
 
 HRESULT d3d12_committed_resource_create(struct d3d12_device *device,
         const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,