summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/nv30/nv30_push.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/nv30/nv30_push.c')
-rw-r--r--src/gallium/drivers/nv30/nv30_push.c280
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);
+}