iris_draw.c revision b8e80941
1/*
2 * Copyright © 2017 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 shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23/**
24 * @file iris_draw.c
25 *
26 * The main driver hooks for drawing and launching compute shaders.
27 */
28
29#include <stdio.h>
30#include <errno.h>
31#include "pipe/p_defines.h"
32#include "pipe/p_state.h"
33#include "pipe/p_context.h"
34#include "pipe/p_screen.h"
35#include "util/u_inlines.h"
36#include "util/u_transfer.h"
37#include "util/u_upload_mgr.h"
38#include "intel/compiler/brw_compiler.h"
39#include "intel/compiler/brw_eu_defines.h"
40#include "iris_context.h"
41#include "iris_defines.h"
42
43static bool
44prim_is_points_or_lines(const struct pipe_draw_info *draw)
45{
46   /* We don't need to worry about adjacency - it can only be used with
47    * geometry shaders, and we don't care about this info when GS is on.
48    */
49   return draw->mode == PIPE_PRIM_POINTS ||
50          draw->mode == PIPE_PRIM_LINES ||
51          draw->mode == PIPE_PRIM_LINE_LOOP ||
52          draw->mode == PIPE_PRIM_LINE_STRIP;
53}
54
55/**
56 * Record the current primitive mode and restart information, flagging
57 * related packets as dirty if necessary.
58 */
59static void
60iris_update_draw_info(struct iris_context *ice,
61                      const struct pipe_draw_info *info)
62{
63   if (ice->state.prim_mode != info->mode) {
64      ice->state.prim_mode = info->mode;
65      ice->state.dirty |= IRIS_DIRTY_VF_TOPOLOGY;
66
67
68      /* For XY Clip enables */
69      bool points_or_lines = prim_is_points_or_lines(info);
70      if (points_or_lines != ice->state.prim_is_points_or_lines) {
71         ice->state.prim_is_points_or_lines = points_or_lines;
72         ice->state.dirty |= IRIS_DIRTY_CLIP;
73      }
74   }
75
76   if (info->mode == PIPE_PRIM_PATCHES &&
77       ice->state.vertices_per_patch != info->vertices_per_patch) {
78      ice->state.vertices_per_patch = info->vertices_per_patch;
79      ice->state.dirty |= IRIS_DIRTY_VF_TOPOLOGY;
80
81      /* Flag constants dirty for gl_PatchVerticesIn if needed. */
82      const struct shader_info *tcs_info =
83         iris_get_shader_info(ice, MESA_SHADER_TESS_CTRL);
84      if (tcs_info &&
85          tcs_info->system_values_read & (1ull << SYSTEM_VALUE_VERTICES_IN)) {
86         ice->state.dirty |= IRIS_DIRTY_CONSTANTS_TCS;
87         ice->state.shaders[MESA_SHADER_TESS_CTRL].cbuf0_needs_upload = true;
88      }
89   }
90
91   if (ice->state.primitive_restart != info->primitive_restart ||
92       ice->state.cut_index != info->restart_index) {
93      ice->state.dirty |= IRIS_DIRTY_VF;
94      ice->state.primitive_restart = info->primitive_restart;
95      ice->state.cut_index = info->restart_index;
96   }
97
98   if (info->indirect) {
99      pipe_resource_reference(&ice->draw.draw_params_res,
100                              info->indirect->buffer);
101      ice->draw.draw_params_offset = info->indirect->offset +
102                                     (info->index_size ? 12 : 8);
103      ice->draw.params.firstvertex = 0;
104      ice->draw.params.baseinstance = 0;
105      ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS |
106                          IRIS_DIRTY_VERTEX_ELEMENTS |
107                          IRIS_DIRTY_VF_SGVS;
108   } else if (ice->draw.is_indirect ||
109              ice->draw.params.firstvertex !=
110              (info->index_size ? info->index_bias : info->start) ||
111              (ice->draw.params.baseinstance != info->start_instance)) {
112      pipe_resource_reference(&ice->draw.draw_params_res, NULL);
113      ice->draw.draw_params_offset = 0;
114      ice->draw.params.firstvertex =
115         info->index_size ? info->index_bias : info->start;
116      ice->draw.params.baseinstance = info->start_instance;
117      ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS |
118                          IRIS_DIRTY_VERTEX_ELEMENTS |
119                          IRIS_DIRTY_VF_SGVS;
120   }
121   ice->draw.is_indirect = info->indirect;
122
123   if (ice->draw.derived_params.drawid != info->drawid ||
124       ice->draw.derived_params.is_indexed_draw != (info->index_size ? ~0 : 0)) {
125      ice->draw.derived_params.drawid = info->drawid;
126      ice->draw.derived_params.is_indexed_draw = info->index_size ? ~0 : 0;
127      ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS |
128                          IRIS_DIRTY_VERTEX_ELEMENTS |
129                          IRIS_DIRTY_VF_SGVS;
130   }
131}
132
133/**
134 * The pipe->draw_vbo() driver hook.  Performs a draw on the GPU.
135 */
136void
137iris_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
138{
139   struct iris_context *ice = (struct iris_context *) ctx;
140   struct iris_screen *screen = (struct iris_screen*)ice->ctx.screen;
141   const struct gen_device_info *devinfo = &screen->devinfo;
142   struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
143
144   if (ice->state.predicate == IRIS_PREDICATE_STATE_DONT_RENDER)
145      return;
146
147   /* We can't safely re-emit 3DSTATE_SO_BUFFERS because it may zero the
148    * write offsets, changing the behavior.
149    */
150   if (unlikely(INTEL_DEBUG & DEBUG_REEMIT))
151      ice->state.dirty |= IRIS_ALL_DIRTY_FOR_RENDER & ~IRIS_DIRTY_SO_BUFFERS;
152
153   iris_batch_maybe_flush(batch, 1500);
154
155   iris_update_draw_info(ice, info);
156
157   if (devinfo->gen == 9)
158      gen9_toggle_preemption(ice, batch, info);
159
160   iris_update_compiled_shaders(ice);
161
162   if (ice->state.dirty & IRIS_DIRTY_RENDER_RESOLVES_AND_FLUSHES) {
163      bool draw_aux_buffer_disabled[BRW_MAX_DRAW_BUFFERS] = { };
164      for (gl_shader_stage stage = 0; stage < MESA_SHADER_COMPUTE; stage++) {
165         if (ice->shaders.prog[stage])
166            iris_predraw_resolve_inputs(ice, batch, draw_aux_buffer_disabled,
167                                        stage, true);
168      }
169      iris_predraw_resolve_framebuffer(ice, batch, draw_aux_buffer_disabled);
170   }
171
172   iris_binder_reserve_3d(ice);
173
174   ice->vtbl.update_surface_base_address(batch, &ice->state.binder);
175   ice->vtbl.upload_render_state(ice, batch, info);
176
177   iris_postdraw_update_resolve_tracking(ice, batch);
178
179   ice->state.dirty &= ~IRIS_ALL_DIRTY_FOR_RENDER;
180}
181
182static void
183iris_update_grid_size_resource(struct iris_context *ice,
184                               const struct pipe_grid_info *grid)
185{
186   const struct iris_screen *screen = (void *) ice->ctx.screen;
187   const struct isl_device *isl_dev = &screen->isl_dev;
188   struct iris_state_ref *grid_ref = &ice->state.grid_size;
189   struct iris_state_ref *state_ref = &ice->state.grid_surf_state;
190
191   // XXX: if the shader doesn't actually care about the grid info,
192   // don't bother uploading the surface?
193
194   if (grid->indirect) {
195      pipe_resource_reference(&grid_ref->res, grid->indirect);
196      grid_ref->offset = grid->indirect_offset;
197
198      /* Zero out the grid size so that the next non-indirect grid launch will
199       * re-upload it properly.
200       */
201      memset(ice->state.last_grid, 0, sizeof(ice->state.last_grid));
202   } else {
203      /* If the size is the same, we don't need to upload anything. */
204      if (memcmp(ice->state.last_grid, grid->grid, sizeof(grid->grid)) == 0)
205         return;
206
207      memcpy(ice->state.last_grid, grid->grid, sizeof(grid->grid));
208
209      u_upload_data(ice->state.dynamic_uploader, 0, sizeof(grid->grid), 4,
210                    grid->grid, &grid_ref->offset, &grid_ref->res);
211   }
212
213   void *surf_map = NULL;
214   u_upload_alloc(ice->state.surface_uploader, 0, isl_dev->ss.size,
215                  isl_dev->ss.align, &state_ref->offset, &state_ref->res,
216                  &surf_map);
217   state_ref->offset +=
218      iris_bo_offset_from_base_address(iris_resource_bo(state_ref->res));
219   isl_buffer_fill_state(&screen->isl_dev, surf_map,
220                         .address = grid_ref->offset +
221                            iris_resource_bo(grid_ref->res)->gtt_offset,
222                         .size_B = sizeof(grid->grid),
223                         .format = ISL_FORMAT_RAW,
224                         .stride_B = 1,
225                         .mocs = 4); // XXX: MOCS
226
227   ice->state.dirty |= IRIS_DIRTY_BINDINGS_CS;
228}
229
230void
231iris_launch_grid(struct pipe_context *ctx, const struct pipe_grid_info *grid)
232{
233   struct iris_context *ice = (struct iris_context *) ctx;
234   struct iris_batch *batch = &ice->batches[IRIS_BATCH_COMPUTE];
235
236   if (ice->state.predicate == IRIS_PREDICATE_STATE_DONT_RENDER)
237      return;
238
239   if (unlikely(INTEL_DEBUG & DEBUG_REEMIT))
240      ice->state.dirty |= IRIS_ALL_DIRTY_FOR_COMPUTE;
241
242   /* We can't do resolves on the compute engine, so awkwardly, we have to
243    * do them on the render batch...
244    */
245   if (ice->state.dirty & IRIS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES) {
246      iris_predraw_resolve_inputs(ice, &ice->batches[IRIS_BATCH_RENDER], NULL,
247                                  MESA_SHADER_COMPUTE, false);
248   }
249
250   iris_batch_maybe_flush(batch, 1500);
251
252   //if (dirty & IRIS_DIRTY_UNCOMPILED_CS)
253      iris_update_compiled_compute_shader(ice);
254
255   iris_update_grid_size_resource(ice, grid);
256
257   iris_binder_reserve_compute(ice);
258   ice->vtbl.update_surface_base_address(batch, &ice->state.binder);
259
260   if (ice->state.compute_predicate) {
261      ice->vtbl.load_register_mem64(batch, MI_PREDICATE_RESULT,
262                                    ice->state.compute_predicate, 0);
263      ice->state.compute_predicate = NULL;
264   }
265
266   ice->vtbl.upload_compute_state(ice, batch, grid);
267
268   ice->state.dirty &= ~IRIS_ALL_DIRTY_FOR_COMPUTE;
269
270   /* Note: since compute shaders can't access the framebuffer, there's
271    * no need to call iris_postdraw_update_resolve_tracking.
272    */
273}
274