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/nv50_context.h" 9#include "nv50/nv50_resource.h" 10 11#include "nv50/nv50_3d.xml.h" 12 13struct 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 bool primitive_restart; 27 28 bool need_vertex_id; 29 int32_t index_bias; 30 31 uint32_t prim; 32 uint32_t restart_index; 33 uint32_t start_instance; 34 uint32_t instance_id; 35}; 36 37static inline unsigned 38prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index) 39{ 40 unsigned i; 41 for (i = 0; i < push; ++i) 42 if (elts[i] == index) 43 break; 44 return i; 45} 46 47static inline unsigned 48prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index) 49{ 50 unsigned i; 51 for (i = 0; i < push; ++i) 52 if (elts[i] == index) 53 break; 54 return i; 55} 56 57static inline unsigned 58prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index) 59{ 60 unsigned i; 61 for (i = 0; i < push; ++i) 62 if (elts[i] == index) 63 break; 64 return i; 65} 66 67static void 68emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count) 69{ 70 uint8_t *elts = (uint8_t *)ctx->idxbuf + start; 71 72 while (count) { 73 unsigned push = MIN2(count, ctx->packet_vertex_limit); 74 unsigned size, nr; 75 76 nr = push; 77 if (ctx->primitive_restart) 78 nr = prim_restart_search_i08(elts, push, ctx->restart_index); 79 80 size = ctx->vertex_words * nr; 81 82 if (unlikely(ctx->need_vertex_id)) { 83 BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1); 84 PUSH_DATA (ctx->push, *elts + ctx->index_bias); 85 } 86 87 BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size); 88 89 ctx->translate->run_elts8(ctx->translate, elts, nr, 90 ctx->start_instance, ctx->instance_id, 91 ctx->push->cur); 92 93 ctx->push->cur += size; 94 count -= nr; 95 elts += nr; 96 97 if (nr != push) { 98 count--; 99 elts++; 100 BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1); 101 PUSH_DATA (ctx->push, ctx->restart_index); 102 } 103 } 104} 105 106static void 107emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count) 108{ 109 uint16_t *elts = (uint16_t *)ctx->idxbuf + start; 110 111 while (count) { 112 unsigned push = MIN2(count, ctx->packet_vertex_limit); 113 unsigned size, nr; 114 115 nr = push; 116 if (ctx->primitive_restart) 117 nr = prim_restart_search_i16(elts, push, ctx->restart_index); 118 119 size = ctx->vertex_words * nr; 120 121 if (unlikely(ctx->need_vertex_id)) { 122 BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1); 123 PUSH_DATA (ctx->push, *elts + ctx->index_bias); 124 } 125 126 BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size); 127 128 ctx->translate->run_elts16(ctx->translate, elts, nr, 129 ctx->start_instance, ctx->instance_id, 130 ctx->push->cur); 131 132 ctx->push->cur += size; 133 count -= nr; 134 elts += nr; 135 136 if (nr != push) { 137 count--; 138 elts++; 139 BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1); 140 PUSH_DATA (ctx->push, ctx->restart_index); 141 } 142 } 143} 144 145static void 146emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count) 147{ 148 uint32_t *elts = (uint32_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_i32(elts, push, ctx->restart_index); 157 158 size = ctx->vertex_words * nr; 159 160 if (unlikely(ctx->need_vertex_id)) { 161 BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1); 162 PUSH_DATA (ctx->push, *elts + ctx->index_bias); 163 } 164 165 BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size); 166 167 ctx->translate->run_elts(ctx->translate, elts, nr, 168 ctx->start_instance, ctx->instance_id, 169 ctx->push->cur); 170 171 ctx->push->cur += size; 172 count -= nr; 173 elts += nr; 174 175 if (nr != push) { 176 count--; 177 elts++; 178 BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1); 179 PUSH_DATA (ctx->push, ctx->restart_index); 180 } 181 } 182} 183 184static void 185emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count) 186{ 187 uint32_t elts = 0; 188 189 while (count) { 190 unsigned push = MIN2(count, ctx->packet_vertex_limit); 191 unsigned size = ctx->vertex_words * push; 192 193 if (unlikely(ctx->need_vertex_id)) { 194 /* For non-indexed draws, gl_VertexID goes up after each vertex. */ 195 BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1); 196 PUSH_DATA (ctx->push, elts++); 197 } 198 199 BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size); 200 201 ctx->translate->run(ctx->translate, start, push, 202 ctx->start_instance, ctx->instance_id, 203 ctx->push->cur); 204 ctx->push->cur += size; 205 count -= push; 206 start += push; 207 } 208} 209 210 211#define NV50_PRIM_GL_CASE(n) \ 212 case PIPE_PRIM_##n: return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n 213 214static inline unsigned 215nv50_prim_gl(unsigned prim) 216{ 217 switch (prim) { 218 NV50_PRIM_GL_CASE(POINTS); 219 NV50_PRIM_GL_CASE(LINES); 220 NV50_PRIM_GL_CASE(LINE_LOOP); 221 NV50_PRIM_GL_CASE(LINE_STRIP); 222 NV50_PRIM_GL_CASE(TRIANGLES); 223 NV50_PRIM_GL_CASE(TRIANGLE_STRIP); 224 NV50_PRIM_GL_CASE(TRIANGLE_FAN); 225 NV50_PRIM_GL_CASE(QUADS); 226 NV50_PRIM_GL_CASE(QUAD_STRIP); 227 NV50_PRIM_GL_CASE(POLYGON); 228 NV50_PRIM_GL_CASE(LINES_ADJACENCY); 229 NV50_PRIM_GL_CASE(LINE_STRIP_ADJACENCY); 230 NV50_PRIM_GL_CASE(TRIANGLES_ADJACENCY); 231 NV50_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY); 232 /* 233 NV50_PRIM_GL_CASE(PATCHES); */ 234 default: 235 return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS; 236 break; 237 } 238} 239 240void 241nv50_push_vbo(struct nv50_context *nv50, const struct pipe_draw_info *info) 242{ 243 struct push_context ctx; 244 unsigned i, index_size; 245 unsigned inst_count = info->instance_count; 246 unsigned vert_count = info->count; 247 bool apply_bias = info->indexed && info->index_bias; 248 249 ctx.push = nv50->base.pushbuf; 250 ctx.translate = nv50->vertex->translate; 251 252 ctx.need_vertex_id = nv50->screen->base.class_3d >= NV84_3D_CLASS && 253 nv50->vertprog->vp.need_vertex_id && (nv50->vertex->num_elements < 32); 254 ctx.index_bias = info->index_bias; 255 ctx.instance_id = 0; 256 257 /* For indexed draws, gl_VertexID must be emitted for every vertex. */ 258 ctx.packet_vertex_limit = 259 ctx.need_vertex_id ? 1 : nv50->vertex->packet_vertex_limit; 260 ctx.vertex_words = nv50->vertex->vertex_size; 261 262 assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS); 263 for (i = 0; i < nv50->num_vtxbufs; ++i) { 264 const struct pipe_vertex_buffer *vb = &nv50->vtxbuf[i]; 265 const uint8_t *data; 266 267 if (unlikely(vb->buffer)) 268 data = nouveau_resource_map_offset(&nv50->base, 269 nv04_resource(vb->buffer), vb->buffer_offset, NOUVEAU_BO_RD); 270 else 271 data = vb->user_buffer; 272 273 if (apply_bias && likely(!(nv50->vertex->instance_bufs & (1 << i)))) 274 data += (ptrdiff_t)info->index_bias * vb->stride; 275 276 ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0); 277 } 278 279 if (info->indexed) { 280 if (nv50->idxbuf.buffer) { 281 ctx.idxbuf = nouveau_resource_map_offset(&nv50->base, 282 nv04_resource(nv50->idxbuf.buffer), nv50->idxbuf.offset, 283 NOUVEAU_BO_RD); 284 } else { 285 ctx.idxbuf = nv50->idxbuf.user_buffer; 286 } 287 if (!ctx.idxbuf) 288 return; 289 index_size = nv50->idxbuf.index_size; 290 ctx.primitive_restart = info->primitive_restart; 291 ctx.restart_index = info->restart_index; 292 } else { 293 if (unlikely(info->count_from_stream_output)) { 294 struct pipe_context *pipe = &nv50->base.pipe; 295 struct nv50_so_target *targ; 296 targ = nv50_so_target(info->count_from_stream_output); 297 if (!targ->pq) { 298 NOUVEAU_ERR("draw_stream_output not supported on pre-NVA0 cards\n"); 299 return; 300 } 301 pipe->get_query_result(pipe, targ->pq, true, (void *)&vert_count); 302 vert_count /= targ->stride; 303 } 304 ctx.idxbuf = NULL; 305 index_size = 0; 306 ctx.primitive_restart = false; 307 ctx.restart_index = 0; 308 } 309 310 ctx.start_instance = info->start_instance; 311 ctx.prim = nv50_prim_gl(info->mode); 312 313 if (info->primitive_restart) { 314 BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 2); 315 PUSH_DATA (ctx.push, 1); 316 PUSH_DATA (ctx.push, info->restart_index); 317 } else 318 if (nv50->state.prim_restart) { 319 BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 1); 320 PUSH_DATA (ctx.push, 0); 321 } 322 nv50->state.prim_restart = info->primitive_restart; 323 324 while (inst_count--) { 325 BEGIN_NV04(ctx.push, NV50_3D(VERTEX_BEGIN_GL), 1); 326 PUSH_DATA (ctx.push, ctx.prim); 327 switch (index_size) { 328 case 0: 329 emit_vertices_seq(&ctx, info->start, vert_count); 330 break; 331 case 1: 332 emit_vertices_i08(&ctx, info->start, vert_count); 333 break; 334 case 2: 335 emit_vertices_i16(&ctx, info->start, vert_count); 336 break; 337 case 4: 338 emit_vertices_i32(&ctx, info->start, vert_count); 339 break; 340 default: 341 assert(0); 342 break; 343 } 344 BEGIN_NV04(ctx.push, NV50_3D(VERTEX_END_GL), 1); 345 PUSH_DATA (ctx.push, 0); 346 347 ctx.instance_id++; 348 ctx.prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; 349 } 350 351 if (unlikely(ctx.need_vertex_id)) { 352 /* Reset gl_VertexID to prevent future indexed draws to be confused. */ 353 BEGIN_NV04(ctx.push, NV84_3D(VERTEX_ID_BASE), 1); 354 PUSH_DATA (ctx.push, nv50->state.index_bias); 355 } 356} 357