1 2 #include "pipe/p_context.h" 3 #include "pipe/p_state.h" 4 #include "util/u_inlines.h" 5 #include "util/u_format.h" 6 #include "translate/translate.h" 7 8 #include "nv50_context.h" 9 #include "nv50_resource.h" 10 11 #include "nv50_3d.xml.h" 12 13 struct push_context { 14 struct nouveau_pushbuf *push; 15 16 const void *idxbuf; 17 18 float edgeflag; 19 int edgeflag_attr; 20 21 uint32_t vertex_words; 22 uint32_t packet_vertex_limit; 23 24 struct translate *translate; 25 26 boolean primitive_restart; 27 uint32_t prim; 28 uint32_t restart_index; 29 uint32_t instance_id; 30 }; 31 32 static INLINE unsigned 33 prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index) 34 { 35 unsigned i; 36 for (i = 0; i < push; ++i) 37 if (elts[i] == index) 38 break; 39 return i; 40 } 41 42 static INLINE unsigned 43 prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index) 44 { 45 unsigned i; 46 for (i = 0; i < push; ++i) 47 if (elts[i] == index) 48 break; 49 return i; 50 } 51 52 static INLINE unsigned 53 prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index) 54 { 55 unsigned i; 56 for (i = 0; i < push; ++i) 57 if (elts[i] == index) 58 break; 59 return i; 60 } 61 62 static void 63 emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count) 64 { 65 uint8_t *elts = (uint8_t *)ctx->idxbuf + start; 66 67 while (count) { 68 unsigned push = MIN2(count, ctx->packet_vertex_limit); 69 unsigned size, nr; 70 71 nr = push; 72 if (ctx->primitive_restart) 73 nr = prim_restart_search_i08(elts, push, ctx->restart_index); 74 75 size = ctx->vertex_words * nr; 76 77 BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size); 78 79 ctx->translate->run_elts8(ctx->translate, elts, nr, ctx->instance_id, 80 ctx->push->cur); 81 82 ctx->push->cur += size; 83 count -= nr; 84 elts += nr; 85 86 if (nr != push) { 87 count--; 88 elts++; 89 BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1); 90 PUSH_DATA (ctx->push, ctx->restart_index); 91 } 92 } 93 } 94 95 static void 96 emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count) 97 { 98 uint16_t *elts = (uint16_t *)ctx->idxbuf + start; 99 100 while (count) { 101 unsigned push = MIN2(count, ctx->packet_vertex_limit); 102 unsigned size, nr; 103 104 nr = push; 105 if (ctx->primitive_restart) 106 nr = prim_restart_search_i16(elts, push, ctx->restart_index); 107 108 size = ctx->vertex_words * nr; 109 110 BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size); 111 112 ctx->translate->run_elts16(ctx->translate, elts, nr, ctx->instance_id, 113 ctx->push->cur); 114 115 ctx->push->cur += size; 116 count -= nr; 117 elts += nr; 118 119 if (nr != push) { 120 count--; 121 elts++; 122 BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1); 123 PUSH_DATA (ctx->push, ctx->restart_index); 124 } 125 } 126 } 127 128 static void 129 emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count) 130 { 131 uint32_t *elts = (uint32_t *)ctx->idxbuf + start; 132 133 while (count) { 134 unsigned push = MIN2(count, ctx->packet_vertex_limit); 135 unsigned size, nr; 136 137 nr = push; 138 if (ctx->primitive_restart) 139 nr = prim_restart_search_i32(elts, push, ctx->restart_index); 140 141 size = ctx->vertex_words * nr; 142 143 BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size); 144 145 ctx->translate->run_elts(ctx->translate, elts, nr, ctx->instance_id, 146 ctx->push->cur); 147 148 ctx->push->cur += size; 149 count -= nr; 150 elts += nr; 151 152 if (nr != push) { 153 count--; 154 elts++; 155 BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1); 156 PUSH_DATA (ctx->push, ctx->restart_index); 157 } 158 } 159 } 160 161 static void 162 emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count) 163 { 164 while (count) { 165 unsigned push = MIN2(count, ctx->packet_vertex_limit); 166 unsigned size = ctx->vertex_words * push; 167 168 BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size); 169 170 ctx->translate->run(ctx->translate, start, push, ctx->instance_id, 171 ctx->push->cur); 172 ctx->push->cur += size; 173 count -= push; 174 start += push; 175 } 176 } 177 178 179 #define NV50_PRIM_GL_CASE(n) \ 180 case PIPE_PRIM_##n: return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n 181 182 static INLINE unsigned 183 nv50_prim_gl(unsigned prim) 184 { 185 switch (prim) { 186 NV50_PRIM_GL_CASE(POINTS); 187 NV50_PRIM_GL_CASE(LINES); 188 NV50_PRIM_GL_CASE(LINE_LOOP); 189 NV50_PRIM_GL_CASE(LINE_STRIP); 190 NV50_PRIM_GL_CASE(TRIANGLES); 191 NV50_PRIM_GL_CASE(TRIANGLE_STRIP); 192 NV50_PRIM_GL_CASE(TRIANGLE_FAN); 193 NV50_PRIM_GL_CASE(QUADS); 194 NV50_PRIM_GL_CASE(QUAD_STRIP); 195 NV50_PRIM_GL_CASE(POLYGON); 196 NV50_PRIM_GL_CASE(LINES_ADJACENCY); 197 NV50_PRIM_GL_CASE(LINE_STRIP_ADJACENCY); 198 NV50_PRIM_GL_CASE(TRIANGLES_ADJACENCY); 199 NV50_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY); 200 /* 201 NV50_PRIM_GL_CASE(PATCHES); */ 202 default: 203 return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS; 204 break; 205 } 206 } 207 208 void 209 nv50_push_vbo(struct nv50_context *nv50, const struct pipe_draw_info *info) 210 { 211 struct push_context ctx; 212 unsigned i, index_size; 213 unsigned inst_count = info->instance_count; 214 unsigned vert_count = info->count; 215 boolean apply_bias = info->indexed && info->index_bias; 216 217 ctx.push = nv50->base.pushbuf; 218 ctx.translate = nv50->vertex->translate; 219 ctx.packet_vertex_limit = nv50->vertex->packet_vertex_limit; 220 ctx.vertex_words = nv50->vertex->vertex_size; 221 222 for (i = 0; i < nv50->num_vtxbufs; ++i) { 223 const struct pipe_vertex_buffer *vb = &nv50->vtxbuf[i]; 224 const uint8_t *data; 225 226 if (unlikely(vb->buffer)) 227 data = nouveau_resource_map_offset(&nv50->base, 228 nv04_resource(vb->buffer), vb->buffer_offset, NOUVEAU_BO_RD); 229 else 230 data = vb->user_buffer; 231 232 if (apply_bias && likely(!(nv50->vertex->instance_bufs & (1 << i)))) 233 data += (ptrdiff_t)info->index_bias * vb->stride; 234 235 ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0); 236 } 237 238 if (info->indexed) { 239 if (nv50->idxbuf.buffer) { 240 ctx.idxbuf = nouveau_resource_map_offset(&nv50->base, 241 nv04_resource(nv50->idxbuf.buffer), nv50->idxbuf.offset, 242 NOUVEAU_BO_RD); 243 } else { 244 ctx.idxbuf = nv50->idxbuf.user_buffer; 245 } 246 if (!ctx.idxbuf) 247 return; 248 index_size = nv50->idxbuf.index_size; 249 ctx.primitive_restart = info->primitive_restart; 250 ctx.restart_index = info->restart_index; 251 } else { 252 if (unlikely(info->count_from_stream_output)) { 253 struct pipe_context *pipe = &nv50->base.pipe; 254 struct nv50_so_target *targ; 255 targ = nv50_so_target(info->count_from_stream_output); 256 if (!targ->pq) { 257 NOUVEAU_ERR("draw_stream_output not supported on pre-NVA0 cards\n"); 258 return; 259 } 260 pipe->get_query_result(pipe, targ->pq, TRUE, (void *)&vert_count); 261 vert_count /= targ->stride; 262 } 263 ctx.idxbuf = NULL; 264 index_size = 0; 265 ctx.primitive_restart = FALSE; 266 ctx.restart_index = 0; 267 } 268 269 ctx.instance_id = info->start_instance; 270 ctx.prim = nv50_prim_gl(info->mode); 271 272 if (info->primitive_restart) { 273 BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 2); 274 PUSH_DATA (ctx.push, 1); 275 PUSH_DATA (ctx.push, info->restart_index); 276 } else 277 if (nv50->state.prim_restart) { 278 BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 1); 279 PUSH_DATA (ctx.push, 0); 280 } 281 nv50->state.prim_restart = info->primitive_restart; 282 283 while (inst_count--) { 284 BEGIN_NV04(ctx.push, NV50_3D(VERTEX_BEGIN_GL), 1); 285 PUSH_DATA (ctx.push, ctx.prim); 286 switch (index_size) { 287 case 0: 288 emit_vertices_seq(&ctx, info->start, vert_count); 289 break; 290 case 1: 291 emit_vertices_i08(&ctx, info->start, vert_count); 292 break; 293 case 2: 294 emit_vertices_i16(&ctx, info->start, vert_count); 295 break; 296 case 4: 297 emit_vertices_i32(&ctx, info->start, vert_count); 298 break; 299 default: 300 assert(0); 301 break; 302 } 303 BEGIN_NV04(ctx.push, NV50_3D(VERTEX_END_GL), 1); 304 PUSH_DATA (ctx.push, 0); 305 306 ctx.instance_id++; 307 ctx.prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; 308 } 309 } 310