From 02a44484f01848775642661c4dd38dfd56f6c345 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Jan 2017 08:34:59 +0100 Subject: [PATCH] i965: Move the pipelined test for SO register access to the screen 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 Reviewed-by: Kenneth Graunke --- src/mesa/drivers/dri/i965/brw_context.c | 2 + src/mesa/drivers/dri/i965/intel_extensions.c | 73 --------------- src/mesa/drivers/dri/i965/intel_screen.c | 93 ++++++++++++++++++++ src/mesa/drivers/dri/i965/intel_screen.h | 8 ++ 4 files changed, 103 insertions(+), 73 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c index 3f3da7d2009..6b390b71f49 100644 --- a/src/mesa/drivers/dri/i965/brw_context.c +++ b/src/mesa/drivers/dri/i965/brw_context.c @@ -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); diff --git a/src/mesa/drivers/dri/i965/intel_extensions.c b/src/mesa/drivers/dri/i965/intel_extensions.c index 1ecefc19449..17fbc37c1dd 100644 --- a/src/mesa/drivers/dri/i965/intel_extensions.c +++ b/src/mesa/drivers/dri/i965/intel_extensions.c @@ -29,77 +29,6 @@ #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; diff --git a/src/mesa/drivers/dri/i965/intel_screen.c b/src/mesa/drivers/dri/i965/intel_screen.c index d0e3ac6875e..758a328ab78 100644 --- a/src/mesa/drivers/dri/i965/intel_screen.c +++ b/src/mesa/drivers/dri/i965/intel_screen.c @@ -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 = diff --git a/src/mesa/drivers/dri/i965/intel_screen.h b/src/mesa/drivers/dri/i965/intel_screen.h index 51c1d4e3dbd..62fde036269 100644 --- a/src/mesa/drivers/dri/i965/intel_screen.h +++ b/src/mesa/drivers/dri/i965/intel_screen.h @@ -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; /** -- 2.30.2