1 /* 2 * Copyright 2012 Red Hat Inc. 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 shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 * 24 */ 25 26 #include "pipe/p_context.h" 27 #include "pipe/p_state.h" 28 #include "util/u_inlines.h" 29 #include "util/u_format.h" 30 #include "translate/translate.h" 31 32 #include "nouveau/nv_object.xml.h" 33 #include "nv30-40_3d.xml.h" 34 #include "nv30_context.h" 35 #include "nv30_resource.h" 36 37 struct push_context { 38 struct nouveau_pushbuf *push; 39 40 const void *idxbuf; 41 42 float edgeflag; 43 int edgeflag_attr; 44 45 uint32_t vertex_words; 46 uint32_t packet_vertex_limit; 47 48 struct translate *translate; 49 50 boolean primitive_restart; 51 uint32_t prim; 52 uint32_t restart_index; 53 }; 54 55 static INLINE unsigned 56 prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index) 57 { 58 unsigned i; 59 for (i = 0; i < push; ++i) 60 if (elts[i] == index) 61 break; 62 return i; 63 } 64 65 static INLINE unsigned 66 prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index) 67 { 68 unsigned i; 69 for (i = 0; i < push; ++i) 70 if (elts[i] == index) 71 break; 72 return i; 73 } 74 75 static INLINE unsigned 76 prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index) 77 { 78 unsigned i; 79 for (i = 0; i < push; ++i) 80 if (elts[i] == index) 81 break; 82 return i; 83 } 84 85 static void 86 emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count) 87 { 88 uint8_t *elts = (uint8_t *)ctx->idxbuf + start; 89 90 while (count) { 91 unsigned push = MIN2(count, ctx->packet_vertex_limit); 92 unsigned size, nr; 93 94 nr = push; 95 if (ctx->primitive_restart) 96 nr = prim_restart_search_i08(elts, push, ctx->restart_index); 97 98 size = ctx->vertex_words * nr; 99 100 BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size); 101 102 ctx->translate->run_elts8(ctx->translate, elts, nr, 0, ctx->push->cur); 103 104 ctx->push->cur += size; 105 count -= nr; 106 elts += nr; 107 108 if (nr != push) { 109 BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1); 110 PUSH_DATA (ctx->push, ctx->restart_index); 111 count--; 112 elts++; 113 } 114 } 115 } 116 117 static void 118 emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count) 119 { 120 uint16_t *elts = (uint16_t *)ctx->idxbuf + start; 121 122 while (count) { 123 unsigned push = MIN2(count, ctx->packet_vertex_limit); 124 unsigned size, nr; 125 126 nr = push; 127 if (ctx->primitive_restart) 128 nr = prim_restart_search_i16(elts, push, ctx->restart_index); 129 130 size = ctx->vertex_words * nr; 131 132 BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size); 133 134 ctx->translate->run_elts16(ctx->translate, elts, nr, 0, ctx->push->cur); 135 136 ctx->push->cur += size; 137 count -= nr; 138 elts += nr; 139 140 if (nr != push) { 141 BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1); 142 PUSH_DATA (ctx->push, ctx->restart_index); 143 count--; 144 elts++; 145 } 146 } 147 } 148 149 static void 150 emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count) 151 { 152 uint32_t *elts = (uint32_t *)ctx->idxbuf + start; 153 154 while (count) { 155 unsigned push = MIN2(count, ctx->packet_vertex_limit); 156 unsigned size, nr; 157 158 nr = push; 159 if (ctx->primitive_restart) 160 nr = prim_restart_search_i32(elts, push, ctx->restart_index); 161 162 size = ctx->vertex_words * nr; 163 164 BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size); 165 166 ctx->translate->run_elts(ctx->translate, elts, nr, 0, ctx->push->cur); 167 168 ctx->push->cur += size; 169 count -= nr; 170 elts += nr; 171 172 if (nr != push) { 173 BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1); 174 PUSH_DATA (ctx->push, ctx->restart_index); 175 count--; 176 elts++; 177 } 178 } 179 } 180 181 static void 182 emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count) 183 { 184 while (count) { 185 unsigned push = MIN2(count, ctx->packet_vertex_limit); 186 unsigned size = ctx->vertex_words * push; 187 188 BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size); 189 190 ctx->translate->run(ctx->translate, start, push, 0, ctx->push->cur); 191 ctx->push->cur += size; 192 count -= push; 193 start += push; 194 } 195 } 196 197 void 198 nv30_push_vbo(struct nv30_context *nv30, const struct pipe_draw_info *info) 199 { 200 struct push_context ctx; 201 unsigned i, index_size; 202 boolean apply_bias = info->indexed && info->index_bias; 203 204 ctx.push = nv30->base.pushbuf; 205 ctx.translate = nv30->vertex->translate; 206 ctx.packet_vertex_limit = nv30->vertex->vtx_per_packet_max; 207 ctx.vertex_words = nv30->vertex->vtx_size; 208 209 for (i = 0; i < nv30->num_vtxbufs; ++i) { 210 uint8_t *data; 211 struct pipe_vertex_buffer *vb = &nv30->vtxbuf[i]; 212 struct nv04_resource *res = nv04_resource(vb->buffer); 213 214 data = nouveau_resource_map_offset(&nv30->base, res, 215 vb->buffer_offset, NOUVEAU_BO_RD); 216 217 if (apply_bias) 218 data += info->index_bias * vb->stride; 219 220 ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0); 221 } 222 223 if (info->indexed) { 224 if (nv30->idxbuf.buffer) 225 ctx.idxbuf = nouveau_resource_map_offset(&nv30->base, 226 nv04_resource(nv30->idxbuf.buffer), nv30->idxbuf.offset, 227 NOUVEAU_BO_RD); 228 else 229 ctx.idxbuf = nv30->idxbuf.user_buffer; 230 if (!ctx.idxbuf) { 231 nv30_state_release(nv30); 232 return; 233 } 234 index_size = nv30->idxbuf.index_size; 235 ctx.primitive_restart = info->primitive_restart; 236 ctx.restart_index = info->restart_index; 237 } else { 238 ctx.idxbuf = NULL; 239 index_size = 0; 240 ctx.primitive_restart = FALSE; 241 ctx.restart_index = 0; 242 } 243 244 if (nv30->screen->eng3d->oclass >= NV40_3D_CLASS) { 245 BEGIN_NV04(ctx.push, NV40_3D(PRIM_RESTART_ENABLE), 2); 246 PUSH_DATA (ctx.push, info->primitive_restart); 247 PUSH_DATA (ctx.push, info->restart_index); 248 nv30->state.prim_restart = info->primitive_restart; 249 } 250 251 ctx.prim = nv30_prim_gl(info->mode); 252 253 PUSH_RESET(ctx.push, BUFCTX_IDXBUF); 254 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1); 255 PUSH_DATA (ctx.push, ctx.prim); 256 switch (index_size) { 257 case 0: 258 emit_vertices_seq(&ctx, info->start, info->count); 259 break; 260 case 1: 261 emit_vertices_i08(&ctx, info->start, info->count); 262 break; 263 case 2: 264 emit_vertices_i16(&ctx, info->start, info->count); 265 break; 266 case 4: 267 emit_vertices_i32(&ctx, info->start, info->count); 268 break; 269 default: 270 assert(0); 271 break; 272 } 273 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1); 274 PUSH_DATA (ctx.push, NV30_3D_VERTEX_BEGIN_END_STOP); 275 276 if (info->indexed) 277 nouveau_resource_unmap(nv04_resource(nv30->idxbuf.buffer)); 278 279 for (i = 0; i < nv30->num_vtxbufs; ++i) 280 nouveau_resource_unmap(nv04_resource(nv30->vtxbuf[i].buffer)); 281 282 nv30_state_release(nv30); 283 } 284