1 /* 2 * Copyright (C) 2009-2010 Francisco Jerez. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial 15 * portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 */ 26 27 #include "tnl/t_context.h" 28 #include "tnl/t_pipeline.h" 29 #include "tnl/t_vertex.h" 30 31 #define SWTNL_VBO_SIZE 65536 32 33 static enum tnl_attr_format 34 swtnl_get_format(int type, int fields) { 35 switch (type) { 36 case GL_FLOAT: 37 switch (fields){ 38 case 1: 39 return EMIT_1F; 40 case 2: 41 return EMIT_2F; 42 case 3: 43 return EMIT_3F; 44 case 4: 45 return EMIT_4F; 46 default: 47 assert(0); 48 } 49 case GL_UNSIGNED_BYTE: 50 switch (fields) { 51 case 4: 52 return EMIT_4UB_4F_RGBA; 53 default: 54 assert(0); 55 } 56 default: 57 assert(0); 58 } 59 } 60 61 static struct swtnl_attr_info { 62 int type; 63 int fields; 64 } swtnl_attrs[VERT_ATTRIB_MAX] = { 65 [VERT_ATTRIB_POS] = { 66 .type = GL_FLOAT, 67 .fields = 4, 68 }, 69 [VERT_ATTRIB_NORMAL] = { 70 .type = GL_FLOAT, 71 .fields = -1, 72 }, 73 [VERT_ATTRIB_COLOR0] = { 74 .type = GL_UNSIGNED_BYTE, 75 .fields = 4, 76 }, 77 [VERT_ATTRIB_COLOR1] = { 78 .type = GL_UNSIGNED_BYTE, 79 .fields = 4, 80 }, 81 [VERT_ATTRIB_FOG] = { 82 .type = GL_FLOAT, 83 .fields = 1, 84 }, 85 [VERT_ATTRIB_TEX0] = { 86 .type = GL_FLOAT, 87 .fields = -1, 88 }, 89 [VERT_ATTRIB_TEX1] = { 90 .type = GL_FLOAT, 91 .fields = -1, 92 }, 93 [VERT_ATTRIB_TEX2] = { 94 .type = GL_FLOAT, 95 .fields = -1, 96 }, 97 [VERT_ATTRIB_TEX3] = { 98 .type = GL_FLOAT, 99 .fields = -1, 100 }, 101 }; 102 103 static void 104 swtnl_choose_attrs(struct gl_context *ctx) 105 { 106 struct nouveau_render_state *render = to_render_state(ctx); 107 TNLcontext *tnl = TNL_CONTEXT(ctx); 108 struct tnl_clipspace *vtx = &tnl->clipspace; 109 static struct tnl_attr_map map[NUM_VERTEX_ATTRS]; 110 int fields, attr, i, n = 0; 111 112 render->mode = VBO; 113 render->attr_count = NUM_VERTEX_ATTRS; 114 115 /* We always want non Ndc coords format */ 116 tnl->vb.AttribPtr[VERT_ATTRIB_POS] = tnl->vb.ClipPtr; 117 118 for (i = 0; i < VERT_ATTRIB_MAX; i++) { 119 struct nouveau_attr_info *ha = &TAG(vertex_attrs)[i]; 120 struct swtnl_attr_info *sa = &swtnl_attrs[i]; 121 struct nouveau_array *a = &render->attrs[i]; 122 123 if (!sa->fields) 124 continue; /* Unsupported attribute. */ 125 126 if (tnl->render_inputs_bitset & BITFIELD64_BIT(i)) { 127 if (sa->fields > 0) 128 fields = sa->fields; 129 else 130 fields = tnl->vb.AttribPtr[i]->size; 131 132 map[n++] = (struct tnl_attr_map) { 133 .attrib = i, 134 .format = swtnl_get_format(sa->type, fields), 135 }; 136 137 render->map[ha->vbo_index] = i; 138 a->attr = i; 139 a->fields = fields; 140 a->type = sa->type; 141 } 142 } 143 144 _tnl_install_attrs(ctx, map, n, NULL, 0); 145 146 FOR_EACH_BOUND_ATTR(render, i, attr) 147 render->attrs[attr].stride = vtx->vertex_size; 148 149 TAG(render_set_format)(ctx); 150 } 151 152 static void 153 swtnl_alloc_vertices(struct gl_context *ctx) 154 { 155 struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl; 156 157 nouveau_bo_ref(NULL, &swtnl->vbo); 158 swtnl->buf = nouveau_get_scratch(ctx, SWTNL_VBO_SIZE, &swtnl->vbo, 159 &swtnl->offset); 160 swtnl->vertex_count = 0; 161 } 162 163 static void 164 swtnl_bind_vertices(struct gl_context *ctx) 165 { 166 struct nouveau_render_state *render = to_render_state(ctx); 167 struct nouveau_swtnl_state *swtnl = &render->swtnl; 168 struct tnl_clipspace *vtx = &TNL_CONTEXT(ctx)->clipspace; 169 int i; 170 171 for (i = 0; i < vtx->attr_count; i++) { 172 struct tnl_clipspace_attr *ta = &vtx->attr[i]; 173 struct nouveau_array *a = &render->attrs[ta->attrib]; 174 175 nouveau_bo_ref(swtnl->vbo, &a->bo); 176 a->offset = swtnl->offset + ta->vertoffset; 177 } 178 179 TAG(render_bind_vertices)(ctx); 180 } 181 182 static void 183 swtnl_unbind_vertices(struct gl_context *ctx) 184 { 185 struct nouveau_render_state *render = to_render_state(ctx); 186 int i, attr; 187 188 TAG(render_release_vertices)(ctx); 189 190 FOR_EACH_BOUND_ATTR(render, i, attr) { 191 nouveau_bo_ref(NULL, &render->attrs[attr].bo); 192 render->map[i] = -1; 193 } 194 195 render->attr_count = 0; 196 } 197 198 static void 199 swtnl_flush_vertices(struct gl_context *ctx) 200 { 201 struct nouveau_pushbuf *push = context_push(ctx); 202 struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl; 203 unsigned npush, start = 0, count = swtnl->vertex_count; 204 RENDER_LOCALS(ctx); 205 206 swtnl_bind_vertices(ctx); 207 208 while (count) { 209 npush = get_max_vertices(ctx, NULL, PUSH_AVAIL(push)); 210 npush = MIN2(npush / 12 * 12, count); 211 count -= npush; 212 213 if (!npush) { 214 PUSH_KICK(push); 215 continue; 216 } 217 218 BATCH_BEGIN(nvgl_primitive(swtnl->primitive)); 219 EMIT_VBO(L, ctx, start, 0, npush); 220 BATCH_END(); 221 222 PUSH_KICK(push); 223 } 224 225 swtnl_alloc_vertices(ctx); 226 } 227 228 /* TnL renderer entry points */ 229 230 static void 231 swtnl_start(struct gl_context *ctx) 232 { 233 swtnl_choose_attrs(ctx); 234 } 235 236 static void 237 swtnl_finish(struct gl_context *ctx) 238 { 239 swtnl_flush_vertices(ctx); 240 swtnl_unbind_vertices(ctx); 241 } 242 243 static void 244 swtnl_primitive(struct gl_context *ctx, GLenum mode) 245 { 246 } 247 248 static void 249 swtnl_reset_stipple(struct gl_context *ctx) 250 { 251 } 252 253 /* Primitive rendering */ 254 255 #define BEGIN_PRIMITIVE(p, n) \ 256 struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl; \ 257 int vertex_len = TNL_CONTEXT(ctx)->clipspace.vertex_size; \ 258 \ 259 if (swtnl->vertex_count + (n) > SWTNL_VBO_SIZE/vertex_len \ 260 || (swtnl->vertex_count && swtnl->primitive != p)) \ 261 swtnl_flush_vertices(ctx); \ 262 \ 263 swtnl->primitive = p; 264 265 #define OUT_VERTEX(i) do { \ 266 memcpy(swtnl->buf + swtnl->vertex_count * vertex_len, \ 267 _tnl_get_vertex(ctx, (i)), vertex_len); \ 268 swtnl->vertex_count++; \ 269 } while (0) 270 271 static void 272 swtnl_points(struct gl_context *ctx, GLuint first, GLuint last) 273 { 274 int i, count; 275 276 while (first < last) { 277 BEGIN_PRIMITIVE(GL_POINTS, last - first); 278 279 count = MIN2(SWTNL_VBO_SIZE / vertex_len, last - first); 280 for (i = 0; i < count; i++) 281 OUT_VERTEX(first + i); 282 283 first += count; 284 } 285 } 286 287 static void 288 swtnl_line(struct gl_context *ctx, GLuint v1, GLuint v2) 289 { 290 BEGIN_PRIMITIVE(GL_LINES, 2); 291 OUT_VERTEX(v1); 292 OUT_VERTEX(v2); 293 } 294 295 static void 296 swtnl_triangle(struct gl_context *ctx, GLuint v1, GLuint v2, GLuint v3) 297 { 298 BEGIN_PRIMITIVE(GL_TRIANGLES, 3); 299 OUT_VERTEX(v1); 300 OUT_VERTEX(v2); 301 OUT_VERTEX(v3); 302 } 303 304 static void 305 swtnl_quad(struct gl_context *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint v4) 306 { 307 BEGIN_PRIMITIVE(GL_QUADS, 4); 308 OUT_VERTEX(v1); 309 OUT_VERTEX(v2); 310 OUT_VERTEX(v3); 311 OUT_VERTEX(v4); 312 } 313 314 /* TnL initialization. */ 315 void 316 TAG(swtnl_init)(struct gl_context *ctx) 317 { 318 TNLcontext *tnl = TNL_CONTEXT(ctx); 319 320 tnl->Driver.RunPipeline = _tnl_run_pipeline; 321 tnl->Driver.Render.Interp = _tnl_interp; 322 tnl->Driver.Render.CopyPV = _tnl_copy_pv; 323 tnl->Driver.Render.ClippedPolygon = _tnl_RenderClippedPolygon; 324 tnl->Driver.Render.ClippedLine = _tnl_RenderClippedLine; 325 tnl->Driver.Render.BuildVertices = _tnl_build_vertices; 326 327 tnl->Driver.Render.Start = swtnl_start; 328 tnl->Driver.Render.Finish = swtnl_finish; 329 tnl->Driver.Render.PrimitiveNotify = swtnl_primitive; 330 tnl->Driver.Render.ResetLineStipple = swtnl_reset_stipple; 331 332 tnl->Driver.Render.Points = swtnl_points; 333 tnl->Driver.Render.Line = swtnl_line; 334 tnl->Driver.Render.Triangle = swtnl_triangle; 335 tnl->Driver.Render.Quad = swtnl_quad; 336 337 _tnl_init_vertices(ctx, tnl->vb.Size, 338 NUM_VERTEX_ATTRS * 4 * sizeof(GLfloat)); 339 _tnl_need_projected_coords(ctx, GL_FALSE); 340 _tnl_allow_vertex_fog(ctx, GL_FALSE); 341 _tnl_wakeup(ctx); 342 343 swtnl_alloc_vertices(ctx); 344 } 345 346 void 347 TAG(swtnl_destroy)(struct gl_context *ctx) 348 { 349 nouveau_bo_ref(NULL, &to_render_state(ctx)->swtnl.vbo); 350 } 351