9291855c129ea9f3ba4e298c44605e4aa8977356
[mesa.git] / src / gallium / drivers / ilo / ilo_render.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2013 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include "genhw/genhw.h"
29 #include "util/u_prim.h"
30 #include "intel_winsys.h"
31
32 #include "ilo_builder.h"
33 #include "ilo_builder_mi.h"
34 #include "ilo_builder_render.h"
35 #include "ilo_query.h"
36 #include "ilo_render_gen.h"
37
38 /* in U0.4 */
39 struct sample_position {
40 uint8_t x, y;
41 };
42
43 /* \see gen6_get_sample_position() */
44 static const struct sample_position sample_position_1x[1] = {
45 { 8, 8 },
46 };
47
48 static const struct sample_position sample_position_4x[4] = {
49 { 6, 2 }, /* distance from the center is sqrt(40) */
50 { 14, 6 }, /* distance from the center is sqrt(40) */
51 { 2, 10 }, /* distance from the center is sqrt(40) */
52 { 10, 14 }, /* distance from the center is sqrt(40) */
53 };
54
55 static const struct sample_position sample_position_8x[8] = {
56 { 7, 9 }, /* distance from the center is sqrt(2) */
57 { 9, 13 }, /* distance from the center is sqrt(26) */
58 { 11, 3 }, /* distance from the center is sqrt(34) */
59 { 13, 11 }, /* distance from the center is sqrt(34) */
60 { 1, 7 }, /* distance from the center is sqrt(50) */
61 { 5, 1 }, /* distance from the center is sqrt(58) */
62 { 15, 5 }, /* distance from the center is sqrt(58) */
63 { 3, 15 }, /* distance from the center is sqrt(74) */
64 };
65
66 struct ilo_render *
67 ilo_render_create(struct ilo_builder *builder)
68 {
69 struct ilo_render *render;
70 int i;
71
72 render = CALLOC_STRUCT(ilo_render);
73 if (!render)
74 return NULL;
75
76 render->dev = builder->dev;
77 render->builder = builder;
78
79 render->workaround_bo = intel_winsys_alloc_buffer(builder->winsys,
80 "PIPE_CONTROL workaround", 4096, false);
81 if (!render->workaround_bo) {
82 ilo_warn("failed to allocate PIPE_CONTROL workaround bo\n");
83 FREE(render);
84 return NULL;
85 }
86
87 render->packed_sample_position_1x =
88 sample_position_1x[0].x << 4 |
89 sample_position_1x[0].y;
90
91 /* pack into dwords */
92 for (i = 0; i < 4; i++) {
93 render->packed_sample_position_4x |=
94 sample_position_4x[i].x << (8 * i + 4) |
95 sample_position_4x[i].y << (8 * i);
96
97 render->packed_sample_position_8x[0] |=
98 sample_position_8x[i].x << (8 * i + 4) |
99 sample_position_8x[i].y << (8 * i);
100
101 render->packed_sample_position_8x[1] |=
102 sample_position_8x[4 + i].x << (8 * i + 4) |
103 sample_position_8x[4 + i].y << (8 * i);
104 }
105
106 ilo_render_invalidate_hw(render);
107 ilo_render_invalidate_builder(render);
108
109 return render;
110 }
111
112 void
113 ilo_render_destroy(struct ilo_render *render)
114 {
115 if (render->workaround_bo)
116 intel_bo_unreference(render->workaround_bo);
117
118 FREE(render);
119 }
120
121 void
122 ilo_render_get_sample_position(const struct ilo_render *render,
123 unsigned sample_count,
124 unsigned sample_index,
125 float *x, float *y)
126 {
127 const struct sample_position *pos;
128
129 switch (sample_count) {
130 case 1:
131 assert(sample_index < Elements(sample_position_1x));
132 pos = sample_position_1x;
133 break;
134 case 4:
135 assert(sample_index < Elements(sample_position_4x));
136 pos = sample_position_4x;
137 break;
138 case 8:
139 assert(sample_index < Elements(sample_position_8x));
140 pos = sample_position_8x;
141 break;
142 default:
143 assert(!"unknown sample count");
144 *x = 0.5f;
145 *y = 0.5f;
146 return;
147 break;
148 }
149
150 *x = (float) pos[sample_index].x / 16.0f;
151 *y = (float) pos[sample_index].y / 16.0f;
152 }
153
154 void
155 ilo_render_invalidate_hw(struct ilo_render *render)
156 {
157 render->hw_ctx_changed = true;
158 }
159
160 void
161 ilo_render_invalidate_builder(struct ilo_render *render)
162 {
163 render->batch_bo_changed = true;
164 render->state_bo_changed = true;
165 render->instruction_bo_changed = true;
166
167 /* Kernel flushes everything. Shouldn't we set all bits here? */
168 render->state.current_pipe_control_dw1 = 0;
169 }
170
171 /**
172 * Return the command length of ilo_render_emit_flush().
173 */
174 int
175 ilo_render_get_flush_len(const struct ilo_render *render)
176 {
177 int len;
178
179 ILO_DEV_ASSERT(render->dev, 6, 7.5);
180
181 len = GEN6_PIPE_CONTROL__SIZE;
182
183 /* plus gen6_wa_pre_pipe_control() */
184 if (ilo_dev_gen(render->dev) == ILO_GEN(6))
185 len *= 3;
186
187 return len;
188 }
189
190 /**
191 * Emit PIPE_CONTROLs to flush all caches.
192 */
193 void
194 ilo_render_emit_flush(struct ilo_render *render)
195 {
196 const uint32_t dw1 = GEN6_PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE |
197 GEN6_PIPE_CONTROL_RENDER_CACHE_FLUSH |
198 GEN6_PIPE_CONTROL_DEPTH_CACHE_FLUSH |
199 GEN6_PIPE_CONTROL_VF_CACHE_INVALIDATE |
200 GEN6_PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
201 GEN6_PIPE_CONTROL_CS_STALL;
202 const unsigned batch_used = ilo_builder_batch_used(render->builder);
203
204 ILO_DEV_ASSERT(render->dev, 6, 7.5);
205
206 if (ilo_dev_gen(render->dev) == ILO_GEN(6))
207 gen6_wa_pre_pipe_control(render, dw1);
208
209 gen6_PIPE_CONTROL(render->builder, dw1, NULL, 0, false);
210
211 render->state.current_pipe_control_dw1 |= dw1;
212 render->state.deferred_pipe_control_dw1 &= ~dw1;
213
214 assert(ilo_builder_batch_used(render->builder) <= batch_used +
215 ilo_render_get_flush_len(render));
216 }
217
218 /**
219 * Return the command length of ilo_render_emit_query().
220 */
221 int
222 ilo_render_get_query_len(const struct ilo_render *render,
223 unsigned query_type)
224 {
225 int len;
226
227 ILO_DEV_ASSERT(render->dev, 6, 7.5);
228
229 /* always a flush or a variant of flush */
230 len = ilo_render_get_flush_len(render);
231
232 switch (query_type) {
233 case PIPE_QUERY_OCCLUSION_COUNTER:
234 case PIPE_QUERY_TIMESTAMP:
235 case PIPE_QUERY_TIME_ELAPSED:
236 /* no reg */
237 break;
238 case PIPE_QUERY_PRIMITIVES_GENERATED:
239 case PIPE_QUERY_PRIMITIVES_EMITTED:
240 len += GEN6_MI_STORE_REGISTER_MEM__SIZE * 2;
241 break;
242 case PIPE_QUERY_PIPELINE_STATISTICS:
243 {
244 const int num_regs =
245 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 10 : 8;
246 const int num_pads =
247 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 1 : 3;
248
249 len += GEN6_MI_STORE_REGISTER_MEM__SIZE * 2 * num_regs +
250 GEN6_MI_STORE_DATA_IMM__SIZE * num_pads;
251 }
252 break;
253 default:
254 len = 0;
255 break;
256 }
257
258 return len;
259 }
260
261 /**
262 * Emit PIPE_CONTROLs or MI_STORE_REGISTER_MEMs to store register values.
263 */
264 void
265 ilo_render_emit_query(struct ilo_render *render,
266 struct ilo_query *q, uint32_t offset)
267 {
268 const uint32_t pipeline_statistics_regs[11] = {
269 GEN6_REG_IA_VERTICES_COUNT,
270 GEN6_REG_IA_PRIMITIVES_COUNT,
271 GEN6_REG_VS_INVOCATION_COUNT,
272 GEN6_REG_GS_INVOCATION_COUNT,
273 GEN6_REG_GS_PRIMITIVES_COUNT,
274 GEN6_REG_CL_INVOCATION_COUNT,
275 GEN6_REG_CL_PRIMITIVES_COUNT,
276 GEN6_REG_PS_INVOCATION_COUNT,
277 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ?
278 GEN7_REG_HS_INVOCATION_COUNT : 0,
279 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ?
280 GEN7_REG_DS_INVOCATION_COUNT : 0,
281 0,
282 };
283 const uint32_t primitives_generated_reg =
284 (ilo_dev_gen(render->dev) >= ILO_GEN(7) && q->index > 0) ?
285 GEN7_REG_SO_PRIM_STORAGE_NEEDED(q->index) :
286 GEN6_REG_CL_INVOCATION_COUNT;
287 const uint32_t primitives_emitted_reg =
288 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ?
289 GEN7_REG_SO_NUM_PRIMS_WRITTEN(q->index) :
290 GEN6_REG_SO_NUM_PRIMS_WRITTEN;
291 const unsigned batch_used = ilo_builder_batch_used(render->builder);
292 const uint32_t *regs;
293 int reg_count = 0, i;
294 uint32_t pipe_control_dw1 = 0;
295
296 ILO_DEV_ASSERT(render->dev, 6, 7.5);
297
298 switch (q->type) {
299 case PIPE_QUERY_OCCLUSION_COUNTER:
300 pipe_control_dw1 = GEN6_PIPE_CONTROL_DEPTH_STALL |
301 GEN6_PIPE_CONTROL_WRITE_PS_DEPTH_COUNT;
302 break;
303 case PIPE_QUERY_TIMESTAMP:
304 case PIPE_QUERY_TIME_ELAPSED:
305 pipe_control_dw1 = GEN6_PIPE_CONTROL_WRITE_TIMESTAMP;
306 break;
307 case PIPE_QUERY_PRIMITIVES_GENERATED:
308 regs = &primitives_generated_reg;
309 reg_count = 1;
310 break;
311 case PIPE_QUERY_PRIMITIVES_EMITTED:
312 regs = &primitives_emitted_reg;
313 reg_count = 1;
314 break;
315 case PIPE_QUERY_PIPELINE_STATISTICS:
316 regs = pipeline_statistics_regs;
317 reg_count = Elements(pipeline_statistics_regs);
318 break;
319 default:
320 break;
321 }
322
323 if (pipe_control_dw1) {
324 assert(!reg_count);
325
326 if (ilo_dev_gen(render->dev) == ILO_GEN(6))
327 gen6_wa_pre_pipe_control(render, pipe_control_dw1);
328
329 gen6_PIPE_CONTROL(render->builder, pipe_control_dw1,
330 q->bo, offset, true);
331
332 render->state.current_pipe_control_dw1 |= pipe_control_dw1;
333 render->state.deferred_pipe_control_dw1 &= ~pipe_control_dw1;
334 } else if (reg_count) {
335 ilo_render_emit_flush(render);
336 }
337
338 for (i = 0; i < reg_count; i++) {
339 if (regs[i]) {
340 /* store lower 32 bits */
341 gen6_MI_STORE_REGISTER_MEM(render->builder, q->bo, offset, regs[i]);
342 /* store higher 32 bits */
343 gen6_MI_STORE_REGISTER_MEM(render->builder, q->bo,
344 offset + 4, regs[i] + 4);
345 } else {
346 gen6_MI_STORE_DATA_IMM(render->builder, q->bo, offset, 0, true);
347 }
348
349 offset += 8;
350 }
351
352 assert(ilo_builder_batch_used(render->builder) <= batch_used +
353 ilo_render_get_query_len(render, q->type));
354 }
355
356 int
357 ilo_render_get_rectlist_len(const struct ilo_render *render,
358 const struct ilo_blitter *blitter)
359 {
360 ILO_DEV_ASSERT(render->dev, 6, 7.5);
361
362 return ilo_render_get_rectlist_dynamic_states_len(render, blitter) +
363 ilo_render_get_rectlist_commands_len(render, blitter);
364 }
365
366 void
367 ilo_render_emit_rectlist(struct ilo_render *render,
368 const struct ilo_blitter *blitter)
369 {
370 ILO_DEV_ASSERT(render->dev, 6, 7.5);
371
372 ilo_render_emit_rectlist_dynamic_states(render, blitter);
373 ilo_render_emit_rectlist_commands(render, blitter);
374 }
375
376 int
377 ilo_render_get_draw_len(const struct ilo_render *render,
378 const struct ilo_state_vector *vec)
379 {
380 ILO_DEV_ASSERT(render->dev, 6, 7.5);
381
382 return ilo_render_get_draw_dynamic_states_len(render, vec) +
383 ilo_render_get_draw_surface_states_len(render, vec) +
384 ilo_render_get_draw_commands_len(render, vec);
385 }
386
387 static void
388 gen6_draw_prepare(struct ilo_render *render,
389 const struct ilo_state_vector *vec,
390 struct gen6_draw_session *session)
391 {
392 memset(session, 0, sizeof(*session));
393 session->pipe_dirty = vec->dirty;
394 session->reduced_prim = u_reduced_prim(vec->draw->mode);
395
396 if (render->hw_ctx_changed) {
397 /* these should be enough to make everything uploaded */
398 render->batch_bo_changed = true;
399 render->state_bo_changed = true;
400 render->instruction_bo_changed = true;
401
402 session->prim_changed = true;
403 session->primitive_restart_changed = true;
404 } else {
405 session->prim_changed =
406 (render->state.reduced_prim != session->reduced_prim);
407 session->primitive_restart_changed =
408 (render->state.primitive_restart != vec->draw->primitive_restart);
409 }
410 }
411
412 static void
413 gen6_draw_end(struct ilo_render *render,
414 const struct ilo_state_vector *vec,
415 struct gen6_draw_session *session)
416 {
417 render->hw_ctx_changed = false;
418
419 render->batch_bo_changed = false;
420 render->state_bo_changed = false;
421 render->instruction_bo_changed = false;
422
423 render->state.reduced_prim = session->reduced_prim;
424 render->state.primitive_restart = vec->draw->primitive_restart;
425 }
426
427 void
428 ilo_render_emit_draw(struct ilo_render *render,
429 const struct ilo_state_vector *vec)
430 {
431 struct gen6_draw_session session;
432
433 ILO_DEV_ASSERT(render->dev, 6, 7.5);
434
435 gen6_draw_prepare(render, vec, &session);
436
437 /* force all states to be uploaded if the state bo changed */
438 if (render->state_bo_changed)
439 session.pipe_dirty = ILO_DIRTY_ALL;
440 else
441 session.pipe_dirty = vec->dirty;
442
443 ilo_render_emit_draw_dynamic_states(render, vec, &session);
444 ilo_render_emit_draw_surface_states(render, vec, &session);
445
446 /* force all commands to be uploaded if the HW context changed */
447 if (render->hw_ctx_changed)
448 session.pipe_dirty = ILO_DIRTY_ALL;
449 else
450 session.pipe_dirty = vec->dirty;
451
452 ilo_render_emit_draw_commands(render, vec, &session);
453
454 gen6_draw_end(render, vec, &session);
455 }