summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Graunke <kenneth@whitecape.org>2013-05-27 20:09:56 -0700
committerKenneth Graunke <kenneth@whitecape.org>2013-10-31 11:04:37 -0700
commit129da5b1c87e4fd45b117a092e5d022ad7041e66 (patch)
treeb0ad4ee60abe48e5c3d93f59876eddd67f7cee95
parent46d3c2bf4ddd227193b98861f1e632498fe547d8 (diff)
i965: Enable ARB_transform_feedback2 on Gen7+ if register writes work.
With Linux 3.12, register writes work on Ivybridge and Baytrail, but not Haswell. That will be fixed in a future kernel revision, at which point this extension will automatically be enabled. v2: Use I915_GEM_DOMAIN_INSTRUCTION for the register read, and also correctly set the writeable flag when mapping (caught by Eric). Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Eric Anholt <eric@anholt.net>
-rw-r--r--src/mesa/drivers/dri/i965/intel_extensions.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/src/mesa/drivers/dri/i965/intel_extensions.c b/src/mesa/drivers/dri/i965/intel_extensions.c
index 22e4aa2c5ad..337e7e87c4f 100644
--- a/src/mesa/drivers/dri/i965/intel_extensions.c
+++ b/src/mesa/drivers/dri/i965/intel_extensions.c
@@ -28,11 +28,68 @@
#include "main/version.h"
#include "brw_context.h"
-#include "intel_chipset.h"
+#include "intel_batchbuffer.h"
#include "intel_reg.h"
#include "utils.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)
+{
+ /* 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->batch.workaround_bo, true);
+ data = brw->batch.workaround_bo->virtual;
+ data[offset] = 0xffffffff;
+ drm_intel_bo_unmap(brw->batch.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();
+
+ intel_batchbuffer_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->batch.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->batch.workaround_bo, false);
+ bool success = data[offset] == expected_value;
+ drm_intel_bo_unmap(brw->batch.workaround_bo);
+
+ return success;
+}
+
+/**
* Initializes potential list of extensions if ctx == NULL, or actually enables
* extensions for a context.
*/
@@ -171,6 +228,9 @@ intelInitExtensions(struct gl_context *ctx)
if (brw->gen >= 7) {
ctx->Extensions.ARB_texture_gather = true;
ctx->Extensions.ARB_conservative_depth = true;
+ if (can_do_pipelined_register_writes(brw)) {
+ ctx->Extensions.ARB_transform_feedback2 = true;
+ }
}
if (ctx->API == API_OPENGL_CORE)