17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2017 Intel Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice shall be included
127ec681f3Smrg * in all copies or substantial portions of the Software.
137ec681f3Smrg *
147ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
157ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
177ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
187ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
197ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
207ec681f3Smrg * DEALINGS IN THE SOFTWARE.
217ec681f3Smrg */
227ec681f3Smrg
237ec681f3Smrg/**
247ec681f3Smrg * @file crocus_draw.c
257ec681f3Smrg *
267ec681f3Smrg * The main driver hooks for drawing and launching compute shaders.
277ec681f3Smrg */
287ec681f3Smrg
297ec681f3Smrg#include <stdio.h>
307ec681f3Smrg#include <errno.h>
317ec681f3Smrg#include "pipe/p_defines.h"
327ec681f3Smrg#include "pipe/p_state.h"
337ec681f3Smrg#include "pipe/p_context.h"
347ec681f3Smrg#include "pipe/p_screen.h"
357ec681f3Smrg#include "util/u_draw.h"
367ec681f3Smrg#include "util/u_inlines.h"
377ec681f3Smrg#include "util/u_transfer.h"
387ec681f3Smrg#include "util/u_upload_mgr.h"
397ec681f3Smrg#include "intel/compiler/brw_compiler.h"
407ec681f3Smrg#include "intel/compiler/brw_eu_defines.h"
417ec681f3Smrg#include "crocus_context.h"
427ec681f3Smrg#include "crocus_defines.h"
437ec681f3Smrg#include "util/u_prim_restart.h"
447ec681f3Smrg#include "util/u_prim.h"
457ec681f3Smrg
467ec681f3Smrgstatic bool
477ec681f3Smrgprim_is_points_or_lines(enum pipe_prim_type mode)
487ec681f3Smrg{
497ec681f3Smrg   /* We don't need to worry about adjacency - it can only be used with
507ec681f3Smrg    * geometry shaders, and we don't care about this info when GS is on.
517ec681f3Smrg    */
527ec681f3Smrg   return mode == PIPE_PRIM_POINTS ||
537ec681f3Smrg          mode == PIPE_PRIM_LINES ||
547ec681f3Smrg          mode == PIPE_PRIM_LINE_LOOP ||
557ec681f3Smrg          mode == PIPE_PRIM_LINE_STRIP;
567ec681f3Smrg}
577ec681f3Smrg
587ec681f3Smrgstatic bool
597ec681f3Smrgcan_cut_index_handle_restart_index(struct crocus_context *ice,
607ec681f3Smrg                                   const struct pipe_draw_info *draw)
617ec681f3Smrg{
627ec681f3Smrg   switch (draw->index_size) {
637ec681f3Smrg   case 1:
647ec681f3Smrg      return draw->restart_index == 0xff;
657ec681f3Smrg   case 2:
667ec681f3Smrg      return draw->restart_index == 0xffff;
677ec681f3Smrg   case 4:
687ec681f3Smrg      return draw->restart_index == 0xffffffff;
697ec681f3Smrg   default:
707ec681f3Smrg      unreachable("illegal index size\n");
717ec681f3Smrg   }
727ec681f3Smrg
737ec681f3Smrg   return false;
747ec681f3Smrg}
757ec681f3Smrg
767ec681f3Smrgstatic bool
777ec681f3Smrgcan_cut_index_handle_prim(struct crocus_context *ice,
787ec681f3Smrg                          const struct pipe_draw_info *draw)
797ec681f3Smrg{
807ec681f3Smrg   struct crocus_screen *screen = (struct crocus_screen*)ice->ctx.screen;
817ec681f3Smrg   const struct intel_device_info *devinfo = &screen->devinfo;
827ec681f3Smrg
837ec681f3Smrg   /* Haswell can do it all. */
847ec681f3Smrg   if (devinfo->verx10 >= 75)
857ec681f3Smrg      return true;
867ec681f3Smrg
877ec681f3Smrg   if (!can_cut_index_handle_restart_index(ice, draw))
887ec681f3Smrg      return false;
897ec681f3Smrg
907ec681f3Smrg   switch (draw->mode) {
917ec681f3Smrg   case PIPE_PRIM_POINTS:
927ec681f3Smrg   case PIPE_PRIM_LINES:
937ec681f3Smrg   case PIPE_PRIM_LINE_STRIP:
947ec681f3Smrg   case PIPE_PRIM_TRIANGLES:
957ec681f3Smrg   case PIPE_PRIM_TRIANGLE_STRIP:
967ec681f3Smrg   case PIPE_PRIM_LINES_ADJACENCY:
977ec681f3Smrg   case PIPE_PRIM_LINE_STRIP_ADJACENCY:
987ec681f3Smrg   case PIPE_PRIM_TRIANGLES_ADJACENCY:
997ec681f3Smrg   case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
1007ec681f3Smrg      return true;
1017ec681f3Smrg   default:
1027ec681f3Smrg      break;
1037ec681f3Smrg   }
1047ec681f3Smrg   return false;
1057ec681f3Smrg}
1067ec681f3Smrg
1077ec681f3Smrg/**
1087ec681f3Smrg * Record the current primitive mode and restart information, flagging
1097ec681f3Smrg * related packets as dirty if necessary.
1107ec681f3Smrg *
1117ec681f3Smrg * This must be called before updating compiled shaders, because the patch
1127ec681f3Smrg * information informs the TCS key.
1137ec681f3Smrg */
1147ec681f3Smrgstatic void
1157ec681f3Smrgcrocus_update_draw_info(struct crocus_context *ice,
1167ec681f3Smrg                        const struct pipe_draw_info *info,
1177ec681f3Smrg                        const struct pipe_draw_start_count_bias *draw)
1187ec681f3Smrg{
1197ec681f3Smrg   struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
1207ec681f3Smrg   enum pipe_prim_type mode = info->mode;
1217ec681f3Smrg
1227ec681f3Smrg   if (screen->devinfo.ver < 6) {
1237ec681f3Smrg      /* Slight optimization to avoid the GS program when not needed:
1247ec681f3Smrg       */
1257ec681f3Smrg      struct pipe_rasterizer_state *rs_state = crocus_get_rast_state(ice);
1267ec681f3Smrg      if (mode == PIPE_PRIM_QUAD_STRIP && !rs_state->flatshade &&
1277ec681f3Smrg          rs_state->fill_front == PIPE_POLYGON_MODE_FILL &&
1287ec681f3Smrg          rs_state->fill_back == PIPE_POLYGON_MODE_FILL)
1297ec681f3Smrg         mode = PIPE_PRIM_TRIANGLE_STRIP;
1307ec681f3Smrg      if (mode == PIPE_PRIM_QUADS &&
1317ec681f3Smrg          draw->count == 4 &&
1327ec681f3Smrg          !rs_state->flatshade &&
1337ec681f3Smrg          rs_state->fill_front == PIPE_POLYGON_MODE_FILL &&
1347ec681f3Smrg          rs_state->fill_back == PIPE_POLYGON_MODE_FILL)
1357ec681f3Smrg         mode = PIPE_PRIM_TRIANGLE_FAN;
1367ec681f3Smrg   }
1377ec681f3Smrg
1387ec681f3Smrg   if (ice->state.prim_mode != mode) {
1397ec681f3Smrg      ice->state.prim_mode = mode;
1407ec681f3Smrg
1417ec681f3Smrg      enum pipe_prim_type reduced = u_reduced_prim(mode);
1427ec681f3Smrg      if (ice->state.reduced_prim_mode != reduced) {
1437ec681f3Smrg         if (screen->devinfo.ver < 6)
1447ec681f3Smrg            ice->state.dirty |= CROCUS_DIRTY_GEN4_CLIP_PROG | CROCUS_DIRTY_GEN4_SF_PROG;
1457ec681f3Smrg         /* if the reduced prim changes the WM needs updating. */
1467ec681f3Smrg         ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_UNCOMPILED_FS;
1477ec681f3Smrg         ice->state.reduced_prim_mode = reduced;
1487ec681f3Smrg      }
1497ec681f3Smrg
1507ec681f3Smrg      if (screen->devinfo.ver == 8)
1517ec681f3Smrg         ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_TOPOLOGY;
1527ec681f3Smrg
1537ec681f3Smrg      if (screen->devinfo.ver <= 6)
1547ec681f3Smrg         ice->state.dirty |= CROCUS_DIRTY_GEN4_FF_GS_PROG;
1557ec681f3Smrg
1567ec681f3Smrg      if (screen->devinfo.ver >= 7)
1577ec681f3Smrg         ice->state.dirty |= CROCUS_DIRTY_GEN7_SBE;
1587ec681f3Smrg
1597ec681f3Smrg      /* For XY Clip enables */
1607ec681f3Smrg      bool points_or_lines = prim_is_points_or_lines(mode);
1617ec681f3Smrg      if (points_or_lines != ice->state.prim_is_points_or_lines) {
1627ec681f3Smrg         ice->state.prim_is_points_or_lines = points_or_lines;
1637ec681f3Smrg         ice->state.dirty |= CROCUS_DIRTY_CLIP;
1647ec681f3Smrg      }
1657ec681f3Smrg   }
1667ec681f3Smrg
1677ec681f3Smrg   if (info->mode == PIPE_PRIM_PATCHES &&
1687ec681f3Smrg       ice->state.vertices_per_patch != ice->state.patch_vertices) {
1697ec681f3Smrg      ice->state.vertices_per_patch = ice->state.patch_vertices;
1707ec681f3Smrg
1717ec681f3Smrg      if (screen->devinfo.ver == 8)
1727ec681f3Smrg         ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_TOPOLOGY;
1737ec681f3Smrg      /* This is needed for key->input_vertices */
1747ec681f3Smrg      ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_UNCOMPILED_TCS;
1757ec681f3Smrg
1767ec681f3Smrg      /* Flag constants dirty for gl_PatchVerticesIn if needed. */
1777ec681f3Smrg      const struct shader_info *tcs_info =
1787ec681f3Smrg         crocus_get_shader_info(ice, MESA_SHADER_TESS_CTRL);
1797ec681f3Smrg      if (tcs_info &&
1807ec681f3Smrg          BITSET_TEST(tcs_info->system_values_read, SYSTEM_VALUE_VERTICES_IN)) {
1817ec681f3Smrg         ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_CONSTANTS_TCS;
1827ec681f3Smrg         ice->state.shaders[MESA_SHADER_TESS_CTRL].sysvals_need_upload = true;
1837ec681f3Smrg      }
1847ec681f3Smrg   }
1857ec681f3Smrg
1867ec681f3Smrg   const unsigned cut_index = info->primitive_restart ? info->restart_index :
1877ec681f3Smrg                                                        ice->state.cut_index;
1887ec681f3Smrg   if (ice->state.primitive_restart != info->primitive_restart ||
1897ec681f3Smrg       ice->state.cut_index != cut_index) {
1907ec681f3Smrg      if (screen->devinfo.verx10 >= 75)
1917ec681f3Smrg         ice->state.dirty |= CROCUS_DIRTY_GEN75_VF;
1927ec681f3Smrg      ice->state.primitive_restart = info->primitive_restart;
1937ec681f3Smrg      ice->state.cut_index = info->restart_index;
1947ec681f3Smrg   }
1957ec681f3Smrg}
1967ec681f3Smrg
1977ec681f3Smrg/**
1987ec681f3Smrg * Update shader draw parameters, flagging VF packets as dirty if necessary.
1997ec681f3Smrg */
2007ec681f3Smrgstatic void
2017ec681f3Smrgcrocus_update_draw_parameters(struct crocus_context *ice,
2027ec681f3Smrg                              const struct pipe_draw_info *info,
2037ec681f3Smrg                              unsigned drawid_offset,
2047ec681f3Smrg                              const struct pipe_draw_indirect_info *indirect,
2057ec681f3Smrg                              const struct pipe_draw_start_count_bias *draw)
2067ec681f3Smrg{
2077ec681f3Smrg   bool changed = false;
2087ec681f3Smrg
2097ec681f3Smrg   if (ice->state.vs_uses_draw_params) {
2107ec681f3Smrg      struct crocus_state_ref *draw_params = &ice->draw.draw_params;
2117ec681f3Smrg
2127ec681f3Smrg      if (indirect && indirect->buffer) {
2137ec681f3Smrg         pipe_resource_reference(&draw_params->res, indirect->buffer);
2147ec681f3Smrg         draw_params->offset =
2157ec681f3Smrg            indirect->offset + (info->index_size ? 12 : 8);
2167ec681f3Smrg
2177ec681f3Smrg         changed = true;
2187ec681f3Smrg         ice->draw.params_valid = false;
2197ec681f3Smrg      } else {
2207ec681f3Smrg         int firstvertex = info->index_size ? draw->index_bias : draw->start;
2217ec681f3Smrg
2227ec681f3Smrg         if (!ice->draw.params_valid ||
2237ec681f3Smrg             ice->draw.params.firstvertex != firstvertex ||
2247ec681f3Smrg             ice->draw.params.baseinstance != info->start_instance) {
2257ec681f3Smrg
2267ec681f3Smrg            changed = true;
2277ec681f3Smrg            ice->draw.params.firstvertex = firstvertex;
2287ec681f3Smrg            ice->draw.params.baseinstance = info->start_instance;
2297ec681f3Smrg            ice->draw.params_valid = true;
2307ec681f3Smrg
2317ec681f3Smrg            u_upload_data(ice->ctx.stream_uploader, 0,
2327ec681f3Smrg                          sizeof(ice->draw.params), 4, &ice->draw.params,
2337ec681f3Smrg                          &draw_params->offset, &draw_params->res);
2347ec681f3Smrg         }
2357ec681f3Smrg      }
2367ec681f3Smrg   }
2377ec681f3Smrg
2387ec681f3Smrg   if (ice->state.vs_uses_derived_draw_params) {
2397ec681f3Smrg      struct crocus_state_ref *derived_params = &ice->draw.derived_draw_params;
2407ec681f3Smrg      int is_indexed_draw = info->index_size ? -1 : 0;
2417ec681f3Smrg
2427ec681f3Smrg      if (ice->draw.derived_params.drawid != drawid_offset ||
2437ec681f3Smrg          ice->draw.derived_params.is_indexed_draw != is_indexed_draw) {
2447ec681f3Smrg
2457ec681f3Smrg         changed = true;
2467ec681f3Smrg         ice->draw.derived_params.drawid = drawid_offset;
2477ec681f3Smrg         ice->draw.derived_params.is_indexed_draw = is_indexed_draw;
2487ec681f3Smrg
2497ec681f3Smrg         u_upload_data(ice->ctx.stream_uploader, 0,
2507ec681f3Smrg                       sizeof(ice->draw.derived_params), 4,
2517ec681f3Smrg                       &ice->draw.derived_params, &derived_params->offset,
2527ec681f3Smrg                       &derived_params->res);
2537ec681f3Smrg      }
2547ec681f3Smrg   }
2557ec681f3Smrg
2567ec681f3Smrg   if (changed) {
2577ec681f3Smrg      struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
2587ec681f3Smrg      ice->state.dirty |= CROCUS_DIRTY_VERTEX_BUFFERS |
2597ec681f3Smrg                          CROCUS_DIRTY_VERTEX_ELEMENTS;
2607ec681f3Smrg      if (screen->devinfo.ver == 8)
2617ec681f3Smrg         ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_SGVS;
2627ec681f3Smrg   }
2637ec681f3Smrg}
2647ec681f3Smrg
2657ec681f3Smrgstatic void
2667ec681f3Smrgcrocus_indirect_draw_vbo(struct crocus_context *ice,
2677ec681f3Smrg                         const struct pipe_draw_info *dinfo,
2687ec681f3Smrg                         unsigned drawid_offset,
2697ec681f3Smrg                         const struct pipe_draw_indirect_info *dindirect,
2707ec681f3Smrg                         const struct pipe_draw_start_count_bias *draws)
2717ec681f3Smrg{
2727ec681f3Smrg   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
2737ec681f3Smrg   struct crocus_screen *screen = batch->screen;
2747ec681f3Smrg   struct pipe_draw_info info = *dinfo;
2757ec681f3Smrg   struct pipe_draw_indirect_info indirect = *dindirect;
2767ec681f3Smrg   const struct intel_device_info *devinfo = &batch->screen->devinfo;
2777ec681f3Smrg
2787ec681f3Smrg   if (devinfo->verx10 >= 75 && indirect.indirect_draw_count &&
2797ec681f3Smrg       ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
2807ec681f3Smrg      /* Upload MI_PREDICATE_RESULT to GPR15.*/
2817ec681f3Smrg      screen->vtbl.load_register_reg64(batch, CS_GPR(15), MI_PREDICATE_RESULT);
2827ec681f3Smrg   }
2837ec681f3Smrg
2847ec681f3Smrg   uint64_t orig_dirty = ice->state.dirty;
2857ec681f3Smrg   uint64_t orig_stage_dirty = ice->state.stage_dirty;
2867ec681f3Smrg
2877ec681f3Smrg   for (int i = 0; i < indirect.draw_count; i++) {
2887ec681f3Smrg      crocus_batch_maybe_flush(batch, 1500);
2897ec681f3Smrg      crocus_require_statebuffer_space(batch, 2400);
2907ec681f3Smrg
2917ec681f3Smrg      if (ice->state.vs_uses_draw_params ||
2927ec681f3Smrg	  ice->state.vs_uses_derived_draw_params)
2937ec681f3Smrg         crocus_update_draw_parameters(ice, &info, drawid_offset + i, &indirect, draws);
2947ec681f3Smrg
2957ec681f3Smrg      screen->vtbl.upload_render_state(ice, batch, &info, drawid_offset + i, &indirect, draws);
2967ec681f3Smrg
2977ec681f3Smrg      ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_RENDER;
2987ec681f3Smrg      ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
2997ec681f3Smrg
3007ec681f3Smrg      indirect.offset += indirect.stride;
3017ec681f3Smrg   }
3027ec681f3Smrg
3037ec681f3Smrg   if (devinfo->verx10 >= 75 && indirect.indirect_draw_count &&
3047ec681f3Smrg       ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
3057ec681f3Smrg      /* Restore MI_PREDICATE_RESULT. */
3067ec681f3Smrg      screen->vtbl.load_register_reg64(batch, MI_PREDICATE_RESULT, CS_GPR(15));
3077ec681f3Smrg   }
3087ec681f3Smrg
3097ec681f3Smrg   /* Put this back for post-draw resolves, we'll clear it again after. */
3107ec681f3Smrg   ice->state.dirty = orig_dirty;
3117ec681f3Smrg   ice->state.stage_dirty = orig_stage_dirty;
3127ec681f3Smrg}
3137ec681f3Smrg
3147ec681f3Smrgstatic void
3157ec681f3Smrgcrocus_simple_draw_vbo(struct crocus_context *ice,
3167ec681f3Smrg                       const struct pipe_draw_info *draw,
3177ec681f3Smrg                       unsigned drawid_offset,
3187ec681f3Smrg                       const struct pipe_draw_indirect_info *indirect,
3197ec681f3Smrg                       const struct pipe_draw_start_count_bias *sc)
3207ec681f3Smrg{
3217ec681f3Smrg   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
3227ec681f3Smrg   struct crocus_screen *screen = batch->screen;
3237ec681f3Smrg
3247ec681f3Smrg   crocus_batch_maybe_flush(batch, 1500);
3257ec681f3Smrg   crocus_require_statebuffer_space(batch, 2400);
3267ec681f3Smrg
3277ec681f3Smrg   if (ice->state.vs_uses_draw_params ||
3287ec681f3Smrg       ice->state.vs_uses_derived_draw_params)
3297ec681f3Smrg      crocus_update_draw_parameters(ice, draw, drawid_offset, indirect, sc);
3307ec681f3Smrg
3317ec681f3Smrg   screen->vtbl.upload_render_state(ice, batch, draw, drawid_offset, indirect, sc);
3327ec681f3Smrg}
3337ec681f3Smrg
3347ec681f3Smrgstatic void
3357ec681f3Smrgcrocus_draw_vbo_get_vertex_count(struct pipe_context *ctx,
3367ec681f3Smrg                                 const struct pipe_draw_info *info_in,
3377ec681f3Smrg                                 unsigned drawid_offset,
3387ec681f3Smrg                                 const struct pipe_draw_indirect_info *indirect)
3397ec681f3Smrg{
3407ec681f3Smrg   struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
3417ec681f3Smrg   struct pipe_draw_info info = *info_in;
3427ec681f3Smrg   struct pipe_draw_start_count_bias draw;
3437ec681f3Smrg
3447ec681f3Smrg   uint32_t val = screen->vtbl.get_so_offset(indirect->count_from_stream_output);
3457ec681f3Smrg
3467ec681f3Smrg   draw.start = 0;
3477ec681f3Smrg   draw.count = val;
3487ec681f3Smrg   ctx->draw_vbo(ctx, &info, drawid_offset, NULL, &draw, 1);
3497ec681f3Smrg}
3507ec681f3Smrg
3517ec681f3Smrg/**
3527ec681f3Smrg * The pipe->draw_vbo() driver hook.  Performs a draw on the GPU.
3537ec681f3Smrg */
3547ec681f3Smrgvoid
3557ec681f3Smrgcrocus_draw_vbo(struct pipe_context *ctx,
3567ec681f3Smrg                const struct pipe_draw_info *info,
3577ec681f3Smrg                unsigned drawid_offset,
3587ec681f3Smrg                const struct pipe_draw_indirect_info *indirect,
3597ec681f3Smrg                const struct pipe_draw_start_count_bias *draws,
3607ec681f3Smrg                unsigned num_draws)
3617ec681f3Smrg{
3627ec681f3Smrg   if (num_draws > 1) {
3637ec681f3Smrg      util_draw_multi(ctx, info, drawid_offset, indirect, draws, num_draws);
3647ec681f3Smrg      return;
3657ec681f3Smrg   }
3667ec681f3Smrg
3677ec681f3Smrg   if (!indirect && (!draws[0].count || !info->instance_count))
3687ec681f3Smrg      return;
3697ec681f3Smrg
3707ec681f3Smrg   struct crocus_context *ice = (struct crocus_context *) ctx;
3717ec681f3Smrg   struct crocus_screen *screen = (struct crocus_screen*)ice->ctx.screen;
3727ec681f3Smrg   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
3737ec681f3Smrg
3747ec681f3Smrg   if (!crocus_check_conditional_render(ice))
3757ec681f3Smrg      return;
3767ec681f3Smrg
3777ec681f3Smrg   if (info->primitive_restart && !can_cut_index_handle_prim(ice, info)) {
3787ec681f3Smrg      util_draw_vbo_without_prim_restart(ctx, info, drawid_offset,
3797ec681f3Smrg                                         indirect, draws);
3807ec681f3Smrg      return;
3817ec681f3Smrg   }
3827ec681f3Smrg
3837ec681f3Smrg   if (screen->devinfo.verx10 < 75 &&
3847ec681f3Smrg       indirect && indirect->count_from_stream_output) {
3857ec681f3Smrg      crocus_draw_vbo_get_vertex_count(ctx, info, drawid_offset, indirect);
3867ec681f3Smrg      return;
3877ec681f3Smrg   }
3887ec681f3Smrg
3897ec681f3Smrg   /**
3907ec681f3Smrg    * The hardware is capable of removing dangling vertices on its own; however,
3917ec681f3Smrg    * prior to Gen6, we sometimes convert quads into trifans (and quad strips
3927ec681f3Smrg    * into tristrips), since pre-Gen6 hardware requires a GS to render quads.
3937ec681f3Smrg    * This function manually trims dangling vertices from a draw call involving
3947ec681f3Smrg    * quads so that those dangling vertices won't get drawn when we convert to
3957ec681f3Smrg    * trifans/tristrips.
3967ec681f3Smrg    */
3977ec681f3Smrg   if (screen->devinfo.ver < 6) {
3987ec681f3Smrg      if (info->mode == PIPE_PRIM_QUADS || info->mode == PIPE_PRIM_QUAD_STRIP) {
3997ec681f3Smrg         bool trim = u_trim_pipe_prim(info->mode, (unsigned *)&draws[0].count);
4007ec681f3Smrg         if (!trim)
4017ec681f3Smrg            return;
4027ec681f3Smrg      }
4037ec681f3Smrg   }
4047ec681f3Smrg
4057ec681f3Smrg   /* We can't safely re-emit 3DSTATE_SO_BUFFERS because it may zero the
4067ec681f3Smrg    * write offsets, changing the behavior.
4077ec681f3Smrg    */
4087ec681f3Smrg   if (INTEL_DEBUG(DEBUG_REEMIT)) {
4097ec681f3Smrg      ice->state.dirty |= CROCUS_ALL_DIRTY_FOR_RENDER & ~(CROCUS_DIRTY_GEN7_SO_BUFFERS | CROCUS_DIRTY_GEN6_SVBI);
4107ec681f3Smrg      ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
4117ec681f3Smrg   }
4127ec681f3Smrg
4137ec681f3Smrg   /* Emit Sandybridge workaround flushes on every primitive, for safety. */
4147ec681f3Smrg   if (screen->devinfo.ver == 6)
4157ec681f3Smrg      crocus_emit_post_sync_nonzero_flush(batch);
4167ec681f3Smrg
4177ec681f3Smrg   crocus_update_draw_info(ice, info, draws);
4187ec681f3Smrg
4197ec681f3Smrg   if (!crocus_update_compiled_shaders(ice))
4207ec681f3Smrg      return;
4217ec681f3Smrg
4227ec681f3Smrg   if (ice->state.dirty & CROCUS_DIRTY_RENDER_RESOLVES_AND_FLUSHES) {
4237ec681f3Smrg      bool draw_aux_buffer_disabled[BRW_MAX_DRAW_BUFFERS] = { };
4247ec681f3Smrg      for (gl_shader_stage stage = 0; stage < MESA_SHADER_COMPUTE; stage++) {
4257ec681f3Smrg         if (ice->shaders.prog[stage])
4267ec681f3Smrg            crocus_predraw_resolve_inputs(ice, batch, draw_aux_buffer_disabled,
4277ec681f3Smrg                                          stage, true);
4287ec681f3Smrg      }
4297ec681f3Smrg      crocus_predraw_resolve_framebuffer(ice, batch, draw_aux_buffer_disabled);
4307ec681f3Smrg   }
4317ec681f3Smrg
4327ec681f3Smrg   crocus_handle_always_flush_cache(batch);
4337ec681f3Smrg
4347ec681f3Smrg   if (indirect && indirect->buffer)
4357ec681f3Smrg      crocus_indirect_draw_vbo(ice, info, drawid_offset, indirect, draws);
4367ec681f3Smrg   else
4377ec681f3Smrg      crocus_simple_draw_vbo(ice, info, drawid_offset, indirect, draws);
4387ec681f3Smrg
4397ec681f3Smrg   crocus_handle_always_flush_cache(batch);
4407ec681f3Smrg
4417ec681f3Smrg   crocus_postdraw_update_resolve_tracking(ice, batch);
4427ec681f3Smrg
4437ec681f3Smrg   ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_RENDER;
4447ec681f3Smrg   ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
4457ec681f3Smrg}
4467ec681f3Smrg
4477ec681f3Smrgstatic void
4487ec681f3Smrgcrocus_update_grid_size_resource(struct crocus_context *ice,
4497ec681f3Smrg                                 const struct pipe_grid_info *grid)
4507ec681f3Smrg{
4517ec681f3Smrg   struct crocus_state_ref *grid_ref = &ice->state.grid_size;
4527ec681f3Smrg   const struct crocus_compiled_shader *shader = ice->shaders.prog[MESA_SHADER_COMPUTE];
4537ec681f3Smrg   bool grid_needs_surface = shader->bt.used_mask[CROCUS_SURFACE_GROUP_CS_WORK_GROUPS];
4547ec681f3Smrg
4557ec681f3Smrg   if (grid->indirect) {
4567ec681f3Smrg      pipe_resource_reference(&grid_ref->res, grid->indirect);
4577ec681f3Smrg      grid_ref->offset = grid->indirect_offset;
4587ec681f3Smrg
4597ec681f3Smrg      /* Zero out the grid size so that the next non-indirect grid launch will
4607ec681f3Smrg       * re-upload it properly.
4617ec681f3Smrg       */
4627ec681f3Smrg      memset(ice->state.last_grid, 0, sizeof(ice->state.last_grid));
4637ec681f3Smrg   } else if (memcmp(ice->state.last_grid, grid->grid, sizeof(grid->grid)) != 0) {
4647ec681f3Smrg      memcpy(ice->state.last_grid, grid->grid, sizeof(grid->grid));
4657ec681f3Smrg      u_upload_data(ice->ctx.const_uploader, 0, sizeof(grid->grid), 4,
4667ec681f3Smrg                    grid->grid, &grid_ref->offset, &grid_ref->res);
4677ec681f3Smrg   }
4687ec681f3Smrg
4697ec681f3Smrg   /* Skip surface upload if we don't need it or we already have one */
4707ec681f3Smrg   if (!grid_needs_surface)
4717ec681f3Smrg      return;
4727ec681f3Smrg
4737ec681f3Smrg   ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_BINDINGS_CS;
4747ec681f3Smrg}
4757ec681f3Smrg
4767ec681f3Smrg
4777ec681f3Smrgvoid
4787ec681f3Smrgcrocus_launch_grid(struct pipe_context *ctx, const struct pipe_grid_info *grid)
4797ec681f3Smrg{
4807ec681f3Smrg   struct crocus_context *ice = (struct crocus_context *) ctx;
4817ec681f3Smrg   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_COMPUTE];
4827ec681f3Smrg   struct crocus_screen *screen = batch->screen;
4837ec681f3Smrg
4847ec681f3Smrg   if (!crocus_check_conditional_render(ice))
4857ec681f3Smrg      return;
4867ec681f3Smrg
4877ec681f3Smrg   if (INTEL_DEBUG(DEBUG_REEMIT)) {
4887ec681f3Smrg      ice->state.dirty |= CROCUS_ALL_DIRTY_FOR_COMPUTE;
4897ec681f3Smrg      ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_FOR_COMPUTE;
4907ec681f3Smrg   }
4917ec681f3Smrg
4927ec681f3Smrg   /* We can't do resolves on the compute engine, so awkwardly, we have to
4937ec681f3Smrg    * do them on the render batch...
4947ec681f3Smrg    */
4957ec681f3Smrg   if (ice->state.dirty & CROCUS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES) {
4967ec681f3Smrg      crocus_predraw_resolve_inputs(ice, &ice->batches[CROCUS_BATCH_RENDER], NULL,
4977ec681f3Smrg                                    MESA_SHADER_COMPUTE, false);
4987ec681f3Smrg   }
4997ec681f3Smrg
5007ec681f3Smrg   crocus_batch_maybe_flush(batch, 1500);
5017ec681f3Smrg   crocus_require_statebuffer_space(batch, 2500);
5027ec681f3Smrg   crocus_update_compiled_compute_shader(ice);
5037ec681f3Smrg
5047ec681f3Smrg   if (memcmp(ice->state.last_block, grid->block, sizeof(grid->block)) != 0) {
5057ec681f3Smrg      memcpy(ice->state.last_block, grid->block, sizeof(grid->block));
5067ec681f3Smrg      ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_CONSTANTS_CS;
5077ec681f3Smrg      ice->state.shaders[MESA_SHADER_COMPUTE].sysvals_need_upload = true;
5087ec681f3Smrg   }
5097ec681f3Smrg
5107ec681f3Smrg   crocus_update_grid_size_resource(ice, grid);
5117ec681f3Smrg
5127ec681f3Smrg   if (ice->state.compute_predicate) {
5137ec681f3Smrg      screen->vtbl.emit_compute_predicate(batch);
5147ec681f3Smrg      ice->state.compute_predicate = NULL;
5157ec681f3Smrg   }
5167ec681f3Smrg
5177ec681f3Smrg   crocus_handle_always_flush_cache(batch);
5187ec681f3Smrg
5197ec681f3Smrg   screen->vtbl.upload_compute_state(ice, batch, grid);
5207ec681f3Smrg
5217ec681f3Smrg   crocus_handle_always_flush_cache(batch);
5227ec681f3Smrg
5237ec681f3Smrg   ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_COMPUTE;
5247ec681f3Smrg   ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_COMPUTE;
5257ec681f3Smrg
5267ec681f3Smrg   /* Note: since compute shaders can't access the framebuffer, there's
5277ec681f3Smrg    * no need to call crocus_postdraw_update_resolve_tracking.
5287ec681f3Smrg    */
5297ec681f3Smrg}
530