i965: Move the pipelined test for SO register access to the screen
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 4 Jan 2017 07:34:59 +0000 (08:34 +0100)
committerIago Toral Quiroga <itoral@igalia.com>
Thu, 5 Jan 2017 07:43:46 +0000 (08:43 +0100)
Moving the test to the screen places it alongside the other global HW
feature tests that want to be shared between contexts.

Also, we need to know if we support pipelined register writes at
screen creation time so that we can tell if we can expose OpenGL 4.0
in gen7.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/mesa/drivers/dri/i965/brw_context.c
src/mesa/drivers/dri/i965/intel_extensions.c
src/mesa/drivers/dri/i965/intel_screen.c
src/mesa/drivers/dri/i965/intel_screen.h

index 3f3da7d20096057aeaaf5de1ecb15600c44e37f0..6b390b71f49163c6375db57649fadd3cfd705ec8 100644 (file)
@@ -983,6 +983,8 @@ brwCreateContext(gl_api api,
 
    brw->must_use_separate_stencil = devinfo->must_use_separate_stencil;
    brw->has_swizzling = screen->hw_has_swizzling;
+   brw->can_do_pipelined_register_writes =
+      screen->hw_has_pipelined_register & HW_HAS_PIPELINED_SOL_OFFSET;
 
    isl_device_init(&brw->isl_dev, devinfo, screen->hw_has_swizzling);
 
index 1ecefc194498ae2feedf8d1f541cf78e3de7cc49..17fbc37c1ddcdf3979b5de913164351812f2bef5 100644 (file)
 #include "brw_defines.h"
 #include "intel_batchbuffer.h"
 
-/**
- * Test if we can use MI_LOAD_REGISTER_MEM from an untrusted batchbuffer.
- *
- * Some combinations of hardware and kernel versions allow this feature,
- * while others don't.  Instead of trying to enumerate every case, just
- * try and write a register and see if works.
- */
-static bool
-can_do_pipelined_register_writes(struct brw_context *brw)
-{
-   /**
-    * gen >= 8 specifically allows these writes. gen <= 6 also
-    * doesn't block them.
-    */
-   if (brw->gen != 7)
-      return true;
-
-   static int result = -1;
-   if (result != -1)
-      return result;
-
-   /* We use SO_WRITE_OFFSET0 since you're supposed to write it (unlike the
-    * statistics registers), and we already reset it to zero before using it.
-    */
-   const int reg = GEN7_SO_WRITE_OFFSET(0);
-   const int expected_value = 0x1337d0d0;
-   const int offset = 100;
-
-   /* The register we picked only exists on Gen7+. */
-   assert(brw->gen == 7);
-
-   uint32_t *data;
-   /* Set a value in a BO to a known quantity.  The workaround BO already
-    * exists and doesn't contain anything important, so we may as well use it.
-    */
-   drm_intel_bo_map(brw->workaround_bo, true);
-   data = brw->workaround_bo->virtual;
-   data[offset] = 0xffffffff;
-   drm_intel_bo_unmap(brw->workaround_bo);
-
-   /* Write the register. */
-   BEGIN_BATCH(3);
-   OUT_BATCH(MI_LOAD_REGISTER_IMM | (3 - 2));
-   OUT_BATCH(reg);
-   OUT_BATCH(expected_value);
-   ADVANCE_BATCH();
-
-   brw_emit_mi_flush(brw);
-
-   /* Save the register's value back to the buffer. */
-   BEGIN_BATCH(3);
-   OUT_BATCH(MI_STORE_REGISTER_MEM | (3 - 2));
-   OUT_BATCH(reg);
-   OUT_RELOC(brw->workaround_bo,
-             I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
-             offset * sizeof(uint32_t));
-   ADVANCE_BATCH();
-
-   intel_batchbuffer_flush(brw);
-
-   /* Check whether the value got written. */
-   drm_intel_bo_map(brw->workaround_bo, false);
-   data = brw->workaround_bo->virtual;
-   bool success = data[offset] == expected_value;
-   drm_intel_bo_unmap(brw->workaround_bo);
-
-   result = success;
-
-   return success;
-}
-
 /**
  * Initializes potential list of extensions if ctx == NULL, or actually enables
  * extensions for a context.
@@ -267,8 +196,6 @@ intelInitExtensions(struct gl_context *ctx)
    }
 
    brw->predicate.supported = false;
-   brw->can_do_pipelined_register_writes =
-      can_do_pipelined_register_writes(brw);
 
    if (brw->gen >= 7) {
       ctx->Extensions.ARB_conservative_depth = true;
index d0e3ac6875e4b62b26f02d976390ac81e92305ee..758a328ab789b53d53556956439e5d33947dda45 100644 (file)
@@ -1271,6 +1271,96 @@ intel_detect_timestamp(struct intel_screen *screen)
    return 0;
 }
 
+ /**
+ * Test if we can use MI_LOAD_REGISTER_MEM from an untrusted batchbuffer.
+ *
+ * Some combinations of hardware and kernel versions allow this feature,
+ * while others don't.  Instead of trying to enumerate every case, just
+ * try and write a register and see if works.
+ */
+static bool
+intel_detect_pipelined_register(struct intel_screen *screen,
+                                int reg, uint32_t expected_value, bool reset)
+{
+   drm_intel_bo *results, *bo;
+   uint32_t *batch;
+   uint32_t offset = 0;
+   bool success = false;
+
+   /* Create a zero'ed temporary buffer for reading our results */
+   results = drm_intel_bo_alloc(screen->bufmgr, "registers", 4096, 0);
+   if (results == NULL)
+      goto err;
+
+   bo = drm_intel_bo_alloc(screen->bufmgr, "batchbuffer", 4096, 0);
+   if (bo == NULL)
+      goto err_results;
+
+   if (drm_intel_bo_map(bo, 1))
+      goto err_batch;
+
+   batch = bo->virtual;
+
+   /* Write the register. */
+   *batch++ = MI_LOAD_REGISTER_IMM | (3 - 2);
+   *batch++ = reg;
+   *batch++ = expected_value;
+
+   /* Save the register's value back to the buffer. */
+   *batch++ = MI_STORE_REGISTER_MEM | (3 - 2);
+   *batch++ = reg;
+   drm_intel_bo_emit_reloc(bo, (char *)batch -(char *)bo->virtual,
+                           results, offset*sizeof(uint32_t),
+                           I915_GEM_DOMAIN_INSTRUCTION,
+                           I915_GEM_DOMAIN_INSTRUCTION);
+   *batch++ = results->offset + offset*sizeof(uint32_t);
+
+   /* And afterwards clear the register */
+   if (reset) {
+      *batch++ = MI_LOAD_REGISTER_IMM | (3 - 2);
+      *batch++ = reg;
+      *batch++ = 0;
+   }
+
+   *batch++ = MI_BATCH_BUFFER_END;
+
+   drm_intel_bo_mrb_exec(bo, ALIGN((char *)batch - (char *)bo->virtual, 8),
+                         NULL, 0, 0,
+                         I915_EXEC_RENDER);
+
+   /* Check whether the value got written. */
+   if (drm_intel_bo_map(results, false) == 0) {
+      success = *((uint32_t *)results->virtual + offset) == expected_value;
+      drm_intel_bo_unmap(results);
+   }
+
+err_batch:
+   drm_intel_bo_unreference(bo);
+err_results:
+   drm_intel_bo_unreference(results);
+err:
+   return success;
+}
+
+static bool
+intel_detect_pipelined_so(struct intel_screen *screen)
+{
+   /* Supposedly, Broadwell just works. */
+   if (screen->devinfo.gen >= 8)
+      return true;
+
+   if (screen->devinfo.gen <= 6)
+      return false;
+
+   /* We use SO_WRITE_OFFSET0 since you're supposed to write it (unlike the
+    * statistics registers), and we already reset it to zero before using it.
+    */
+   return intel_detect_pipelined_register(screen,
+                                          GEN7_SO_WRITE_OFFSET(0),
+                                          0x1337d0d0,
+                                          false);
+}
+
 /**
  * Return array of MSAA modes supported by the hardware. The array is
  * zero-terminated and sorted in decreasing order.
@@ -1643,6 +1733,9 @@ __DRIconfig **intelInitScreen2(__DRIscreen *dri_screen)
       screen->subslice_total = 1 << (screen->devinfo.gt - 1);
    }
 
+   if (intel_detect_pipelined_so(screen))
+      screen->hw_has_pipelined_register |= HW_HAS_PIPELINED_SOL_OFFSET;
+
    const char *force_msaa = getenv("INTEL_FORCE_MSAA");
    if (force_msaa) {
       screen->winsys_msaa_samples_override =
index 51c1d4e3dbdd8a4a61510df9f15ad8d733b0710a..62fde0362695b07367e9e5211f4d9a34001739f1 100644 (file)
@@ -68,6 +68,14 @@ struct intel_screen
     */
    bool has_context_reset_notification;
 
+   /**
+    * Does the kernel support pipelined register access?
+    * Due to whitelisting we need to do seperate checks
+    * for each register.
+    */
+   unsigned hw_has_pipelined_register;
+#define HW_HAS_PIPELINED_SOL_OFFSET (1<<0)
+
    dri_bufmgr *bufmgr;
 
    /**