diff options
author | Ben Skeggs <[email protected]> | 2012-01-11 12:42:07 +0100 |
---|---|---|
committer | Ben Skeggs <[email protected]> | 2012-04-14 02:56:34 +1000 |
commit | a2fc42b899de22273c1df96091bfb5c636075cb0 (patch) | |
tree | d3c4981bf8b611e1cea9876e9235b142f7fd39d0 /src/gallium/drivers/nv30/nv30_push.c | |
parent | 6d1cdec3ba151168bfc3aef222fba6265dfb41fb (diff) |
nv30: import new driver for GeForce FX/6/7 chipsets, and Quadro variants
The primary motivation for this rewrite was to have a maintainable driver
going forward, as nvfx was quite horrible in a lot of ways.
The driver is heavily based on the design of the nv50/nvc0 3d drivers we
already have, and uses the same common buffer/fence code. It also passes
a HEAP more piglit tests than nvfx did, supports a couple more features,
and a few more to come still probably.
The CPU footprint of this driver is far far less than nvfx, and translates
into far greater framerates in a lot of applications (unless you're using
a CPU that's way way newer than the GPUs of these generations....)
Basically, we once again have a maintained driver for these chipsets \o/
Feel free to report bugs now!
Diffstat (limited to 'src/gallium/drivers/nv30/nv30_push.c')
-rw-r--r-- | src/gallium/drivers/nv30/nv30_push.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/gallium/drivers/nv30/nv30_push.c b/src/gallium/drivers/nv30/nv30_push.c new file mode 100644 index 00000000000..16575ee2686 --- /dev/null +++ b/src/gallium/drivers/nv30/nv30_push.c @@ -0,0 +1,280 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: Ben Skeggs + * + */ + +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "util/u_inlines.h" +#include "util/u_format.h" +#include "translate/translate.h" + +#include "nouveau/nv_object.xml.h" +#include "nv30-40_3d.xml.h" +#include "nv30_context.h" +#include "nv30_resource.h" + +struct push_context { + struct nouveau_pushbuf *push; + + void *idxbuf; + + float edgeflag; + int edgeflag_attr; + + uint32_t vertex_words; + uint32_t packet_vertex_limit; + + struct translate *translate; + + boolean primitive_restart; + uint32_t prim; + uint32_t restart_index; +}; + +static INLINE unsigned +prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index) +{ + unsigned i; + for (i = 0; i < push; ++i) + if (elts[i] == index) + break; + return i; +} + +static INLINE unsigned +prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index) +{ + unsigned i; + for (i = 0; i < push; ++i) + if (elts[i] == index) + break; + return i; +} + +static INLINE unsigned +prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index) +{ + unsigned i; + for (i = 0; i < push; ++i) + if (elts[i] == index) + break; + return i; +} + +static void +emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count) +{ + uint8_t *elts = (uint8_t *)ctx->idxbuf + start; + + while (count) { + unsigned push = MIN2(count, ctx->packet_vertex_limit); + unsigned size, nr; + + nr = push; + if (ctx->primitive_restart) + nr = prim_restart_search_i08(elts, push, ctx->restart_index); + + size = ctx->vertex_words * nr; + + BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size); + + ctx->translate->run_elts8(ctx->translate, elts, nr, 0, ctx->push->cur); + + ctx->push->cur += size; + count -= nr; + elts += nr; + + if (nr != push) { + BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1); + PUSH_DATA (ctx->push, ctx->restart_index); + count--; + elts++; + } + } +} + +static void +emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count) +{ + uint16_t *elts = (uint16_t *)ctx->idxbuf + start; + + while (count) { + unsigned push = MIN2(count, ctx->packet_vertex_limit); + unsigned size, nr; + + nr = push; + if (ctx->primitive_restart) + nr = prim_restart_search_i16(elts, push, ctx->restart_index); + + size = ctx->vertex_words * nr; + + BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size); + + ctx->translate->run_elts16(ctx->translate, elts, nr, 0, ctx->push->cur); + + ctx->push->cur += size; + count -= nr; + elts += nr; + + if (nr != push) { + BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1); + PUSH_DATA (ctx->push, ctx->restart_index); + count--; + elts++; + } + } +} + +static void +emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count) +{ + uint32_t *elts = (uint32_t *)ctx->idxbuf + start; + + while (count) { + unsigned push = MIN2(count, ctx->packet_vertex_limit); + unsigned size, nr; + + nr = push; + if (ctx->primitive_restart) + nr = prim_restart_search_i32(elts, push, ctx->restart_index); + + size = ctx->vertex_words * nr; + + BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size); + + ctx->translate->run_elts(ctx->translate, elts, nr, 0, ctx->push->cur); + + ctx->push->cur += size; + count -= nr; + elts += nr; + + if (nr != push) { + BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1); + PUSH_DATA (ctx->push, ctx->restart_index); + count--; + elts++; + } + } +} + +static void +emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count) +{ + while (count) { + unsigned push = MIN2(count, ctx->packet_vertex_limit); + unsigned size = ctx->vertex_words * push; + + BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size); + + ctx->translate->run(ctx->translate, start, push, 0, ctx->push->cur); + ctx->push->cur += size; + count -= push; + start += push; + } +} + +void +nv30_push_vbo(struct nv30_context *nv30, const struct pipe_draw_info *info) +{ + struct push_context ctx; + unsigned i, index_size; + boolean apply_bias = info->indexed && info->index_bias; + + ctx.push = nv30->base.pushbuf; + ctx.translate = nv30->vertex->translate; + ctx.packet_vertex_limit = nv30->vertex->vtx_per_packet_max; + ctx.vertex_words = nv30->vertex->vtx_size; + + for (i = 0; i < nv30->num_vtxbufs; ++i) { + uint8_t *data; + struct pipe_vertex_buffer *vb = &nv30->vtxbuf[i]; + struct nv04_resource *res = nv04_resource(vb->buffer); + + data = nouveau_resource_map_offset(&nv30->base, res, + vb->buffer_offset, NOUVEAU_BO_RD); + + if (apply_bias) + data += info->index_bias * vb->stride; + + ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0); + } + + if (info->indexed) { + ctx.idxbuf = nouveau_resource_map_offset(&nv30->base, + nv04_resource(nv30->idxbuf.buffer), + nv30->idxbuf.offset, NOUVEAU_BO_RD); + if (!ctx.idxbuf) { + nv30_state_release(nv30); + return; + } + index_size = nv30->idxbuf.index_size; + ctx.primitive_restart = info->primitive_restart; + ctx.restart_index = info->restart_index; + } else { + ctx.idxbuf = NULL; + index_size = 0; + ctx.primitive_restart = FALSE; + ctx.restart_index = 0; + } + + if (nv30->screen->eng3d->oclass >= NV40_3D_CLASS) { + BEGIN_NV04(ctx.push, NV40_3D(PRIM_RESTART_ENABLE), 2); + PUSH_DATA (ctx.push, info->primitive_restart); + PUSH_DATA (ctx.push, info->restart_index); + nv30->state.prim_restart = info->primitive_restart; + } + + ctx.prim = nv30_prim_gl(info->mode); + + PUSH_RESET(ctx.push, BUFCTX_IDXBUF); + BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1); + PUSH_DATA (ctx.push, ctx.prim); + switch (index_size) { + case 0: + emit_vertices_seq(&ctx, info->start, info->count); + break; + case 1: + emit_vertices_i08(&ctx, info->start, info->count); + break; + case 2: + emit_vertices_i16(&ctx, info->start, info->count); + break; + case 4: + emit_vertices_i32(&ctx, info->start, info->count); + break; + default: + assert(0); + break; + } + BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1); + PUSH_DATA (ctx.push, NV30_3D_VERTEX_BEGIN_END_STOP); + + if (info->indexed) + nouveau_resource_unmap(nv04_resource(nv30->idxbuf.buffer)); + + for (i = 0; i < nv30->num_vtxbufs; ++i) + nouveau_resource_unmap(nv04_resource(nv30->vtxbuf[i].buffer)); + + nv30_state_release(nv30); +} |