nv30_push.c revision a2fc42b899de22273c1df96091bfb5c636075cb0
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 37struct push_context { 38 struct nouveau_pushbuf *push; 39 40 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 55static INLINE unsigned 56prim_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 65static INLINE unsigned 66prim_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 75static INLINE unsigned 76prim_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 85static void 86emit_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 117static void 118emit_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 149static void 150emit_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 181static void 182emit_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 197void 198nv30_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 ctx.idxbuf = nouveau_resource_map_offset(&nv30->base, 225 nv04_resource(nv30->idxbuf.buffer), 226 nv30->idxbuf.offset, NOUVEAU_BO_RD); 227 if (!ctx.idxbuf) { 228 nv30_state_release(nv30); 229 return; 230 } 231 index_size = nv30->idxbuf.index_size; 232 ctx.primitive_restart = info->primitive_restart; 233 ctx.restart_index = info->restart_index; 234 } else { 235 ctx.idxbuf = NULL; 236 index_size = 0; 237 ctx.primitive_restart = FALSE; 238 ctx.restart_index = 0; 239 } 240 241 if (nv30->screen->eng3d->oclass >= NV40_3D_CLASS) { 242 BEGIN_NV04(ctx.push, NV40_3D(PRIM_RESTART_ENABLE), 2); 243 PUSH_DATA (ctx.push, info->primitive_restart); 244 PUSH_DATA (ctx.push, info->restart_index); 245 nv30->state.prim_restart = info->primitive_restart; 246 } 247 248 ctx.prim = nv30_prim_gl(info->mode); 249 250 PUSH_RESET(ctx.push, BUFCTX_IDXBUF); 251 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1); 252 PUSH_DATA (ctx.push, ctx.prim); 253 switch (index_size) { 254 case 0: 255 emit_vertices_seq(&ctx, info->start, info->count); 256 break; 257 case 1: 258 emit_vertices_i08(&ctx, info->start, info->count); 259 break; 260 case 2: 261 emit_vertices_i16(&ctx, info->start, info->count); 262 break; 263 case 4: 264 emit_vertices_i32(&ctx, info->start, info->count); 265 break; 266 default: 267 assert(0); 268 break; 269 } 270 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1); 271 PUSH_DATA (ctx.push, NV30_3D_VERTEX_BEGIN_END_STOP); 272 273 if (info->indexed) 274 nouveau_resource_unmap(nv04_resource(nv30->idxbuf.buffer)); 275 276 for (i = 0; i < nv30->num_vtxbufs; ++i) 277 nouveau_resource_unmap(nv04_resource(nv30->vtxbuf[i].buffer)); 278 279 nv30_state_release(nv30); 280} 281