1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /**
25  * \file brw_lower_texture_gradients.cpp
26  */
27 
28 #include "glsl/ir.h"
29 #include "glsl/ir_builder.h"
30 #include "program/prog_instruction.h"
31 
32 using namespace ir_builder;
33 
34 class lower_texture_grad_visitor : public ir_hierarchical_visitor {
35 public:
lower_texture_grad_visitor()36    lower_texture_grad_visitor()
37    {
38       progress = false;
39    }
40 
41    ir_visitor_status visit_leave(ir_texture *ir);
42 
43 
44    bool progress;
45 
46 private:
47    void emit(ir_variable *, ir_rvalue *);
48 };
49 
50 /**
51  * Emit a variable declaration and an assignment to initialize it.
52  */
53 void
emit(ir_variable * var,ir_rvalue * value)54 lower_texture_grad_visitor::emit(ir_variable *var, ir_rvalue *value)
55 {
56    base_ir->insert_before(var);
57    base_ir->insert_before(assign(var, value));
58 }
59 
60 static const glsl_type *
txs_type(const glsl_type * type)61 txs_type(const glsl_type *type)
62 {
63    unsigned dims;
64    switch (type->sampler_dimensionality) {
65    case GLSL_SAMPLER_DIM_1D:
66       dims = 1;
67       break;
68    case GLSL_SAMPLER_DIM_2D:
69    case GLSL_SAMPLER_DIM_RECT:
70    case GLSL_SAMPLER_DIM_CUBE:
71       dims = 2;
72       break;
73    case GLSL_SAMPLER_DIM_3D:
74       dims = 3;
75       break;
76    default:
77       assert(!"Should not get here: invalid sampler dimensionality");
78    }
79 
80    if (type->sampler_array)
81       dims++;
82 
83    return glsl_type::get_instance(GLSL_TYPE_INT, dims, 1);
84 }
85 
86 ir_visitor_status
visit_leave(ir_texture * ir)87 lower_texture_grad_visitor::visit_leave(ir_texture *ir)
88 {
89    /* Only lower textureGrad with shadow samplers */
90    if (ir->op != ir_txd || !ir->shadow_comparitor)
91       return visit_continue;
92 
93    void *mem_ctx = ralloc_parent(ir);
94 
95    const glsl_type *grad_type = ir->lod_info.grad.dPdx->type;
96 
97    /* Use textureSize() to get the width and height of LOD 0; swizzle away
98     * the depth/number of array slices.
99     */
100    ir_texture *txs = new(mem_ctx) ir_texture(ir_txs);
101    txs->set_sampler(ir->sampler->clone(mem_ctx, NULL),
102 		    txs_type(ir->sampler->type));
103    txs->lod_info.lod = new(mem_ctx) ir_constant(0);
104    ir_variable *size =
105       new(mem_ctx) ir_variable(grad_type, "size", ir_var_temporary);
106    if (ir->sampler->type->sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE) {
107       base_ir->insert_before(size);
108       base_ir->insert_before(assign(size, expr(ir_unop_i2f, txs), WRITEMASK_XY));
109       base_ir->insert_before(assign(size, new(mem_ctx) ir_constant(1.0f), WRITEMASK_Z));
110    } else {
111       emit(size, expr(ir_unop_i2f,
112                       swizzle_for_size(txs, grad_type->vector_elements)));
113    }
114 
115    /* Scale the gradients by width and height.  Effectively, the incoming
116     * gradients are s'(x,y), t'(x,y), and r'(x,y) from equation 3.19 in the
117     * GL 3.0 spec; we want u'(x,y), which is w_t * s'(x,y).
118     */
119    ir_variable *dPdx =
120       new(mem_ctx) ir_variable(grad_type, "dPdx", ir_var_temporary);
121    emit(dPdx, mul(size, ir->lod_info.grad.dPdx));
122 
123    ir_variable *dPdy =
124       new(mem_ctx) ir_variable(grad_type, "dPdy", ir_var_temporary);
125    emit(dPdy, mul(size, ir->lod_info.grad.dPdy));
126 
127    /* Calculate rho from equation 3.20 of the GL 3.0 specification. */
128    ir_rvalue *rho;
129    if (dPdx->type->is_scalar()) {
130       rho = expr(ir_binop_max, expr(ir_unop_abs, dPdx),
131 			       expr(ir_unop_abs, dPdy));
132    } else {
133       rho = expr(ir_binop_max, expr(ir_unop_sqrt, dot(dPdx, dPdx)),
134 			       expr(ir_unop_sqrt, dot(dPdy, dPdy)));
135    }
136 
137    /* lambda_base = log2(rho).  We're ignoring GL state biases for now. */
138    ir->op = ir_txl;
139    ir->lod_info.lod = expr(ir_unop_log2, rho);
140 
141    progress = true;
142    return visit_continue;
143 }
144 
145 extern "C" {
146 
147 bool
brw_lower_texture_gradients(struct exec_list * instructions)148 brw_lower_texture_gradients(struct exec_list *instructions)
149 {
150    lower_texture_grad_visitor v;
151 
152    visit_list_elements(&v, instructions);
153 
154    return v.progress;
155 }
156 
157 }
158