const char*
depth_layout_string(ir_depth_layout layout);
+/**
+ * Description of built-in state associated with a uniform
+ *
+ * \sa ir_variable::state_slots
+ */
+struct ir_state_slot {
+ int tokens[5];
+ int swizzle;
+};
+
class ir_variable : public ir_instruction {
public:
ir_variable(const struct glsl_type *, const char *, ir_variable_mode);
*/
int location;
+ /**
+ * Built-in state that backs this uniform
+ *
+ * Once set at variable creation, \c state_slots must remain invariant.
+ * This is because, ideally, this array would be shared by all clones of
+ * this variable in the IR tree. In other words, we'd really like for it
+ * to be a fly-weight.
+ *
+ * If the variable is not a uniform, \c num_state_slots will be zero and
+ * \c state_slots will be \c NULL.
+ */
+ /*@{*/
+ unsigned num_state_slots; /**< Number of state slots used */
+ ir_state_slot *state_slots; /**< State descriptors. */
+ /*@}*/
+
/**
* Emit a warning if this variable is accessed.
*/
var->origin_upper_left = this->origin_upper_left;
var->pixel_center_integer = this->pixel_center_integer;
var->explicit_location = this->explicit_location;
+
+ var->num_state_slots = this->num_state_slots;
+ if (this->state_slots) {
+ /* FINISHME: This really wants to use something like talloc_reference, but
+ * FINISHME: ralloc doesn't have any similar function.
+ */
+ var->state_slots = ralloc_array(var, ir_state_slot,
+ this->num_state_slots);
+ memcpy(var->state_slots, this->state_slots,
+ sizeof(this->state_slots[0]) * var->num_state_slots);
+ }
+
if (this->explicit_location)
var->location = this->location;
add_uniform(exec_list *instructions, glsl_symbol_table *symtab,
const char *name, const glsl_type *type)
{
- return add_variable(instructions, symtab, name, type, ir_var_uniform, -1);
+ ir_variable *const uni =
+ add_variable(instructions, symtab, name, type, ir_var_uniform, -1);
+
+ unsigned i;
+ for (i = 0; _mesa_builtin_uniform_desc[i].name != NULL; i++) {
+ if (strcmp(_mesa_builtin_uniform_desc[i].name, name) == 0) {
+ break;
+ }
+ }
+
+ assert(_mesa_builtin_uniform_desc[i].name != NULL);
+ const struct gl_builtin_uniform_desc* const statevar =
+ &_mesa_builtin_uniform_desc[i];
+
+ const unsigned array_count = type->is_array() ? type->length : 1;
+ uni->num_state_slots = array_count * statevar->num_elements;
+
+ ir_state_slot *slots =
+ ralloc_array(uni, ir_state_slot, uni->num_state_slots);
+
+ uni->state_slots = slots;
+
+ for (unsigned a = 0; a < array_count; a++) {
+ for (unsigned j = 0; j < statevar->num_elements; j++) {
+ struct gl_builtin_uniform_element *element = &statevar->elements[j];
+
+ memcpy(slots->tokens, element->tokens, sizeof(element->tokens));
+ if (type->is_array()) {
+ slots->tokens[1] = a;
+ }
+
+ slots->swizzle = element->swizzle;
+ slots++;
+ }
+ }
+
+ return uni;
}
static void
assert(type != NULL);
- add_variable(instructions, symtab, proto->name, type, proto->mode,
- proto->slot);
+ if (proto->mode == ir_var_uniform) {
+ add_uniform(instructions, symtab, proto->name, type);
+ } else {
+ add_variable(instructions, symtab, proto->name, type, proto->mode,
+ proto->slot);
+ }
}
static void
}
if (size + 1 != var->type->fields.array->length) {
+ /* If this is a built-in uniform (i.e., it's backed by some
+ * fixed-function state), adjust the number of state slots to
+ * match the new array size. The number of slots per array entry
+ * is not known. It seems saft to assume that the total number of
+ * slots is an integer multiple of the number of array elements.
+ * Determine the number of slots per array element by dividing by
+ * the old (total) size.
+ */
+ if (var->num_state_slots > 0) {
+ var->num_state_slots = (size + 1)
+ * (var->num_state_slots / var->type->length);
+ }
+
var->type = glsl_type::get_array_instance(var->type->fields.array,
size + 1);
/* FINISHME: We should update the types of array
void
fs_visitor::setup_builtin_uniform_values(ir_variable *ir)
{
- const struct gl_builtin_uniform_desc *statevar = NULL;
-
- for (unsigned int i = 0; _mesa_builtin_uniform_desc[i].name; i++) {
- statevar = &_mesa_builtin_uniform_desc[i];
- if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0)
- break;
- }
-
- if (!statevar->name) {
- fail("Failed to find builtin uniform `%s'\n", ir->name);
- return;
- }
-
- int array_count;
- if (ir->type->is_array()) {
- array_count = ir->type->length;
- } else {
- array_count = 1;
- }
-
- for (int a = 0; a < array_count; a++) {
- for (unsigned int i = 0; i < statevar->num_elements; i++) {
- struct gl_builtin_uniform_element *element = &statevar->elements[i];
- int tokens[STATE_LENGTH];
-
- memcpy(tokens, element->tokens, sizeof(element->tokens));
- if (ir->type->is_array()) {
- tokens[1] = a;
- }
+ const ir_state_slot *const slots = ir->state_slots;
+ assert(ir->state_slots != NULL);
+ {
+ for (unsigned int i = 0; i < ir->num_state_slots; i++) {
/* This state reference has already been setup by ir_to_mesa,
* but we'll get the same index back here.
*/
int index = _mesa_add_state_reference(this->fp->Base.Parameters,
- (gl_state_index *)tokens);
+ (gl_state_index *)slots[i].tokens);
/* Add each of the unique swizzles of the element as a
* parameter. This'll end up matching the expected layout of
*/
int last_swiz = -1;
for (unsigned int j = 0; j < 4; j++) {
- int swiz = GET_SWZ(element->swizzle, j);
+ int swiz = GET_SWZ(slots[i].swizzle, j);
if (swiz == last_swiz)
break;
last_swiz = swiz;
if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) {
unsigned int i;
- const struct gl_builtin_uniform_desc *statevar;
-
- for (i = 0; _mesa_builtin_uniform_desc[i].name; i++) {
- if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0)
- break;
- }
-
- if (!_mesa_builtin_uniform_desc[i].name) {
- fail_link(this->shader_program,
- "Failed to find builtin uniform `%s'\n", ir->name);
- return;
- }
-
- statevar = &_mesa_builtin_uniform_desc[i];
-
- int array_count;
- if (ir->type->is_array()) {
- array_count = ir->type->length;
- } else {
- array_count = 1;
- }
+ const ir_state_slot *const slots = ir->state_slots;
+ assert(ir->state_slots != NULL);
/* Check if this statevar's setup in the STATE file exactly
* matches how we'll want to reference it as a
* temporary storage and hope that it'll get copy-propagated
* out.
*/
- for (i = 0; i < statevar->num_elements; i++) {
- if (statevar->elements[i].swizzle != SWIZZLE_XYZW) {
+ for (i = 0; i < ir->num_state_slots; i++) {
+ if (slots[i].swizzle != SWIZZLE_XYZW) {
break;
}
}
struct variable_storage *storage;
ir_to_mesa_dst_reg dst;
- if (i == statevar->num_elements) {
+ if (i == ir->num_state_slots) {
/* We'll set the index later. */
storage = new(mem_ctx) variable_storage(ir, PROGRAM_STATE_VAR, -1);
this->variables.push_tail(storage);
dst = ir_to_mesa_undef_dst;
} else {
+ /* The variable_storage constructor allocates slots based on the size
+ * of the type. However, this had better match the number of state
+ * elements that we're going to copy into the new temporary.
+ */
+ assert(ir->num_state_slots == type_size(ir->type));
+
storage = new(mem_ctx) variable_storage(ir, PROGRAM_TEMPORARY,
this->next_temp);
this->variables.push_tail(storage);
}
- for (int a = 0; a < array_count; a++) {
- for (unsigned int i = 0; i < statevar->num_elements; i++) {
- struct gl_builtin_uniform_element *element = &statevar->elements[i];
- int tokens[STATE_LENGTH];
-
- memcpy(tokens, element->tokens, sizeof(element->tokens));
- if (ir->type->is_array()) {
- tokens[1] = a;
- }
-
+ {
+ for (unsigned int i = 0; i < ir->num_state_slots; i++) {
int index = _mesa_add_state_reference(this->prog->Parameters,
- (gl_state_index *)tokens);
+ (gl_state_index *)slots[i].tokens);
if (storage->file == PROGRAM_STATE_VAR) {
if (storage->index == -1) {
storage->index = index;
} else {
- assert(index ==
- (int)(storage->index + a * statevar->num_elements + i));
+ assert(index == storage->index + (int)i);
}
} else {
ir_to_mesa_src_reg src(PROGRAM_STATE_VAR, index, NULL);
- src.swizzle = element->swizzle;
+ src.swizzle = slots[i].swizzle;
ir_to_mesa_emit_op1(ir, OPCODE_MOV, dst, src);
/* even a float takes up a whole vec4 reg in a struct/array. */
dst.index++;
}
}
if (storage->file == PROGRAM_TEMPORARY &&
- dst.index != storage->index + type_size(ir->type)) {
+ dst.index != storage->index + ir->num_state_slots) {
fail_link(this->shader_program,
"failed to load builtin uniform `%s' (%d/%d regs loaded)\n",
ir->name, dst.index - storage->index,