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