• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "core/ilo_builder.h"
30 #include "core/ilo_builder_mi.h"
31 #include "core/ilo_builder_render.h"
32 #include "core/intel_winsys.h"
33 #include "util/u_prim.h"
34 
35 #include "ilo_query.h"
36 #include "ilo_render_gen.h"
37 
38 struct ilo_render *
ilo_render_create(struct ilo_builder * builder)39 ilo_render_create(struct ilo_builder *builder)
40 {
41    struct ilo_render *render;
42 
43    render = CALLOC_STRUCT(ilo_render);
44    if (!render)
45       return NULL;
46 
47    render->dev = builder->dev;
48    render->builder = builder;
49 
50    render->workaround_bo = intel_winsys_alloc_bo(builder->winsys,
51          "PIPE_CONTROL workaround", 4096, false);
52    if (!render->workaround_bo) {
53       ilo_warn("failed to allocate PIPE_CONTROL workaround bo\n");
54       FREE(render);
55       return NULL;
56    }
57 
58    ilo_state_sample_pattern_init_default(&render->sample_pattern,
59          render->dev);
60 
61    ilo_render_invalidate_hw(render);
62    ilo_render_invalidate_builder(render);
63 
64    return render;
65 }
66 
67 void
ilo_render_destroy(struct ilo_render * render)68 ilo_render_destroy(struct ilo_render *render)
69 {
70    intel_bo_unref(render->vs_scratch.bo);
71    intel_bo_unref(render->gs_scratch.bo);
72    intel_bo_unref(render->fs_scratch.bo);
73 
74    intel_bo_unref(render->workaround_bo);
75    FREE(render);
76 }
77 
78 static bool
resize_scratch_space(struct ilo_render * render,struct ilo_render_scratch_space * scratch,const char * name,int new_size)79 resize_scratch_space(struct ilo_render *render,
80                      struct ilo_render_scratch_space *scratch,
81                      const char *name, int new_size)
82 {
83    struct intel_bo *bo;
84 
85    if (scratch->size >= new_size)
86       return true;
87 
88    bo = intel_winsys_alloc_bo(render->builder->winsys, name, new_size, false);
89    if (!bo)
90       return false;
91 
92    intel_bo_unref(scratch->bo);
93    scratch->bo = bo;
94    scratch->size = new_size;
95 
96    return true;
97 }
98 
99 bool
ilo_render_prepare_scratch_spaces(struct ilo_render * render,int vs_scratch_size,int gs_scratch_size,int fs_scratch_size)100 ilo_render_prepare_scratch_spaces(struct ilo_render *render,
101                                   int vs_scratch_size,
102                                   int gs_scratch_size,
103                                   int fs_scratch_size)
104 {
105    return (resize_scratch_space(render, &render->vs_scratch,
106             "vs scratch", vs_scratch_size) &&
107            resize_scratch_space(render, &render->gs_scratch,
108             "gs scratch", gs_scratch_size) &&
109            resize_scratch_space(render, &render->fs_scratch,
110             "fs scratch", fs_scratch_size));
111 }
112 
113 void
ilo_render_get_sample_position(const struct ilo_render * render,unsigned sample_count,unsigned sample_index,float * x,float * y)114 ilo_render_get_sample_position(const struct ilo_render *render,
115                                unsigned sample_count,
116                                unsigned sample_index,
117                                float *x, float *y)
118 {
119    uint8_t off_x, off_y;
120 
121    ilo_state_sample_pattern_get_offset(&render->sample_pattern, render->dev,
122          sample_count, sample_index, &off_x, &off_y);
123 
124    *x = (float) off_x / 16.0f;
125    *y = (float) off_y / 16.0f;
126 }
127 
128 void
ilo_render_invalidate_hw(struct ilo_render * render)129 ilo_render_invalidate_hw(struct ilo_render *render)
130 {
131    render->hw_ctx_changed = true;
132 }
133 
134 void
ilo_render_invalidate_builder(struct ilo_render * render)135 ilo_render_invalidate_builder(struct ilo_render *render)
136 {
137    render->batch_bo_changed = true;
138    render->state_bo_changed = true;
139    render->instruction_bo_changed = true;
140 
141    /* Kernel flushes everything.  Shouldn't we set all bits here? */
142    render->state.current_pipe_control_dw1 = 0;
143 }
144 
145 /**
146  * Return the command length of ilo_render_emit_flush().
147  */
148 int
ilo_render_get_flush_len(const struct ilo_render * render)149 ilo_render_get_flush_len(const struct ilo_render *render)
150 {
151    int len;
152 
153    ILO_DEV_ASSERT(render->dev, 6, 8);
154 
155    len = GEN6_PIPE_CONTROL__SIZE;
156 
157    /* plus gen6_wa_pre_pipe_control() */
158    if (ilo_dev_gen(render->dev) == ILO_GEN(6))
159       len *= 3;
160 
161    return len;
162 }
163 
164 /**
165  * Emit PIPE_CONTROLs to flush all caches.
166  */
167 void
ilo_render_emit_flush(struct ilo_render * render)168 ilo_render_emit_flush(struct ilo_render *render)
169 {
170    const uint32_t dw1 = GEN6_PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE |
171                         GEN6_PIPE_CONTROL_RENDER_CACHE_FLUSH |
172                         GEN6_PIPE_CONTROL_DEPTH_CACHE_FLUSH |
173                         GEN6_PIPE_CONTROL_VF_CACHE_INVALIDATE |
174                         GEN6_PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
175                         GEN6_PIPE_CONTROL_CS_STALL;
176    const unsigned batch_used = ilo_builder_batch_used(render->builder);
177 
178    ILO_DEV_ASSERT(render->dev, 6, 8);
179 
180    if (ilo_dev_gen(render->dev) == ILO_GEN(6))
181       gen6_wa_pre_pipe_control(render, dw1);
182 
183    ilo_render_pipe_control(render, dw1);
184 
185    assert(ilo_builder_batch_used(render->builder) <= batch_used +
186          ilo_render_get_flush_len(render));
187 }
188 
189 /**
190  * Return the command length of ilo_render_emit_query().
191  */
192 int
ilo_render_get_query_len(const struct ilo_render * render,unsigned query_type)193 ilo_render_get_query_len(const struct ilo_render *render,
194                          unsigned query_type)
195 {
196    int len;
197 
198    ILO_DEV_ASSERT(render->dev, 6, 8);
199 
200    /* always a flush or a variant of flush */
201    len = ilo_render_get_flush_len(render);
202 
203    switch (query_type) {
204    case PIPE_QUERY_OCCLUSION_COUNTER:
205    case PIPE_QUERY_OCCLUSION_PREDICATE:
206    case PIPE_QUERY_TIMESTAMP:
207    case PIPE_QUERY_TIME_ELAPSED:
208       /* no reg */
209       break;
210    case PIPE_QUERY_PRIMITIVES_GENERATED:
211    case PIPE_QUERY_PRIMITIVES_EMITTED:
212       len += GEN6_MI_STORE_REGISTER_MEM__SIZE * 2;
213       break;
214    case PIPE_QUERY_PIPELINE_STATISTICS:
215       {
216          const int num_regs =
217             (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 10 : 8;
218          const int num_pads =
219             (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 1 : 3;
220 
221          len += GEN6_MI_STORE_REGISTER_MEM__SIZE * 2 * num_regs +
222                 GEN6_MI_STORE_DATA_IMM__SIZE * num_pads;
223       }
224       break;
225    default:
226       len = 0;
227       break;
228    }
229 
230    return len;
231 }
232 
233 /**
234  * Emit PIPE_CONTROLs or MI_STORE_REGISTER_MEMs to store register values.
235  */
236 void
ilo_render_emit_query(struct ilo_render * render,struct ilo_query * q,uint32_t offset)237 ilo_render_emit_query(struct ilo_render *render,
238                       struct ilo_query *q, uint32_t offset)
239 {
240    const uint32_t pipeline_statistics_regs[11] = {
241       GEN6_REG_IA_VERTICES_COUNT,
242       GEN6_REG_IA_PRIMITIVES_COUNT,
243       GEN6_REG_VS_INVOCATION_COUNT,
244       GEN6_REG_GS_INVOCATION_COUNT,
245       GEN6_REG_GS_PRIMITIVES_COUNT,
246       GEN6_REG_CL_INVOCATION_COUNT,
247       GEN6_REG_CL_PRIMITIVES_COUNT,
248       GEN6_REG_PS_INVOCATION_COUNT,
249       (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ?
250          GEN7_REG_HS_INVOCATION_COUNT : 0,
251       (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ?
252          GEN7_REG_DS_INVOCATION_COUNT : 0,
253       0,
254    };
255    const uint32_t primitives_generated_reg =
256       (ilo_dev_gen(render->dev) >= ILO_GEN(7) && q->index > 0) ?
257       GEN7_REG_SO_PRIM_STORAGE_NEEDED(q->index) :
258       GEN6_REG_CL_INVOCATION_COUNT;
259    const uint32_t primitives_emitted_reg =
260       (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ?
261       GEN7_REG_SO_NUM_PRIMS_WRITTEN(q->index) :
262       GEN6_REG_SO_NUM_PRIMS_WRITTEN;
263    const unsigned batch_used = ilo_builder_batch_used(render->builder);
264    const uint32_t *regs;
265    int reg_count = 0, i;
266    uint32_t pipe_control_dw1 = 0;
267 
268    ILO_DEV_ASSERT(render->dev, 6, 8);
269 
270    switch (q->type) {
271    case PIPE_QUERY_OCCLUSION_COUNTER:
272    case PIPE_QUERY_OCCLUSION_PREDICATE:
273       pipe_control_dw1 = GEN6_PIPE_CONTROL_DEPTH_STALL |
274                          GEN6_PIPE_CONTROL_WRITE_PS_DEPTH_COUNT;
275       break;
276    case PIPE_QUERY_TIMESTAMP:
277    case PIPE_QUERY_TIME_ELAPSED:
278       pipe_control_dw1 = GEN6_PIPE_CONTROL_WRITE_TIMESTAMP;
279       break;
280    case PIPE_QUERY_PRIMITIVES_GENERATED:
281       regs = &primitives_generated_reg;
282       reg_count = 1;
283       break;
284    case PIPE_QUERY_PRIMITIVES_EMITTED:
285       regs = &primitives_emitted_reg;
286       reg_count = 1;
287       break;
288    case PIPE_QUERY_PIPELINE_STATISTICS:
289       regs = pipeline_statistics_regs;
290       reg_count = ARRAY_SIZE(pipeline_statistics_regs);
291       break;
292    default:
293       break;
294    }
295 
296    if (pipe_control_dw1) {
297       assert(!reg_count);
298 
299       if (ilo_dev_gen(render->dev) == ILO_GEN(6))
300          gen6_wa_pre_pipe_control(render, pipe_control_dw1);
301 
302       gen6_PIPE_CONTROL(render->builder, pipe_control_dw1, q->bo, offset, 0);
303 
304       render->state.current_pipe_control_dw1 |= pipe_control_dw1;
305       render->state.deferred_pipe_control_dw1 &= ~pipe_control_dw1;
306    } else if (reg_count) {
307       ilo_render_emit_flush(render);
308    }
309 
310    for (i = 0; i < reg_count; i++) {
311       if (regs[i]) {
312          /* store lower 32 bits */
313          gen6_MI_STORE_REGISTER_MEM(render->builder, regs[i], q->bo, offset);
314          /* store higher 32 bits */
315          gen6_MI_STORE_REGISTER_MEM(render->builder, regs[i] + 4,
316                q->bo, offset + 4);
317       } else {
318          gen6_MI_STORE_DATA_IMM(render->builder, q->bo, offset, 0);
319       }
320 
321       offset += 8;
322    }
323 
324    assert(ilo_builder_batch_used(render->builder) <= batch_used +
325          ilo_render_get_query_len(render, q->type));
326 }
327 
328 int
ilo_render_get_rectlist_len(const struct ilo_render * render,const struct ilo_blitter * blitter)329 ilo_render_get_rectlist_len(const struct ilo_render *render,
330                             const struct ilo_blitter *blitter)
331 {
332    ILO_DEV_ASSERT(render->dev, 6, 8);
333 
334    return ilo_render_get_rectlist_dynamic_states_len(render, blitter) +
335           ilo_render_get_rectlist_commands_len(render, blitter);
336 }
337 
338 void
ilo_render_emit_rectlist(struct ilo_render * render,const struct ilo_blitter * blitter)339 ilo_render_emit_rectlist(struct ilo_render *render,
340                          const struct ilo_blitter *blitter)
341 {
342    struct ilo_render_rectlist_session session;
343 
344    ILO_DEV_ASSERT(render->dev, 6, 8);
345 
346    memset(&session, 0, sizeof(session));
347    ilo_render_emit_rectlist_dynamic_states(render, blitter, &session);
348    ilo_render_emit_rectlist_commands(render, blitter, &session);
349 }
350 
351 int
ilo_render_get_draw_len(const struct ilo_render * render,const struct ilo_state_vector * vec)352 ilo_render_get_draw_len(const struct ilo_render *render,
353                         const struct ilo_state_vector *vec)
354 {
355    ILO_DEV_ASSERT(render->dev, 6, 8);
356 
357    return ilo_render_get_draw_dynamic_states_len(render, vec) +
358           ilo_render_get_draw_surface_states_len(render, vec) +
359           ilo_render_get_draw_commands_len(render, vec);
360 }
361 
362 static void
draw_session_prepare(struct ilo_render * render,const struct ilo_state_vector * vec,struct ilo_render_draw_session * session)363 draw_session_prepare(struct ilo_render *render,
364                      const struct ilo_state_vector *vec,
365                      struct ilo_render_draw_session *session)
366 {
367    memset(session, 0, sizeof(*session));
368    session->pipe_dirty = vec->dirty;
369    session->reduced_prim = u_reduced_prim(vec->draw->mode);
370 
371    if (render->hw_ctx_changed) {
372       /* these should be enough to make everything uploaded */
373       render->batch_bo_changed = true;
374       render->state_bo_changed = true;
375       render->instruction_bo_changed = true;
376 
377       session->prim_changed = true;
378 
379       ilo_state_urb_full_delta(&vec->urb, render->dev, &session->urb_delta);
380       ilo_state_vf_full_delta(&vec->ve->vf, render->dev, &session->vf_delta);
381 
382       ilo_state_raster_full_delta(&vec->rasterizer->rs, render->dev,
383             &session->rs_delta);
384 
385       ilo_state_viewport_full_delta(&vec->viewport.vp, render->dev,
386             &session->vp_delta);
387 
388       ilo_state_cc_full_delta(&vec->blend->cc, render->dev,
389             &session->cc_delta);
390    } else {
391       session->prim_changed =
392          (render->state.reduced_prim != session->reduced_prim);
393 
394       ilo_state_urb_get_delta(&vec->urb, render->dev,
395             &render->state.urb, &session->urb_delta);
396 
397       if (vec->dirty & ILO_DIRTY_VE) {
398          ilo_state_vf_full_delta(&vec->ve->vf, render->dev,
399                &session->vf_delta);
400       }
401 
402       if (vec->dirty & ILO_DIRTY_RASTERIZER) {
403          ilo_state_raster_get_delta(&vec->rasterizer->rs, render->dev,
404                &render->state.rs, &session->rs_delta);
405       }
406 
407       if (vec->dirty & ILO_DIRTY_VIEWPORT) {
408          ilo_state_viewport_full_delta(&vec->viewport.vp, render->dev,
409                &session->vp_delta);
410       }
411 
412       if (vec->dirty & ILO_DIRTY_BLEND) {
413          ilo_state_cc_get_delta(&vec->blend->cc, render->dev,
414                &render->state.cc, &session->cc_delta);
415       }
416    }
417 }
418 
419 static void
draw_session_end(struct ilo_render * render,const struct ilo_state_vector * vec,struct ilo_render_draw_session * session)420 draw_session_end(struct ilo_render *render,
421                  const struct ilo_state_vector *vec,
422                  struct ilo_render_draw_session *session)
423 {
424    render->hw_ctx_changed = false;
425 
426    render->batch_bo_changed = false;
427    render->state_bo_changed = false;
428    render->instruction_bo_changed = false;
429 
430    render->state.reduced_prim = session->reduced_prim;
431 
432    render->state.urb = vec->urb;
433    render->state.rs = vec->rasterizer->rs;
434    render->state.cc = vec->blend->cc;
435 }
436 
437 void
ilo_render_emit_draw(struct ilo_render * render,const struct ilo_state_vector * vec)438 ilo_render_emit_draw(struct ilo_render *render,
439                      const struct ilo_state_vector *vec)
440 {
441    struct ilo_render_draw_session session;
442 
443    ILO_DEV_ASSERT(render->dev, 6, 8);
444 
445    draw_session_prepare(render, vec, &session);
446 
447    /* force all states to be uploaded if the state bo changed */
448    if (render->state_bo_changed)
449       session.pipe_dirty = ILO_DIRTY_ALL;
450    else
451       session.pipe_dirty = vec->dirty;
452 
453    ilo_render_emit_draw_dynamic_states(render, vec, &session);
454    ilo_render_emit_draw_surface_states(render, vec, &session);
455 
456    /* force all commands to be uploaded if the HW context changed */
457    if (render->hw_ctx_changed)
458       session.pipe_dirty = ILO_DIRTY_ALL;
459    else
460       session.pipe_dirty = vec->dirty;
461 
462    ilo_render_emit_draw_commands(render, vec, &session);
463 
464    draw_session_end(render, vec, &session);
465 }
466 
467 int
ilo_render_get_launch_grid_len(const struct ilo_render * render,const struct ilo_state_vector * vec)468 ilo_render_get_launch_grid_len(const struct ilo_render *render,
469                                const struct ilo_state_vector *vec)
470 {
471    ILO_DEV_ASSERT(render->dev, 7, 7.5);
472 
473    return ilo_render_get_launch_grid_surface_states_len(render, vec) +
474           ilo_render_get_launch_grid_dynamic_states_len(render, vec) +
475           ilo_render_get_launch_grid_commands_len(render, vec);
476 }
477 
478 void
ilo_render_emit_launch_grid(struct ilo_render * render,const struct ilo_state_vector * vec,const unsigned thread_group_offset[3],const unsigned thread_group_dim[3],unsigned thread_group_size,const struct pipe_constant_buffer * input,uint32_t pc)479 ilo_render_emit_launch_grid(struct ilo_render *render,
480                             const struct ilo_state_vector *vec,
481                             const unsigned thread_group_offset[3],
482                             const unsigned thread_group_dim[3],
483                             unsigned thread_group_size,
484                             const struct pipe_constant_buffer *input,
485                             uint32_t pc)
486 {
487    struct ilo_render_launch_grid_session session;
488 
489    ILO_DEV_ASSERT(render->dev, 7, 7.5);
490 
491    assert(input->buffer);
492 
493    memset(&session, 0, sizeof(session));
494 
495    session.thread_group_offset = thread_group_offset;
496    session.thread_group_dim = thread_group_dim;
497    session.thread_group_size = thread_group_size;
498    session.input = input;
499    session.pc = pc;
500 
501    ilo_render_emit_launch_grid_surface_states(render, vec, &session);
502    ilo_render_emit_launch_grid_dynamic_states(render, vec, &session);
503    ilo_render_emit_launch_grid_commands(render, vec, &session);
504 }
505