|
|
|
@@ -0,0 +1,365 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2010 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_wm_channel_expressions.cpp
|
|
|
|
|
*
|
|
|
|
|
* Breaks vector operations down into operations on each component.
|
|
|
|
|
*
|
|
|
|
|
* The 965 fragment shader receives 8 or 16 pixels at a time, so each
|
|
|
|
|
* channel of a vector is laid out as 1 or 2 8-float registers. Each
|
|
|
|
|
* ALU operation operates on one of those channel registers. As a
|
|
|
|
|
* result, there is no value to the 965 fragment shader in tracking
|
|
|
|
|
* "vector" expressions in the sense of GLSL fragment shaders, when
|
|
|
|
|
* doing a channel at a time may help in constant folding, algebraic
|
|
|
|
|
* simplification, and reducing the liveness of channel registers.
|
|
|
|
|
*
|
|
|
|
|
* The exception to the desire to break everything down to floats is
|
|
|
|
|
* texturing. The texture sampler returns a writemasked masked
|
|
|
|
|
* 4/8-register sequence containing the texture values. We don't want
|
|
|
|
|
* to dispatch to the sampler separately for each channel we need, so
|
|
|
|
|
* we do retain the vector types in that case.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
#include "main/core.h"
|
|
|
|
|
#include "brw_wm.h"
|
|
|
|
|
}
|
|
|
|
|
#include "../glsl/ir.h"
|
|
|
|
|
#include "../glsl/ir_expression_flattening.h"
|
|
|
|
|
#include "../glsl/glsl_types.h"
|
|
|
|
|
|
|
|
|
|
class ir_channel_expressions_visitor : public ir_hierarchical_visitor {
|
|
|
|
|
public:
|
|
|
|
|
ir_channel_expressions_visitor()
|
|
|
|
|
{
|
|
|
|
|
this->progress = false;
|
|
|
|
|
this->mem_ctx = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_visitor_status visit_leave(ir_assignment *);
|
|
|
|
|
|
|
|
|
|
ir_rvalue *get_element(ir_variable *var, unsigned int element);
|
|
|
|
|
void assign(ir_assignment *ir, int elem, ir_rvalue *val);
|
|
|
|
|
|
|
|
|
|
bool progress;
|
|
|
|
|
void *mem_ctx;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
channel_expressions_predicate(ir_instruction *ir)
|
|
|
|
|
{
|
|
|
|
|
ir_expression *expr = ir->as_expression();
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
if (!expr)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < expr->get_num_operands(); i++) {
|
|
|
|
|
if (expr->operands[i]->type->is_vector())
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
GLboolean
|
|
|
|
|
brw_do_channel_expressions(exec_list *instructions)
|
|
|
|
|
{
|
|
|
|
|
ir_channel_expressions_visitor v;
|
|
|
|
|
|
|
|
|
|
/* Pull out any matrix expression to a separate assignment to a
|
|
|
|
|
* temp. This will make our handling of the breakdown to
|
|
|
|
|
* operations on the matrix's vector components much easier.
|
|
|
|
|
*/
|
|
|
|
|
do_expression_flattening(instructions, channel_expressions_predicate);
|
|
|
|
|
|
|
|
|
|
visit_list_elements(&v, instructions);
|
|
|
|
|
|
|
|
|
|
return v.progress;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_rvalue *
|
|
|
|
|
ir_channel_expressions_visitor::get_element(ir_variable *var, unsigned int elem)
|
|
|
|
|
{
|
|
|
|
|
ir_dereference *deref;
|
|
|
|
|
|
|
|
|
|
if (var->type->is_scalar())
|
|
|
|
|
return new(mem_ctx) ir_dereference_variable(var);
|
|
|
|
|
|
|
|
|
|
assert(elem < var->type->components());
|
|
|
|
|
deref = new(mem_ctx) ir_dereference_variable(var);
|
|
|
|
|
return new(mem_ctx) ir_swizzle(deref, elem, 0, 0, 0, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ir_channel_expressions_visitor::assign(ir_assignment *ir, int elem, ir_rvalue *val)
|
|
|
|
|
{
|
|
|
|
|
ir_dereference *lhs = ir->lhs->clone(mem_ctx, NULL);
|
|
|
|
|
ir_assignment *assign;
|
|
|
|
|
ir_swizzle *val_swiz;
|
|
|
|
|
|
|
|
|
|
/* This assign-of-expression should have been generated by the
|
|
|
|
|
* expression flattening visitor (since we never short circit to
|
|
|
|
|
* not flatten, even for plain assignments of variables), so the
|
|
|
|
|
* writemask is always full.
|
|
|
|
|
*/
|
|
|
|
|
assert(ir->write_mask == (1 << ir->lhs->type->components()) - 1);
|
|
|
|
|
|
|
|
|
|
/* Smear the float across all the channels for the masked write. */
|
|
|
|
|
val_swiz = new(mem_ctx) ir_swizzle(val, 0, 0, 0, 0,
|
|
|
|
|
ir->lhs->type->components());
|
|
|
|
|
assign = new(mem_ctx) ir_assignment(lhs, val_swiz, NULL, (1 << elem));
|
|
|
|
|
ir->insert_before(assign);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_visitor_status
|
|
|
|
|
ir_channel_expressions_visitor::visit_leave(ir_assignment *ir)
|
|
|
|
|
{
|
|
|
|
|
ir_expression *expr = ir->rhs->as_expression();
|
|
|
|
|
bool found_vector = false;
|
|
|
|
|
unsigned int i, vector_elements = 1;
|
|
|
|
|
ir_variable *op_var[2];
|
|
|
|
|
|
|
|
|
|
if (!expr)
|
|
|
|
|
return visit_continue;
|
|
|
|
|
|
|
|
|
|
if (!this->mem_ctx)
|
|
|
|
|
this->mem_ctx = talloc_parent(ir);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < expr->get_num_operands(); i++) {
|
|
|
|
|
if (expr->operands[i]->type->is_vector()) {
|
|
|
|
|
found_vector = true;
|
|
|
|
|
vector_elements = expr->operands[i]->type->vector_elements;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found_vector)
|
|
|
|
|
return visit_continue;
|
|
|
|
|
|
|
|
|
|
/* Store the expression operands in temps so we can use them
|
|
|
|
|
* multiple times.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < expr->get_num_operands(); i++) {
|
|
|
|
|
ir_assignment *assign;
|
|
|
|
|
ir_dereference *deref;
|
|
|
|
|
|
|
|
|
|
assert(!expr->operands[i]->type->is_matrix());
|
|
|
|
|
|
|
|
|
|
op_var[i] = new(mem_ctx) ir_variable(expr->operands[i]->type,
|
|
|
|
|
"channel_expressions",
|
|
|
|
|
ir_var_temporary);
|
|
|
|
|
ir->insert_before(op_var[i]);
|
|
|
|
|
|
|
|
|
|
deref = new(mem_ctx) ir_dereference_variable(op_var[i]);
|
|
|
|
|
assign = new(mem_ctx) ir_assignment(deref,
|
|
|
|
|
expr->operands[i],
|
|
|
|
|
NULL);
|
|
|
|
|
ir->insert_before(assign);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const glsl_type *element_type = glsl_type::get_instance(ir->lhs->type->base_type,
|
|
|
|
|
1, 1);
|
|
|
|
|
|
|
|
|
|
/* OK, time to break down this vector operation. */
|
|
|
|
|
switch (expr->operation) {
|
|
|
|
|
case ir_unop_bit_not:
|
|
|
|
|
case ir_unop_logic_not:
|
|
|
|
|
case ir_unop_neg:
|
|
|
|
|
case ir_unop_abs:
|
|
|
|
|
case ir_unop_sign:
|
|
|
|
|
case ir_unop_rcp:
|
|
|
|
|
case ir_unop_rsq:
|
|
|
|
|
case ir_unop_sqrt:
|
|
|
|
|
case ir_unop_exp:
|
|
|
|
|
case ir_unop_log:
|
|
|
|
|
case ir_unop_exp2:
|
|
|
|
|
case ir_unop_log2:
|
|
|
|
|
case ir_unop_f2i:
|
|
|
|
|
case ir_unop_i2f:
|
|
|
|
|
case ir_unop_f2b:
|
|
|
|
|
case ir_unop_b2f:
|
|
|
|
|
case ir_unop_i2b:
|
|
|
|
|
case ir_unop_b2i:
|
|
|
|
|
case ir_unop_u2f:
|
|
|
|
|
case ir_unop_trunc:
|
|
|
|
|
case ir_unop_ceil:
|
|
|
|
|
case ir_unop_floor:
|
|
|
|
|
case ir_unop_fract:
|
|
|
|
|
case ir_unop_sin:
|
|
|
|
|
case ir_unop_cos:
|
|
|
|
|
case ir_unop_dFdx:
|
|
|
|
|
case ir_unop_dFdy:
|
|
|
|
|
for (i = 0; i < vector_elements; i++) {
|
|
|
|
|
ir_rvalue *op0 = get_element(op_var[0], i);
|
|
|
|
|
|
|
|
|
|
assign(ir, i, new(mem_ctx) ir_expression(expr->operation,
|
|
|
|
|
element_type,
|
|
|
|
|
op0,
|
|
|
|
|
NULL));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ir_binop_add:
|
|
|
|
|
case ir_binop_sub:
|
|
|
|
|
case ir_binop_mul:
|
|
|
|
|
case ir_binop_div:
|
|
|
|
|
case ir_binop_mod:
|
|
|
|
|
case ir_binop_min:
|
|
|
|
|
case ir_binop_max:
|
|
|
|
|
case ir_binop_pow:
|
|
|
|
|
case ir_binop_lshift:
|
|
|
|
|
case ir_binop_rshift:
|
|
|
|
|
case ir_binop_bit_and:
|
|
|
|
|
case ir_binop_bit_xor:
|
|
|
|
|
case ir_binop_bit_or:
|
|
|
|
|
for (i = 0; i < vector_elements; i++) {
|
|
|
|
|
ir_rvalue *op0 = get_element(op_var[0], i);
|
|
|
|
|
ir_rvalue *op1 = get_element(op_var[1], i);
|
|
|
|
|
|
|
|
|
|
assign(ir, i, new(mem_ctx) ir_expression(expr->operation,
|
|
|
|
|
element_type,
|
|
|
|
|
op0,
|
|
|
|
|
op1));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ir_unop_any: {
|
|
|
|
|
ir_expression *temp;
|
|
|
|
|
temp = new(mem_ctx) ir_expression(ir_binop_logic_or,
|
|
|
|
|
element_type,
|
|
|
|
|
get_element(op_var[0], 0),
|
|
|
|
|
get_element(op_var[0], 1));
|
|
|
|
|
|
|
|
|
|
for (i = 2; i < vector_elements; i++) {
|
|
|
|
|
temp = new(mem_ctx) ir_expression(ir_binop_logic_or,
|
|
|
|
|
element_type,
|
|
|
|
|
get_element(op_var[0], i),
|
|
|
|
|
temp);
|
|
|
|
|
}
|
|
|
|
|
assign(ir, 0, temp);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case ir_binop_dot: {
|
|
|
|
|
ir_expression *last = NULL;
|
|
|
|
|
for (i = 0; i < vector_elements; i++) {
|
|
|
|
|
ir_rvalue *op0 = get_element(op_var[0], i);
|
|
|
|
|
ir_rvalue *op1 = get_element(op_var[1], i);
|
|
|
|
|
ir_expression *temp;
|
|
|
|
|
|
|
|
|
|
temp = new(mem_ctx) ir_expression(ir_binop_mul,
|
|
|
|
|
element_type,
|
|
|
|
|
op0,
|
|
|
|
|
op1);
|
|
|
|
|
if (last) {
|
|
|
|
|
last = new(mem_ctx) ir_expression(ir_binop_add,
|
|
|
|
|
element_type,
|
|
|
|
|
temp,
|
|
|
|
|
last);
|
|
|
|
|
} else {
|
|
|
|
|
last = temp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assign(ir, 0, last);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case ir_binop_cross: {
|
|
|
|
|
for (i = 0; i < vector_elements; i++) {
|
|
|
|
|
int swiz0 = (i + 1) % 3;
|
|
|
|
|
int swiz1 = (i + 2) % 3;
|
|
|
|
|
ir_expression *temp1, *temp2;
|
|
|
|
|
|
|
|
|
|
temp1 = new(mem_ctx) ir_expression(ir_binop_mul,
|
|
|
|
|
element_type,
|
|
|
|
|
get_element(op_var[0], swiz0),
|
|
|
|
|
get_element(op_var[1], swiz1));
|
|
|
|
|
|
|
|
|
|
temp2 = new(mem_ctx) ir_expression(ir_binop_mul,
|
|
|
|
|
element_type,
|
|
|
|
|
get_element(op_var[1], swiz0),
|
|
|
|
|
get_element(op_var[0], swiz1));
|
|
|
|
|
|
|
|
|
|
temp2 = new(mem_ctx) ir_expression(ir_unop_neg,
|
|
|
|
|
element_type,
|
|
|
|
|
temp2,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
assign(ir, i, new(mem_ctx) ir_expression(ir_binop_add,
|
|
|
|
|
element_type,
|
|
|
|
|
temp1, temp2));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case ir_binop_less:
|
|
|
|
|
case ir_binop_greater:
|
|
|
|
|
case ir_binop_lequal:
|
|
|
|
|
case ir_binop_gequal:
|
|
|
|
|
case ir_binop_logic_and:
|
|
|
|
|
case ir_binop_logic_xor:
|
|
|
|
|
case ir_binop_logic_or:
|
|
|
|
|
ir->print();
|
|
|
|
|
printf("\n");
|
|
|
|
|
assert(!"not reached: expression operates on scalars only");
|
|
|
|
|
break;
|
|
|
|
|
case ir_binop_equal:
|
|
|
|
|
case ir_binop_nequal: {
|
|
|
|
|
ir_expression *last = NULL;
|
|
|
|
|
for (i = 0; i < vector_elements; i++) {
|
|
|
|
|
ir_rvalue *op0 = get_element(op_var[0], i);
|
|
|
|
|
ir_rvalue *op1 = get_element(op_var[1], i);
|
|
|
|
|
ir_expression *temp;
|
|
|
|
|
ir_expression_operation join;
|
|
|
|
|
|
|
|
|
|
if (expr->operation == ir_binop_equal)
|
|
|
|
|
join = ir_binop_logic_and;
|
|
|
|
|
else
|
|
|
|
|
join = ir_binop_logic_or;
|
|
|
|
|
|
|
|
|
|
temp = new(mem_ctx) ir_expression(expr->operation,
|
|
|
|
|
element_type,
|
|
|
|
|
op0,
|
|
|
|
|
op1);
|
|
|
|
|
if (last) {
|
|
|
|
|
last = new(mem_ctx) ir_expression(join,
|
|
|
|
|
element_type,
|
|
|
|
|
temp,
|
|
|
|
|
last);
|
|
|
|
|
} else {
|
|
|
|
|
last = temp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assign(ir, 0, last);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir->remove();
|
|
|
|
|
this->progress = true;
|
|
|
|
|
|
|
|
|
|
return visit_continue;
|
|
|
|
|
}
|