diff --git a/src/gallium/auxiliary/meson.build b/src/gallium/auxiliary/meson.build index 3e91a6c2723..76dd0e1f4a5 100644 --- a/src/gallium/auxiliary/meson.build +++ b/src/gallium/auxiliary/meson.build @@ -183,6 +183,7 @@ files_libgallium = files( 'tgsi/tgsi_build.h', 'tgsi/tgsi_dump.c', 'tgsi/tgsi_dump.h', + 'tgsi/tgsi_dynamic_indexing.c', 'tgsi/tgsi_exec.c', 'tgsi/tgsi_exec.h', 'tgsi/tgsi_emulate.c', @@ -217,6 +218,7 @@ files_libgallium = files( 'tgsi/tgsi_ureg.h', 'tgsi/tgsi_util.c', 'tgsi/tgsi_util.h', + 'tgsi/tgsi_vpos.c', 'translate/translate.c', 'translate/translate.h', 'translate/translate_cache.c', diff --git a/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.c b/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.c new file mode 100644 index 00000000000..3f3a3ba523e --- /dev/null +++ b/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.c @@ -0,0 +1,361 @@ +/* + * Copyright 2018 VMware, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS 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. + */ + + +/** + * This utility transforms the shader to support dynamic array indexing + * for samplers and constant buffers. + * It calculates dynamic array index first and then compare it with each + * index and operation will be performed with matching index + */ + +#include "util/u_debug.h" +#include "util/u_math.h" +#include "tgsi_info.h" +#include "tgsi_dynamic_indexing.h" +#include "tgsi_transform.h" +#include "tgsi_dump.h" +#include "pipe/p_state.h" + + +struct dIndexing_transform_context +{ + struct tgsi_transform_context base; + unsigned orig_num_tmp; + unsigned orig_num_imm; + unsigned num_const_bufs; + unsigned num_samplers; + unsigned num_iterations; + unsigned const_buf_range[PIPE_MAX_CONSTANT_BUFFERS]; +}; + + +static inline struct dIndexing_transform_context * +dIndexing_transform_context(struct tgsi_transform_context *ctx) +{ + return (struct dIndexing_transform_context *) ctx; +} + + +/** + * TGSI declaration transform callback. + */ +static void +dIndexing_decl(struct tgsi_transform_context *ctx, + struct tgsi_full_declaration *decl) +{ + struct dIndexing_transform_context *dc = dIndexing_transform_context(ctx); + + if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { + /** + * Emit some extra temporary register to use in keeping track of + * dynamic index. + */ + dc->orig_num_tmp = decl->Range.Last; + decl->Range.Last = decl->Range.Last + 3; + } + else if (decl->Declaration.File == TGSI_FILE_CONSTANT) { + /* Keep track of number of constants in each buffer */ + dc->const_buf_range[decl->Dim.Index2D] = decl->Range.Last; + } + ctx->emit_declaration(ctx, decl); +} + + +/** + * TGSI transform prolog callback. + */ +static void +dIndexing_prolog(struct tgsi_transform_context *ctx) +{ + tgsi_transform_immediate_int_decl(ctx, 0, 1, 2, 3); + tgsi_transform_immediate_int_decl(ctx, 4, 5, 6, 7); +} + + +/** + * This function emits some extra instruction to remove dynamic array + * indexing of constant buffers / samplers from the shader. + * It calculates dynamic array index first and compare it with each index for + * declared constants/samplers. + */ +static void +remove_dynamic_indexes(struct tgsi_transform_context *ctx, + struct tgsi_full_instruction *orig_inst, + const struct tgsi_full_src_register *reg) +{ + struct dIndexing_transform_context *dc = dIndexing_transform_context(ctx); + int i, j; + int tmp_loopIdx = dc->orig_num_tmp + 1; + int tmp_cond = dc->orig_num_tmp + 2; + int tmp_arrayIdx = dc->orig_num_tmp + 3; + int imm_index = dc->orig_num_imm; + struct tgsi_full_instruction inst; + unsigned INVALID_INDEX = 99999; + unsigned file = TGSI_FILE_NULL, index = INVALID_INDEX; + unsigned imm_swz_index = INVALID_INDEX; + + /* calculate dynamic array index store it in tmp_arrayIdx.x */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_UADD; + inst.Instruction.NumDstRegs = 1; + tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, + tmp_arrayIdx, TGSI_WRITEMASK_X); + inst.Instruction.NumSrcRegs = 2; + if (reg->Register.File == TGSI_FILE_CONSTANT) { + file = reg->DimIndirect.File; + index = reg->DimIndirect.Index; + imm_swz_index = reg->Dimension.Index; + } + else if (reg->Register.File == TGSI_FILE_SAMPLER) { + file = reg->Indirect.File; + index = reg->Indirect.Index; + imm_swz_index = reg->Register.Index; + } + tgsi_transform_src_reg(&inst.Src[0], file, + index, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, TGSI_SWIZZLE_X); + tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_IMMEDIATE, + imm_index + (imm_swz_index / 4), + imm_swz_index % 4, + imm_swz_index % 4, + imm_swz_index % 4, + imm_swz_index % 4); + ctx->emit_instruction(ctx, &inst); + + /* initialize counter to zero: tmp_loopIdx = 0 */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MOV; + inst.Instruction.NumDstRegs = 1; + tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, + tmp_loopIdx, TGSI_WRITEMASK_X); + inst.Instruction.NumSrcRegs = 1; + tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_IMMEDIATE, + imm_index, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X); + ctx->emit_instruction(ctx, &inst); + + for (i = 0; i < dc->num_iterations; i++) { + boolean out_of_bound_index = FALSE; + /** + * Make sure we are not exceeding index limit of constant buffer + * + * For example, In declaration, We have + * + * DCL CONST[0][0..1] + * DCL CONST[1][0..2] + * DCL CONST[2][0] + * + * and our dynamic index instruction is + * MOV TEMP[0], CONST[ADDR[0].x][1] + * + * We have to make sure to skip unrolling for CONST[2] because + * it has only one constant in the buffer + */ + if ((reg->Register.File == TGSI_FILE_CONSTANT) && + (!reg->Register.Indirect && + (reg->Register.Index > dc->const_buf_range[i]))) { + out_of_bound_index = TRUE; + } + + if (!out_of_bound_index) { + /** + * If we have an instruction of the format: + * OPCODE dst, src..., CONST[K][foo], src... + * where K is dynamic and tmp_loopIdx = i (loopcount), + * replace it with: + * + * if (K == tmp_loopIdx) + * OPCODE dst, src... where src is CONST[i][foo] and i is constant + * } + * + * Similarly, If instruction uses dynamic array index for samplers + * e.g. OPCODE dst, src, SAMPL[k] .. + * replace it with: + * if (K == tmp_loopIdx) + * OPCODE dst, src, SAMPL[i][foo]... where i is constant. + * } + */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_USEQ; + inst.Instruction.NumDstRegs = 1; + tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, + tmp_cond, TGSI_WRITEMASK_X); + inst.Instruction.NumSrcRegs = 2; + tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY, + tmp_arrayIdx, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X); + tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_TEMPORARY, + tmp_loopIdx, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X); + ctx->emit_instruction(ctx, &inst); + + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_UIF; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 1; + tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY, + tmp_cond, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X); + ctx->emit_instruction(ctx, &inst); + + /* emit instruction with new, non-dynamic source registers */ + inst = *orig_inst; + for (j = 0; j < inst.Instruction.NumSrcRegs; j++) { + if (inst.Src[j].Dimension.Indirect && + inst.Src[j].Register.File == TGSI_FILE_CONSTANT) { + inst.Src[j].Register.Dimension = 1; + inst.Src[j].Dimension.Index = i; + inst.Src[j].Dimension.Indirect = 0; + } + else if (inst.Src[j].Register.Indirect && + inst.Src[j].Register.File == TGSI_FILE_SAMPLER) { + inst.Src[j].Register.Indirect = 0; + inst.Src[j].Register.Index = i; + } + } + ctx->emit_instruction(ctx, &inst); + + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ENDIF; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + ctx->emit_instruction(ctx, &inst); + } + + /** + * Increment counter + * UADD tmp_loopIdx.x tmp_loopIdx.x imm(1) + */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_UADD; + inst.Instruction.NumDstRegs = 1; + tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, + tmp_loopIdx, TGSI_WRITEMASK_X); + inst.Instruction.NumSrcRegs = 2; + tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY, + tmp_loopIdx, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, TGSI_SWIZZLE_X); + tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_IMMEDIATE, imm_index, + TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y, + TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y); + + ctx->emit_instruction(ctx, &inst); + } +} + + +/** + * TGSI instruction transform callback. + */ +static void +dIndexing_inst(struct tgsi_transform_context *ctx, + struct tgsi_full_instruction *inst) +{ + int i; + boolean indexing = FALSE; + struct dIndexing_transform_context *dc = dIndexing_transform_context(ctx); + + for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { + struct tgsi_full_src_register *src; + src = &inst->Src[i]; + /* check if constant buffer/sampler is using dynamic index */ + if ((src->Dimension.Indirect && + src->Register.File == TGSI_FILE_CONSTANT) || + (src->Register.Indirect && + src->Register.File == TGSI_FILE_SAMPLER)) { + + if (indexing) + assert("More than one src has dynamic indexing"); + + if (src->Register.File == TGSI_FILE_CONSTANT) + dc->num_iterations = dc->num_const_bufs; + else + dc->num_iterations = dc->num_samplers; + + remove_dynamic_indexes(ctx, inst, src); + indexing = TRUE; + } + } + + if (!indexing) { + ctx->emit_instruction(ctx, inst); + } +} + +/** + * TGSI utility to remove dynamic array indexing for constant buffers and + * samplers. + * + * This utility accepts bitmask of declared constant buffers and samplers, + * number of immediates used in shader. + * + * If dynamic array index is used for constant buffers and samplers, this + * utility removes those dynamic indexes from shader. It also makes sure + * that it has same output as per original shader. + * This is achieved by calculating dynamic array index first and then compare + * it with each constant buffer/ sampler index and replace that dynamic index + * with static index. + */ +struct tgsi_token * +tgsi_remove_dynamic_indexing(const struct tgsi_token *tokens_in, + unsigned const_buffers_declared_bitmask, + unsigned samplers_declared_bitmask, + unsigned imm_count) +{ + struct dIndexing_transform_context transform; + const uint num_new_tokens = 1000; /* should be enough */ + const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens; + struct tgsi_token *new_tokens; + + /* setup transformation context */ + memset(&transform, 0, sizeof(transform)); + transform.base.transform_declaration = dIndexing_decl; + transform.base.transform_instruction = dIndexing_inst; + transform.base.prolog = dIndexing_prolog; + + transform.orig_num_tmp = 0; + transform.orig_num_imm = imm_count; + /* get count of declared const buffers and sampler from their bitmasks*/ + transform.num_const_bufs = log2(const_buffers_declared_bitmask + 1); + transform.num_samplers = log2(samplers_declared_bitmask + 1); + transform.num_iterations = 0; + + /* allocate new tokens buffer */ + new_tokens = tgsi_alloc_tokens(new_len); + if (!new_tokens) + return NULL; + + /* transform the shader */ + tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base); + + return new_tokens; +} + + diff --git a/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.h b/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.h new file mode 100644 index 00000000000..c1b0d6f34f5 --- /dev/null +++ b/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.h @@ -0,0 +1,38 @@ +/* + * Copyright 2018 VMware, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS 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. + */ + +#ifndef TGSI_DYNAMIC_INDEXING_H +#define TGSI_DYNAMIC_INDEXING_H + +struct tgsi_token; +struct tgsi_shader_info; + +struct tgsi_token * +tgsi_remove_dynamic_indexing(const struct tgsi_token *tokens_in, + unsigned const_buffers_declared, + unsigned samplers_declared, + unsigned imm_count); + +#endif /* TGSI_DYNAMIC_INDEXING_H */ diff --git a/src/gallium/auxiliary/tgsi/tgsi_transform.h b/src/gallium/auxiliary/tgsi/tgsi_transform.h index 018e4a06d82..727edeb05ac 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_transform.h +++ b/src/gallium/auxiliary/tgsi/tgsi_transform.h @@ -223,6 +223,24 @@ tgsi_transform_immediate_decl(struct tgsi_transform_context *ctx, ctx->emit_immediate(ctx, &immed); } +static inline void +tgsi_transform_immediate_int_decl(struct tgsi_transform_context *ctx, + int x, int y, int z, int w) +{ + struct tgsi_full_immediate immed; + unsigned size = 4; + + immed = tgsi_default_full_immediate(); + immed.Immediate.DataType = TGSI_IMM_INT32; + immed.Immediate.NrTokens = 1 + size; /* one for the token itself */ + immed.u[0].Int = x; + immed.u[1].Int = y; + immed.u[2].Int = z; + immed.u[3].Int = w; + + ctx->emit_immediate(ctx, &immed); +} + static inline void tgsi_transform_dst_reg(struct tgsi_full_dst_register *reg, unsigned file, unsigned index, unsigned writemask) diff --git a/src/gallium/auxiliary/tgsi/tgsi_vpos.c b/src/gallium/auxiliary/tgsi/tgsi_vpos.c new file mode 100644 index 00000000000..daae4f4aeca --- /dev/null +++ b/src/gallium/auxiliary/tgsi/tgsi_vpos.c @@ -0,0 +1,109 @@ +/* + * Copyright 2018 VMware, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS 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. + */ + + +/** + * TGSI utility transforms the shader to write imm(0, 0, 0, 1) to vertex + * position + */ + +#include "util/u_debug.h" +#include "util/u_math.h" +#include "tgsi_vpos.h" +#include "tgsi_transform.h" +#include "tgsi_dump.h" +#include "pipe/p_state.h" + + +struct write_vpos_context +{ + struct tgsi_transform_context base; + unsigned imm_index; +}; + + +static inline struct write_vpos_context * +write_vpos_context(struct tgsi_transform_context *ctx) +{ + return (struct write_vpos_context *) ctx; +} + + +/** + * TGSI transform prolog callback. + */ +static void +write_vpos_prolog(struct tgsi_transform_context *ctx) +{ + struct write_vpos_context *vc = write_vpos_context(ctx); + struct tgsi_full_instruction inst; + + tgsi_transform_immediate_decl(ctx, 0.0, 0.0, 0.0, 1.0); + tgsi_transform_output_decl(ctx, 0, + TGSI_SEMANTIC_POSITION, 0, + 0); + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MOV; + inst.Instruction.NumDstRegs = 1; + tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_OUTPUT, + 0, TGSI_WRITEMASK_XYZW); + inst.Instruction.NumSrcRegs = 1; + tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_IMMEDIATE, + vc->imm_index, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_W); + ctx->emit_instruction(ctx, &inst); +} + + +/** + * TGSI utility writes imm(0, 0, 0, 1) to vertex position + */ +struct tgsi_token * +tgsi_write_vpos(const struct tgsi_token *tokens_in, + unsigned num_immediates) +{ + struct write_vpos_context transform; + const uint num_new_tokens = 1000; /* should be enough */ + const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens; + struct tgsi_token *new_tokens; + + /* setup transformation context */ + memset(&transform, 0, sizeof(transform)); + transform.base.prolog = write_vpos_prolog; + + transform.imm_index = num_immediates; + + /* allocate new tokens buffer */ + new_tokens = tgsi_alloc_tokens(new_len); + if (!new_tokens) + return NULL; + + /* transform the shader */ + tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base); + + return new_tokens; +} + + diff --git a/src/gallium/auxiliary/tgsi/tgsi_vpos.h b/src/gallium/auxiliary/tgsi/tgsi_vpos.h new file mode 100644 index 00000000000..4c2ef81fdb9 --- /dev/null +++ b/src/gallium/auxiliary/tgsi/tgsi_vpos.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 VMware, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS 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. + */ + +#ifndef TGSI_WRITE_VPOS_H +#define TGSI_WRITE_VPOS_H + +struct tgsi_token; + +struct tgsi_token * +tgsi_write_vpos(const struct tgsi_token *tokens_in, + unsigned num_immediates); + +#endif /* TGSI_WRIE_VPOS_H */ diff --git a/src/gallium/auxiliary/util/u_simple_shaders.c b/src/gallium/auxiliary/util/u_simple_shaders.c index ceb59507901..1908f6198a3 100644 --- a/src/gallium/auxiliary/util/u_simple_shaders.c +++ b/src/gallium/auxiliary/util/u_simple_shaders.c @@ -895,6 +895,7 @@ util_make_geometry_passthrough_shader(struct pipe_context *pipe, return ureg_create_shader_and_destroy(ureg, pipe); } + /** * Blit from color to ZS or from ZS to color in a manner that is equivalent * to memcpy. @@ -1056,3 +1057,110 @@ util_make_fs_pack_color_zs(struct pipe_context *pipe, return ureg_create_shader_and_destroy(ureg, pipe); } + + +/** + * Create passthrough tessellation control shader. + * Passthrough tessellation control shader has output of vertex shader + * as input and input of tessellation eval shader as output. + */ +void * +util_make_tess_ctrl_passthrough_shader(struct pipe_context *pipe, + uint num_vs_outputs, + uint num_tes_inputs, + const ubyte *vs_semantic_names, + const ubyte *vs_semantic_indexes, + const ubyte *tes_semantic_names, + const ubyte *tes_semantic_indexes, + const unsigned vertices_per_patch) +{ + unsigned i, j; + unsigned num_regs; + + struct ureg_program *ureg; + struct ureg_dst temp, addr; + struct ureg_src invocationID; + struct ureg_dst dst[PIPE_MAX_SHADER_OUTPUTS]; + struct ureg_src src[PIPE_MAX_SHADER_INPUTS]; + + ureg = ureg_create(PIPE_SHADER_TESS_CTRL); + + if (!ureg) + return NULL; + + ureg_property(ureg, TGSI_PROPERTY_TCS_VERTICES_OUT, vertices_per_patch); + + num_regs = 0; + + for (i = 0; i < num_tes_inputs; i++) { + switch (tes_semantic_names[i]) { + case TGSI_SEMANTIC_POSITION: + case TGSI_SEMANTIC_PSIZE: + case TGSI_SEMANTIC_COLOR: + case TGSI_SEMANTIC_BCOLOR: + case TGSI_SEMANTIC_CLIPDIST: + case TGSI_SEMANTIC_CLIPVERTEX: + case TGSI_SEMANTIC_TEXCOORD: + case TGSI_SEMANTIC_FOG: + case TGSI_SEMANTIC_GENERIC: + for (j = 0; j < num_vs_outputs; j++) { + if (tes_semantic_names[i] == vs_semantic_names[j] && + tes_semantic_indexes[i] == vs_semantic_indexes[j]) { + + dst[num_regs] = ureg_DECL_output(ureg, + tes_semantic_names[i], + tes_semantic_indexes[i]); + src[num_regs] = ureg_DECL_input(ureg, vs_semantic_names[j], + vs_semantic_indexes[j], + 0, 1); + + if (tes_semantic_names[i] == TGSI_SEMANTIC_GENERIC || + tes_semantic_names[i] == TGSI_SEMANTIC_POSITION) { + src[num_regs] = ureg_src_dimension(src[num_regs], 0); + dst[num_regs] = ureg_dst_dimension(dst[num_regs], 0); + } + + num_regs++; + break; + } + } + break; + default: + break; + } + } + + dst[num_regs] = ureg_DECL_output(ureg, TGSI_SEMANTIC_TESSOUTER, + num_regs); + src[num_regs] = ureg_DECL_constant(ureg, 0); + num_regs++; + dst[num_regs] = ureg_DECL_output(ureg, TGSI_SEMANTIC_TESSINNER, + num_regs); + src[num_regs] = ureg_DECL_constant(ureg, 1); + num_regs++; + + if (vertices_per_patch > 1) { + invocationID = ureg_DECL_system_value(ureg, + TGSI_SEMANTIC_INVOCATIONID, 0); + temp = ureg_DECL_local_temporary(ureg); + addr = ureg_DECL_address(ureg); + ureg_UARL(ureg, ureg_writemask(addr, TGSI_WRITEMASK_X), + ureg_scalar(invocationID, TGSI_SWIZZLE_X)); + } + + for (i = 0; i < num_regs; i++) { + if (dst[i].Dimension && vertices_per_patch > 1) { + struct ureg_src addr_x = ureg_scalar(ureg_src(addr), TGSI_SWIZZLE_X); + ureg_MOV(ureg, temp, ureg_src_dimension_indirect(src[i], + addr_x, 0)); + ureg_MOV(ureg, ureg_dst_dimension_indirect(dst[i], + addr_x, 0), ureg_src(temp)); + } + else + ureg_MOV(ureg, dst[i], src[i]); + } + + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} diff --git a/src/gallium/auxiliary/util/u_simple_shaders.h b/src/gallium/auxiliary/util/u_simple_shaders.h index 501906d6fd3..9e024d05f72 100644 --- a/src/gallium/auxiliary/util/u_simple_shaders.h +++ b/src/gallium/auxiliary/util/u_simple_shaders.h @@ -159,6 +159,15 @@ util_make_fs_pack_color_zs(struct pipe_context *pipe, enum pipe_format zs_format, bool dst_is_color); +extern void * +util_make_tess_ctrl_passthrough_shader(struct pipe_context *pipe, + uint num_vs_outputs, + uint num_tes_inputs, + const ubyte *vs_semantic_names, + const ubyte *vs_semantic_indexes, + const ubyte *tes_semantic_names, + const ubyte *tes_semantic_indexes, + const unsigned vertices_per_patch); #ifdef __cplusplus } #endif