[Mesa-dev] [PATCH v2 12/13] i965: Add tessellation control shaders.
Jordan Justen
jordan.l.justen at intel.com
Tue Dec 22 01:43:33 PST 2015
We discussed all my questions / comments on irc...
12 & 13 Reviewed-by: Jordan Justen <jordan.l.justen at intel.com>
On 2015-12-11 13:24:01, Kenneth Graunke wrote:
> The TCS is the first tessellation shader stage, and the most
> complicated. It has access to each of the control points in the input
> patch, and computes a new output patch. There is one logical invocation
> per output control point; all invocations run in parallel, and can
> communicate by reading and writing output variables.
>
> One of the main responsibilities of the TCS is to write the special
> gl_TessLevelOuter[] and gl_TessLevelInner[] output variables which
> control how much new geometry the hardware tessellation engine will
> produce. Otherwise, it simply writes outputs that are passed along
> to the TES.
>
> We run in SIMD4x2 mode, handling two logical invocations per EU thread.
> The hardware doesn't properly manage the dispatch mask for us; it always
> initializes it to 0xFF. We wrap the whole program in an IF..ENDIF block
> to handle an odd number of invocations, essentially falling back to
> SIMD4x1 on the last thread.
>
> Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
> ---
> src/mesa/drivers/dri/i965/Makefile.sources | 2 +
> src/mesa/drivers/dri/i965/brw_compiler.h | 26 ++
> src/mesa/drivers/dri/i965/brw_context.h | 6 +
> src/mesa/drivers/dri/i965/brw_defines.h | 8 +
> src/mesa/drivers/dri/i965/brw_link.cpp | 4 +
> src/mesa/drivers/dri/i965/brw_program.h | 1 +
> src/mesa/drivers/dri/i965/brw_reg.h | 1 +
> src/mesa/drivers/dri/i965/brw_shader.cpp | 17 +
> src/mesa/drivers/dri/i965/brw_shader.h | 3 +
> src/mesa/drivers/dri/i965/brw_state_upload.c | 1 +
> src/mesa/drivers/dri/i965/brw_tcs.c | 262 +++++++++++
> src/mesa/drivers/dri/i965/brw_vec4.cpp | 10 +-
> src/mesa/drivers/dri/i965/brw_vec4.h | 1 +
> src/mesa/drivers/dri/i965/brw_vec4_cse.cpp | 2 +
> .../dri/i965/brw_vec4_dead_code_eliminate.cpp | 3 +
> src/mesa/drivers/dri/i965/brw_vec4_generator.cpp | 238 ++++++++++
> src/mesa/drivers/dri/i965/brw_vec4_nir.cpp | 23 +-
> src/mesa/drivers/dri/i965/brw_vec4_tcs.cpp | 496 +++++++++++++++++++++
> src/mesa/drivers/dri/i965/brw_vec4_tcs.h | 84 ++++
> 19 files changed, 1186 insertions(+), 2 deletions(-)
> create mode 100644 src/mesa/drivers/dri/i965/brw_tcs.c
> create mode 100644 src/mesa/drivers/dri/i965/brw_vec4_tcs.cpp
> create mode 100644 src/mesa/drivers/dri/i965/brw_vec4_tcs.h
>
> diff --git a/src/mesa/drivers/dri/i965/Makefile.sources b/src/mesa/drivers/dri/i965/Makefile.sources
> index 7354aaf..0b706de 100644
> --- a/src/mesa/drivers/dri/i965/Makefile.sources
> +++ b/src/mesa/drivers/dri/i965/Makefile.sources
> @@ -75,6 +75,7 @@ i965_compiler_FILES = \
> brw_vec4_reg_allocate.cpp \
> brw_vec4_surface_builder.cpp \
> brw_vec4_surface_builder.h \
> + brw_vec4_tcs.cpp \
> brw_vec4_visitor.cpp \
> brw_vec4_vs_visitor.cpp \
> brw_vue_map.c \
> @@ -150,6 +151,7 @@ i965_FILES = \
> brw_state.h \
> brw_state_upload.c \
> brw_structs.h \
> + brw_tcs.c \
> brw_tcs_surface_state.c \
> brw_tes.c \
> brw_tes_surface_state.c \
> diff --git a/src/mesa/drivers/dri/i965/brw_compiler.h b/src/mesa/drivers/dri/i965/brw_compiler.h
> index 64d831d..e6bae8e 100644
> --- a/src/mesa/drivers/dri/i965/brw_compiler.h
> +++ b/src/mesa/drivers/dri/i965/brw_compiler.h
> @@ -191,6 +191,16 @@ struct brw_vs_prog_key {
> struct brw_sampler_prog_key_data tex;
> };
>
> +/** The program key for Tessellation Control Shaders. */
> +struct brw_tcs_prog_key
> +{
> + unsigned program_string_id;
> +
> + GLenum tes_primitive_mode;
> +
> + struct brw_sampler_prog_key_data tex;
> +};
> +
> /** The program key for Tessellation Evaluation Shaders. */
> struct brw_tes_prog_key
> {
> @@ -677,6 +687,22 @@ brw_compile_vs(const struct brw_compiler *compiler, void *log_data,
> char **error_str);
>
> /**
> + * Compile a tessellation control shader.
> + *
> + * Returns the final assembly and the program's size.
> + */
> +const unsigned *
> +brw_compile_tcs(const struct brw_compiler *compiler,
> + void *log_data,
> + void *mem_ctx,
> + const struct brw_tcs_prog_key *key,
> + struct brw_tcs_prog_data *prog_data,
> + const struct nir_shader *nir,
> + int shader_time_index,
> + unsigned *final_assembly_size,
> + char **error_str);
> +
> +/**
> * Compile a tessellation evaluation shader.
> *
> * Returns the final assembly and the program's size.
> diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
> index 5e840d1..1d989f3 100644
> --- a/src/mesa/drivers/dri/i965/brw_context.h
> +++ b/src/mesa/drivers/dri/i965/brw_context.h
> @@ -1704,6 +1704,12 @@ brw_vertex_program_const(const struct gl_vertex_program *p)
> return (const struct brw_vertex_program *) p;
> }
>
> +static inline struct brw_tess_ctrl_program *
> +brw_tess_ctrl_program(struct gl_tess_ctrl_program *p)
> +{
> + return (struct brw_tess_ctrl_program *) p;
> +}
> +
> static inline struct brw_tess_eval_program *
> brw_tess_eval_program(struct gl_tess_eval_program *p)
> {
> diff --git a/src/mesa/drivers/dri/i965/brw_defines.h b/src/mesa/drivers/dri/i965/brw_defines.h
> index 4a184cf..cc19c06 100644
> --- a/src/mesa/drivers/dri/i965/brw_defines.h
> +++ b/src/mesa/drivers/dri/i965/brw_defines.h
> @@ -1305,6 +1305,14 @@ enum opcode {
> * UD immediate).
> */
> SHADER_OPCODE_MOV_INDIRECT,
> +
> + VEC4_OPCODE_URB_READ,
> + TCS_OPCODE_GET_INSTANCE_ID,
> + TCS_OPCODE_URB_WRITE,
> + TCS_OPCODE_SET_INPUT_URB_OFFSETS,
> + TCS_OPCODE_SET_OUTPUT_URB_OFFSETS,
> + TCS_OPCODE_GET_PRIMITIVE_ID,
> + TCS_OPCODE_CREATE_BARRIER_HEADER,
> };
>
> enum brw_urb_write_flags {
> diff --git a/src/mesa/drivers/dri/i965/brw_link.cpp b/src/mesa/drivers/dri/i965/brw_link.cpp
> index f5a7d20..7cdc830 100644
> --- a/src/mesa/drivers/dri/i965/brw_link.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_link.cpp
> @@ -42,6 +42,7 @@ brw_shader_precompile(struct gl_context *ctx,
> struct gl_shader_program *sh_prog)
> {
> struct gl_shader *vs = sh_prog->_LinkedShaders[MESA_SHADER_VERTEX];
> + struct gl_shader *tcs = sh_prog->_LinkedShaders[MESA_SHADER_TESS_CTRL];
> struct gl_shader *tes = sh_prog->_LinkedShaders[MESA_SHADER_TESS_EVAL];
> struct gl_shader *gs = sh_prog->_LinkedShaders[MESA_SHADER_GEOMETRY];
> struct gl_shader *fs = sh_prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
> @@ -56,6 +57,9 @@ brw_shader_precompile(struct gl_context *ctx,
> if (tes && !brw_tes_precompile(ctx, sh_prog, tes->Program))
> return false;
>
> + if (tcs && !brw_tcs_precompile(ctx, sh_prog, tcs->Program))
> + return false;
> +
> if (vs && !brw_vs_precompile(ctx, sh_prog, vs->Program))
> return false;
>
> diff --git a/src/mesa/drivers/dri/i965/brw_program.h b/src/mesa/drivers/dri/i965/brw_program.h
> index 1cdab97..3d9e1b9 100644
> --- a/src/mesa/drivers/dri/i965/brw_program.h
> +++ b/src/mesa/drivers/dri/i965/brw_program.h
> @@ -56,6 +56,7 @@ void
> brw_dump_ir(const char *stage, struct gl_shader_program *shader_prog,
> struct gl_shader *shader, struct gl_program *prog);
>
> +void brw_upload_tcs_prog(struct brw_context *brw);
> void brw_upload_tes_prog(struct brw_context *brw);
>
> #ifdef __cplusplus
> diff --git a/src/mesa/drivers/dri/i965/brw_reg.h b/src/mesa/drivers/dri/i965/brw_reg.h
> index fa912c9..9f2ff9a 100644
> --- a/src/mesa/drivers/dri/i965/brw_reg.h
> +++ b/src/mesa/drivers/dri/i965/brw_reg.h
> @@ -84,6 +84,7 @@ struct brw_device_info;
> #define BRW_SWIZZLE_YZXW BRW_SWIZZLE4(1,2,0,3)
> #define BRW_SWIZZLE_ZXYW BRW_SWIZZLE4(2,0,1,3)
> #define BRW_SWIZZLE_ZWZW BRW_SWIZZLE4(2,3,2,3)
> +#define BRW_SWIZZLE_WZYX BRW_SWIZZLE4(3,2,1,0)
>
> static inline bool
> brw_is_single_value_swizzle(unsigned swiz)
> diff --git a/src/mesa/drivers/dri/i965/brw_shader.cpp b/src/mesa/drivers/dri/i965/brw_shader.cpp
> index d954568..9b64ae4 100644
> --- a/src/mesa/drivers/dri/i965/brw_shader.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_shader.cpp
> @@ -85,6 +85,7 @@ brw_compiler_create(void *mem_ctx, const struct brw_device_info *devinfo)
>
> compiler->scalar_stage[MESA_SHADER_VERTEX] =
> devinfo->gen >= 8 && !(INTEL_DEBUG & DEBUG_VEC4VS);
> + compiler->scalar_stage[MESA_SHADER_TESS_CTRL] = false;
> compiler->scalar_stage[MESA_SHADER_TESS_EVAL] = true;
> compiler->scalar_stage[MESA_SHADER_GEOMETRY] =
> devinfo->gen >= 8 && env_var_as_boolean("INTEL_SCALAR_GS", false);
> @@ -137,6 +138,7 @@ brw_compiler_create(void *mem_ctx, const struct brw_device_info *devinfo)
> compiler->glsl_compiler_options[i].LowerBufferInterfaceBlocks = true;
> }
>
> + compiler->glsl_compiler_options[MESA_SHADER_TESS_CTRL].EmitNoIndirectInput = false;
> compiler->glsl_compiler_options[MESA_SHADER_TESS_EVAL].EmitNoIndirectInput = false;
>
> if (compiler->scalar_stage[MESA_SHADER_GEOMETRY])
> @@ -549,6 +551,21 @@ brw_instruction_name(enum opcode op)
> return "mulh";
> case SHADER_OPCODE_MOV_INDIRECT:
> return "mov_indirect";
> +
> + case VEC4_OPCODE_URB_READ:
> + return "urb_read";
> + case TCS_OPCODE_GET_INSTANCE_ID:
> + return "tcs_get_instance_id";
> + case TCS_OPCODE_URB_WRITE:
> + return "tcs_urb_write";
> + case TCS_OPCODE_SET_INPUT_URB_OFFSETS:
> + return "tcs_set_input_urb_offsets";
> + case TCS_OPCODE_SET_OUTPUT_URB_OFFSETS:
> + return "tcs_set_output_urb_offsets";
> + case TCS_OPCODE_GET_PRIMITIVE_ID:
> + return "tcs_get_primitive_id";
> + case TCS_OPCODE_CREATE_BARRIER_HEADER:
> + return "tcs_create_barrier_header";
> }
>
> unreachable("not reached");
> diff --git a/src/mesa/drivers/dri/i965/brw_shader.h b/src/mesa/drivers/dri/i965/brw_shader.h
> index 2e73f12..5933613 100644
> --- a/src/mesa/drivers/dri/i965/brw_shader.h
> +++ b/src/mesa/drivers/dri/i965/brw_shader.h
> @@ -273,6 +273,9 @@ brw_assign_common_binding_table_offsets(gl_shader_stage stage,
> bool brw_vs_precompile(struct gl_context *ctx,
> struct gl_shader_program *shader_prog,
> struct gl_program *prog);
> +bool brw_tcs_precompile(struct gl_context *ctx,
> + struct gl_shader_program *shader_prog,
> + struct gl_program *prog);
> bool brw_tes_precompile(struct gl_context *ctx,
> struct gl_shader_program *shader_prog,
> struct gl_program *prog);
> diff --git a/src/mesa/drivers/dri/i965/brw_state_upload.c b/src/mesa/drivers/dri/i965/brw_state_upload.c
> index c657b25..56962d5 100644
> --- a/src/mesa/drivers/dri/i965/brw_state_upload.c
> +++ b/src/mesa/drivers/dri/i965/brw_state_upload.c
> @@ -678,6 +678,7 @@ brw_upload_programs(struct brw_context *brw,
> {
> if (pipeline == BRW_RENDER_PIPELINE) {
> brw_upload_vs_prog(brw);
> + brw_upload_tcs_prog(brw);
> brw_upload_tes_prog(brw);
>
> if (brw->gen < 6)
> diff --git a/src/mesa/drivers/dri/i965/brw_tcs.c b/src/mesa/drivers/dri/i965/brw_tcs.c
> new file mode 100644
> index 0000000..4acfaea
> --- /dev/null
> +++ b/src/mesa/drivers/dri/i965/brw_tcs.c
> @@ -0,0 +1,262 @@
> +/*
> + * Copyright © 2013 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 brw_tcs.c
> + *
> + * Tessellation control shader state upload code.
> + */
> +
> +#include "brw_context.h"
> +#include "brw_nir.h"
> +#include "brw_program.h"
> +#include "brw_shader.h"
> +#include "brw_state.h"
> +#include "program/prog_parameter.h"
> +
> +static void
> +brw_tcs_debug_recompile(struct brw_context *brw,
> + struct gl_shader_program *shader_prog,
> + const struct brw_tcs_prog_key *key)
> +{
> + struct brw_cache_item *c = NULL;
> + const struct brw_tcs_prog_key *old_key = NULL;
> + bool found = false;
> +
> + perf_debug("Recompiling tessellation control shader for program %d\n",
> + shader_prog->Name);
> +
> + for (unsigned int i = 0; i < brw->cache.size; i++) {
> + for (c = brw->cache.items[i]; c; c = c->next) {
> + if (c->cache_id == BRW_CACHE_TCS_PROG) {
> + old_key = c->key;
> +
> + if (old_key->program_string_id == key->program_string_id)
> + break;
> + }
> + }
> + if (c)
> + break;
> + }
> +
> + if (!c) {
> + perf_debug(" Didn't find previous compile in the shader cache for "
> + "debug\n");
> + return;
> + }
> +
> + found |= key_debug(brw, "TES primitive mode", old_key->tes_primitive_mode,
> + key->tes_primitive_mode);
> + found |= brw_debug_recompile_sampler_key(brw, &old_key->tex, &key->tex);
> +
> + if (!found) {
> + perf_debug(" Something else\n");
> + }
> +}
> +
> +static bool
> +brw_codegen_tcs_prog(struct brw_context *brw,
> + struct gl_shader_program *shader_prog,
> + struct brw_tess_ctrl_program *tcp,
> + struct brw_tcs_prog_key *key)
> +{
> + const struct brw_compiler *compiler = brw->intelScreen->compiler;
> + struct brw_stage_state *stage_state = &brw->tcs.base;
> + nir_shader *nir = tcp->program.Base.nir;
> + struct brw_tcs_prog_data prog_data;
> + bool start_busy = false;
> + double start_time = 0;
> +
> + memset(&prog_data, 0, sizeof(prog_data));
> +
> + /* Allocate the references to the uniforms that will end up in the
> + * prog_data associated with the compiled program, and which will be freed
> + * by the state cache.
> + *
> + * Note: param_count needs to be num_uniform_components * 4, since we add
> + * padding around uniform values below vec4 size, so the worst case is that
> + * every uniform is a float which gets padded to the size of a vec4.
> + */
> + struct gl_shader *tcs = shader_prog->_LinkedShaders[MESA_SHADER_TESS_CTRL];
> + int param_count = nir->num_uniforms;
> + if (!compiler->scalar_stage[MESA_SHADER_TESS_CTRL])
> + param_count *= 4;
> +
> + prog_data.base.base.param =
> + rzalloc_array(NULL, const gl_constant_value *, param_count);
> + prog_data.base.base.pull_param =
> + rzalloc_array(NULL, const gl_constant_value *, param_count);
> + prog_data.base.base.image_param =
> + rzalloc_array(NULL, struct brw_image_param, tcs->NumImages);
> + prog_data.base.base.nr_params = param_count;
> + prog_data.base.base.nr_image_params = tcs->NumImages;
> +
> + brw_nir_setup_glsl_uniforms(nir, shader_prog, &tcp->program.Base,
> + &prog_data.base.base, false);
> +
> + if (unlikely(INTEL_DEBUG & DEBUG_TCS))
> + brw_dump_ir("tessellation control", shader_prog, tcs, NULL);
> +
> + int st_index = -1;
> + if (unlikely(INTEL_DEBUG & DEBUG_SHADER_TIME))
> + st_index = brw_get_shader_time_index(brw, shader_prog, NULL, ST_TCS);
> +
> + if (unlikely(brw->perf_debug)) {
> + start_busy = brw->batch.last_bo && drm_intel_bo_busy(brw->batch.last_bo);
> + start_time = get_time();
> + }
> +
> + void *mem_ctx = ralloc_context(NULL);
> + unsigned program_size;
> + char *error_str;
> + const unsigned *program =
> + brw_compile_tcs(compiler, brw, mem_ctx, key, &prog_data, nir, st_index,
> + &program_size, &error_str);
> + if (program == NULL) {
> + if (shader_prog) {
> + shader_prog->LinkStatus = false;
> + ralloc_strcat(&shader_prog->InfoLog, error_str);
> + }
> +
> + _mesa_problem(NULL, "Failed to compile tessellation control shader: "
> + "%s\n", error_str);
> +
> + ralloc_free(mem_ctx);
> + return false;
> + }
> +
> + if (unlikely(brw->perf_debug)) {
> + struct brw_shader *btcs = (struct brw_shader *) tcs;
> + if (btcs->compiled_once) {
> + brw_tcs_debug_recompile(brw, shader_prog, key);
> + }
> + if (start_busy && !drm_intel_bo_busy(brw->batch.last_bo)) {
> + perf_debug("TCS compile took %.03f ms and stalled the GPU\n",
> + (get_time() - start_time) * 1000);
> + }
> + btcs->compiled_once = true;
> + }
> +
> + /* Scratch space is used for register spilling */
> + if (prog_data.base.base.total_scratch) {
> + brw_get_scratch_bo(brw, &stage_state->scratch_bo,
> + prog_data.base.base.total_scratch *
> + brw->max_hs_threads);
> + }
> +
> + brw_upload_cache(&brw->cache, BRW_CACHE_TCS_PROG,
> + key, sizeof(*key),
> + program, program_size,
> + &prog_data, sizeof(prog_data),
> + &stage_state->prog_offset, &brw->tcs.prog_data);
> + ralloc_free(mem_ctx);
> +
> + return true;
> +}
> +
> +
> +void
> +brw_upload_tcs_prog(struct brw_context *brw)
> +{
> + struct gl_context *ctx = &brw->ctx;
> + struct gl_shader_program **current = ctx->_Shader->CurrentProgram;
> + struct brw_stage_state *stage_state = &brw->tcs.base;
> + struct brw_tcs_prog_key key;
> + /* BRW_NEW_TESS_CTRL_PROGRAM */
> + struct brw_tess_ctrl_program *tcp =
> + (struct brw_tess_ctrl_program *) brw->tess_ctrl_program;
> +
> + if (!brw_state_dirty(brw,
> + _NEW_TEXTURE,
> + BRW_NEW_TESS_CTRL_PROGRAM |
> + BRW_NEW_TESS_EVAL_PROGRAM))
> + return;
> +
> + if (tcp == NULL) {
> + /* Other state atoms had better not try to access prog_data, since
> + * there's no HS program.
> + */
> + brw->tcs.prog_data = NULL;
> + brw->tcs.base.prog_data = NULL;
> + return;
> + }
> +
> + struct gl_program *prog = &tcp->program.Base;
> +
> + memset(&key, 0, sizeof(key));
> +
> + key.program_string_id = tcp->id;
> +
> + /* _NEW_TEXTURE */
> + brw_populate_sampler_prog_key_data(ctx, prog, stage_state->sampler_count,
> + &key.tex);
> +
> + /* BRW_NEW_TESS_EVAL_PROGRAM */
> + /* We need to specialize our code generation for tessellation levels
> + * based on the domain the DS is expecting to tessellate.
> + */
> + struct brw_tess_eval_program *tep =
> + (struct brw_tess_eval_program *) brw->tess_eval_program;
> + assert(tep);
> + key.tes_primitive_mode = tep->program.PrimitiveMode;
> +
> + if (!brw_search_cache(&brw->cache, BRW_CACHE_TCS_PROG,
> + &key, sizeof(key),
> + &stage_state->prog_offset, &brw->tcs.prog_data)) {
> + bool success = brw_codegen_tcs_prog(brw, current[MESA_SHADER_TESS_CTRL],
> + tcp, &key);
> + assert(success);
> + (void)success;
> + }
> + brw->tcs.base.prog_data = &brw->tcs.prog_data->base.base;
> +}
> +
> +
> +bool
> +brw_tcs_precompile(struct gl_context *ctx,
> + struct gl_shader_program *shader_prog,
> + struct gl_program *prog)
> +{
> + struct brw_context *brw = brw_context(ctx);
> + struct brw_tcs_prog_key key;
> + uint32_t old_prog_offset = brw->tcs.base.prog_offset;
> + struct brw_tcs_prog_data *old_prog_data = brw->tcs.prog_data;
> + bool success;
> +
> + struct gl_tess_ctrl_program *tcp = (struct gl_tess_ctrl_program *)prog;
> + struct brw_tess_ctrl_program *btcp = brw_tess_ctrl_program(tcp);
> +
> + memset(&key, 0, sizeof(key));
> +
> + key.program_string_id = btcp->id;
> + brw_setup_tex_for_precompile(brw, &key.tex, prog);
> +
> + key.tes_primitive_mode = GL_TRIANGLES;
> +
> + success = brw_codegen_tcs_prog(brw, shader_prog, btcp, &key);
> +
> + brw->tcs.base.prog_offset = old_prog_offset;
> + brw->tcs.prog_data = old_prog_data;
> +
> + return success;
> +}
> diff --git a/src/mesa/drivers/dri/i965/brw_vec4.cpp b/src/mesa/drivers/dri/i965/brw_vec4.cpp
> index a697bdf..0cded0c 100644
> --- a/src/mesa/drivers/dri/i965/brw_vec4.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_vec4.cpp
> @@ -155,6 +155,9 @@ vec4_instruction::is_send_from_grf()
> case SHADER_OPCODE_TYPED_ATOMIC:
> case SHADER_OPCODE_TYPED_SURFACE_READ:
> case SHADER_OPCODE_TYPED_SURFACE_WRITE:
> + case VEC4_OPCODE_URB_READ:
> + case TCS_OPCODE_URB_WRITE:
> + case SHADER_OPCODE_BARRIER:
> return true;
> default:
> return false;
> @@ -184,7 +187,9 @@ bool
> vec4_instruction::has_source_and_destination_hazard() const
> {
> switch (opcode) {
> - /* Most opcodes in the vec4 world use MRFs. */
> + case TCS_OPCODE_SET_INPUT_URB_OFFSETS:
> + case TCS_OPCODE_SET_OUTPUT_URB_OFFSETS:
> + return true;
> default:
> return false;
> }
> @@ -204,6 +209,7 @@ vec4_instruction::regs_read(unsigned arg) const
> case SHADER_OPCODE_TYPED_ATOMIC:
> case SHADER_OPCODE_TYPED_SURFACE_READ:
> case SHADER_OPCODE_TYPED_SURFACE_WRITE:
> + case TCS_OPCODE_URB_WRITE:
> return arg == 0 ? mlen : 1;
>
> case VS_OPCODE_PULL_CONSTANT_LOAD_GEN7:
> @@ -281,6 +287,8 @@ vec4_visitor::implied_mrf_writes(vec4_instruction *inst)
> return 0;
> case GS_OPCODE_FF_SYNC:
> return 1;
> + case TCS_OPCODE_URB_WRITE:
> + return 0;
> case SHADER_OPCODE_SHADER_TIME_ADD:
> return 0;
> case SHADER_OPCODE_TEX:
> diff --git a/src/mesa/drivers/dri/i965/brw_vec4.h b/src/mesa/drivers/dri/i965/brw_vec4.h
> index ae5bf69..6bbac83 100644
> --- a/src/mesa/drivers/dri/i965/brw_vec4.h
> +++ b/src/mesa/drivers/dri/i965/brw_vec4.h
> @@ -340,6 +340,7 @@ public:
> unsigned num_components = 4);
> src_reg get_nir_src(nir_src src,
> unsigned num_components = 4);
> + src_reg get_indirect_offset(nir_intrinsic_instr *instr);
>
> virtual dst_reg *make_reg_for_system_value(int location,
> const glsl_type *type) = 0;
> diff --git a/src/mesa/drivers/dri/i965/brw_vec4_cse.cpp b/src/mesa/drivers/dri/i965/brw_vec4_cse.cpp
> index 85cbf24..0c1f0c3 100644
> --- a/src/mesa/drivers/dri/i965/brw_vec4_cse.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_vec4_cse.cpp
> @@ -75,6 +75,8 @@ is_expression(const vec4_instruction *const inst)
> case VEC4_OPCODE_UNPACK_UNIFORM:
> case SHADER_OPCODE_FIND_LIVE_CHANNEL:
> case SHADER_OPCODE_BROADCAST:
> + case TCS_OPCODE_SET_INPUT_URB_OFFSETS:
> + case TCS_OPCODE_SET_OUTPUT_URB_OFFSETS:
> return true;
> case SHADER_OPCODE_RCP:
> case SHADER_OPCODE_RSQ:
> diff --git a/src/mesa/drivers/dri/i965/brw_vec4_dead_code_eliminate.cpp b/src/mesa/drivers/dri/i965/brw_vec4_dead_code_eliminate.cpp
> index 2d0722a..c31e72d 100644
> --- a/src/mesa/drivers/dri/i965/brw_vec4_dead_code_eliminate.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_vec4_dead_code_eliminate.cpp
> @@ -45,6 +45,9 @@ can_do_writemask(const struct brw_device_info *devinfo,
> case VS_OPCODE_PULL_CONSTANT_LOAD:
> case VS_OPCODE_PULL_CONSTANT_LOAD_GEN7:
> case VS_OPCODE_SET_SIMD4X2_HEADER_GEN9:
> + case TCS_OPCODE_SET_INPUT_URB_OFFSETS:
> + case TCS_OPCODE_SET_OUTPUT_URB_OFFSETS:
> + case VEC4_OPCODE_URB_READ:
> return false;
> default:
> /* The MATH instruction on Gen6 only executes in align1 mode, which does
> diff --git a/src/mesa/drivers/dri/i965/brw_vec4_generator.cpp b/src/mesa/drivers/dri/i965/brw_vec4_generator.cpp
> index c3426dd..076b1dd 100644
> --- a/src/mesa/drivers/dri/i965/brw_vec4_generator.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_vec4_generator.cpp
> @@ -714,6 +714,211 @@ generate_gs_set_primitive_id(struct brw_codegen *p, struct brw_reg dst)
> }
>
> static void
> +generate_tcs_get_instance_id(struct brw_codegen *p, struct brw_reg dst)
> +{
> + /* "Instance Count" comes as part of the payload in r0.2 bits 23:17.
> + *
> + * Since we operate in SIMD4x2 mode, we need run half as many threads
> + * as necessary. So we assign (2i + 1, 2i) as the thread counts. We
> + * shift right by one less to accomplish the multiplication by two.
> + */
> + dst = retype(dst, BRW_REGISTER_TYPE_UD);
> + struct brw_reg r0(retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UD));
> +
> + brw_push_insn_state(p);
> + brw_set_default_access_mode(p, BRW_ALIGN_1);
> +
> + const int mask = INTEL_MASK(23, 17);
> + const int shift = 17;
> +
> + brw_AND(p, get_element_ud(dst, 0), get_element_ud(r0, 2), brw_imm_ud(mask));
> + brw_SHR(p, get_element_ud(dst, 0), get_element_ud(dst, 0),
> + brw_imm_ud(shift - 1));
> + brw_ADD(p, get_element_ud(dst, 4), get_element_ud(dst, 0), brw_imm_ud(1));
> +
> + brw_pop_insn_state(p);
> +}
> +
> +static void
> +generate_tcs_urb_write(struct brw_codegen *p,
> + vec4_instruction *inst,
> + struct brw_reg urb_header)
> +{
> + const struct brw_device_info *devinfo = p->devinfo;
> +
> + brw_inst *send = brw_next_insn(p, BRW_OPCODE_SEND);
> + brw_set_dest(p, send, brw_null_reg());
> + brw_set_src0(p, send, urb_header);
> +
> + brw_set_message_descriptor(p, send, BRW_SFID_URB,
> + inst->mlen /* mlen */, 0 /* rlen */,
> + true /* header */, false /* eot */);
> + brw_inst_set_urb_opcode(devinfo, send, BRW_URB_OPCODE_WRITE_OWORD);
> + brw_inst_set_urb_global_offset(devinfo, send, inst->offset);
> + brw_inst_set_urb_per_slot_offset(devinfo, send, 1);
> + brw_inst_set_urb_swizzle_control(devinfo, send, BRW_URB_SWIZZLE_INTERLEAVE);
> +
> + /* what happens to swizzles? */
> +}
> +
> +
> +static void
> +generate_tcs_input_urb_offsets(struct brw_codegen *p,
> + struct brw_reg dst,
> + struct brw_reg vertex,
> + struct brw_reg offset)
> +{
> + /* Generates an URB read/write message header for HS/DS operation.
> + * Inputs are a vertex index, and a byte offset from the beginning of
> + * the vertex. */
> +
> + /* If `vertex` is not an immediate, we clobber a0.0 */
> +
> + assert(vertex.file == BRW_IMMEDIATE_VALUE || vertex.file == BRW_GENERAL_REGISTER_FILE);
> + assert(vertex.type == BRW_REGISTER_TYPE_UD || vertex.type == BRW_REGISTER_TYPE_D);
> +
> + assert(dst.file == BRW_GENERAL_REGISTER_FILE);
> +
> + brw_push_insn_state(p);
> + brw_set_default_access_mode(p, BRW_ALIGN_1);
> + brw_set_default_mask_control(p, BRW_MASK_DISABLE);
> + brw_MOV(p, dst, brw_imm_ud(0));
> +
> + /* m0.5 bits 8-15 are channel enables */
> + brw_MOV(p, get_element_ud(dst, 5), brw_imm_ud(0xff00));
> +
> + /* m0.0-0.1: URB handles */
> + if (vertex.file == BRW_IMMEDIATE_VALUE) {
> + uint32_t vertex_index = vertex.ud;
> + struct brw_reg index_reg = brw_vec1_grf(
> + 1 + (vertex_index >> 3), vertex_index & 7);
> +
> + brw_MOV(p, vec2(get_element_ud(dst, 0)),
> + retype(index_reg, BRW_REGISTER_TYPE_UD));
> + } else {
> + /* indirect via a0.0 */
> + struct brw_reg addr = brw_address_reg(0);
> +
> + /* bottom half: m0.0 = g[1.0 + vertex.0]UD */
> + brw_ADD(p, addr, get_element_ud(vertex, 0), brw_imm_uw(0x8));
> + brw_SHL(p, addr, addr, brw_imm_ud(2));
> + brw_MOV(p, get_element_ud(dst, 0), deref_1ud(brw_indirect(0, 0), 0));
> +
> + /* top half: m0.1 = g[1.0 + vertex.4]UD */
> + brw_ADD(p, addr, get_element_ud(vertex, 4), brw_imm_uw(0x8));
> + brw_SHL(p, addr, addr, brw_imm_ud(2));
> + brw_MOV(p, get_element_ud(dst, 1), deref_1ud(brw_indirect(0, 0), 0));
> + }
> +
> + /* m0.3-0.4: 128bit-granular offsets into the URB from the handles */
> + if (offset.file != ARF)
> + brw_MOV(p, vec2(get_element_ud(dst, 3)), stride(offset, 4, 1, 0));
> +
> + brw_pop_insn_state(p);
> +}
> +
> +
> +static void
> +generate_tcs_output_urb_offsets(struct brw_codegen *p,
> + struct brw_reg dst,
> + struct brw_reg write_mask,
> + struct brw_reg offset)
> +{
> + /* Generates an URB read/write message header for HS/DS operation, for the patch URB entry. */
> + assert(dst.file == BRW_GENERAL_REGISTER_FILE || dst.file == BRW_MESSAGE_REGISTER_FILE);
> +
> + assert(write_mask.file == BRW_IMMEDIATE_VALUE);
> + assert(write_mask.type == BRW_REGISTER_TYPE_UD);
> +
> + brw_push_insn_state(p);
> +
> + brw_set_default_access_mode(p, BRW_ALIGN_1);
> + brw_set_default_mask_control(p, BRW_MASK_DISABLE);
> + brw_MOV(p, dst, brw_imm_ud(0));
> +
> + unsigned mask = write_mask.ud;
> +
> + /* m0.5 bits 15:12 and 11:8 are channel enables */
> + brw_MOV(p, get_element_ud(dst, 5), brw_imm_ud((mask << 8) | (mask << 12)));
> +
> + /* HS patch URB handle is delivered in r0.0 */
> + struct brw_reg urb_handle = brw_vec1_grf(0, 0);
> +
> + /* m0.0-0.1: URB handles */
> + brw_MOV(p, vec2(get_element_ud(dst, 0)),
> + retype(urb_handle, BRW_REGISTER_TYPE_UD));
> +
> + /* m0.3-0.4: 128bit-granular offsets into the URB from the handles */
> + if (offset.file != ARF)
> + brw_MOV(p, vec2(get_element_ud(dst, 3)), stride(offset, 4, 1, 0));
> +
> + brw_pop_insn_state(p);
> +}
> +
> +static void
> +generate_vec4_urb_read(struct brw_codegen *p,
> + vec4_instruction *inst,
> + struct brw_reg dst,
> + struct brw_reg header)
> +{
> + const struct brw_device_info *devinfo = p->devinfo;
> +
> + assert(header.file == BRW_GENERAL_REGISTER_FILE);
> + assert(header.type == BRW_REGISTER_TYPE_UD);
> +
> + brw_inst *send = brw_next_insn(p, BRW_OPCODE_SEND);
> + brw_set_dest(p, send, dst);
> + brw_set_src0(p, send, header);
> +
> + brw_set_message_descriptor(p, send, BRW_SFID_URB,
> + 1 /* mlen */, 1 /* rlen */,
> + true /* header */, false /* eot */);
> + brw_inst_set_urb_opcode(devinfo, send, BRW_URB_OPCODE_READ_OWORD);
> + brw_inst_set_urb_swizzle_control(devinfo, send, BRW_URB_SWIZZLE_INTERLEAVE);
> + brw_inst_set_urb_per_slot_offset(devinfo, send, 1);
> +
> + brw_inst_set_urb_global_offset(devinfo, send, inst->offset);
> +}
> +
> +static void
> +generate_tcs_get_primitive_id(struct brw_codegen *p, struct brw_reg dst)
> +{
> + brw_push_insn_state(p);
> + brw_set_default_access_mode(p, BRW_ALIGN_1);
> + brw_MOV(p, dst, retype(brw_vec1_grf(0, 1), BRW_REGISTER_TYPE_UD));
> + brw_pop_insn_state(p);
> +}
> +
> +static void
> +generate_tcs_create_barrier_header(struct brw_codegen *p,
> + struct brw_vue_prog_data *prog_data,
> + struct brw_reg dst)
> +{
> + struct brw_reg m0_2 = get_element_ud(dst, 2);
> + unsigned instances = ((struct brw_tcs_prog_data *) prog_data)->instances;
> +
> + brw_push_insn_state(p);
> + brw_set_default_access_mode(p, BRW_ALIGN_1);
> + brw_set_default_mask_control(p, BRW_MASK_DISABLE);
> +
> + /* Zero the message header */
> + brw_MOV(p, retype(dst, BRW_REGISTER_TYPE_UD), brw_imm_ud(0u));
> +
> + /* Copy "Barrier ID" from DW0 bits 16:13 */
> + brw_AND(p, m0_2,
> + retype(brw_vec1_grf(0, 2), BRW_REGISTER_TYPE_UD),
> + brw_imm_ud(0x1e000));
> +
> + /* Shift it into place */
> + brw_SHL(p, m0_2, get_element_ud(dst, 2), brw_imm_ud(11));
> +
> + /* Set the Barrier Count and the enable bit */
> + brw_OR(p, m0_2, m0_2, brw_imm_ud(instances << 9 | (1 << 15)));
> +
> + brw_pop_insn_state(p);
> +}
> +
> +static void
> generate_oword_dual_block_offsets(struct brw_codegen *p,
> struct brw_reg m1,
> struct brw_reg index)
> @@ -1538,6 +1743,39 @@ generate_code(struct brw_codegen *p,
> break;
> }
>
> + case TCS_OPCODE_URB_WRITE:
> + generate_tcs_urb_write(p, inst, src[0]);
> + break;
> +
> + case VEC4_OPCODE_URB_READ:
> + generate_vec4_urb_read(p, inst, dst, src[0]);
> + break;
> +
> + case TCS_OPCODE_SET_INPUT_URB_OFFSETS:
> + generate_tcs_input_urb_offsets(p, dst, src[0], src[1]);
> + break;
> +
> + case TCS_OPCODE_SET_OUTPUT_URB_OFFSETS:
> + generate_tcs_output_urb_offsets(p, dst, src[0], src[1]);
> + break;
> +
> + case TCS_OPCODE_GET_INSTANCE_ID:
> + generate_tcs_get_instance_id(p, dst);
> + break;
> +
> + case TCS_OPCODE_GET_PRIMITIVE_ID:
> + generate_tcs_get_primitive_id(p, dst);
> + break;
> +
> + case TCS_OPCODE_CREATE_BARRIER_HEADER:
> + generate_tcs_create_barrier_header(p, prog_data, dst);
> + break;
> +
> + case SHADER_OPCODE_BARRIER:
> + brw_barrier(p, src[0]);
> + brw_WAIT(p);
> + break;
> +
> default:
> unreachable("Unsupported opcode");
> }
> diff --git a/src/mesa/drivers/dri/i965/brw_vec4_nir.cpp b/src/mesa/drivers/dri/i965/brw_vec4_nir.cpp
> index f965b39..45ff7a3 100644
> --- a/src/mesa/drivers/dri/i965/brw_vec4_nir.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_vec4_nir.cpp
> @@ -327,6 +327,24 @@ vec4_visitor::get_nir_src(nir_src src, unsigned num_components)
> return get_nir_src(src, nir_type_int, num_components);
> }
>
> +src_reg
> +vec4_visitor::get_indirect_offset(nir_intrinsic_instr *instr)
> +{
> + nir_src *offset_src = nir_get_io_offset_src(instr);
> + nir_const_value *const_value = nir_src_as_const_value(*offset_src);
> +
> + if (const_value) {
> + /* The only constant offset we should find is 0. brw_nir.c's
> + * add_const_offset_to_base() will fold other constant offsets
> + * into instr->const_index[0].
> + */
> + assert(const_value->u[0] == 0);
> + return src_reg();
> + }
> +
> + return get_nir_src(*offset_src, BRW_REGISTER_TYPE_UD, 1);
> +}
> +
> void
> vec4_visitor::nir_emit_load_const(nir_load_const_instr *instr)
> {
> @@ -650,7 +668,10 @@ vec4_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr)
>
> case nir_intrinsic_load_vertex_id_zero_base:
> case nir_intrinsic_load_base_vertex:
> - case nir_intrinsic_load_instance_id: {
> + case nir_intrinsic_load_instance_id:
> + case nir_intrinsic_load_invocation_id:
> + case nir_intrinsic_load_tess_level_inner:
> + case nir_intrinsic_load_tess_level_outer: {
> gl_system_value sv = nir_system_value_from_intrinsic(instr->intrinsic);
> src_reg val = src_reg(nir_system_values[sv]);
> assert(val.file != BAD_FILE);
> diff --git a/src/mesa/drivers/dri/i965/brw_vec4_tcs.cpp b/src/mesa/drivers/dri/i965/brw_vec4_tcs.cpp
> new file mode 100644
> index 0000000..22224d1
> --- /dev/null
> +++ b/src/mesa/drivers/dri/i965/brw_vec4_tcs.cpp
> @@ -0,0 +1,496 @@
> +/*
> + * Copyright © 2013 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 brw_vec4_tcs.cpp
> + *
> + * Tessellaton control shader specific code derived from the vec4_visitor class.
> + */
> +
> +#include "brw_nir.h"
> +#include "brw_vec4_tcs.h"
> +
> +namespace brw {
> +
> +vec4_tcs_visitor::vec4_tcs_visitor(const struct brw_compiler *compiler,
> + void *log_data,
> + const struct brw_tcs_prog_key *key,
> + struct brw_tcs_prog_data *prog_data,
> + const nir_shader *nir,
> + void *mem_ctx,
> + int shader_time_index)
> + : vec4_visitor(compiler, log_data, &key->tex, &prog_data->base,
> + nir, mem_ctx, false, shader_time_index),
> + key(key)
> +{
> +}
> +
> +
> +void
> +vec4_tcs_visitor::nir_setup_system_value_intrinsic(nir_intrinsic_instr *instr)
> +{
> +}
> +
> +dst_reg *
> +vec4_tcs_visitor::make_reg_for_system_value(int location, const glsl_type *type)
> +{
> + return NULL;
> +}
> +
> +
> +void
> +vec4_tcs_visitor::setup_payload()
> +{
> + int reg = 0;
> +
> + /* The payload always contains important data in r0, which contains
> + * the URB handles that are passed on to the URB write at the end
> + * of the thread.
> + */
> + reg++;
> +
> + /* r1.0 - r4.7 may contain the input control point URB handles,
> + * which we use to pull vertex data.
> + */
> + reg += 4;
> +
> + /* Push constants may start at r5.0 */
> + reg = setup_uniforms(reg);
> +
> + this->first_non_payload_grf = reg;
> +}
> +
> +
> +void
> +vec4_tcs_visitor::emit_prolog()
> +{
> + invocation_id = src_reg(this, glsl_type::uint_type);
> + emit(TCS_OPCODE_GET_INSTANCE_ID, dst_reg(invocation_id));
> +
> + /* HS threads are dispatched with the dispatch mask set to 0xFF.
> + * If there are an odd number of output vertices, then the final
> + * HS instance dispatched will only have its bottom half doing real
> + * work, and so we need to disable the upper half:
> + */
> + if (nir->info.tcs.vertices_out % 2) {
> + emit(CMP(dst_null_d(), invocation_id,
> + brw_imm_ud(nir->info.tcs.vertices_out), BRW_CONDITIONAL_L));
> +
> + /* Matching ENDIF is in emit_thread_end() */
> + emit(IF(BRW_PREDICATE_NORMAL));
> + }
> +}
> +
> +
> +void
> +vec4_tcs_visitor::emit_thread_end()
> +{
> + current_annotation = "thread end";
> +
> + if (nir->info.tcs.vertices_out % 2) {
> + emit(BRW_OPCODE_ENDIF);
> + }
> +
> + if (unlikely(INTEL_DEBUG & DEBUG_SHADER_TIME))
> + emit_shader_time_end();
> +
> + vec4_instruction *inst = emit(VS_OPCODE_URB_WRITE);
> + inst->mlen = 1; /* just the header, no data. */
> + inst->urb_write_flags = BRW_URB_WRITE_EOT_COMPLETE;
> +}
> +
> +
> +void
> +vec4_tcs_visitor::emit_input_urb_read(const dst_reg &dst,
> + const src_reg &vertex_index,
> + unsigned base_offset,
> + const src_reg &indirect_offset)
> +{
> + vec4_instruction *inst;
> + dst_reg temp(this, glsl_type::ivec4_type);
> + temp.type = dst.type;
> +
> + /* Set up the message header to reference the proper parts of the URB */
> + dst_reg header = dst_reg(this, glsl_type::uvec4_type);
> + inst = emit(TCS_OPCODE_SET_INPUT_URB_OFFSETS, header, vertex_index,
> + indirect_offset);
> + inst->force_writemask_all = true;
> +
> + /* Read into a temporary, ignoring writemasking. */
> + inst = emit(VEC4_OPCODE_URB_READ, temp, src_reg(header));
> + inst->offset = base_offset;
> + inst->mlen = 1;
> + inst->base_mrf = -1;
> +
> + /* Copy the temporary to the destination to deal with writemasking.
> + *
> + * Also attempt to deal with gl_PointSize being in the .w component.
> + */
> + if (inst->offset == 0 && indirect_offset.file == BAD_FILE) {
> + emit(MOV(dst, swizzle(src_reg(temp), BRW_SWIZZLE_WWWW)));
> + } else {
> + emit(MOV(dst, src_reg(temp)));
> + }
> +}
> +
> +void
> +vec4_tcs_visitor::emit_output_urb_read(const dst_reg &dst,
> + unsigned base_offset,
> + const src_reg &indirect_offset)
> +{
> + vec4_instruction *inst;
> +
> + /* Set up the message header to reference the proper parts of the URB */
> + dst_reg header = dst_reg(this, glsl_type::uvec4_type);
> + inst = emit(TCS_OPCODE_SET_OUTPUT_URB_OFFSETS, header,
> + brw_imm_ud(dst.writemask), indirect_offset);
> + inst->force_writemask_all = true;
> +
> + /* Read into a temporary, ignoring writemasking. */
> + vec4_instruction *read = emit(VEC4_OPCODE_URB_READ, dst, src_reg(header));
> + read->offset = base_offset;
> + read->mlen = 1;
> + read->base_mrf = -1;
> +}
> +
> +void
> +vec4_tcs_visitor::emit_urb_write(const src_reg &value,
> + unsigned writemask,
> + unsigned base_offset,
> + const src_reg &indirect_offset)
> +{
> + if (writemask == 0)
> + return;
> +
> + src_reg message(this, glsl_type::uvec4_type, 2);
> + vec4_instruction *inst;
> +
> + inst = emit(TCS_OPCODE_SET_OUTPUT_URB_OFFSETS, dst_reg(message),
> + brw_imm_ud(writemask), indirect_offset);
> + inst->force_writemask_all = true;
> + inst = emit(MOV(offset(dst_reg(retype(message, value.type)), 1), value));
> + inst->force_writemask_all = true;
> +
> + inst = emit(TCS_OPCODE_URB_WRITE, dst_null_f(), message);
> + inst->offset = base_offset;
> + inst->mlen = 2;
> + inst->base_mrf = -1;
> +}
> +
> +static unsigned
> +tesslevel_outer_components(GLenum tes_primitive_mode)
> +{
> + switch (tes_primitive_mode) {
> + case GL_QUADS:
> + return 4;
> + case GL_TRIANGLES:
> + return 3;
> + case GL_ISOLINES:
> + return 2;
> + default:
> + unreachable("Bogus tessellation domain");
> + }
> + return 0;
> +}
> +
> +static unsigned
> +tesslevel_inner_components(GLenum tes_primitive_mode)
> +{
> + switch (tes_primitive_mode) {
> + case GL_QUADS:
> + return 2;
> + case GL_TRIANGLES:
> + return 1;
> + case GL_ISOLINES:
> + return 0;
> + default:
> + unreachable("Bogus tessellation domain");
> + }
> + return 0;
> +}
> +
> +/**
> + * Given a normal .xyzw writemask, convert it to a writemask for a vector
> + * that's stored backwards, i.e. .wzyx.
> + */
> +static unsigned
> +writemask_for_backwards_vector(unsigned mask)
> +{
> + unsigned new_mask = 0;
> +
> + for (int i = 0; i < 4; i++)
> + new_mask |= ((mask >> i) & 1) << (3 - i);
> +
> + return new_mask;
> +}
> +
> +void
> +vec4_tcs_visitor::nir_emit_intrinsic(nir_intrinsic_instr *instr)
> +{
> + switch (instr->intrinsic) {
> + case nir_intrinsic_load_invocation_id:
> + emit(MOV(get_nir_dest(instr->dest, BRW_REGISTER_TYPE_UD),
> + invocation_id));
> + break;
> + case nir_intrinsic_load_primitive_id:
> + emit(TCS_OPCODE_GET_PRIMITIVE_ID,
> + get_nir_dest(instr->dest, BRW_REGISTER_TYPE_UD));
> + break;
> + case nir_intrinsic_load_patch_vertices_in:
> + unreachable("XXX: gl_PatchVerticesIn not implemented yet.");
> + break;
> + case nir_intrinsic_load_per_vertex_input: {
> + src_reg indirect_offset = get_indirect_offset(instr);
> + unsigned imm_offset = instr->const_index[0];
> +
> + nir_const_value *vertex_const = nir_src_as_const_value(instr->src[0]);
> + src_reg vertex_index =
> + vertex_const ? src_reg(brw_imm_ud(vertex_const->u[0]))
> + : get_nir_src(instr->src[0], BRW_REGISTER_TYPE_UD, 1);
> +
> + dst_reg dst = get_nir_dest(instr->dest, BRW_REGISTER_TYPE_D);
> + dst.writemask = brw_writemask_for_size(instr->num_components);
> +
> + emit_input_urb_read(dst, vertex_index, imm_offset, indirect_offset);
> + break;
> + }
> + case nir_intrinsic_load_input:
> + unreachable("nir_lower_io should use load_per_vertex_input intrinsics");
> + break;
> + case nir_intrinsic_load_output:
> + case nir_intrinsic_load_per_vertex_output: {
> + src_reg indirect_offset = get_indirect_offset(instr);
> + unsigned imm_offset = instr->const_index[0];;
> +
> + dst_reg dst = get_nir_dest(instr->dest, BRW_REGISTER_TYPE_D);
> + dst.writemask = brw_writemask_for_size(instr->num_components);
> +
> + if (imm_offset == 0 && indirect_offset.file == BAD_FILE) {
> + dst.type = BRW_REGISTER_TYPE_F;
> +
> + /* This is a read of gl_TessLevelInner[], which lives in the
> + * Patch URB header. The layout depends on the domain.
> + */
> + switch (key->tes_primitive_mode) {
> + case GL_QUADS: {
> + /* DWords 3-2 (reversed); use offset 0 and WZYX swizzle. */
> + dst_reg tmp(this, glsl_type::vec4_type);
> + emit_output_urb_read(tmp, 0, src_reg());
> + emit(MOV(writemask(dst, WRITEMASK_XY),
> + swizzle(src_reg(tmp), BRW_SWIZZLE_WZYX)));
> + break;
> + }
> + case GL_TRIANGLES:
> + /* DWord 4; use offset 1 but normal swizzle/writemask. */
> + emit_output_urb_read(writemask(dst, WRITEMASK_X), 1, src_reg());
> + break;
> + case GL_ISOLINES:
> + /* All channels are undefined. */
> + return;
> + default:
> + unreachable("Bogus tessellation domain");
> + }
> + } else if (imm_offset == 1 && indirect_offset.file == BAD_FILE) {
> + dst.type = BRW_REGISTER_TYPE_F;
> +
> + /* This is a read of gl_TessLevelOuter[], which lives in the
> + * high 4 DWords of the Patch URB header, in reverse order.
> + */
> + switch (key->tes_primitive_mode) {
> + case GL_QUADS:
> + dst.writemask = WRITEMASK_XYZW;
> + break;
> + case GL_TRIANGLES:
> + dst.writemask = WRITEMASK_XYZ;
> + break;
> + case GL_ISOLINES:
> + dst.writemask = WRITEMASK_XY;
> + return;
> + default:
> + unreachable("Bogus tessellation domain");
> + }
> +
> + dst_reg tmp(this, glsl_type::vec4_type);
> + emit_output_urb_read(tmp, 1, src_reg());
> + emit(MOV(dst, swizzle(src_reg(tmp), BRW_SWIZZLE_WZYX)));
> + } else {
> + emit_output_urb_read(dst, imm_offset, indirect_offset);
> + }
> + break;
> + }
> + case nir_intrinsic_store_output:
> + case nir_intrinsic_store_per_vertex_output: {
> + src_reg value = get_nir_src(instr->src[0]);
> + unsigned mask = instr->const_index[1];
> + unsigned swiz = BRW_SWIZZLE_XYZW;
> +
> + src_reg indirect_offset = get_indirect_offset(instr);
> + unsigned imm_offset = instr->const_index[0];
> +
> + if (imm_offset == 0 && indirect_offset.file == BAD_FILE) {
> + value.type = BRW_REGISTER_TYPE_F;
> +
> + mask &= (1 << tesslevel_inner_components(key->tes_primitive_mode)) - 1;
> +
> + /* This is a write to gl_TessLevelInner[], which lives in the
> + * Patch URB header. The layout depends on the domain.
> + */
> + switch (key->tes_primitive_mode) {
> + case GL_QUADS:
> + /* gl_TessLevelInner[].xy lives at DWords 3-2 (reversed).
> + * We use an XXYX swizzle to reverse put .xy in the .wz
> + * channels, and use a .zw writemask.
> + */
> + swiz = BRW_SWIZZLE4(0, 0, 1, 0);
> + mask = writemask_for_backwards_vector(mask);
> + break;
> + case GL_TRIANGLES:
> + /* gl_TessLevelInner[].x lives at DWord 4, so we set the
> + * writemask to X and bump the URB offset by 1.
> + */
> + imm_offset = 1;
> + break;
> + case GL_ISOLINES:
> + /* Skip; gl_TessLevelInner[] doesn't exist for isolines. */
> + return;
> + default:
> + unreachable("Bogus tessellation domain");
> + }
> + } else if (imm_offset == 1 && indirect_offset.file == BAD_FILE) {
> + value.type = BRW_REGISTER_TYPE_F;
> +
> + mask &= (1 << tesslevel_outer_components(key->tes_primitive_mode)) - 1;
> +
> + /* This is a write to gl_TessLevelOuter[] which lives in the
> + * Patch URB Header at DWords 4-7. However, it's reversed, so
> + * instead of .xyzw we have .wzyx.
> + */
> + swiz = BRW_SWIZZLE_WZYX;
> + mask = writemask_for_backwards_vector(mask);
> + }
> +
> + emit_urb_write(swizzle(value, swiz), mask,
> + imm_offset, indirect_offset);
> + break;
> + }
> +
> + case nir_intrinsic_barrier: {
> + dst_reg header = dst_reg(this, glsl_type::uvec4_type);
> + emit(TCS_OPCODE_CREATE_BARRIER_HEADER, header);
> + emit(SHADER_OPCODE_BARRIER, dst_null_ud(), src_reg(header));
> + break;
> + }
> +
> + default:
> + vec4_visitor::nir_emit_intrinsic(instr);
> + }
> +}
> +
> +
> +extern "C" const unsigned *
> +brw_compile_tcs(const struct brw_compiler *compiler,
> + void *log_data,
> + void *mem_ctx,
> + const struct brw_tcs_prog_key *key,
> + struct brw_tcs_prog_data *prog_data,
> + const nir_shader *src_shader,
> + int shader_time_index,
> + unsigned *final_assembly_size,
> + char **error_str)
> +{
> + const struct brw_device_info *devinfo = compiler->devinfo;
> + struct brw_vue_prog_data *vue_prog_data = &prog_data->base;
> + const bool is_scalar = compiler->scalar_stage[MESA_SHADER_TESS_CTRL];
> +
> + nir_shader *nir = nir_shader_clone(mem_ctx, src_shader);
> + nir = brw_nir_apply_sampler_key(nir, devinfo, &key->tex, is_scalar);
> + nir = brw_postprocess_nir(nir, compiler->devinfo, is_scalar);
> +
> + prog_data->instances = DIV_ROUND_UP(nir->info.tcs.vertices_out, 2);
> +
> + brw_compute_tess_vue_map(&vue_prog_data->vue_map,
> + nir->info.outputs_written,
> + nir->info.patch_outputs_written);
> +
> + /* Compute URB entry size. The maximum allowed URB entry size is 32k.
> + * That divides up as follows:
> + *
> + * 32 bytes for the patch header (tessellation factors)
> + * 480 bytes for per-patch varyings (a varying component is 4 bytes and
> + * gl_MaxTessPatchComponents = 120)
> + * 16384 bytes for per-vertex varyings (a varying component is 4 bytes,
> + * gl_MaxPatchVertices = 32 and
> + * gl_MaxTessControlOutputComponents = 128)
> + *
> + * 15808 bytes left for varying packing overhead
> + */
> + const int num_per_patch_slots = vue_prog_data->vue_map.num_per_patch_slots;
> + const int num_per_vertex_slots = vue_prog_data->vue_map.num_per_vertex_slots;
> + unsigned output_size_bytes = 0;
> + /* Note that the patch header is counted in num_per_patch_slots. */
> + output_size_bytes += num_per_patch_slots * 16;
> + output_size_bytes += nir->info.tcs.vertices_out * num_per_vertex_slots * 16;
> +
> + assert(output_size_bytes >= 1);
> + if (output_size_bytes > GEN7_MAX_HS_URB_ENTRY_SIZE_BYTES)
> + return false;
> +
> + /* URB entry sizes are stored as a multiple of 64 bytes. */
> + vue_prog_data->urb_entry_size = ALIGN(output_size_bytes, 64) / 64;
> +
> + struct brw_vue_map input_vue_map;
> + brw_compute_vue_map(devinfo, &input_vue_map,
> + nir->info.inputs_read & ~VARYING_BIT_PRIMITIVE_ID,
> + true);
> +
> + /* HS does not use the usual payload pushing from URB to GRFs,
> + * because we don't have enough registers for a full-size payload, and
> + * the hardware is broken on Haswell anyway.
> + */
> + vue_prog_data->urb_read_length = 0;
> +
> + if (unlikely(INTEL_DEBUG & DEBUG_TCS)) {
> + fprintf(stderr, "TCS Input ");
> + brw_print_vue_map(stderr, &input_vue_map);
> + fprintf(stderr, "TCS Output ");
> + brw_print_vue_map(stderr, &vue_prog_data->vue_map);
> + }
> +
> + vec4_tcs_visitor v(compiler, log_data, key, prog_data,
> + nir, mem_ctx, shader_time_index);
> + if (!v.run()) {
> + if (error_str)
> + *error_str = ralloc_strdup(mem_ctx, v.fail_msg);
> + return NULL;
> + }
> +
> + if (unlikely(INTEL_DEBUG & DEBUG_TCS))
> + v.dump_instructions();
> +
> + return brw_vec4_generate_assembly(compiler, log_data, mem_ctx, nir,
> + &prog_data->base, v.cfg,
> + final_assembly_size);
> +}
> +
> +
> +} /* namespace brw */
> diff --git a/src/mesa/drivers/dri/i965/brw_vec4_tcs.h b/src/mesa/drivers/dri/i965/brw_vec4_tcs.h
> new file mode 100644
> index 0000000..2bf4885
> --- /dev/null
> +++ b/src/mesa/drivers/dri/i965/brw_vec4_tcs.h
> @@ -0,0 +1,84 @@
> +/*
> + * Copyright © 2013 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 brw_vec4_tcs.h
> + *
> + * The vec4-mode tessellation control shader compiler backend.
> + */
> +
> +#ifndef BRW_VEC4_TCS_H
> +#define BRW_VEC4_TCS_H
> +
> +#include "brw_compiler.h"
> +#include "brw_vec4.h"
> +
> +#ifdef __cplusplus
> +namespace brw {
> +
> +class vec4_tcs_visitor : public vec4_visitor
> +{
> +public:
> + vec4_tcs_visitor(const struct brw_compiler *compiler,
> + void *log_data,
> + const struct brw_tcs_prog_key *key,
> + struct brw_tcs_prog_data *prog_data,
> + const nir_shader *nir,
> + void *mem_ctx,
> + int shader_time_index);
> +
> +protected:
> + virtual dst_reg *make_reg_for_system_value(int location,
> + const glsl_type *type);
> + virtual void nir_setup_system_value_intrinsic(nir_intrinsic_instr *instr);
> + virtual void setup_payload();
> + virtual void emit_prolog();
> + virtual void emit_thread_end();
> +
> + virtual void nir_emit_intrinsic(nir_intrinsic_instr *instr);
> +
> + void emit_input_urb_read(const dst_reg &dst,
> + const src_reg &vertex_index,
> + unsigned base_offset,
> + const src_reg &indirect_offset);
> + void emit_output_urb_read(const dst_reg &dst,
> + unsigned base_offset,
> + const src_reg &indirect_offset);
> +
> + void emit_urb_write(const src_reg &value, unsigned writemask,
> + unsigned base_offset, const src_reg &indirect_offset);
> +
> + /* we do not use the normal end-of-shader URB write mechanism -- but every vec4 stage
> + * must provide implementations of these:
> + */
> + virtual void emit_urb_write_header(int mrf) {}
> + virtual vec4_instruction *emit_urb_write_opcode(bool complete) { return NULL; }
> +
> + const struct brw_tcs_prog_key *key;
> + src_reg invocation_id;
> +};
> +
> +} /* namespace brw */
> +#endif /* __cplusplus */
> +
> +#endif /* BRW_VEC4_TCS_H */
> --
> 2.6.3
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list