[Mesa-dev] [PATCH 8/9] i965: Implement ARB_query_buffer_object for HSW+
Kenneth Graunke
kenneth at whitecape.org
Wed Apr 27 06:25:12 UTC 2016
On Thursday, April 21, 2016 10:18:48 PM PDT Jordan Justen wrote:
> Signed-off-by: Jordan Justen <jordan.l.justen at intel.com>
> ---
> src/mesa/drivers/dri/i965/Makefile.sources | 1 +
> src/mesa/drivers/dri/i965/brw_context.c | 4 +-
> src/mesa/drivers/dri/i965/brw_context.h | 5 +
> src/mesa/drivers/dri/i965/brw_queryobj.c | 35 ++-
> src/mesa/drivers/dri/i965/gen6_queryobj.c | 33 ++
> src/mesa/drivers/dri/i965/hsw_queryobj.c | 432 ++++++++++++++++++++++++
+++
> src/mesa/drivers/dri/i965/intel_extensions.c | 4 +
> src/mesa/drivers/dri/i965/intel_reg.h | 1 +
> 8 files changed, 512 insertions(+), 3 deletions(-)
> create mode 100644 src/mesa/drivers/dri/i965/hsw_queryobj.c
>
> diff --git a/src/mesa/drivers/dri/i965/Makefile.sources b/src/mesa/drivers/
dri/i965/Makefile.sources
> index 632f2e9..66ecd37 100644
> --- a/src/mesa/drivers/dri/i965/Makefile.sources
> +++ b/src/mesa/drivers/dri/i965/Makefile.sources
> @@ -227,6 +227,7 @@ i965_FILES = \
> gen8_viewport_state.c \
> gen8_vs_state.c \
> gen8_wm_depth_stencil.c \
> + hsw_queryobj.c \
> intel_batchbuffer.c \
> intel_batchbuffer.h \
> intel_blit.c \
> diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/
i965/brw_context.c
> index 63ac3bc..1380d41 100644
> --- a/src/mesa/drivers/dri/i965/brw_context.c
> +++ b/src/mesa/drivers/dri/i965/brw_context.c
> @@ -358,7 +358,9 @@ brw_init_driver_functions(struct brw_context *brw,
>
> brwInitFragProgFuncs( functions );
> brw_init_common_queryobj_functions(functions);
> - if (brw->gen >= 6)
> + if (brw->gen >= 8 || brw->is_haswell)
> + hsw_init_queryobj_functions(functions);
> + else if (brw->gen >= 6)
> gen6_init_queryobj_functions(functions);
> else
> gen4_init_queryobj_functions(functions);
> diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/
i965/brw_context.h
> index 5a4e42b..b75eabd 100644
> --- a/src/mesa/drivers/dri/i965/brw_context.h
> +++ b/src/mesa/drivers/dri/i965/brw_context.h
> @@ -1425,12 +1425,17 @@ void brw_init_common_queryobj_functions(struct
dd_function_table *functions);
> void gen4_init_queryobj_functions(struct dd_function_table *functions);
> void brw_emit_query_begin(struct brw_context *brw);
> void brw_emit_query_end(struct brw_context *brw);
> +void brw_query_counter(struct gl_context *ctx, struct gl_query_object *q);
> +bool brw_is_query_pipelined(struct brw_query_object *query);
>
> /** gen6_queryobj.c */
> void gen6_init_queryobj_functions(struct dd_function_table *functions);
> void brw_write_timestamp(struct brw_context *brw, drm_intel_bo *bo, int
idx);
> void brw_write_depth_count(struct brw_context *brw, drm_intel_bo *bo, int
idx);
>
> +/** hsw_queryobj.c */
> +void hsw_init_queryobj_functions(struct dd_function_table *functions);
> +
> /** brw_conditional_render.c */
> void brw_init_conditional_render_functions(struct dd_function_table
*functions);
> bool brw_check_conditional_render(struct brw_context *brw);
> diff --git a/src/mesa/drivers/dri/i965/brw_queryobj.c b/src/mesa/drivers/
dri/i965/brw_queryobj.c
> index a8e5aba..81ee5ea 100644
> --- a/src/mesa/drivers/dri/i965/brw_queryobj.c
> +++ b/src/mesa/drivers/dri/i965/brw_queryobj.c
> @@ -462,7 +462,7 @@ brw_emit_query_end(struct brw_context *brw)
> * current GPU time. This is unlike GL_TIME_ELAPSED, which measures the
> * time while the query is active.
> */
> -static void
> +void
> brw_query_counter(struct gl_context *ctx, struct gl_query_object *q)
> {
> struct brw_context *brw = brw_context(ctx);
> @@ -507,12 +507,42 @@ brw_get_timestamp(struct gl_context *ctx)
> return result;
> }
>
> +bool
> +brw_is_query_pipelined(struct brw_query_object *query)
> +{
> + switch (query->Base.Target) {
> + case GL_TIMESTAMP:
> + case GL_TIME_ELAPSED:
> + case GL_ANY_SAMPLES_PASSED:
> + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
> + case GL_SAMPLES_PASSED_ARB:
> + return true;
> +
> + case GL_PRIMITIVES_GENERATED:
> + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
> + case GL_VERTICES_SUBMITTED_ARB:
> + case GL_PRIMITIVES_SUBMITTED_ARB:
> + case GL_VERTEX_SHADER_INVOCATIONS_ARB:
> + case GL_GEOMETRY_SHADER_INVOCATIONS:
> + case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
> + case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
> + case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
> + case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
> + case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
> + case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
> + case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
> + return false;
> +
> + default:
> + unreachable("Unrecognized query target in is_query_pipelined()");
> + }
> +}
> +
> /* Initialize query object functions used on all generations. */
> void brw_init_common_queryobj_functions(struct dd_function_table
*functions)
> {
> functions->NewQueryObject = brw_new_query_object;
> functions->DeleteQuery = brw_delete_query;
> - functions->QueryCounter = brw_query_counter;
> functions->GetTimestamp = brw_get_timestamp;
> }
>
> @@ -523,4 +553,5 @@ void gen4_init_queryobj_functions(struct
dd_function_table *functions)
> functions->EndQuery = brw_end_query;
> functions->CheckQuery = brw_check_query;
> functions->WaitQuery = brw_wait_query;
> + functions->QueryCounter = brw_query_counter;
> }
> diff --git a/src/mesa/drivers/dri/i965/gen6_queryobj.c b/src/mesa/drivers/
dri/i965/gen6_queryobj.c
> index 960ccfd..f95c9fc 100644
> --- a/src/mesa/drivers/dri/i965/gen6_queryobj.c
> +++ b/src/mesa/drivers/dri/i965/gen6_queryobj.c
> @@ -37,8 +37,25 @@
> #include "brw_defines.h"
> #include "brw_state.h"
> #include "intel_batchbuffer.h"
> +#include "intel_buffer_objects.h"
> #include "intel_reg.h"
>
> +static inline void
> +set_query_availability(struct brw_context *brw, struct brw_query_object
*query,
> + bool available)
> +{
> + /* For ARB_query_buffer_object we write the query availability for
> + * pipelined results
> + */
> + if (brw->ctx.Extensions.ARB_query_buffer_object &&
> + brw_is_query_pipelined(query)) {
> + brw_emit_pipe_control_write(brw,
> + PIPE_CONTROL_WRITE_IMMEDIATE,
> + query->bo, 2 * sizeof(uint64_t),
> + available, 0);
> + }
> +}
> +
> static void
> write_primitives_generated(struct brw_context *brw,
> drm_intel_bo *query_bo, int stream, int idx)
> @@ -243,6 +260,9 @@ gen6_begin_query(struct gl_context *ctx, struct
gl_query_object *q)
> drm_intel_bo_unreference(query->bo);
> query->bo = drm_intel_bo_alloc(brw->bufmgr, "query results", 4096,
4096);
>
> + /* For ARB_query_buffer_object: The result is not available */
> + set_query_availability(brw, query, false);
> +
> switch (query->Base.Target) {
> case GL_TIME_ELAPSED:
> /* For timestamp queries, we record the starting time right away so
that
> @@ -356,6 +376,9 @@ gen6_end_query(struct gl_context *ctx, struct
gl_query_object *q)
> * but they won't actually execute until it is flushed.
> */
> query->flushed = false;
> +
> + /* For ARB_query_buffer_object: The result is now available */
> + set_query_availability(brw, query, true);
> }
>
> /**
> @@ -425,6 +448,15 @@ static void gen6_check_query(struct gl_context *ctx,
struct gl_query_object *q)
> }
> }
>
> +static void
> +gen6_query_counter(struct gl_context *ctx, struct gl_query_object *q)
> +{
> + struct brw_context *brw = brw_context(ctx);
> + struct brw_query_object *query = (struct brw_query_object *)q;
> + brw_query_counter(ctx, q);
> + set_query_availability(brw, query, true);
> +}
> +
> /* Initialize Gen6+-specific query object functions. */
> void gen6_init_queryobj_functions(struct dd_function_table *functions)
> {
> @@ -432,4 +464,5 @@ void gen6_init_queryobj_functions(struct
dd_function_table *functions)
> functions->EndQuery = gen6_end_query;
> functions->CheckQuery = gen6_check_query;
> functions->WaitQuery = gen6_wait_query;
> + functions->QueryCounter = gen6_query_counter;
> }
> diff --git a/src/mesa/drivers/dri/i965/hsw_queryobj.c b/src/mesa/drivers/
dri/i965/hsw_queryobj.c
> new file mode 100644
> index 0000000..58c9a09
> --- /dev/null
> +++ b/src/mesa/drivers/dri/i965/hsw_queryobj.c
> @@ -0,0 +1,432 @@
> +/*
> + * Copyright (c) 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
"Software"),
> + * to deal in the Software without restriction, including without
limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
next
> + * paragraph) shall be included in all copies or substantial portions of
the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +/** @file hsw_queryobj.c
> + *
> + * Support for query buffer objects (GL_ARB_query_buffer_object) on Haswell
+.
> + */
> +#include "main/imports.h"
> +
> +#include "brw_context.h"
> +#include "brw_defines.h"
> +#include "intel_batchbuffer.h"
> +#include "intel_buffer_objects.h"
> +#include "intel_reg.h"
> +
> +/*
> + * GPR0 = 80 * GPR0;
> + */
> +static void
> +mult_gpr0_by_80(struct brw_context *brw)
> +{
> + int m;
> + uint32_t maths[] = {
> + MI_MATH_ALU2(LOAD, SRCA, R0),
> + MI_MATH_ALU2(LOAD, SRCB, R0),
> + MI_MATH_ALU0(ADD),
> + MI_MATH_ALU2(STORE, R1, ACCU),
> + MI_MATH_ALU2(LOAD, SRCA, R1),
> + MI_MATH_ALU2(LOAD, SRCB, R1),
> + MI_MATH_ALU0(ADD),
> + MI_MATH_ALU2(STORE, R1, ACCU),
> + MI_MATH_ALU2(LOAD, SRCA, R1),
> + MI_MATH_ALU2(LOAD, SRCB, R1),
> + MI_MATH_ALU0(ADD),
> + MI_MATH_ALU2(STORE, R1, ACCU),
> + MI_MATH_ALU2(LOAD, SRCA, R1),
> + MI_MATH_ALU2(LOAD, SRCB, R1),
> + MI_MATH_ALU0(ADD),
> + /* GPR1 = 16 * GPR0 */
> + MI_MATH_ALU2(STORE, R1, ACCU),
> + MI_MATH_ALU2(LOAD, SRCA, R1),
> + MI_MATH_ALU2(LOAD, SRCB, R1),
> + MI_MATH_ALU0(ADD),
> + MI_MATH_ALU2(STORE, R2, ACCU),
> + MI_MATH_ALU2(LOAD, SRCA, R2),
> + MI_MATH_ALU2(LOAD, SRCB, R2),
> + MI_MATH_ALU0(ADD),
> + /* GPR2 = 64 * GPR0 */
> + MI_MATH_ALU2(STORE, R2, ACCU),
> + MI_MATH_ALU2(LOAD, SRCA, R1),
> + MI_MATH_ALU2(LOAD, SRCB, R2),
> + MI_MATH_ALU0(ADD),
> + /* GPR0 = 80 * GPR0 */
> + MI_MATH_ALU2(STORE, R0, ACCU),
> + };
> +
> + BEGIN_BATCH(1 + ARRAY_SIZE(maths));
> + OUT_BATCH(HSW_MI_MATH | (1 + ARRAY_SIZE(maths) - 2));
> +
> + for (m = 0; m < ARRAY_SIZE(maths); m++)
> + OUT_BATCH(maths[m]);
> +
> + ADVANCE_BATCH();
> +}
> +
> +/*
> + * GPR0 = GPR0 & ((1ull << n) - 1);
> + */
> +static void
> +keep_gpr0_lower_n_bits(struct brw_context *brw, uint32_t n)
> +{
> + int m;
> + uint32_t maths[] = {
> + MI_MATH_ALU2(LOAD, SRCA, R0),
> + MI_MATH_ALU2(LOAD, SRCB, R1),
> + MI_MATH_ALU0(AND),
> + MI_MATH_ALU2(STORE, R0, ACCU),
> + };
> +
> + assert(n < 64);
> + brw_load_register_imm64(brw, HSW_CS_GPR(1), (1ull << n) - 1);
> +
> + BEGIN_BATCH(1 + ARRAY_SIZE(maths));
> + OUT_BATCH(HSW_MI_MATH | (1 + ARRAY_SIZE(maths) - 2));
> +
> + for (m = 0; m < ARRAY_SIZE(maths); m++)
> + OUT_BATCH(maths[m]);
> +
> + ADVANCE_BATCH();
> +}
> +
> +/*
> + * GPR0 = GPR0 << 30;
> + */
> +static void
> +shl_gpr0_by_30_bits(struct brw_context *brw)
> +{
> + /* First we mask 34 bits of GPR0 to prevent overflow */
> + keep_gpr0_lower_n_bits(brw, 34);
> +
> + uint32_t shl_maths[] = {
> + MI_MATH_ALU2(LOAD, SRCA, R0),
> + MI_MATH_ALU2(LOAD, SRCB, R0),
> + MI_MATH_ALU0(ADD),
> + MI_MATH_ALU2(STORE, R0, ACCU),
> + };
> +
> + const uint32_t outer_count = 5;
> + const uint32_t inner_count = 6;
> + STATIC_ASSERT(outer_count * inner_count == 30);
> + const uint32_t cmd_len = 1 + inner_count * ARRAY_SIZE(shl_maths);
> + const uint32_t batch_len = cmd_len * outer_count;
> +
> + BEGIN_BATCH(batch_len);
> +
> + /* We'll emit 5 commands, each shifting GPR0 left by 6 bits, for a total
of
> + * 30 left shifts.
> + */
> + for (int o = 0; o < outer_count; o++) {
> + /* Submit one MI_MATH to shift left by 6 bits */
> + OUT_BATCH(HSW_MI_MATH | (cmd_len - 2));
> + for (int i = 0; i < inner_count; i++)
> + for (int m = 0; m < ARRAY_SIZE(shl_maths); m++)
> + OUT_BATCH(shl_maths[m]);
> + }
> +
> + ADVANCE_BATCH();
> +}
> +
> +/*
> + * GPR0 = GPR0 >> 2;
> + *
> + * Note that the upper 30 bits of GPR0 are lost!
> + */
> +static void
> +shr_gpr0_by_2_bits(struct brw_context *brw)
> +{
> + shl_gpr0_by_30_bits(brw);
> + brw_load_register_reg(brw, HSW_CS_GPR(0) + 4, HSW_CS_GPR(0));
> + brw_load_register_imm32(brw, HSW_CS_GPR(0) + 4, 0);
> +}
> +
> +/*
> + * GPR0 = (GPR0 == 0) ? 0 : 1;
> + */
> +static void
> +gpr0_to_bool(struct brw_context *brw)
> +{
> + int m;
> + uint32_t maths[] = {
> + MI_MATH_ALU2(LOAD, SRCA, R0),
> + MI_MATH_ALU1(LOAD0, SRCB),
> + MI_MATH_ALU0(ADD),
> + MI_MATH_ALU2(STOREINV, R0, ZF),
> + MI_MATH_ALU2(LOAD, SRCA, R0),
> + MI_MATH_ALU2(LOAD, SRCB, R1),
> + MI_MATH_ALU0(AND),
> + MI_MATH_ALU2(STORE, R0, ACCU),
> + };
> +
> + brw_load_register_imm64(brw, HSW_CS_GPR(1), 1ull);
> +
> + BEGIN_BATCH(1 + ARRAY_SIZE(maths));
> + OUT_BATCH(HSW_MI_MATH | (1 + ARRAY_SIZE(maths) - 2));
> +
> + for (m = 0; m < ARRAY_SIZE(maths); m++)
> + OUT_BATCH(maths[m]);
> +
> + ADVANCE_BATCH();
> +}
> +
> +static void
> +hsw_result_to_gpr0(struct gl_context *ctx, struct brw_query_object *query,
> + struct gl_buffer_object *buf, intptr_t offset,
> + GLenum pname, GLenum ptype)
> +{
> + struct brw_context *brw = brw_context(ctx);
> +
> + assert(query->bo);
> + assert(pname != GL_QUERY_TARGET);
> +
> + if (pname == GL_QUERY_RESULT_AVAILABLE) {
> + /* The query result availability is stored at offset 0 of the buffer.
*/
> + brw_load_register_mem64(brw,
> + HSW_CS_GPR(0),
> + query->bo,
> + I915_GEM_DOMAIN_INSTRUCTION,
> + I915_GEM_DOMAIN_INSTRUCTION,
> + 2 * sizeof(uint64_t));
> + return;
> + }
> +
> + if (pname == GL_QUERY_RESULT) {
> + /* Since GL_QUERY_RESULT_NO_WAIT wasn't used, they want us to stall
to
> + * make sure the query is available.
> + */
> + brw_emit_pipe_control_flush(brw,
> + PIPE_CONTROL_CS_STALL |
> + PIPE_CONTROL_STALL_AT_SCOREBOARD);
> + }
> +
> + switch (query->Base.Target) {
> + case GL_TIMESTAMP:
How about we just do:
if (query->Base.Target == GL_TIMESTAMP) {
...
} else {
...
}
instead of a switch statement? It'd be a lot less code.
> + brw_load_register_mem64(brw,
> + HSW_CS_GPR(0),
> + query->bo,
> + I915_GEM_DOMAIN_INSTRUCTION,
> + I915_GEM_DOMAIN_INSTRUCTION,
> + 0 * sizeof(uint64_t));
> + break;
> +
> + case GL_TIME_ELAPSED:
> + case GL_ANY_SAMPLES_PASSED:
> + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
> + case GL_SAMPLES_PASSED_ARB:
> + case GL_PRIMITIVES_GENERATED:
> + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
> + case GL_VERTICES_SUBMITTED_ARB:
> + case GL_PRIMITIVES_SUBMITTED_ARB:
> + case GL_VERTEX_SHADER_INVOCATIONS_ARB:
> + case GL_GEOMETRY_SHADER_INVOCATIONS:
> + case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
> + case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
> + case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
> + case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
> + case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
> + case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
> + case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
> + brw_load_register_mem64(brw,
> + HSW_CS_GPR(1),
> + query->bo,
> + I915_GEM_DOMAIN_INSTRUCTION,
> + I915_GEM_DOMAIN_INSTRUCTION,
> + 0 * sizeof(uint64_t));
> + brw_load_register_mem64(brw,
> + HSW_CS_GPR(2),
> + query->bo,
> + I915_GEM_DOMAIN_INSTRUCTION,
> + I915_GEM_DOMAIN_INSTRUCTION,
> + 1 * sizeof(uint64_t));
> +
> + BEGIN_BATCH(5);
> + OUT_BATCH(HSW_MI_MATH | (5 - 2));
> +
> + OUT_BATCH(MI_MATH_ALU2(LOAD, SRCA, R2));
> + OUT_BATCH(MI_MATH_ALU2(LOAD, SRCB, R1));
> + OUT_BATCH(MI_MATH_ALU0(SUB));
> + OUT_BATCH(MI_MATH_ALU2(STORE, R0, ACCU));
> +
> + ADVANCE_BATCH();
> + break;
> +
> + default:
> + unreachable("Unrecognized query target in
brw_queryobj_get_results()");
The function name is wrong here, but if we switch to if/else we won't
need the unreachable().
> + }
> +
> + switch (query->Base.Target) {
> + case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
> + /* Implement the "WaDividePSInvocationCountBy4:HSW,BDW" workaround:
> + * "Invocation counter is 4 times actual. WA: SW to divide HW
reported
> + * PS Invocations value by 4."
> + *
> + * Prior to Haswell, invocation count was counted by the WM, and it
> + * buggily counted invocations in units of subspans (2x2 unit). To
get the
> + * correct value, the CS multiplied this by 4. With HSW the logic
moved,
> + * and correctly emitted the number of pixel shader invocations, but,
> + * whomever forgot to undo the multiply by 4.
> + */
We need to skip this on Skylake and later:
if (brw->gen < 9)
shr_gpr0_by_2_bits(brw);
> + shr_gpr0_by_2_bits(brw);
> + break;
> + case GL_TIME_ELAPSED:
> + case GL_TIMESTAMP:
> + mult_gpr0_by_80(brw);
> + if (query->Base.Target == GL_TIMESTAMP) {
> + keep_gpr0_lower_n_bits(brw, 36);
> + }
> + break;
> + case GL_ANY_SAMPLES_PASSED:
> + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
> + gpr0_to_bool(brw);
> + break;
> + }
> +}
> +
> +/*
> + * Store immediate data into the user buffer using the requested size.
> + */
> +static void
> +store_query_result_imm(struct brw_context *brw, drm_intel_bo *bo,
> + uint32_t offset, GLenum ptype, uint64_t imm)
> +{
> + switch (ptype) {
> + case GL_INT:
> + case GL_UNSIGNED_INT:
> + //printf("imm @ %d = %ld\n", offset, imm);
> + brw_store_data_imm32(brw, bo, offset, imm);
> + break;
> + case GL_INT64_ARB:
> + case GL_UNSIGNED_INT64_ARB:
> + brw_store_data_imm64(brw, bo, offset, imm);
> + break;
> + default:
> + unreachable("Unexpected result type");
> + }
> +}
> +
> +static void
> +set_predicate(struct brw_context *brw, drm_intel_bo *query_bo)
> +{
> + brw_load_register_imm64(brw, MI_PREDICATE_SRC1, 0ull);
> +
> + /* Load query availability into SRC0 */
> + brw_load_register_mem64(brw, MI_PREDICATE_SRC0, query_bo,
> + I915_GEM_DOMAIN_INSTRUCTION, 0,
> + 2 * sizeof(uint64_t));
> +
> + /* predicate = !(query_availability == 0); */
> + BEGIN_BATCH(1);
> + OUT_BATCH(GEN7_MI_PREDICATE |
> + MI_PREDICATE_LOADOP_LOADINV |
> + MI_PREDICATE_COMBINEOP_SET |
> + MI_PREDICATE_COMPAREOP_SRCS_EQUAL);
> + ADVANCE_BATCH();
> +}
> +
> +/*
> + * Store data from the register into the user buffer using the requested
size.
> + * The write also enables the predication to prevent writing the result if
the
> + * query has not finished yet.
> + */
> +static void
> +store_query_result_reg(struct brw_context *brw, drm_intel_bo *bo,
> + uint32_t offset, GLenum ptype, uint32_t reg,
> + const bool pipelined)
> +{
> + uint32_t cmd_size = brw->gen >= 8 ? 4 : 3;
> + uint32_t dwords = (ptype == GL_INT || ptype == GL_UNSIGNED_INT) ? 1 : 2;
> + assert(brw->gen >= 6);
> +
> + BEGIN_BATCH(dwords * cmd_size);
> + for (int i = 0; i < dwords; i++) {
> + OUT_BATCH(MI_STORE_REGISTER_MEM |
> + (pipelined ? MI_STORE_REGISTER_MEM_PREDICATE : 0) |
> + (cmd_size - 2));
> + OUT_BATCH(reg + 4 * i);
> + if (brw->gen >= 8) {
> + OUT_RELOC64(bo, I915_GEM_DOMAIN_INSTRUCTION,
> + I915_GEM_DOMAIN_INSTRUCTION, offset + 4 * i);
> + } else {
> + OUT_RELOC(bo, I915_GEM_DOMAIN_INSTRUCTION,
> + I915_GEM_DOMAIN_INSTRUCTION, offset + 4 * i);
> + }
> + }
> + ADVANCE_BATCH();
> +}
> +
> +static void
> +hsw_store_query_result(struct gl_context *ctx, struct gl_query_object *q,
> + struct gl_buffer_object *buf, intptr_t offset,
> + GLenum pname, GLenum ptype)
> +{
> + struct brw_context *brw = brw_context(ctx);
> + struct brw_query_object *query = (struct brw_query_object *)q;
> + struct intel_buffer_object *bo = intel_buffer_object(buf);
> + const bool pipelined = brw_is_query_pipelined(query);
> +
> + if (pname == GL_QUERY_TARGET) {
> + store_query_result_imm(brw, bo->buffer, offset, ptype,
> + query->Base.Target);
> + return;
> + } else if (pname == GL_QUERY_RESULT_AVAILABLE && !pipelined) {
> + store_query_result_imm(brw, bo->buffer, offset, ptype, 1ull);
> + } else if (query->bo) {
> + /* The query bo still around. Therefore, we:
> + *
> + * 1. Compute the current result in GPR0
> + * 2. Set the command streamer predicate based on query availability
> + * 3. (With predication) Write GPR0 to the requested buffer
> + */
> + hsw_result_to_gpr0(ctx, query, buf, offset, pname, ptype);
> + if (pipelined)
> + set_predicate(brw, query->bo);
> + store_query_result_reg(brw, bo->buffer, offset, ptype, HSW_CS_GPR(0),
> + pipelined);
> + } else {
> + /* The query bo is gone, so the query must have been processed into
> + * client memory. In this case we can fill the buffer location with
the
> + * requested data using MI_STORE_DATA_IMM.
> + */
> + switch (pname) {
> + case GL_QUERY_RESULT_AVAILABLE:
> + store_query_result_imm(brw, bo->buffer, offset, ptype, 1ull);
> + break;
> + case GL_QUERY_RESULT_NO_WAIT:
> + case GL_QUERY_RESULT:
> + store_query_result_imm(brw, bo->buffer, offset, ptype,
> + q->Result);
> + break;
> + default:
> + unreachable("Unexpected result type");
> + }
> + }
> +
> +}
> +
> +/* Initialize hsw+-specific query object functions. */
> +void hsw_init_queryobj_functions(struct dd_function_table *functions)
> +{
> + gen6_init_queryobj_functions(functions);
> + functions->StoreQueryResult = hsw_store_query_result;
> +}
> diff --git a/src/mesa/drivers/dri/i965/intel_extensions.c b/src/mesa/
drivers/dri/i965/intel_extensions.c
> index 6a20bd6..af922ee 100644
> --- a/src/mesa/drivers/dri/i965/intel_extensions.c
> +++ b/src/mesa/drivers/dri/i965/intel_extensions.c
> @@ -366,6 +366,10 @@ intelInitExtensions(struct gl_context *ctx)
> }
> }
>
> + if (brw->gen >= 8 || brw->is_haswell) {
> + ctx->Extensions.ARB_query_buffer_object = true;
> + }
> +
> if (brw->gen >= 8) {
> ctx->Extensions.ARB_stencil_texturing = true;
> }
> diff --git a/src/mesa/drivers/dri/i965/intel_reg.h b/src/mesa/drivers/dri/
i965/intel_reg.h
> index 40931b3..95365fe 100644
> --- a/src/mesa/drivers/dri/i965/intel_reg.h
> +++ b/src/mesa/drivers/dri/i965/intel_reg.h
> @@ -43,6 +43,7 @@
>
> #define MI_STORE_REGISTER_MEM (CMD_MI | (0x24 << 23))
> # define MI_STORE_REGISTER_MEM_USE_GGTT (1 << 22)
> +# define MI_STORE_REGISTER_MEM_PREDICATE (1 << 21)
>
> /* Load a value from memory into a register. Only available on Gen7+. */
> #define GEN7_MI_LOAD_REGISTER_MEM (CMD_MI | (0x29 << 23))
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part.
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20160426/ec5401ec/attachment.sig>
More information about the mesa-dev
mailing list