1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2017 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
12bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
21bf215546Sopenharmony_ci */
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci/**
24bf215546Sopenharmony_ci * @file crocus_draw.c
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci * The main driver hooks for drawing and launching compute shaders.
27bf215546Sopenharmony_ci */
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include <stdio.h>
30bf215546Sopenharmony_ci#include <errno.h>
31bf215546Sopenharmony_ci#include "pipe/p_defines.h"
32bf215546Sopenharmony_ci#include "pipe/p_state.h"
33bf215546Sopenharmony_ci#include "pipe/p_context.h"
34bf215546Sopenharmony_ci#include "pipe/p_screen.h"
35bf215546Sopenharmony_ci#include "util/u_draw.h"
36bf215546Sopenharmony_ci#include "util/u_inlines.h"
37bf215546Sopenharmony_ci#include "util/u_transfer.h"
38bf215546Sopenharmony_ci#include "util/u_upload_mgr.h"
39bf215546Sopenharmony_ci#include "intel/compiler/brw_compiler.h"
40bf215546Sopenharmony_ci#include "intel/compiler/brw_eu_defines.h"
41bf215546Sopenharmony_ci#include "compiler/shader_info.h"
42bf215546Sopenharmony_ci#include "crocus_context.h"
43bf215546Sopenharmony_ci#include "crocus_defines.h"
44bf215546Sopenharmony_ci#include "util/u_prim_restart.h"
45bf215546Sopenharmony_ci#include "util/u_prim.h"
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_cistatic bool
48bf215546Sopenharmony_ciprim_is_points_or_lines(enum pipe_prim_type mode)
49bf215546Sopenharmony_ci{
50bf215546Sopenharmony_ci   /* We don't need to worry about adjacency - it can only be used with
51bf215546Sopenharmony_ci    * geometry shaders, and we don't care about this info when GS is on.
52bf215546Sopenharmony_ci    */
53bf215546Sopenharmony_ci   return mode == PIPE_PRIM_POINTS ||
54bf215546Sopenharmony_ci          mode == PIPE_PRIM_LINES ||
55bf215546Sopenharmony_ci          mode == PIPE_PRIM_LINE_LOOP ||
56bf215546Sopenharmony_ci          mode == PIPE_PRIM_LINE_STRIP;
57bf215546Sopenharmony_ci}
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_cistatic bool
60bf215546Sopenharmony_cican_cut_index_handle_restart_index(struct crocus_context *ice,
61bf215546Sopenharmony_ci                                   const struct pipe_draw_info *draw)
62bf215546Sopenharmony_ci{
63bf215546Sopenharmony_ci   switch (draw->index_size) {
64bf215546Sopenharmony_ci   case 1:
65bf215546Sopenharmony_ci      return draw->restart_index == 0xff;
66bf215546Sopenharmony_ci   case 2:
67bf215546Sopenharmony_ci      return draw->restart_index == 0xffff;
68bf215546Sopenharmony_ci   case 4:
69bf215546Sopenharmony_ci      return draw->restart_index == 0xffffffff;
70bf215546Sopenharmony_ci   default:
71bf215546Sopenharmony_ci      unreachable("illegal index size\n");
72bf215546Sopenharmony_ci   }
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci   return false;
75bf215546Sopenharmony_ci}
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_cistatic bool
78bf215546Sopenharmony_cican_cut_index_handle_prim(struct crocus_context *ice,
79bf215546Sopenharmony_ci                          const struct pipe_draw_info *draw)
80bf215546Sopenharmony_ci{
81bf215546Sopenharmony_ci   struct crocus_screen *screen = (struct crocus_screen*)ice->ctx.screen;
82bf215546Sopenharmony_ci   const struct intel_device_info *devinfo = &screen->devinfo;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   /* Haswell can do it all. */
85bf215546Sopenharmony_ci   if (devinfo->verx10 >= 75)
86bf215546Sopenharmony_ci      return true;
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   if (!can_cut_index_handle_restart_index(ice, draw))
89bf215546Sopenharmony_ci      return false;
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci   switch (draw->mode) {
92bf215546Sopenharmony_ci   case PIPE_PRIM_POINTS:
93bf215546Sopenharmony_ci   case PIPE_PRIM_LINES:
94bf215546Sopenharmony_ci   case PIPE_PRIM_LINE_STRIP:
95bf215546Sopenharmony_ci   case PIPE_PRIM_TRIANGLES:
96bf215546Sopenharmony_ci   case PIPE_PRIM_TRIANGLE_STRIP:
97bf215546Sopenharmony_ci   case PIPE_PRIM_LINES_ADJACENCY:
98bf215546Sopenharmony_ci   case PIPE_PRIM_LINE_STRIP_ADJACENCY:
99bf215546Sopenharmony_ci   case PIPE_PRIM_TRIANGLES_ADJACENCY:
100bf215546Sopenharmony_ci   case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
101bf215546Sopenharmony_ci      return true;
102bf215546Sopenharmony_ci   default:
103bf215546Sopenharmony_ci      break;
104bf215546Sopenharmony_ci   }
105bf215546Sopenharmony_ci   return false;
106bf215546Sopenharmony_ci}
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci/**
109bf215546Sopenharmony_ci * Record the current primitive mode and restart information, flagging
110bf215546Sopenharmony_ci * related packets as dirty if necessary.
111bf215546Sopenharmony_ci *
112bf215546Sopenharmony_ci * This must be called before updating compiled shaders, because the patch
113bf215546Sopenharmony_ci * information informs the TCS key.
114bf215546Sopenharmony_ci */
115bf215546Sopenharmony_cistatic void
116bf215546Sopenharmony_cicrocus_update_draw_info(struct crocus_context *ice,
117bf215546Sopenharmony_ci                        const struct pipe_draw_info *info,
118bf215546Sopenharmony_ci                        const struct pipe_draw_start_count_bias *draw)
119bf215546Sopenharmony_ci{
120bf215546Sopenharmony_ci   struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
121bf215546Sopenharmony_ci   enum pipe_prim_type mode = info->mode;
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci   if (screen->devinfo.ver < 6) {
124bf215546Sopenharmony_ci      /* Slight optimization to avoid the GS program when not needed:
125bf215546Sopenharmony_ci       */
126bf215546Sopenharmony_ci      struct pipe_rasterizer_state *rs_state = crocus_get_rast_state(ice);
127bf215546Sopenharmony_ci      if (mode == PIPE_PRIM_QUAD_STRIP && !rs_state->flatshade &&
128bf215546Sopenharmony_ci          rs_state->fill_front == PIPE_POLYGON_MODE_FILL &&
129bf215546Sopenharmony_ci          rs_state->fill_back == PIPE_POLYGON_MODE_FILL)
130bf215546Sopenharmony_ci         mode = PIPE_PRIM_TRIANGLE_STRIP;
131bf215546Sopenharmony_ci      if (mode == PIPE_PRIM_QUADS &&
132bf215546Sopenharmony_ci          draw->count == 4 &&
133bf215546Sopenharmony_ci          !rs_state->flatshade &&
134bf215546Sopenharmony_ci          rs_state->fill_front == PIPE_POLYGON_MODE_FILL &&
135bf215546Sopenharmony_ci          rs_state->fill_back == PIPE_POLYGON_MODE_FILL)
136bf215546Sopenharmony_ci         mode = PIPE_PRIM_TRIANGLE_FAN;
137bf215546Sopenharmony_ci   }
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci   if (ice->state.prim_mode != mode) {
140bf215546Sopenharmony_ci      ice->state.prim_mode = mode;
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci      enum pipe_prim_type reduced = u_reduced_prim(mode);
143bf215546Sopenharmony_ci      if (ice->state.reduced_prim_mode != reduced) {
144bf215546Sopenharmony_ci         if (screen->devinfo.ver < 6)
145bf215546Sopenharmony_ci            ice->state.dirty |= CROCUS_DIRTY_GEN4_CLIP_PROG | CROCUS_DIRTY_GEN4_SF_PROG;
146bf215546Sopenharmony_ci         /* if the reduced prim changes the WM needs updating. */
147bf215546Sopenharmony_ci         ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_UNCOMPILED_FS;
148bf215546Sopenharmony_ci         ice->state.reduced_prim_mode = reduced;
149bf215546Sopenharmony_ci      }
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci      if (screen->devinfo.ver == 8)
152bf215546Sopenharmony_ci         ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_TOPOLOGY;
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci      if (screen->devinfo.ver <= 6)
155bf215546Sopenharmony_ci         ice->state.dirty |= CROCUS_DIRTY_GEN4_FF_GS_PROG;
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci      if (screen->devinfo.ver >= 7)
158bf215546Sopenharmony_ci         ice->state.dirty |= CROCUS_DIRTY_GEN7_SBE;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci      /* For XY Clip enables */
161bf215546Sopenharmony_ci      bool points_or_lines = prim_is_points_or_lines(mode);
162bf215546Sopenharmony_ci      if (points_or_lines != ice->state.prim_is_points_or_lines) {
163bf215546Sopenharmony_ci         ice->state.prim_is_points_or_lines = points_or_lines;
164bf215546Sopenharmony_ci         ice->state.dirty |= CROCUS_DIRTY_CLIP;
165bf215546Sopenharmony_ci      }
166bf215546Sopenharmony_ci   }
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   if (info->mode == PIPE_PRIM_PATCHES &&
169bf215546Sopenharmony_ci       ice->state.vertices_per_patch != ice->state.patch_vertices) {
170bf215546Sopenharmony_ci      ice->state.vertices_per_patch = ice->state.patch_vertices;
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci      if (screen->devinfo.ver == 8)
173bf215546Sopenharmony_ci         ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_TOPOLOGY;
174bf215546Sopenharmony_ci      /* This is needed for key->input_vertices */
175bf215546Sopenharmony_ci      ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_UNCOMPILED_TCS;
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci      /* Flag constants dirty for gl_PatchVerticesIn if needed. */
178bf215546Sopenharmony_ci      const struct shader_info *tcs_info =
179bf215546Sopenharmony_ci         crocus_get_shader_info(ice, MESA_SHADER_TESS_CTRL);
180bf215546Sopenharmony_ci      if (tcs_info &&
181bf215546Sopenharmony_ci          BITSET_TEST(tcs_info->system_values_read, SYSTEM_VALUE_VERTICES_IN)) {
182bf215546Sopenharmony_ci         ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_CONSTANTS_TCS;
183bf215546Sopenharmony_ci         ice->state.shaders[MESA_SHADER_TESS_CTRL].sysvals_need_upload = true;
184bf215546Sopenharmony_ci      }
185bf215546Sopenharmony_ci   }
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci   const unsigned cut_index = info->primitive_restart ? info->restart_index :
188bf215546Sopenharmony_ci                                                        ice->state.cut_index;
189bf215546Sopenharmony_ci   if (ice->state.primitive_restart != info->primitive_restart ||
190bf215546Sopenharmony_ci       ice->state.cut_index != cut_index) {
191bf215546Sopenharmony_ci      if (screen->devinfo.verx10 >= 75)
192bf215546Sopenharmony_ci         ice->state.dirty |= CROCUS_DIRTY_GEN75_VF;
193bf215546Sopenharmony_ci      ice->state.primitive_restart = info->primitive_restart;
194bf215546Sopenharmony_ci      ice->state.cut_index = info->restart_index;
195bf215546Sopenharmony_ci   }
196bf215546Sopenharmony_ci}
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci/**
199bf215546Sopenharmony_ci * Update shader draw parameters, flagging VF packets as dirty if necessary.
200bf215546Sopenharmony_ci */
201bf215546Sopenharmony_cistatic void
202bf215546Sopenharmony_cicrocus_update_draw_parameters(struct crocus_context *ice,
203bf215546Sopenharmony_ci                              const struct pipe_draw_info *info,
204bf215546Sopenharmony_ci                              unsigned drawid_offset,
205bf215546Sopenharmony_ci                              const struct pipe_draw_indirect_info *indirect,
206bf215546Sopenharmony_ci                              const struct pipe_draw_start_count_bias *draw)
207bf215546Sopenharmony_ci{
208bf215546Sopenharmony_ci   bool changed = false;
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   if (ice->state.vs_uses_draw_params) {
211bf215546Sopenharmony_ci      struct crocus_state_ref *draw_params = &ice->draw.draw_params;
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci      if (indirect && indirect->buffer) {
214bf215546Sopenharmony_ci         pipe_resource_reference(&draw_params->res, indirect->buffer);
215bf215546Sopenharmony_ci         draw_params->offset =
216bf215546Sopenharmony_ci            indirect->offset + (info->index_size ? 12 : 8);
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci         changed = true;
219bf215546Sopenharmony_ci         ice->draw.params_valid = false;
220bf215546Sopenharmony_ci      } else {
221bf215546Sopenharmony_ci         int firstvertex = info->index_size ? draw->index_bias : draw->start;
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci         if (!ice->draw.params_valid ||
224bf215546Sopenharmony_ci             ice->draw.params.firstvertex != firstvertex ||
225bf215546Sopenharmony_ci             ice->draw.params.baseinstance != info->start_instance) {
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci            changed = true;
228bf215546Sopenharmony_ci            ice->draw.params.firstvertex = firstvertex;
229bf215546Sopenharmony_ci            ice->draw.params.baseinstance = info->start_instance;
230bf215546Sopenharmony_ci            ice->draw.params_valid = true;
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci            u_upload_data(ice->ctx.stream_uploader, 0,
233bf215546Sopenharmony_ci                          sizeof(ice->draw.params), 4, &ice->draw.params,
234bf215546Sopenharmony_ci                          &draw_params->offset, &draw_params->res);
235bf215546Sopenharmony_ci         }
236bf215546Sopenharmony_ci      }
237bf215546Sopenharmony_ci   }
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci   if (ice->state.vs_uses_derived_draw_params) {
240bf215546Sopenharmony_ci      struct crocus_state_ref *derived_params = &ice->draw.derived_draw_params;
241bf215546Sopenharmony_ci      int is_indexed_draw = info->index_size ? -1 : 0;
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci      if (ice->draw.derived_params.drawid != drawid_offset ||
244bf215546Sopenharmony_ci          ice->draw.derived_params.is_indexed_draw != is_indexed_draw) {
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci         changed = true;
247bf215546Sopenharmony_ci         ice->draw.derived_params.drawid = drawid_offset;
248bf215546Sopenharmony_ci         ice->draw.derived_params.is_indexed_draw = is_indexed_draw;
249bf215546Sopenharmony_ci
250bf215546Sopenharmony_ci         u_upload_data(ice->ctx.stream_uploader, 0,
251bf215546Sopenharmony_ci                       sizeof(ice->draw.derived_params), 4,
252bf215546Sopenharmony_ci                       &ice->draw.derived_params, &derived_params->offset,
253bf215546Sopenharmony_ci                       &derived_params->res);
254bf215546Sopenharmony_ci      }
255bf215546Sopenharmony_ci   }
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   if (changed) {
258bf215546Sopenharmony_ci      struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
259bf215546Sopenharmony_ci      ice->state.dirty |= CROCUS_DIRTY_VERTEX_BUFFERS |
260bf215546Sopenharmony_ci                          CROCUS_DIRTY_VERTEX_ELEMENTS;
261bf215546Sopenharmony_ci      if (screen->devinfo.ver == 8)
262bf215546Sopenharmony_ci         ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_SGVS;
263bf215546Sopenharmony_ci   }
264bf215546Sopenharmony_ci}
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_cistatic void
267bf215546Sopenharmony_cicrocus_indirect_draw_vbo(struct crocus_context *ice,
268bf215546Sopenharmony_ci                         const struct pipe_draw_info *dinfo,
269bf215546Sopenharmony_ci                         unsigned drawid_offset,
270bf215546Sopenharmony_ci                         const struct pipe_draw_indirect_info *dindirect,
271bf215546Sopenharmony_ci                         const struct pipe_draw_start_count_bias *draws)
272bf215546Sopenharmony_ci{
273bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
274bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
275bf215546Sopenharmony_ci   struct pipe_draw_info info = *dinfo;
276bf215546Sopenharmony_ci   struct pipe_draw_indirect_info indirect = *dindirect;
277bf215546Sopenharmony_ci   const struct intel_device_info *devinfo = &batch->screen->devinfo;
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci   if (devinfo->verx10 >= 75 && indirect.indirect_draw_count &&
280bf215546Sopenharmony_ci       ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
281bf215546Sopenharmony_ci      /* Upload MI_PREDICATE_RESULT to GPR15.*/
282bf215546Sopenharmony_ci      screen->vtbl.load_register_reg64(batch, CS_GPR(15), MI_PREDICATE_RESULT);
283bf215546Sopenharmony_ci   }
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci   uint64_t orig_dirty = ice->state.dirty;
286bf215546Sopenharmony_ci   uint64_t orig_stage_dirty = ice->state.stage_dirty;
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_ci   for (int i = 0; i < indirect.draw_count; i++) {
289bf215546Sopenharmony_ci      crocus_batch_maybe_flush(batch, 1500);
290bf215546Sopenharmony_ci      crocus_require_statebuffer_space(batch, 2400);
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci      if (ice->state.vs_uses_draw_params ||
293bf215546Sopenharmony_ci	  ice->state.vs_uses_derived_draw_params)
294bf215546Sopenharmony_ci         crocus_update_draw_parameters(ice, &info, drawid_offset + i, &indirect, draws);
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci      screen->vtbl.upload_render_state(ice, batch, &info, drawid_offset + i, &indirect, draws);
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci      ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_RENDER;
299bf215546Sopenharmony_ci      ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci      indirect.offset += indirect.stride;
302bf215546Sopenharmony_ci   }
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   if (devinfo->verx10 >= 75 && indirect.indirect_draw_count &&
305bf215546Sopenharmony_ci       ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
306bf215546Sopenharmony_ci      /* Restore MI_PREDICATE_RESULT. */
307bf215546Sopenharmony_ci      screen->vtbl.load_register_reg64(batch, MI_PREDICATE_RESULT, CS_GPR(15));
308bf215546Sopenharmony_ci   }
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci   /* Put this back for post-draw resolves, we'll clear it again after. */
311bf215546Sopenharmony_ci   ice->state.dirty = orig_dirty;
312bf215546Sopenharmony_ci   ice->state.stage_dirty = orig_stage_dirty;
313bf215546Sopenharmony_ci}
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_cistatic void
316bf215546Sopenharmony_cicrocus_simple_draw_vbo(struct crocus_context *ice,
317bf215546Sopenharmony_ci                       const struct pipe_draw_info *draw,
318bf215546Sopenharmony_ci                       unsigned drawid_offset,
319bf215546Sopenharmony_ci                       const struct pipe_draw_indirect_info *indirect,
320bf215546Sopenharmony_ci                       const struct pipe_draw_start_count_bias *sc)
321bf215546Sopenharmony_ci{
322bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
323bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ci   crocus_batch_maybe_flush(batch, 1500);
326bf215546Sopenharmony_ci   crocus_require_statebuffer_space(batch, 2400);
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci   if (ice->state.vs_uses_draw_params ||
329bf215546Sopenharmony_ci       ice->state.vs_uses_derived_draw_params)
330bf215546Sopenharmony_ci      crocus_update_draw_parameters(ice, draw, drawid_offset, indirect, sc);
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   screen->vtbl.upload_render_state(ice, batch, draw, drawid_offset, indirect, sc);
333bf215546Sopenharmony_ci}
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_cistatic void
336bf215546Sopenharmony_cicrocus_draw_vbo_get_vertex_count(struct pipe_context *ctx,
337bf215546Sopenharmony_ci                                 const struct pipe_draw_info *info_in,
338bf215546Sopenharmony_ci                                 unsigned drawid_offset,
339bf215546Sopenharmony_ci                                 const struct pipe_draw_indirect_info *indirect)
340bf215546Sopenharmony_ci{
341bf215546Sopenharmony_ci   struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
342bf215546Sopenharmony_ci   struct pipe_draw_info info = *info_in;
343bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias draw;
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci   uint32_t val = screen->vtbl.get_so_offset(indirect->count_from_stream_output);
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   draw.start = 0;
348bf215546Sopenharmony_ci   draw.count = val;
349bf215546Sopenharmony_ci   ctx->draw_vbo(ctx, &info, drawid_offset, NULL, &draw, 1);
350bf215546Sopenharmony_ci}
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_ci/**
353bf215546Sopenharmony_ci * The pipe->draw_vbo() driver hook.  Performs a draw on the GPU.
354bf215546Sopenharmony_ci */
355bf215546Sopenharmony_civoid
356bf215546Sopenharmony_cicrocus_draw_vbo(struct pipe_context *ctx,
357bf215546Sopenharmony_ci                const struct pipe_draw_info *info,
358bf215546Sopenharmony_ci                unsigned drawid_offset,
359bf215546Sopenharmony_ci                const struct pipe_draw_indirect_info *indirect,
360bf215546Sopenharmony_ci                const struct pipe_draw_start_count_bias *draws,
361bf215546Sopenharmony_ci                unsigned num_draws)
362bf215546Sopenharmony_ci{
363bf215546Sopenharmony_ci   if (num_draws > 1) {
364bf215546Sopenharmony_ci      util_draw_multi(ctx, info, drawid_offset, indirect, draws, num_draws);
365bf215546Sopenharmony_ci      return;
366bf215546Sopenharmony_ci   }
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   if (!indirect && (!draws[0].count || !info->instance_count))
369bf215546Sopenharmony_ci      return;
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci   struct crocus_context *ice = (struct crocus_context *) ctx;
372bf215546Sopenharmony_ci   struct crocus_screen *screen = (struct crocus_screen*)ice->ctx.screen;
373bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci   if (!crocus_check_conditional_render(ice))
376bf215546Sopenharmony_ci      return;
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci   if (info->primitive_restart && !can_cut_index_handle_prim(ice, info)) {
379bf215546Sopenharmony_ci      util_draw_vbo_without_prim_restart(ctx, info, drawid_offset,
380bf215546Sopenharmony_ci                                         indirect, draws);
381bf215546Sopenharmony_ci      return;
382bf215546Sopenharmony_ci   }
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci   if (screen->devinfo.verx10 < 75 &&
385bf215546Sopenharmony_ci       indirect && indirect->count_from_stream_output) {
386bf215546Sopenharmony_ci      crocus_draw_vbo_get_vertex_count(ctx, info, drawid_offset, indirect);
387bf215546Sopenharmony_ci      return;
388bf215546Sopenharmony_ci   }
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci   /**
391bf215546Sopenharmony_ci    * The hardware is capable of removing dangling vertices on its own; however,
392bf215546Sopenharmony_ci    * prior to Gen6, we sometimes convert quads into trifans (and quad strips
393bf215546Sopenharmony_ci    * into tristrips), since pre-Gen6 hardware requires a GS to render quads.
394bf215546Sopenharmony_ci    * This function manually trims dangling vertices from a draw call involving
395bf215546Sopenharmony_ci    * quads so that those dangling vertices won't get drawn when we convert to
396bf215546Sopenharmony_ci    * trifans/tristrips.
397bf215546Sopenharmony_ci    */
398bf215546Sopenharmony_ci   if (screen->devinfo.ver < 6) {
399bf215546Sopenharmony_ci      if (info->mode == PIPE_PRIM_QUADS || info->mode == PIPE_PRIM_QUAD_STRIP) {
400bf215546Sopenharmony_ci         bool trim = u_trim_pipe_prim(info->mode, (unsigned *)&draws[0].count);
401bf215546Sopenharmony_ci         if (!trim)
402bf215546Sopenharmony_ci            return;
403bf215546Sopenharmony_ci      }
404bf215546Sopenharmony_ci   }
405bf215546Sopenharmony_ci
406bf215546Sopenharmony_ci   /* We can't safely re-emit 3DSTATE_SO_BUFFERS because it may zero the
407bf215546Sopenharmony_ci    * write offsets, changing the behavior.
408bf215546Sopenharmony_ci    */
409bf215546Sopenharmony_ci   if (INTEL_DEBUG(DEBUG_REEMIT)) {
410bf215546Sopenharmony_ci      ice->state.dirty |= CROCUS_ALL_DIRTY_FOR_RENDER & ~(CROCUS_DIRTY_GEN7_SO_BUFFERS | CROCUS_DIRTY_GEN6_SVBI);
411bf215546Sopenharmony_ci      ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
412bf215546Sopenharmony_ci   }
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   /* Emit Sandybridge workaround flushes on every primitive, for safety. */
415bf215546Sopenharmony_ci   if (screen->devinfo.ver == 6)
416bf215546Sopenharmony_ci      crocus_emit_post_sync_nonzero_flush(batch);
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci   crocus_update_draw_info(ice, info, draws);
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci   if (!crocus_update_compiled_shaders(ice))
421bf215546Sopenharmony_ci      return;
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci   if (ice->state.dirty & CROCUS_DIRTY_RENDER_RESOLVES_AND_FLUSHES) {
424bf215546Sopenharmony_ci      bool draw_aux_buffer_disabled[BRW_MAX_DRAW_BUFFERS] = { };
425bf215546Sopenharmony_ci      for (gl_shader_stage stage = 0; stage < MESA_SHADER_COMPUTE; stage++) {
426bf215546Sopenharmony_ci         if (ice->shaders.prog[stage])
427bf215546Sopenharmony_ci            crocus_predraw_resolve_inputs(ice, batch, draw_aux_buffer_disabled,
428bf215546Sopenharmony_ci                                          stage, true);
429bf215546Sopenharmony_ci      }
430bf215546Sopenharmony_ci      crocus_predraw_resolve_framebuffer(ice, batch, draw_aux_buffer_disabled);
431bf215546Sopenharmony_ci   }
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   crocus_handle_always_flush_cache(batch);
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci   if (indirect && indirect->buffer)
436bf215546Sopenharmony_ci      crocus_indirect_draw_vbo(ice, info, drawid_offset, indirect, draws);
437bf215546Sopenharmony_ci   else
438bf215546Sopenharmony_ci      crocus_simple_draw_vbo(ice, info, drawid_offset, indirect, draws);
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci   crocus_handle_always_flush_cache(batch);
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci   crocus_postdraw_update_resolve_tracking(ice, batch);
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ci   ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_RENDER;
445bf215546Sopenharmony_ci   ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
446bf215546Sopenharmony_ci}
447bf215546Sopenharmony_ci
448bf215546Sopenharmony_cistatic void
449bf215546Sopenharmony_cicrocus_update_grid_size_resource(struct crocus_context *ice,
450bf215546Sopenharmony_ci                                 const struct pipe_grid_info *grid)
451bf215546Sopenharmony_ci{
452bf215546Sopenharmony_ci   struct crocus_state_ref *grid_ref = &ice->state.grid_size;
453bf215546Sopenharmony_ci   const struct crocus_compiled_shader *shader = ice->shaders.prog[MESA_SHADER_COMPUTE];
454bf215546Sopenharmony_ci   bool grid_needs_surface = shader->bt.used_mask[CROCUS_SURFACE_GROUP_CS_WORK_GROUPS];
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   if (grid->indirect) {
457bf215546Sopenharmony_ci      pipe_resource_reference(&grid_ref->res, grid->indirect);
458bf215546Sopenharmony_ci      grid_ref->offset = grid->indirect_offset;
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci      /* Zero out the grid size so that the next non-indirect grid launch will
461bf215546Sopenharmony_ci       * re-upload it properly.
462bf215546Sopenharmony_ci       */
463bf215546Sopenharmony_ci      memset(ice->state.last_grid, 0, sizeof(ice->state.last_grid));
464bf215546Sopenharmony_ci   } else if (memcmp(ice->state.last_grid, grid->grid, sizeof(grid->grid)) != 0) {
465bf215546Sopenharmony_ci      memcpy(ice->state.last_grid, grid->grid, sizeof(grid->grid));
466bf215546Sopenharmony_ci      u_upload_data(ice->ctx.const_uploader, 0, sizeof(grid->grid), 4,
467bf215546Sopenharmony_ci                    grid->grid, &grid_ref->offset, &grid_ref->res);
468bf215546Sopenharmony_ci   }
469bf215546Sopenharmony_ci
470bf215546Sopenharmony_ci   /* Skip surface upload if we don't need it or we already have one */
471bf215546Sopenharmony_ci   if (!grid_needs_surface)
472bf215546Sopenharmony_ci      return;
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci   ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_BINDINGS_CS;
475bf215546Sopenharmony_ci}
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_civoid
479bf215546Sopenharmony_cicrocus_launch_grid(struct pipe_context *ctx, const struct pipe_grid_info *grid)
480bf215546Sopenharmony_ci{
481bf215546Sopenharmony_ci   struct crocus_context *ice = (struct crocus_context *) ctx;
482bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_COMPUTE];
483bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
484bf215546Sopenharmony_ci
485bf215546Sopenharmony_ci   if (!crocus_check_conditional_render(ice))
486bf215546Sopenharmony_ci      return;
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_ci   if (INTEL_DEBUG(DEBUG_REEMIT)) {
489bf215546Sopenharmony_ci      ice->state.dirty |= CROCUS_ALL_DIRTY_FOR_COMPUTE;
490bf215546Sopenharmony_ci      ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_FOR_COMPUTE;
491bf215546Sopenharmony_ci   }
492bf215546Sopenharmony_ci
493bf215546Sopenharmony_ci   /* We can't do resolves on the compute engine, so awkwardly, we have to
494bf215546Sopenharmony_ci    * do them on the render batch...
495bf215546Sopenharmony_ci    */
496bf215546Sopenharmony_ci   if (ice->state.dirty & CROCUS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES) {
497bf215546Sopenharmony_ci      crocus_predraw_resolve_inputs(ice, &ice->batches[CROCUS_BATCH_RENDER], NULL,
498bf215546Sopenharmony_ci                                    MESA_SHADER_COMPUTE, false);
499bf215546Sopenharmony_ci   }
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_ci   crocus_batch_maybe_flush(batch, 1500);
502bf215546Sopenharmony_ci   crocus_require_statebuffer_space(batch, 2500);
503bf215546Sopenharmony_ci   crocus_update_compiled_compute_shader(ice);
504bf215546Sopenharmony_ci
505bf215546Sopenharmony_ci   if (memcmp(ice->state.last_block, grid->block, sizeof(grid->block)) != 0) {
506bf215546Sopenharmony_ci      memcpy(ice->state.last_block, grid->block, sizeof(grid->block));
507bf215546Sopenharmony_ci      ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_CONSTANTS_CS;
508bf215546Sopenharmony_ci      ice->state.shaders[MESA_SHADER_COMPUTE].sysvals_need_upload = true;
509bf215546Sopenharmony_ci   }
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   crocus_update_grid_size_resource(ice, grid);
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci   if (ice->state.compute_predicate) {
514bf215546Sopenharmony_ci      screen->vtbl.emit_compute_predicate(batch);
515bf215546Sopenharmony_ci      ice->state.compute_predicate = NULL;
516bf215546Sopenharmony_ci   }
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci   crocus_handle_always_flush_cache(batch);
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci   screen->vtbl.upload_compute_state(ice, batch, grid);
521bf215546Sopenharmony_ci
522bf215546Sopenharmony_ci   crocus_handle_always_flush_cache(batch);
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci   ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_COMPUTE;
525bf215546Sopenharmony_ci   ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_COMPUTE;
526bf215546Sopenharmony_ci
527bf215546Sopenharmony_ci   /* Note: since compute shaders can't access the framebuffer, there's
528bf215546Sopenharmony_ci    * no need to call crocus_postdraw_update_resolve_tracking.
529bf215546Sopenharmony_ci    */
530bf215546Sopenharmony_ci}
531