nvc0_push.c revision 14bd9d764802b5fedb652c791faafe4d13b65262
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 "nvc0_context.h" 9#include "nvc0_resource.h" 10 11#include "nvc0_3d.xml.h" 12 13struct push_context { 14 struct nouveau_channel *chan; 15 16 void *idxbuf; 17 18 uint32_t vertex_words; 19 uint32_t packet_vertex_limit; 20 21 struct translate *translate; 22 23 boolean primitive_restart; 24 uint32_t prim; 25 uint32_t restart_index; 26 uint32_t instance_id; 27 28 struct { 29 int buffer; 30 float value; 31 uint8_t *data; 32 unsigned offset; 33 unsigned stride; 34 } edgeflag; 35}; 36 37static void 38init_push_context(struct nvc0_context *nvc0, struct push_context *ctx) 39{ 40 struct pipe_vertex_element *ve; 41 42 ctx->chan = nvc0->screen->base.channel; 43 ctx->translate = nvc0->vertex->translate; 44 45 ctx->edgeflag.value = 0.5f; 46 47 if (NVC0_USING_EDGEFLAG(nvc0)) { 48 ve = &nvc0->vertex->element[nvc0->vertprog->vp.edgeflag].pipe; 49 50 ctx->edgeflag.buffer = ve->vertex_buffer_index; 51 ctx->edgeflag.offset = ve->src_offset; 52 53 ctx->packet_vertex_limit = 1; 54 } else { 55 ctx->edgeflag.buffer = -1; 56 ctx->edgeflag.offset = 0; 57 ctx->edgeflag.stride = 0; 58 ctx->edgeflag.data = NULL; 59 60 ctx->packet_vertex_limit = nvc0->vertex->vtx_per_packet_max; 61 } 62 63 ctx->vertex_words = nvc0->vertex->vtx_size; 64} 65 66static INLINE void 67set_edgeflag(struct push_context *ctx, unsigned vtx_id) 68{ 69 float f = *(float *)(ctx->edgeflag.data + vtx_id * ctx->edgeflag.stride); 70 71 if (ctx->edgeflag.value != f) { 72 ctx->edgeflag.value = f; 73 IMMED_RING(ctx->chan, RING_3D(EDGEFLAG_ENABLE), f ? 1 : 0); 74 } 75} 76 77static INLINE unsigned 78prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index) 79{ 80 unsigned i; 81 for (i = 0; i < push; ++i) 82 if (elts[i] == index) 83 break; 84 return i; 85} 86 87static INLINE unsigned 88prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index) 89{ 90 unsigned i; 91 for (i = 0; i < push; ++i) 92 if (elts[i] == index) 93 break; 94 return i; 95} 96 97static INLINE unsigned 98prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index) 99{ 100 unsigned i; 101 for (i = 0; i < push; ++i) 102 if (elts[i] == index) 103 break; 104 return i; 105} 106 107static void 108emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count) 109{ 110 uint8_t *restrict elts = (uint8_t *)ctx->idxbuf + start; 111 112 while (count) { 113 unsigned push = MIN2(count, ctx->packet_vertex_limit); 114 unsigned size, nr; 115 116 nr = push; 117 if (ctx->primitive_restart) 118 nr = prim_restart_search_i08(elts, push, ctx->restart_index); 119 120 if (unlikely(ctx->edgeflag.buffer >= 0) && nr) 121 set_edgeflag(ctx, elts[0]); 122 123 size = ctx->vertex_words * nr; 124 125 BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size); 126 127 ctx->translate->run_elts8(ctx->translate, elts, nr, ctx->instance_id, 128 ctx->chan->cur); 129 130 ctx->chan->cur += size; 131 count -= nr; 132 elts += nr; 133 134 if (nr != push) { 135 count--; 136 elts++; 137 BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2); 138 OUT_RING (ctx->chan, 0); 139 OUT_RING (ctx->chan, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT | 140 (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT)); 141 } 142 } 143} 144 145static void 146emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count) 147{ 148 uint16_t *restrict elts = (uint16_t *)ctx->idxbuf + start; 149 150 while (count) { 151 unsigned push = MIN2(count, ctx->packet_vertex_limit); 152 unsigned size, nr; 153 154 nr = push; 155 if (ctx->primitive_restart) 156 nr = prim_restart_search_i16(elts, push, ctx->restart_index); 157 158 if (unlikely(ctx->edgeflag.buffer >= 0) && nr) 159 set_edgeflag(ctx, elts[0]); 160 161 size = ctx->vertex_words * nr; 162 163 BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size); 164 165 ctx->translate->run_elts16(ctx->translate, elts, nr, ctx->instance_id, 166 ctx->chan->cur); 167 168 ctx->chan->cur += size; 169 count -= nr; 170 elts += nr; 171 172 if (nr != push) { 173 count--; 174 elts++; 175 BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2); 176 OUT_RING (ctx->chan, 0); 177 OUT_RING (ctx->chan, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT | 178 (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT)); 179 } 180 } 181} 182 183static void 184emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count) 185{ 186 uint32_t *restrict elts = (uint32_t *)ctx->idxbuf + start; 187 188 while (count) { 189 unsigned push = MIN2(count, ctx->packet_vertex_limit); 190 unsigned size, nr; 191 192 nr = push; 193 if (ctx->primitive_restart) 194 nr = prim_restart_search_i32(elts, push, ctx->restart_index); 195 196 if (unlikely(ctx->edgeflag.buffer >= 0) && nr) 197 set_edgeflag(ctx, elts[0]); 198 199 size = ctx->vertex_words * nr; 200 201 BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size); 202 203 ctx->translate->run_elts(ctx->translate, elts, nr, ctx->instance_id, 204 ctx->chan->cur); 205 206 ctx->chan->cur += size; 207 count -= nr; 208 elts += nr; 209 210 if (nr != push) { 211 count--; 212 elts++; 213 BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2); 214 OUT_RING (ctx->chan, 0); 215 OUT_RING (ctx->chan, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT | 216 (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT)); 217 } 218 } 219} 220 221static void 222emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count) 223{ 224 while (count) { 225 unsigned push = MIN2(count, ctx->packet_vertex_limit); 226 unsigned size = ctx->vertex_words * push; 227 228 if (unlikely(ctx->edgeflag.buffer >= 0)) 229 set_edgeflag(ctx, start); 230 231 BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size); 232 233 ctx->translate->run(ctx->translate, start, push, ctx->instance_id, 234 ctx->chan->cur); 235 ctx->chan->cur += size; 236 count -= push; 237 start += push; 238 } 239} 240 241 242#define NVC0_PRIM_GL_CASE(n) \ 243 case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n 244 245static INLINE unsigned 246nvc0_prim_gl(unsigned prim) 247{ 248 switch (prim) { 249 NVC0_PRIM_GL_CASE(POINTS); 250 NVC0_PRIM_GL_CASE(LINES); 251 NVC0_PRIM_GL_CASE(LINE_LOOP); 252 NVC0_PRIM_GL_CASE(LINE_STRIP); 253 NVC0_PRIM_GL_CASE(TRIANGLES); 254 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP); 255 NVC0_PRIM_GL_CASE(TRIANGLE_FAN); 256 NVC0_PRIM_GL_CASE(QUADS); 257 NVC0_PRIM_GL_CASE(QUAD_STRIP); 258 NVC0_PRIM_GL_CASE(POLYGON); 259 NVC0_PRIM_GL_CASE(LINES_ADJACENCY); 260 NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY); 261 NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY); 262 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY); 263 /* 264 NVC0_PRIM_GL_CASE(PATCHES); */ 265 default: 266 return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS; 267 break; 268 } 269} 270 271void 272nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info) 273{ 274 struct push_context ctx; 275 unsigned i, index_size; 276 unsigned inst_count = info->instance_count; 277 unsigned vert_count = info->count; 278 boolean apply_bias = info->indexed && info->index_bias; 279 280 init_push_context(nvc0, &ctx); 281 282 for (i = 0; i < nvc0->num_vtxbufs; ++i) { 283 uint8_t *data; 284 struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[i]; 285 struct nv04_resource *res = nv04_resource(vb->buffer); 286 287 data = nouveau_resource_map_offset(&nvc0->base, res, 288 vb->buffer_offset, NOUVEAU_BO_RD); 289 290 if (apply_bias && likely(!(nvc0->vertex->instance_bufs & (1 << i)))) 291 data += info->index_bias * vb->stride; 292 293 ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0); 294 295 if (unlikely(i == ctx.edgeflag.buffer)) { 296 ctx.edgeflag.data = data + ctx.edgeflag.offset; 297 ctx.edgeflag.stride = vb->stride; 298 } 299 } 300 301 if (info->indexed) { 302 ctx.idxbuf = 303 nouveau_resource_map_offset(&nvc0->base, 304 nv04_resource(nvc0->idxbuf.buffer), 305 nvc0->idxbuf.offset, NOUVEAU_BO_RD); 306 if (!ctx.idxbuf) 307 return; 308 index_size = nvc0->idxbuf.index_size; 309 ctx.primitive_restart = info->primitive_restart; 310 ctx.restart_index = info->restart_index; 311 } else { 312 ctx.idxbuf = NULL; 313 index_size = 0; 314 ctx.primitive_restart = FALSE; 315 ctx.restart_index = 0; 316 317 if (info->count_from_stream_output) { 318 struct pipe_context *pipe = &nvc0->base.pipe; 319 struct nvc0_so_target *targ; 320 targ = nvc0_so_target(info->count_from_stream_output); 321 pipe->get_query_result(pipe, targ->pq, TRUE, &vert_count); 322 vert_count /= targ->stride; 323 } 324 } 325 326 ctx.instance_id = info->start_instance; 327 ctx.prim = nvc0_prim_gl(info->mode); 328 329 while (inst_count--) { 330 BEGIN_RING(ctx.chan, RING_3D(VERTEX_BEGIN_GL), 1); 331 OUT_RING (ctx.chan, ctx.prim); 332 switch (index_size) { 333 case 0: 334 emit_vertices_seq(&ctx, info->start, vert_count); 335 break; 336 case 1: 337 emit_vertices_i08(&ctx, info->start, vert_count); 338 break; 339 case 2: 340 emit_vertices_i16(&ctx, info->start, vert_count); 341 break; 342 case 4: 343 emit_vertices_i32(&ctx, info->start, vert_count); 344 break; 345 default: 346 assert(0); 347 break; 348 } 349 IMMED_RING(ctx.chan, RING_3D(VERTEX_END_GL), 0); 350 351 ctx.instance_id++; 352 ctx.prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; 353 } 354 355 if (unlikely(ctx.edgeflag.value == 0.0f)) 356 IMMED_RING(ctx.chan, RING_3D(EDGEFLAG_ENABLE), 1); 357 358 if (info->indexed) 359 nouveau_resource_unmap(nv04_resource(nvc0->idxbuf.buffer)); 360 361 for (i = 0; i < nvc0->num_vtxbufs; ++i) 362 nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer)); 363} 364