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 <chris@chris-wilson.co.uk>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
Chris Wilson 2017-01-04 08:34:59 +01:00 committed by Iago Toral Quiroga
parent ab1ec7de93
commit 02a44484f0
4 changed files with 103 additions and 73 deletions

View 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);

View File

@ -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;

View 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 =

View 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;
/**