{
this->file = file;
this->index = index;
+ this->index2D = 0;
this->writemask = writemask;
this->cond_mask = COND_TR;
this->reladdr = NULL;
+ this->reladdr2 = NULL;
+ this->has_index2 = false;
this->type = type;
this->array_id = 0;
}
{
this->file = file;
this->index = 0;
+ this->index2D = 0;
this->writemask = writemask;
this->cond_mask = COND_TR;
this->reladdr = NULL;
+ this->reladdr2 = NULL;
+ this->has_index2 = false;
this->type = type;
this->array_id = 0;
}
this->type = GLSL_TYPE_ERROR;
this->file = PROGRAM_UNDEFINED;
this->index = 0;
+ this->index2D = 0;
this->writemask = 0;
this->cond_mask = COND_TR;
this->reladdr = NULL;
+ this->reladdr2 = NULL;
+ this->has_index2 = false;
this->array_id = 0;
}
gl_register_file file; /**< PROGRAM_* from Mesa */
int index; /**< temporary index, VERT_ATTRIB_*, VARYING_SLOT_*, etc. */
+ int index2D;
int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
GLuint cond_mask:4;
int type; /** GLSL_TYPE_* from GLSL IR (enum glsl_base_type) */
/** Register index should be offset by the integer in this reg. */
st_src_reg *reladdr;
+ st_src_reg *reladdr2;
+ bool has_index2;
unsigned array_id;
};
this->swizzle = SWIZZLE_XYZW;
this->negate = 0;
this->reladdr = reg.reladdr;
- this->index2D = 0;
- this->reladdr2 = NULL;
- this->has_index2 = false;
+ this->index2D = reg.index2D;
+ this->reladdr2 = reg.reladdr2;
+ this->has_index2 = reg.has_index2;
this->double_reg2 = false;
this->array_id = reg.array_id;
}
this->writemask = WRITEMASK_XYZW;
this->cond_mask = COND_TR;
this->reladdr = reg.reladdr;
+ this->index2D = reg.index2D;
+ this->reladdr2 = reg.reladdr2;
+ this->has_index2 = reg.has_index2;
this->array_id = reg.array_id;
}
* reg directly for one of the regs, and preload the other reladdr
* sources into temps.
*/
- num_reladdr += dst.reladdr != NULL;
- num_reladdr += dst1.reladdr != NULL;
+ num_reladdr += dst.reladdr != NULL || dst.reladdr2;
+ num_reladdr += dst1.reladdr != NULL || dst1.reladdr2;
num_reladdr += src0.reladdr != NULL || src0.reladdr2 != NULL;
num_reladdr += src1.reladdr != NULL || src1.reladdr2 != NULL;
num_reladdr += src2.reladdr != NULL || src2.reladdr2 != NULL;
reladdr_to_temp(ir, &src1, &num_reladdr);
reladdr_to_temp(ir, &src0, &num_reladdr);
- if (dst.reladdr) {
- emit_arl(ir, address_reg, *dst.reladdr);
+ if (dst.reladdr || dst.reladdr2) {
+ if (dst.reladdr)
+ emit_arl(ir, address_reg, *dst.reladdr);
+ if (dst.reladdr2)
+ emit_arl(ir, address_reg2, *dst.reladdr2);
num_reladdr--;
}
if (dst1.reladdr) {
inst->function = NULL;
/* Update indirect addressing status used by TGSI */
- if (dst.reladdr) {
+ if (dst.reladdr || dst.reladdr2) {
switch(dst.file) {
case PROGRAM_STATE_VAR:
case PROGRAM_CONSTANT:
case TGSI_OPCODE_##c: \
if (type == GLSL_TYPE_DOUBLE) \
op = TGSI_OPCODE_##d; \
- else if (type == GLSL_TYPE_INT) \
+ else if (type == GLSL_TYPE_INT || type == GLSL_TYPE_SUBROUTINE) \
op = TGSI_OPCODE_##i; \
else if (type == GLSL_TYPE_UINT) \
op = TGSI_OPCODE_##u; \
return size;
case GLSL_TYPE_SAMPLER:
case GLSL_TYPE_IMAGE:
+ case GLSL_TYPE_SUBROUTINE:
/* Samplers take up one slot in UNIFORMS[], but they're baked in
* at link time.
*/
result_src = op[0];
}
break;
+ case ir_unop_subroutine_to_int:
+ emit_asm(ir, TGSI_OPCODE_MOV, result_dst, op[0]);
+ break;
case ir_unop_abs:
emit_asm(ir, TGSI_OPCODE_ABS, result_dst, op[0]);
break;
*is_2d = false;
- if (stage == MESA_SHADER_GEOMETRY && var->data.mode == ir_var_shader_in) {
+ if (((stage == MESA_SHADER_GEOMETRY && var->data.mode == ir_var_shader_in) ||
+ (stage == MESA_SHADER_TESS_EVAL && var->data.mode == ir_var_shader_in) ||
+ stage == MESA_SHADER_TESS_CTRL) &&
+ !var->data.patch) {
if (!var->type->is_array())
return false; /* a system value probably */
static void
shrink_array_declarations(struct array_decl *arrays, unsigned count,
- GLbitfield64 usage_mask)
+ GLbitfield64 usage_mask,
+ GLbitfield patch_usage_mask)
{
unsigned i, j;
/* Shrink the beginning. */
for (j = 0; j < decl->array_size; j++) {
- if (usage_mask & BITFIELD64_BIT(decl->mesa_index+j))
- break;
+ if (decl->mesa_index >= VARYING_SLOT_PATCH0) {
+ if (patch_usage_mask &
+ BITFIELD64_BIT(decl->mesa_index - VARYING_SLOT_PATCH0 + j))
+ break;
+ }
+ else {
+ if (usage_mask & BITFIELD64_BIT(decl->mesa_index+j))
+ break;
+ }
decl->mesa_index++;
decl->array_size--;
/* Shrink the end. */
for (j = decl->array_size-1; j >= 0; j--) {
- if (usage_mask & BITFIELD64_BIT(decl->mesa_index+j))
- break;
+ if (decl->mesa_index >= VARYING_SLOT_PATCH0) {
+ if (patch_usage_mask &
+ BITFIELD64_BIT(decl->mesa_index - VARYING_SLOT_PATCH0 + j))
+ break;
+ }
+ else {
+ if (usage_mask & BITFIELD64_BIT(decl->mesa_index+j))
+ break;
+ }
decl->array_size--;
}
ir_constant *index;
st_src_reg src;
int element_size = type_size(ir->type);
- bool is_2D_input;
+ bool is_2D = false;
index = ir->array_index->constant_expression_value();
ir->array->accept(this);
src = this->result;
- is_2D_input = this->prog->Target == GL_GEOMETRY_PROGRAM_NV &&
- src.file == PROGRAM_INPUT &&
- ir->array->ir_type != ir_type_dereference_array;
+ if (ir->array->ir_type != ir_type_dereference_array) {
+ switch (this->prog->Target) {
+ case GL_TESS_CONTROL_PROGRAM_NV:
+ is_2D = (src.file == PROGRAM_INPUT || src.file == PROGRAM_OUTPUT) &&
+ !ir->variable_referenced()->data.patch;
+ break;
+ case GL_TESS_EVALUATION_PROGRAM_NV:
+ is_2D = src.file == PROGRAM_INPUT &&
+ !ir->variable_referenced()->data.patch;
+ break;
+ case GL_GEOMETRY_PROGRAM_NV:
+ is_2D = src.file == PROGRAM_INPUT;
+ break;
+ }
+ }
- if (is_2D_input)
+ if (is_2D)
element_size = 1;
if (index) {
- if (is_2D_input) {
+ if (is_2D) {
src.index2D = index->value.i[0];
src.has_index2 = true;
} else
/* If there was already a relative address register involved, add the
* new and the old together to get the new offset.
*/
- if (!is_2D_input && src.reladdr != NULL) {
+ if (!is_2D && src.reladdr != NULL) {
st_src_reg accum_reg = get_temp(native_integers ?
glsl_type::int_type : glsl_type::float_type);
index_reg = accum_reg;
}
- if (is_2D_input) {
+ if (is_2D) {
src.reladdr2 = ralloc(mem_ctx, st_src_reg);
memcpy(src.reladdr2, &index_reg, sizeof(index_reg));
src.index2D = 0;
void
glsl_to_tgsi_visitor::visit(ir_barrier *ir)
{
- unreachable("Not implemented!");
+ assert(this->prog->Target == GL_TESS_CONTROL_PROGRAM_NV ||
+ this->prog->Target == GL_COMPUTE_PROGRAM_NV);
+
+ emit_asm(ir, TGSI_OPCODE_BARRIER);
}
glsl_to_tgsi_visitor::glsl_to_tgsi_visitor()
{
int tempWritesSize = 0;
unsigned *tempWrites = NULL;
- unsigned outputWrites[MAX_PROGRAM_OUTPUTS];
+ unsigned outputWrites[VARYING_SLOT_TESS_MAX];
memset(outputWrites, 0, sizeof(outputWrites));
unsigned prevWriteMask = 0;
/* Give up if we encounter relative addressing or flow control. */
- if (inst->dst[0].reladdr ||
- inst->dst[1].reladdr ||
+ if (inst->dst[0].reladdr || inst->dst[0].reladdr2 ||
+ inst->dst[1].reladdr || inst->dst[1].reladdr2 ||
tgsi_get_opcode_info(inst->op)->is_branch ||
inst->op == TGSI_OPCODE_BGNSUB ||
inst->op == TGSI_OPCODE_CONT ||
}
if (inst->dst[0].file == PROGRAM_OUTPUT) {
- assert(inst->dst[0].index < MAX_PROGRAM_OUTPUTS);
+ assert(inst->dst[0].index < (signed)ARRAY_SIZE(outputWrites));
prevWriteMask = outputWrites[inst->dst[0].index];
outputWrites[inst->dst[0].index] |= inst->dst[0].writemask;
} else if (inst->dst[0].file == PROGRAM_TEMPORARY) {
!(inst->dst[0].file == inst->src[0].file &&
inst->dst[0].index == inst->src[0].index) &&
!inst->dst[0].reladdr &&
+ !inst->dst[0].reladdr2 &&
!inst->saturate &&
inst->src[0].file != PROGRAM_ARRAY &&
!inst->src[0].reladdr &&
TGSI_SEMANTIC_SAMPLEID,
TGSI_SEMANTIC_SAMPLEPOS,
TGSI_SEMANTIC_SAMPLEMASK,
+
+ /* Tessellation shaders
+ */
+ TGSI_SEMANTIC_TESSCOORD,
+ TGSI_SEMANTIC_VERTICESIN,
+ TGSI_SEMANTIC_PRIMID,
+ TGSI_SEMANTIC_TESSOUTER,
+ TGSI_SEMANTIC_TESSINNER,
};
/**
if (!array_id) {
if (t->procType == TGSI_PROCESSOR_FRAGMENT)
assert(index < FRAG_RESULT_MAX);
+ else if (t->procType == TGSI_PROCESSOR_TESS_CTRL ||
+ t->procType == TGSI_PROCESSOR_TESS_EVAL)
+ assert(index < VARYING_SLOT_TESS_MAX);
else
assert(index < VARYING_SLOT_MAX);
dst = ureg_dst_indirect(dst, ureg_src(t->address[0]));
}
+ if (dst_reg->has_index2) {
+ if (dst_reg->reladdr2)
+ dst = ureg_dst_dimension_indirect(dst, ureg_src(t->address[1]),
+ dst_reg->index2D);
+ else
+ dst = ureg_dst_dimension(dst, dst_reg->index2D);
+ }
+
return dst;
}
TGSI_SEMANTIC_VERTEXID_NOBASE);
assert(_mesa_sysval_to_semantic[SYSTEM_VALUE_BASE_VERTEX] ==
TGSI_SEMANTIC_BASEVERTEX);
+ assert(_mesa_sysval_to_semantic[SYSTEM_VALUE_TESS_COORD] ==
+ TGSI_SEMANTIC_TESSCOORD);
t = CALLOC_STRUCT(st_translate);
if (!t) {
}
break;
case TGSI_PROCESSOR_GEOMETRY:
+ case TGSI_PROCESSOR_TESS_EVAL:
+ case TGSI_PROCESSOR_TESS_CTRL:
for (i = 0; i < numInputs; i++) {
unsigned array_id = 0;
unsigned array_size;
case TGSI_PROCESSOR_FRAGMENT:
break;
case TGSI_PROCESSOR_GEOMETRY:
+ case TGSI_PROCESSOR_TESS_EVAL:
+ case TGSI_PROCESSOR_TESS_CTRL:
case TGSI_PROCESSOR_VERTEX:
for (i = 0; i < numOutputs; i++) {
unsigned array_id = 0;
/* ----------------------------- End TGSI code ------------------------------ */
-static unsigned
-shader_stage_to_ptarget(gl_shader_stage stage)
-{
- switch (stage) {
- case MESA_SHADER_VERTEX:
- return PIPE_SHADER_VERTEX;
- case MESA_SHADER_FRAGMENT:
- return PIPE_SHADER_FRAGMENT;
- case MESA_SHADER_GEOMETRY:
- return PIPE_SHADER_GEOMETRY;
- case MESA_SHADER_COMPUTE:
- return PIPE_SHADER_COMPUTE;
- }
-
- assert(!"should not be reached");
- return PIPE_SHADER_VERTEX;
-}
-
-
/**
* Convert a shader's GLSL IR into a Mesa gl_program, although without
* generating Mesa IR.
struct gl_shader_compiler_options *options =
&ctx->Const.ShaderCompilerOptions[_mesa_shader_enum_to_shader_stage(shader->Type)];
struct pipe_screen *pscreen = ctx->st->pipe->screen;
- unsigned ptarget = shader_stage_to_ptarget(shader->Stage);
+ unsigned ptarget = st_shader_stage_to_ptarget(shader->Stage);
validate_ir_tree(shader->ir);
prog->Parameters);
/* Remove reads from output registers. */
- lower_output_reads(shader->ir);
+ lower_output_reads(shader->Stage, shader->ir);
/* Emit intermediate IR for main(). */
visit_exec_list(shader->ir, v);
/* Perform optimizations on the instructions in the glsl_to_tgsi_visitor. */
v->simplify_cmp();
- v->copy_propagate();
+
+ if (shader->Type != GL_TESS_CONTROL_SHADER &&
+ shader->Type != GL_TESS_EVALUATION_SHADER)
+ v->copy_propagate();
+
while (v->eliminate_dead_code());
v->merge_two_dsts();
do_set_program_inouts(shader->ir, prog, shader->Stage);
shrink_array_declarations(v->input_arrays, v->num_input_arrays,
- prog->InputsRead);
+ prog->InputsRead, prog->PatchInputsRead);
shrink_array_declarations(v->output_arrays, v->num_output_arrays,
- prog->OutputsWritten);
+ prog->OutputsWritten, prog->PatchOutputsWritten);
count_resources(v, prog);
/* This must be done before the uniform storage is associated. */
struct st_vertex_program *stvp;
struct st_fragment_program *stfp;
struct st_geometry_program *stgp;
+ struct st_tessctrl_program *sttcp;
+ struct st_tesseval_program *sttep;
switch (shader->Type) {
case GL_VERTEX_SHADER:
stgp = (struct st_geometry_program *)prog;
stgp->glsl_to_tgsi = v;
break;
+ case GL_TESS_CONTROL_SHADER:
+ sttcp = (struct st_tessctrl_program *)prog;
+ sttcp->glsl_to_tgsi = v;
+ break;
+ case GL_TESS_EVALUATION_SHADER:
+ sttep = (struct st_tesseval_program *)prog;
+ sttep->glsl_to_tgsi = v;
+ break;
default:
assert(!"should not be reached");
return NULL;
extern "C" {
+static void
+st_dump_program_for_shader_db(struct gl_context *ctx,
+ struct gl_shader_program *prog)
+{
+ /* Dump only successfully compiled and linked shaders to the specified
+ * file. This is for shader-db.
+ *
+ * These options allow some pre-processing of shaders while dumping,
+ * because some apps have ill-formed shaders.
+ */
+ const char *dump_filename = os_get_option("ST_DUMP_SHADERS");
+ const char *insert_directives = os_get_option("ST_DUMP_INSERT");
+
+ if (dump_filename && prog->Name != 0) {
+ FILE *f = fopen(dump_filename, "a");
+
+ if (f) {
+ for (unsigned i = 0; i < prog->NumShaders; i++) {
+ const struct gl_shader *sh = prog->Shaders[i];
+ const char *source;
+ bool skip_version = false;
+
+ if (!sh)
+ continue;
+
+ source = sh->Source;
+
+ /* This string mustn't be changed. shader-db uses it to find
+ * where the shader begins.
+ */
+ fprintf(f, "GLSL %s shader %d source for linked program %d:\n",
+ _mesa_shader_stage_to_string(sh->Stage),
+ i, prog->Name);
+
+ /* Dump the forced version if set. */
+ if (ctx->Const.ForceGLSLVersion) {
+ fprintf(f, "#version %i\n", ctx->Const.ForceGLSLVersion);
+ skip_version = true;
+ }
+
+ /* Insert directives (optional). */
+ if (insert_directives) {
+ if (!ctx->Const.ForceGLSLVersion && prog->Version)
+ fprintf(f, "#version %i\n", prog->Version);
+ fprintf(f, "%s\n", insert_directives);
+ skip_version = true;
+ }
+
+ if (skip_version && strncmp(source, "#version ", 9) == 0) {
+ const char *next_line = strstr(source, "\n");
+
+ if (next_line)
+ source = next_line + 1;
+ else
+ continue;
+ }
+
+ fprintf(f, "%s", source);
+ fprintf(f, "\n");
+ }
+ fclose(f);
+ }
+ }
+}
+
/**
* Link a shader.
* Called via ctx->Driver.LinkShader()
gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(prog->_LinkedShaders[i]->Type);
const struct gl_shader_compiler_options *options =
&ctx->Const.ShaderCompilerOptions[stage];
- unsigned ptarget = shader_stage_to_ptarget(stage);
+ unsigned ptarget = st_shader_stage_to_ptarget(stage);
bool have_dround = pscreen->get_shader_param(pscreen, ptarget,
PIPE_SHADER_CAP_TGSI_DROUND_SUPPORTED);
bool have_dfrexp = pscreen->get_shader_param(pscreen, ptarget,
_mesa_reference_program(ctx, &linked_prog, NULL);
}
+ st_dump_program_for_shader_db(ctx, prog);
return GL_TRUE;
}