gallium/radeon: move a comment to the correct place
[mesa.git] / src / gallium / drivers / radeon / r600_viewport.c
1 /*
2 * Copyright 2012 Advanced Micro Devices, Inc.
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "r600_cs.h"
25 #include "tgsi/tgsi_scan.h"
26
27 #define GET_MAX_SCISSOR(rctx) (rctx->chip_class >= EVERGREEN ? 16384 : 8192)
28
29 static void r600_set_scissor_states(struct pipe_context *ctx,
30 unsigned start_slot,
31 unsigned num_scissors,
32 const struct pipe_scissor_state *state)
33 {
34 struct r600_common_context *rctx = (struct r600_common_context *)ctx;
35 int i;
36
37 for (i = 0; i < num_scissors; i++)
38 rctx->scissors.states[start_slot + i] = state[i];
39
40 if (!rctx->scissor_enabled)
41 return;
42
43 rctx->scissors.dirty_mask |= ((1 << num_scissors) - 1) << start_slot;
44 rctx->set_atom_dirty(rctx, &rctx->scissors.atom, true);
45 }
46
47 /* Since the guard band disables clipping, we have to clip per-pixel
48 * using a scissor.
49 */
50 static void r600_get_scissor_from_viewport(struct r600_common_context *rctx,
51 const struct pipe_viewport_state *vp,
52 struct r600_signed_scissor *scissor)
53 {
54 int tmp;
55
56 /* Convert (-1, -1) and (1, 1) from clip space into window space. */
57 scissor->minx = -vp->scale[0] + vp->translate[0];
58 scissor->miny = -vp->scale[1] + vp->translate[1];
59 scissor->maxx = vp->scale[0] + vp->translate[0];
60 scissor->maxy = vp->scale[1] + vp->translate[1];
61
62 /* r600_draw_rectangle sets this. Disable the scissor. */
63 if (scissor->minx == -1 && scissor->miny == -1 &&
64 scissor->maxx == 1 && scissor->maxy == 1) {
65 scissor->minx = scissor->miny = 0;
66 scissor->maxx = scissor->maxy = GET_MAX_SCISSOR(rctx);
67 }
68
69 /* Handle inverted viewports. */
70 if (scissor->minx > scissor->maxx) {
71 tmp = scissor->minx;
72 scissor->minx = scissor->maxx;
73 scissor->maxx = tmp;
74 }
75 if (scissor->miny > scissor->maxy) {
76 tmp = scissor->miny;
77 scissor->miny = scissor->maxy;
78 scissor->maxy = tmp;
79 }
80 }
81
82 static void r600_clamp_scissor(struct r600_common_context *rctx,
83 struct pipe_scissor_state *out,
84 struct r600_signed_scissor *scissor)
85 {
86 unsigned max_scissor = GET_MAX_SCISSOR(rctx);
87 out->minx = CLAMP(scissor->minx, 0, max_scissor);
88 out->miny = CLAMP(scissor->miny, 0, max_scissor);
89 out->maxx = CLAMP(scissor->maxx, 0, max_scissor);
90 out->maxy = CLAMP(scissor->maxy, 0, max_scissor);
91 }
92
93 static void r600_clip_scissor(struct pipe_scissor_state *out,
94 struct pipe_scissor_state *clip)
95 {
96 out->minx = MAX2(out->minx, clip->minx);
97 out->miny = MAX2(out->miny, clip->miny);
98 out->maxx = MIN2(out->maxx, clip->maxx);
99 out->maxy = MIN2(out->maxy, clip->maxy);
100 }
101
102 static void r600_scissor_make_union(struct r600_signed_scissor *out,
103 struct r600_signed_scissor *in)
104 {
105 out->minx = MIN2(out->minx, in->minx);
106 out->miny = MIN2(out->miny, in->miny);
107 out->maxx = MAX2(out->maxx, in->maxx);
108 out->maxy = MAX2(out->maxy, in->maxy);
109 }
110
111 void evergreen_apply_scissor_bug_workaround(struct r600_common_context *rctx,
112 struct pipe_scissor_state *scissor)
113 {
114 if (rctx->chip_class == EVERGREEN || rctx->chip_class == CAYMAN) {
115 if (scissor->maxx == 0)
116 scissor->minx = 1;
117 if (scissor->maxy == 0)
118 scissor->miny = 1;
119
120 if (rctx->chip_class == CAYMAN &&
121 scissor->maxx == 1 && scissor->maxy == 1)
122 scissor->maxx = 2;
123 }
124 }
125
126 static void r600_emit_one_scissor(struct r600_common_context *rctx,
127 struct radeon_winsys_cs *cs,
128 struct r600_signed_scissor *vp_scissor,
129 struct pipe_scissor_state *scissor)
130 {
131 struct pipe_scissor_state final;
132
133 r600_clamp_scissor(rctx, &final, vp_scissor);
134
135 if (scissor)
136 r600_clip_scissor(&final, scissor);
137
138 evergreen_apply_scissor_bug_workaround(rctx, &final);
139
140 radeon_emit(cs, S_028250_TL_X(final.minx) |
141 S_028250_TL_Y(final.miny) |
142 S_028250_WINDOW_OFFSET_DISABLE(1));
143 radeon_emit(cs, S_028254_BR_X(final.maxx) |
144 S_028254_BR_Y(final.maxy));
145 }
146
147 /* the range is [-MAX, MAX] */
148 #define GET_MAX_VIEWPORT_RANGE(rctx) (rctx->chip_class >= EVERGREEN ? 32768 : 16384)
149
150 static void r600_emit_guardband(struct r600_common_context *rctx,
151 struct r600_signed_scissor *vp_as_scissor)
152 {
153 struct radeon_winsys_cs *cs = rctx->gfx.cs;
154 struct pipe_viewport_state vp;
155 float left, top, right, bottom, max_range, guardband_x, guardband_y;
156
157 /* Reconstruct the viewport transformation from the scissor. */
158 vp.translate[0] = (vp_as_scissor->minx + vp_as_scissor->maxx) / 2.0;
159 vp.translate[1] = (vp_as_scissor->miny + vp_as_scissor->maxy) / 2.0;
160 vp.scale[0] = vp_as_scissor->maxx - vp.translate[0];
161 vp.scale[1] = vp_as_scissor->maxy - vp.translate[1];
162
163 /* Treat a 0x0 viewport as 1x1 to prevent division by zero. */
164 if (vp_as_scissor->minx == vp_as_scissor->maxx)
165 vp.scale[0] = 0.5;
166 if (vp_as_scissor->miny == vp_as_scissor->maxy)
167 vp.scale[1] = 0.5;
168
169 /* Find the biggest guard band that is inside the supported viewport
170 * range. The guard band is specified as a horizontal and vertical
171 * distance from (0,0) in clip space.
172 *
173 * This is done by applying the inverse viewport transformation
174 * on the viewport limits to get those limits in clip space.
175 *
176 * Use a limit one pixel smaller to allow for some precision error.
177 */
178 max_range = GET_MAX_VIEWPORT_RANGE(rctx) - 1;
179 left = (-max_range - vp.translate[0]) / vp.scale[0];
180 right = ( max_range - vp.translate[0]) / vp.scale[0];
181 top = (-max_range - vp.translate[1]) / vp.scale[1];
182 bottom = ( max_range - vp.translate[1]) / vp.scale[1];
183
184 assert(left <= -1 && top <= -1 && right >= 1 && bottom >= 1);
185
186 guardband_x = MIN2(-left, right);
187 guardband_y = MIN2(-top, bottom);
188
189 /* If any of the GB registers is updated, all of them must be updated. */
190 if (rctx->chip_class >= CAYMAN)
191 radeon_set_context_reg_seq(cs, CM_R_028BE8_PA_CL_GB_VERT_CLIP_ADJ, 4);
192 else
193 radeon_set_context_reg_seq(cs, R600_R_028C0C_PA_CL_GB_VERT_CLIP_ADJ, 4);
194
195 radeon_emit(cs, fui(guardband_y)); /* R_028BE8_PA_CL_GB_VERT_CLIP_ADJ */
196 radeon_emit(cs, fui(1.0)); /* R_028BEC_PA_CL_GB_VERT_DISC_ADJ */
197 radeon_emit(cs, fui(guardband_x)); /* R_028BF0_PA_CL_GB_HORZ_CLIP_ADJ */
198 radeon_emit(cs, fui(1.0)); /* R_028BF4_PA_CL_GB_HORZ_DISC_ADJ */
199 }
200
201 static void r600_emit_scissors(struct r600_common_context *rctx, struct r600_atom *atom)
202 {
203 struct radeon_winsys_cs *cs = rctx->gfx.cs;
204 struct pipe_scissor_state *states = rctx->scissors.states;
205 unsigned mask = rctx->scissors.dirty_mask;
206 bool scissor_enabled = rctx->scissor_enabled;
207 struct r600_signed_scissor max_vp_scissor;
208 int i;
209
210 /* The simple case: Only 1 viewport is active. */
211 if (!rctx->vs_writes_viewport_index) {
212 struct r600_signed_scissor *vp = &rctx->viewports.as_scissor[0];
213
214 if (!(mask & 1))
215 return;
216
217 radeon_set_context_reg_seq(cs, R_028250_PA_SC_VPORT_SCISSOR_0_TL, 2);
218 r600_emit_one_scissor(rctx, cs, vp, scissor_enabled ? &states[0] : NULL);
219 r600_emit_guardband(rctx, vp);
220 rctx->scissors.dirty_mask &= ~1; /* clear one bit */
221 return;
222 }
223
224 /* Shaders can draw to any viewport. Make a union of all viewports. */
225 max_vp_scissor = rctx->viewports.as_scissor[0];
226 for (i = 1; i < R600_MAX_VIEWPORTS; i++)
227 r600_scissor_make_union(&max_vp_scissor,
228 &rctx->viewports.as_scissor[i]);
229
230 while (mask) {
231 int start, count, i;
232
233 u_bit_scan_consecutive_range(&mask, &start, &count);
234
235 radeon_set_context_reg_seq(cs, R_028250_PA_SC_VPORT_SCISSOR_0_TL +
236 start * 4 * 2, count * 2);
237 for (i = start; i < start+count; i++) {
238 r600_emit_one_scissor(rctx, cs, &rctx->viewports.as_scissor[i],
239 scissor_enabled ? &states[i] : NULL);
240 }
241 }
242 r600_emit_guardband(rctx, &max_vp_scissor);
243 rctx->scissors.dirty_mask = 0;
244 }
245
246 static void r600_set_viewport_states(struct pipe_context *ctx,
247 unsigned start_slot,
248 unsigned num_viewports,
249 const struct pipe_viewport_state *state)
250 {
251 struct r600_common_context *rctx = (struct r600_common_context *)ctx;
252 int i;
253
254 for (i = 0; i < num_viewports; i++) {
255 unsigned index = start_slot + i;
256
257 rctx->viewports.states[index] = state[i];
258 r600_get_scissor_from_viewport(rctx, &state[i],
259 &rctx->viewports.as_scissor[index]);
260 }
261
262 rctx->viewports.dirty_mask |= ((1 << num_viewports) - 1) << start_slot;
263 rctx->scissors.dirty_mask |= ((1 << num_viewports) - 1) << start_slot;
264 rctx->set_atom_dirty(rctx, &rctx->viewports.atom, true);
265 rctx->set_atom_dirty(rctx, &rctx->scissors.atom, true);
266 }
267
268 static void r600_emit_viewports(struct r600_common_context *rctx, struct r600_atom *atom)
269 {
270 struct radeon_winsys_cs *cs = rctx->gfx.cs;
271 struct pipe_viewport_state *states = rctx->viewports.states;
272 unsigned mask = rctx->viewports.dirty_mask;
273
274 /* The simple case: Only 1 viewport is active. */
275 if (!rctx->vs_writes_viewport_index) {
276 if (!(mask & 1))
277 return;
278
279 radeon_set_context_reg_seq(cs, R_02843C_PA_CL_VPORT_XSCALE, 6);
280 radeon_emit(cs, fui(states[0].scale[0]));
281 radeon_emit(cs, fui(states[0].translate[0]));
282 radeon_emit(cs, fui(states[0].scale[1]));
283 radeon_emit(cs, fui(states[0].translate[1]));
284 radeon_emit(cs, fui(states[0].scale[2]));
285 radeon_emit(cs, fui(states[0].translate[2]));
286 rctx->viewports.dirty_mask &= ~1; /* clear one bit */
287 return;
288 }
289
290 while (mask) {
291 int start, count, i;
292
293 u_bit_scan_consecutive_range(&mask, &start, &count);
294
295 radeon_set_context_reg_seq(cs, R_02843C_PA_CL_VPORT_XSCALE +
296 start * 4 * 6, count * 6);
297 for (i = start; i < start+count; i++) {
298 radeon_emit(cs, fui(states[i].scale[0]));
299 radeon_emit(cs, fui(states[i].translate[0]));
300 radeon_emit(cs, fui(states[i].scale[1]));
301 radeon_emit(cs, fui(states[i].translate[1]));
302 radeon_emit(cs, fui(states[i].scale[2]));
303 radeon_emit(cs, fui(states[i].translate[2]));
304 }
305 }
306 rctx->viewports.dirty_mask = 0;
307 }
308
309 void r600_set_scissor_enable(struct r600_common_context *rctx, bool enable)
310 {
311 if (rctx->scissor_enabled != enable) {
312 rctx->scissor_enabled = enable;
313 rctx->scissors.dirty_mask = (1 << R600_MAX_VIEWPORTS) - 1;
314 rctx->set_atom_dirty(rctx, &rctx->scissors.atom, true);
315 }
316 }
317
318 /**
319 * Normally, we only emit 1 viewport and 1 scissor if no shader is using
320 * the VIEWPORT_INDEX output, and emitting the other viewports and scissors
321 * is delayed. When a shader with VIEWPORT_INDEX appears, this should be
322 * called to emit the rest.
323 */
324 void r600_update_vs_writes_viewport_index(struct r600_common_context *rctx,
325 struct tgsi_shader_info *info)
326 {
327 if (!info)
328 return;
329
330 rctx->vs_writes_viewport_index = info->writes_viewport_index;
331 if (!rctx->vs_writes_viewport_index)
332 return;
333
334 if (rctx->scissors.dirty_mask)
335 rctx->set_atom_dirty(rctx, &rctx->scissors.atom, true);
336 if (rctx->viewports.dirty_mask)
337 rctx->set_atom_dirty(rctx, &rctx->viewports.atom, true);
338 }
339
340 void r600_init_viewport_functions(struct r600_common_context *rctx)
341 {
342 rctx->scissors.atom.emit = r600_emit_scissors;
343 rctx->viewports.atom.emit = r600_emit_viewports;
344
345 rctx->scissors.atom.num_dw = (2 + 16 * 2) + 6;
346 rctx->viewports.atom.num_dw = 2 + 16 * 6;
347
348 rctx->b.set_scissor_states = r600_set_scissor_states;
349 rctx->b.set_viewport_states = r600_set_viewport_states;
350 }