Mesa (master): anv: Add support for 48-bit addresses

Jason Ekstrand jekstrand at kemper.freedesktop.org
Wed Apr 5 01:34:56 UTC 2017


Module: Mesa
Branch: master
Commit: 651ec926fc10258ddc567da44c231d5303b8740f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=651ec926fc10258ddc567da44c231d5303b8740f

Author: Jason Ekstrand <jason.ekstrand at intel.com>
Date:   Fri Mar 17 17:31:44 2017 -0700

anv: Add support for 48-bit addresses

This commit adds support for using the full 48-bit address space on
Broadwell and newer hardware.  Thanks to certain limitations, not all
objects can be placed above the 32-bit boundary.  In particular, general
and state base address need to live within 32 bits.  (See also
Wa32bitGeneralStateOffset and Wa32bitInstructionBaseOffset.)  In order
to handle this, we add a supports_48bit_address field to anv_bo and only
set EXEC_OBJECT_SUPPORTS_48B_ADDRESS if that bit is set.  We set the bit
for all client-allocated memory objects but leave it false for
driver-allocated objects.  While this is more conservative than needed,
all driver allocations should easily fit in the first 32 bits of address
space and keeps things simple because we don't have to think about
whether or not any given one of our allocation data structures will be
used in a 48-bit-unsafe way.

Reviewed-by: Kristian H. Kristensen <krh at bitplanet.net>

---

 src/intel/vulkan/anv_allocator.c | 26 ++++++++++++++++++++++++++
 src/intel/vulkan/anv_device.c    |  5 +++++
 src/intel/vulkan/anv_gem.c       | 18 ++++++++++++++++++
 src/intel/vulkan/anv_intel.c     |  3 +++
 src/intel/vulkan/anv_private.h   |  2 ++
 5 files changed, 54 insertions(+)

diff --git a/src/intel/vulkan/anv_allocator.c b/src/intel/vulkan/anv_allocator.c
index 45c663b670..78327df343 100644
--- a/src/intel/vulkan/anv_allocator.c
+++ b/src/intel/vulkan/anv_allocator.c
@@ -475,6 +475,32 @@ anv_block_pool_grow(struct anv_block_pool *pool, struct anv_block_state *state)
     * values back into pool. */
    pool->map = map + center_bo_offset;
    pool->center_bo_offset = center_bo_offset;
+
+   /* For block pool BOs we have to be a bit careful about where we place them
+    * in the GTT.  There are two documented workarounds for state base address
+    * placement : Wa32bitGeneralStateOffset and Wa32bitInstructionBaseOffset
+    * which state that those two base addresses do not support 48-bit
+    * addresses and need to be placed in the bottom 32-bit range.
+    * Unfortunately, this is not quite accurate.
+    *
+    * The real problem is that we always set the size of our state pools in
+    * STATE_BASE_ADDRESS to 0xfffff (the maximum) even though the BO is most
+    * likely significantly smaller.  We do this because we do not no at the
+    * time we emit STATE_BASE_ADDRESS whether or not we will need to expand
+    * the pool during command buffer building so we don't actually have a
+    * valid final size.  If the address + size, as seen by STATE_BASE_ADDRESS
+    * overflows 48 bits, the GPU appears to treat all accesses to the buffer
+    * as being out of bounds and returns zero.  For dynamic state, this
+    * usually just leads to rendering corruptions, but shaders that are all
+    * zero hang the GPU immediately.
+    *
+    * The easiest solution to do is exactly what the bogus workarounds say to
+    * do: restrict these buffers to 32-bit addresses.  We could also pin the
+    * BO to some particular location of our choosing, but that's significantly
+    * more work than just not setting a flag.  So, we explicitly DO NOT set
+    * the EXEC_OBJECT_SUPPORTS_48B_ADDRESS flag and the kernel does all of the
+    * hard work for us.
+    */
    anv_bo_init(&pool->bo, gem_handle, size);
    pool->bo.map = map;
 
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 9e860d5189..22dd5d6bf3 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -149,6 +149,8 @@ anv_physical_device_init(struct anv_physical_device *device,
       goto fail;
    }
 
+   device->supports_48bit_addresses = anv_gem_supports_48b_addresses(fd);
+
    if (!anv_device_get_cache_uuid(device->uuid)) {
       result = vk_errorf(VK_ERROR_INITIALIZATION_FAILED,
                          "cannot generate UUID");
@@ -1452,6 +1454,9 @@ anv_bo_init_new(struct anv_bo *bo, struct anv_device *device, uint64_t size)
 
    anv_bo_init(bo, gem_handle, size);
 
+   if (device->instance->physicalDevice.supports_48bit_addresses)
+      bo->flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
+
    return VK_SUCCESS;
 }
 
diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c
index 7612f493aa..6a996ea3db 100644
--- a/src/intel/vulkan/anv_gem.c
+++ b/src/intel/vulkan/anv_gem.c
@@ -301,6 +301,24 @@ anv_gem_get_aperture(int fd, uint64_t *size)
    return 0;
 }
 
+bool
+anv_gem_supports_48b_addresses(int fd)
+{
+   struct drm_i915_gem_exec_object2 obj = {
+      .flags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS,
+   };
+
+   struct drm_i915_gem_execbuffer2 execbuf = {
+      .buffers_ptr = (uintptr_t)&obj,
+      .buffer_count = 1,
+      .rsvd1 = 0xffffffu,
+   };
+
+   int ret = anv_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+
+   return ret == -1 && errno == ENOENT;
+}
+
 int
 anv_gem_gpu_get_reset_stats(struct anv_device *device,
                             uint32_t *active, uint32_t *pending)
diff --git a/src/intel/vulkan/anv_intel.c b/src/intel/vulkan/anv_intel.c
index c356e848fe..eda474e62e 100644
--- a/src/intel/vulkan/anv_intel.c
+++ b/src/intel/vulkan/anv_intel.c
@@ -59,6 +59,9 @@ VkResult anv_CreateDmaBufImageINTEL(
 
    anv_bo_init(&mem->bo, gem_handle, size);
 
+   if (device->instance->physicalDevice.supports_48bit_addresses)
+      mem->bo.flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
+
    anv_image_create(_device,
       &(struct anv_image_create_info) {
          .isl_tiling_flags = ISL_TILING_X_BIT,
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index ee0f79b6dd..0338199915 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -517,6 +517,7 @@ struct anv_physical_device {
     const char *                                name;
     struct gen_device_info                      info;
     uint64_t                                    aperture_size;
+    bool                                        supports_48bit_addresses;
     struct brw_compiler *                       compiler;
     struct isl_device                           isl_dev;
     int                                         cmd_parser_version;
@@ -654,6 +655,7 @@ int anv_gem_destroy_context(struct anv_device *device, int context);
 int anv_gem_get_param(int fd, uint32_t param);
 bool anv_gem_get_bit6_swizzle(int fd, uint32_t tiling);
 int anv_gem_get_aperture(int fd, uint64_t *size);
+bool anv_gem_supports_48b_addresses(int fd);
 int anv_gem_gpu_get_reset_stats(struct anv_device *device,
                                 uint32_t *active, uint32_t *pending);
 int anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle);




More information about the mesa-commit mailing list