brw_primitive_restart.c revision b922999a404322a1034c4f96c21acae860483bb0
1/*
2 * Copyright © 2012 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 (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 *    Jordan Justen <jordan.l.justen@intel.com>
25 *
26 */
27
28#include "main/imports.h"
29#include "main/bufferobj.h"
30
31#include "brw_context.h"
32#include "brw_defines.h"
33#include "brw_draw.h"
34
35#include "intel_batchbuffer.h"
36
37/**
38 * Check if the hardware's cut index support can handle the primitive
39 * restart index value.
40 */
41static bool
42can_cut_index_handle_restart_index(struct gl_context *ctx,
43                                   const struct _mesa_index_buffer *ib)
44{
45   struct intel_context *intel = intel_context(ctx);
46
47   /* Haswell supports an arbitrary cut index. */
48   if (intel->is_haswell)
49      return true;
50
51   bool cut_index_will_work;
52
53   switch (ib->type) {
54   case GL_UNSIGNED_BYTE:
55      cut_index_will_work = (ctx->Array.RestartIndex & 0xff) == 0xff;
56      break;
57   case GL_UNSIGNED_SHORT:
58      cut_index_will_work = (ctx->Array.RestartIndex & 0xffff) == 0xffff;
59      break;
60   case GL_UNSIGNED_INT:
61      cut_index_will_work = ctx->Array.RestartIndex == 0xffffffff;
62      break;
63   default:
64      cut_index_will_work = false;
65      assert(0);
66   }
67
68   return cut_index_will_work;
69}
70
71/**
72 * Check if the hardware's cut index support can handle the primitive
73 * restart case.
74 */
75static bool
76can_cut_index_handle_prims(struct gl_context *ctx,
77                           const struct _mesa_prim *prim,
78                           GLuint nr_prims,
79                           const struct _mesa_index_buffer *ib)
80{
81   struct brw_context *brw = brw_context(ctx);
82
83   if (brw->sol.counting_primitives_generated ||
84       brw->sol.counting_primitives_written) {
85      /* Counting primitives generated in hardware is not currently
86       * supported, so take the software path. We need to investigate
87       * the *_PRIMITIVES_COUNT registers to allow this to be handled
88       * entirely in hardware.
89       */
90      return false;
91   }
92
93   if (!can_cut_index_handle_restart_index(ctx, ib)) {
94      /* The primitive restart index can't be handled, so take
95       * the software path
96       */
97      return false;
98   }
99
100   for ( ; nr_prims > 0; nr_prims--) {
101      switch(prim->mode) {
102      case GL_POINTS:
103      case GL_LINES:
104      case GL_LINE_STRIP:
105      case GL_TRIANGLES:
106      case GL_TRIANGLE_STRIP:
107         /* Cut index supports these primitive types */
108         break;
109      default:
110         /* Cut index does not support these primitive types */
111      //case GL_LINE_LOOP:
112      //case GL_TRIANGLE_FAN:
113      //case GL_QUADS:
114      //case GL_QUAD_STRIP:
115      //case GL_POLYGON:
116         return false;
117      }
118   }
119
120   return true;
121}
122
123/**
124 * Check if primitive restart is enabled, and if so, handle it properly.
125 *
126 * In some cases the support will be handled in software. When available
127 * hardware will handle primitive restart.
128 */
129GLboolean
130brw_handle_primitive_restart(struct gl_context *ctx,
131                             const struct _mesa_prim *prim,
132                             GLuint nr_prims,
133                             const struct _mesa_index_buffer *ib)
134{
135   struct brw_context *brw = brw_context(ctx);
136
137   /* We only need to handle cases where there is an index buffer. */
138   if (ib == NULL) {
139      return GL_FALSE;
140   }
141
142   /* If the driver has requested software handling of primitive restarts,
143    * then the VBO module has already taken care of things, and we can
144    * just draw as normal.
145    */
146   if (ctx->Const.PrimitiveRestartInSoftware) {
147      return GL_FALSE;
148   }
149
150   /* If we have set the in_progress flag, then we are in the middle
151    * of handling the primitive restart draw.
152    */
153   if (brw->prim_restart.in_progress) {
154      return GL_FALSE;
155   }
156
157   /* If PrimitiveRestart is not enabled, then we aren't concerned about
158    * handling this draw.
159    */
160   if (!(ctx->Array.PrimitiveRestart)) {
161      return GL_FALSE;
162   }
163
164   /* Signal that we are in the process of handling the
165    * primitive restart draw
166    */
167   brw->prim_restart.in_progress = true;
168
169   if (can_cut_index_handle_prims(ctx, prim, nr_prims, ib)) {
170      /* Cut index should work for primitive restart, so use it
171       */
172      brw->prim_restart.enable_cut_index = true;
173      brw_draw_prims(ctx, prim, nr_prims, ib, GL_FALSE, -1, -1, NULL);
174      brw->prim_restart.enable_cut_index = false;
175   } else {
176      /* Not all the primitive draw modes are supported by the cut index,
177       * so take the software path
178       */
179      vbo_sw_primitive_restart(ctx, prim, nr_prims, ib);
180   }
181
182   brw->prim_restart.in_progress = false;
183
184   /* The primitive restart draw was completed, so return true. */
185   return GL_TRUE;
186}
187
188static void
189haswell_upload_cut_index(struct brw_context *brw)
190{
191   struct intel_context *intel = &brw->intel;
192   struct gl_context *ctx = &intel->ctx;
193
194   /* Don't trigger on Ivybridge */
195   if (!intel->is_haswell)
196      return;
197
198   const unsigned cut_index_setting =
199      ctx->Array.PrimitiveRestart ? HSW_CUT_INDEX_ENABLE : 0;
200
201   BEGIN_BATCH(2);
202   OUT_BATCH(_3DSTATE_VF << 16 | cut_index_setting | (2 - 2));
203   OUT_BATCH(ctx->Array.RestartIndex);
204   ADVANCE_BATCH();
205}
206
207const struct brw_tracked_state haswell_cut_index = {
208   .dirty = {
209      .mesa  = _NEW_TRANSFORM,
210      .brw   = 0,
211      .cache = 0,
212   },
213   .emit = haswell_upload_cut_index,
214};
215