1 /************************************************************************** 2 * 3 * Copyright 2003 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 /* 29 * Render unclipped vertex buffers by emitting vertices directly to 30 * dma buffers. Use strip/fan hardware acceleration where possible. 31 * 32 */ 33 #include "main/glheader.h" 34 #include "main/context.h" 35 #include "main/macros.h" 36 #include "main/imports.h" 37 #include "main/mtypes.h" 38 #include "main/enums.h" 39 40 #include "math/m_xform.h" 41 42 #include "tnl/t_context.h" 43 #include "tnl/t_vertex.h" 44 #include "tnl/t_pipeline.h" 45 46 #include "intel_screen.h" 47 #include "intel_context.h" 48 #include "intel_tris.h" 49 #include "intel_batchbuffer.h" 50 #include "intel_reg.h" 51 52 /* 53 * Render unclipped vertex buffers by emitting vertices directly to 54 * dma buffers. Use strip/fan hardware primitives where possible. 55 * Try to simulate missing primitives with indexed vertices. 56 */ 57 #define HAVE_POINTS 1 58 #define HAVE_LINES 1 59 #define HAVE_LINE_STRIPS 1 60 #define HAVE_TRIANGLES 1 61 #define HAVE_TRI_STRIPS 1 62 #define HAVE_TRI_FANS 1 63 #define HAVE_POLYGONS 1 64 65 #define HAVE_QUADS 0 66 #define HAVE_QUAD_STRIPS 0 67 #define HAVE_ELTS 0 68 69 static const uint32_t hw_prim[GL_POLYGON + 1] = { 70 [GL_POINTS] = PRIM3D_POINTLIST, 71 [GL_LINES ] = PRIM3D_LINELIST, 72 [GL_LINE_LOOP] = PRIM3D_LINESTRIP, 73 [GL_LINE_STRIP] = PRIM3D_LINESTRIP, 74 [GL_TRIANGLES] = PRIM3D_TRILIST, 75 [GL_TRIANGLE_STRIP] = PRIM3D_TRISTRIP, 76 [GL_TRIANGLE_FAN] = PRIM3D_TRIFAN, 77 [GL_QUADS] = 0, 78 [GL_QUAD_STRIP] = 0, 79 [GL_POLYGON] = PRIM3D_POLY, 80 }; 81 82 static const GLenum reduced_prim[GL_POLYGON + 1] = { 83 [GL_POINTS] = GL_POINTS, 84 [GL_LINES] = GL_LINES, 85 [GL_LINE_LOOP] = GL_LINES, 86 [GL_LINE_STRIP] = GL_LINES, 87 [GL_TRIANGLES] = GL_TRIANGLES, 88 [GL_TRIANGLE_STRIP] = GL_TRIANGLES, 89 [GL_TRIANGLE_FAN] = GL_TRIANGLES, 90 [GL_QUADS] = GL_TRIANGLES, 91 [GL_QUAD_STRIP] = GL_TRIANGLES, 92 [GL_POLYGON] = GL_TRIANGLES, 93 }; 94 95 static const int scale_prim[GL_POLYGON + 1] = { 96 [GL_POINTS] = 1, 97 [GL_LINES] = 1, 98 [GL_LINE_LOOP] = 2, 99 [GL_LINE_STRIP] = 2, 100 [GL_TRIANGLES] = 1, 101 [GL_TRIANGLE_STRIP] = 3, 102 [GL_TRIANGLE_FAN] = 3, 103 [GL_QUADS] = 0, /* fallback case */ 104 [GL_QUAD_STRIP] = 0, /* fallback case */ 105 [GL_POLYGON] = 3, 106 }; 107 108 109 static void 110 intelDmaPrimitive(struct intel_context *intel, GLenum prim) 111 { 112 if (0) 113 fprintf(stderr, "%s %s\n", __func__, _mesa_enum_to_string(prim)); 114 INTEL_FIREVERTICES(intel); 115 intel->vtbl.reduced_primitive_state(intel, reduced_prim[prim]); 116 intel_set_prim(intel, hw_prim[prim]); 117 } 118 119 #define INTEL_NO_VBO_STATE_RESERVED 1500 120 121 static inline GLuint intel_get_vb_max(struct intel_context *intel) 122 { 123 GLuint ret; 124 125 if (intel->intelScreen->no_vbo) { 126 ret = intel->batch.bo->size - INTEL_NO_VBO_STATE_RESERVED; 127 } else 128 ret = INTEL_VB_SIZE; 129 ret /= (intel->vertex_size * 4); 130 return ret; 131 } 132 133 static inline GLuint intel_get_current_max(struct intel_context *intel) 134 { 135 GLuint ret; 136 137 if (intel->intelScreen->no_vbo) { 138 ret = intel_batchbuffer_space(intel); 139 ret = ret <= INTEL_NO_VBO_STATE_RESERVED ? 0 : ret - INTEL_NO_VBO_STATE_RESERVED; 140 } else 141 ret = (INTEL_VB_SIZE - intel->prim.current_offset); 142 143 return ret / (intel->vertex_size * 4); 144 } 145 146 #define LOCAL_VARS struct intel_context *intel = intel_context(ctx) 147 #define INIT( prim ) \ 148 do { \ 149 intelDmaPrimitive( intel, prim ); \ 150 } while (0) 151 152 #define FLUSH() INTEL_FIREVERTICES(intel) 153 154 #define GET_SUBSEQUENT_VB_MAX_VERTS() intel_get_vb_max(intel) 155 #define GET_CURRENT_VB_MAX_VERTS() intel_get_current_max(intel) 156 157 #define ALLOC_VERTS(nr) intel_get_prim_space(intel, nr) 158 159 #define EMIT_VERTS( ctx, j, nr, buf ) \ 160 _tnl_emit_vertices_to_buffer(ctx, j, (j)+(nr), buf ) 161 162 #define TAG(x) intel_##x 163 #include "tnl_dd/t_dd_dmatmp.h" 164 165 166 /**********************************************************************/ 167 /* Render pipeline stage */ 168 /**********************************************************************/ 169 170 /* Heuristic to choose between the two render paths: 171 */ 172 static bool 173 choose_render(struct intel_context *intel, struct vertex_buffer *VB) 174 { 175 int vertsz = intel->vertex_size; 176 int cost_render = 0; 177 int cost_fallback = 0; 178 int nr_prims = 0; 179 int nr_rprims = 0; 180 int nr_rverts = 0; 181 int rprim = intel->reduced_primitive; 182 int i = 0; 183 184 for (i = 0; i < VB->PrimitiveCount; i++) { 185 GLuint prim = VB->Primitive[i].mode; 186 GLuint length = VB->Primitive[i].count; 187 188 if (!length) 189 continue; 190 191 nr_prims++; 192 nr_rverts += length * scale_prim[prim & PRIM_MODE_MASK]; 193 194 if (reduced_prim[prim & PRIM_MODE_MASK] != rprim) { 195 nr_rprims++; 196 rprim = reduced_prim[prim & PRIM_MODE_MASK]; 197 } 198 } 199 200 /* One point for each generated primitive: 201 */ 202 cost_render = nr_prims; 203 cost_fallback = nr_rprims; 204 205 /* One point for every 1024 dwords (4k) of dma: 206 */ 207 cost_render += (vertsz * i) / 1024; 208 cost_fallback += (vertsz * nr_rverts) / 1024; 209 210 if (0) 211 fprintf(stderr, "cost render: %d fallback: %d\n", 212 cost_render, cost_fallback); 213 214 if (cost_render > cost_fallback) 215 return false; 216 217 return true; 218 } 219 220 221 static GLboolean 222 intel_run_render(struct gl_context * ctx, struct tnl_pipeline_stage *stage) 223 { 224 struct intel_context *intel = intel_context(ctx); 225 TNLcontext *tnl = TNL_CONTEXT(ctx); 226 struct vertex_buffer *VB = &tnl->vb; 227 GLuint i; 228 229 intel->vtbl.render_prevalidate( intel ); 230 231 /* Don't handle clipping or indexed vertices. 232 */ 233 if (intel->RenderIndex != 0 || 234 !intel_validate_render(ctx, VB) || !choose_render(intel, VB)) { 235 return true; 236 } 237 238 tnl->clipspace.new_inputs |= VERT_BIT_POS; 239 240 tnl->Driver.Render.Start(ctx); 241 242 for (i = 0; i < VB->PrimitiveCount; i++) { 243 GLuint prim = _tnl_translate_prim(&VB->Primitive[i]); 244 GLuint start = VB->Primitive[i].start; 245 GLuint length = VB->Primitive[i].count; 246 247 if (!length) 248 continue; 249 250 intel_render_tab_verts[prim & PRIM_MODE_MASK] (ctx, start, 251 length, prim); 252 } 253 254 tnl->Driver.Render.Finish(ctx); 255 256 INTEL_FIREVERTICES(intel); 257 258 return false; /* finished the pipe */ 259 } 260 261 static const struct tnl_pipeline_stage _intel_render_stage = { 262 "intel render", 263 NULL, 264 NULL, 265 NULL, 266 NULL, 267 intel_run_render /* run */ 268 }; 269 270 const struct tnl_pipeline_stage *intel_pipeline[] = { 271 &_tnl_vertex_transform_stage, 272 &_tnl_normal_transform_stage, 273 &_tnl_lighting_stage, 274 &_tnl_fog_coordinate_stage, 275 &_tnl_texgen_stage, 276 &_tnl_texture_transform_stage, 277 &_tnl_point_attenuation_stage, 278 &_tnl_vertex_program_stage, 279 #if 1 280 &_intel_render_stage, /* ADD: unclipped rastersetup-to-dma */ 281 #endif 282 &_tnl_render_stage, 283 0, 284 }; 285