boolean nv30_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start, unsigned count) { struct nv30_context *nv30 = nv30_context(pipe); struct nouveau_channel *chan = nv30->screen->base.channel; unsigned restart = 0; nv30_vbo_set_idxbuf(nv30, NULL, 0); if (FORCE_SWTNL || !nv30_state_validate(nv30)) { /*return nv30_draw_elements_swtnl(pipe, NULL, 0, mode, start, count);*/ return FALSE; } while (count) { unsigned vc, nr; nv30_state_emit(nv30); vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256, mode, start, count, &restart); if (!vc) { FIRE_RING(NULL); continue; } BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1); OUT_RING (nvgl_primitive(mode)); nr = (vc & 0xff); if (nr) { BEGIN_RING(rankine, NV34TCL_VB_VERTEX_BATCH, 1); OUT_RING (((nr - 1) << 24) | start); start += nr; } nr = vc >> 8; while (nr) { unsigned push = nr > 2047 ? 2047 : nr; nr -= push; BEGIN_RING_NI(rankine, NV34TCL_VB_VERTEX_BATCH, push); while (push--) { OUT_RING(((0x100 - 1) << 24) | start); start += 0x100; } } BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1); OUT_RING (0); count -= vc; start = restart; } pipe->flush(pipe, 0, NULL); return TRUE; }
static INLINE void emit_elt32(void* priv, unsigned start, unsigned vc) { struct push_context* ctx = priv; struct nouveau_grobj *eng3d = ctx->eng3d; struct nouveau_channel *chan = ctx->chan; uint32_t *elts = (uint32_t *)ctx->idxbuf + start; int idxbias = ctx->idxbias; while (vc) { unsigned push = MIN2(vc, 2047); BEGIN_RING_NI(chan, eng3d, NV30_3D_VB_ELEMENT_U32, push); if(idxbias) { for(unsigned i = 0; i < push; ++i) OUT_RING(chan, elts[i] + idxbias); } else OUT_RINGp(chan, elts, push); vc -= push; elts += push; } }
static void emit_ranges(void* priv, unsigned start, unsigned vc, unsigned reg) { struct push_context* ctx = priv; struct nouveau_grobj *eng3d = ctx->eng3d; struct nouveau_channel *chan = ctx->chan; unsigned nr = (vc & 0xff); if (nr) { BEGIN_RING(chan, eng3d, reg, 1); OUT_RING (chan, ((nr - 1) << 24) | start); start += nr; } nr = vc >> 8; while (nr) { unsigned push = nr > 2047 ? 2047 : nr; nr -= push; BEGIN_RING_NI(chan, eng3d, reg, push); while (push--) { OUT_RING(chan, ((0x100 - 1) << 24) | start); start += 0x100; } } }
static void nvc0_m2mf_push_rect(struct pipe_screen *pscreen, const struct nv50_m2mf_rect *dst, const void *data, unsigned nblocksx, unsigned nblocksy) { struct nouveau_channel *chan; const uint8_t *src = (const uint8_t *)data; const int cpp = dst->cpp; const int line_len = nblocksx * cpp; int dy = dst->y; assert(nouveau_bo_tile_layout(dst->bo)); BEGIN_RING(chan, RING_MF(TILING_MODE_OUT), 5); OUT_RING (chan, dst->tile_mode); OUT_RING (chan, dst->width * cpp); OUT_RING (chan, dst->height); OUT_RING (chan, dst->depth); OUT_RING (chan, dst->z); while (nblocksy) { int line_count, words; int size = MIN2(AVAIL_RING(chan), NV04_PFIFO_MAX_PACKET_LEN); if (size < (12 + words)) { FIRE_RING(chan); continue; } line_count = (size * 4) / line_len; words = (line_count * line_len + 3) / 4; BEGIN_RING(chan, RING_MF(OFFSET_OUT_HIGH), 2); OUT_RELOCh(chan, dst->bo, dst->base, dst->domain | NOUVEAU_BO_WR); OUT_RELOCl(chan, dst->bo, dst->base, dst->domain | NOUVEAU_BO_WR); BEGIN_RING(chan, RING_MF(TILING_POSITION_OUT_X), 2); OUT_RING (chan, dst->x * cpp); OUT_RING (chan, dy); BEGIN_RING(chan, RING_MF(LINE_LENGTH_IN), 2); OUT_RING (chan, line_len); OUT_RING (chan, line_count); BEGIN_RING(chan, RING_MF(EXEC), 1); OUT_RING (chan, (1 << NVC0_M2MF_EXEC_INC__SHIFT) | NVC0_M2MF_EXEC_PUSH | NVC0_M2MF_EXEC_LINEAR_IN); BEGIN_RING_NI(chan, RING_MF(DATA), words); OUT_RINGp (chan, src, words); dy += line_count; src += line_len * line_count; nblocksy -= line_count; } }
static boolean nv40_draw_elements_vbo(struct pipe_context *pipe, unsigned mode, unsigned start, unsigned count) { struct nv40_context *nv40 = nv40_context(pipe); struct nouveau_channel *chan = nv40->nvws->channel; unsigned restart; while (count) { unsigned nr, vc; nv40_state_emit(nv40); vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256, mode, start, count, &restart); if (!vc) { FIRE_RING(NULL); continue; } BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); OUT_RING (nvgl_primitive(mode)); nr = (vc & 0xff); if (nr) { BEGIN_RING(curie, NV40TCL_VB_INDEX_BATCH, 1); OUT_RING (((nr - 1) << 24) | start); start += nr; } nr = vc >> 8; while (nr) { unsigned push = nr > 2047 ? 2047 : nr; nr -= push; BEGIN_RING_NI(curie, NV40TCL_VB_INDEX_BATCH, push); while (push--) { OUT_RING(((0x100 - 1) << 24) | start); start += 0x100; } } BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); OUT_RING (0); count -= vc; start = restart; } return TRUE; }
static INLINE void emit_vertex(struct push_context *ctx, unsigned n) { struct nouveau_channel *chan = ctx->nvc0->screen->base.channel; int i; if (ctx->edgeflag_input < 32) { /* TODO */ } BEGIN_RING_NI(chan, RING_3D(VERTEX_DATA), ctx->vertex_size); for (i = 0; i < ctx->num_attrs; ++i) ctx->attr[i].push(chan, (uint8_t *)ctx->attr[i].map + n * ctx->attr[i].stride); }
static void emit_vertices(void *priv, unsigned start, unsigned count) { struct push_context *ctx = priv; struct nouveau_grobj *eng3d = ctx->eng3d; while(count) { unsigned push = MIN2(count, ctx->max_vertices_per_packet); unsigned length = push * ctx->vertex_length; BEGIN_RING_NI(ctx->chan, eng3d, NV30_3D_VERTEX_DATA, length); ctx->translate->run(ctx->translate, start, push, 0, ctx->chan->cur); ctx->chan->cur += length; count -= push; start += push; } }
static void emit_vertices_lookup32(void *priv, unsigned start, unsigned count) { struct push_context *ctx = priv; struct nouveau_grobj *eng3d = ctx->eng3d; uint32_t* elts = (uint32_t*)ctx->idxbuf + start; while(count) { unsigned push = MIN2(count, ctx->max_vertices_per_packet); unsigned length = push * ctx->vertex_length; BEGIN_RING_NI(ctx->chan, eng3d, NV30_3D_VERTEX_DATA, length); ctx->translate->run_elts(ctx->translate, elts, push, 0, ctx->chan->cur); ctx->chan->cur += length; count -= push; elts += push; } }
static INLINE void nv40_draw_elements_u32(struct nv40_context *nv40, void *ib, unsigned mode, unsigned start, unsigned count) { struct nouveau_channel *chan = nv40->nvws->channel; while (count) { uint32_t *elts = (uint32_t *)ib + start; unsigned vc, push, restart; nv40_state_emit(nv40); vc = nouveau_vbuf_split(chan->pushbuf->remaining, 5, 1, mode, start, count, &restart); if (vc == 0) { FIRE_RING(NULL); continue; } count -= vc; BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); OUT_RING (nvgl_primitive(mode)); while (vc) { push = MIN2(vc, 2047); BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U32, push); OUT_RINGp (elts, push); vc -= push; elts += push; } BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); OUT_RING (0); start = restart; } }
void nvc0_m2mf_push_linear(struct nouveau_context *nv, struct nouveau_bo *dst, unsigned offset, unsigned domain, unsigned size, void *data) { struct nouveau_channel *chan = nv->screen->channel; uint32_t *src = (uint32_t *)data; unsigned count = (size + 3) / 4; MARK_RING (chan, 8, 2); BEGIN_RING(chan, RING_MF(OFFSET_OUT_HIGH), 2); OUT_RELOCh(chan, dst, offset, domain | NOUVEAU_BO_WR); OUT_RELOCl(chan, dst, offset, domain | NOUVEAU_BO_WR); BEGIN_RING(chan, RING_MF(LINE_LENGTH_IN), 2); OUT_RING (chan, size); OUT_RING (chan, 1); BEGIN_RING(chan, RING_MF(EXEC), 1); OUT_RING (chan, 0x100111); while (count) { unsigned nr = AVAIL_RING(chan); if (nr < 9) { FIRE_RING(chan); nouveau_bo_validate(chan, dst, NOUVEAU_BO_WR); continue; } nr = MIN2(count, nr - 1); nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN); BEGIN_RING_NI(chan, RING_MF(DATA), nr); OUT_RINGp (chan, src, nr); src += nr; count -= nr; } }
static INLINE void emit_vertex(struct push_context *ctx, unsigned n) { struct nouveau_grobj *tesla = ctx->nv50->screen->tesla; struct nouveau_channel *chan = tesla->channel; int i; if (ctx->edgeflag_attr < 16) { float *edgeflag = (float *) ((uint8_t *)ctx->attr[ctx->edgeflag_attr].map + ctx->attr[ctx->edgeflag_attr].stride * n); if (*edgeflag != ctx->edgeflag) { BEGIN_RING(chan, tesla, NV50TCL_EDGEFLAG_ENABLE, 1); OUT_RING (chan, *edgeflag ? 1 : 0); ctx->edgeflag = *edgeflag; } } BEGIN_RING_NI(chan, tesla, NV50TCL_VERTEX_DATA, ctx->vtx_size); for (i = 0; i < ctx->attr_nr; i++) ctx->attr[i].push(chan, (uint8_t *)ctx->attr[i].map + ctx->attr[i].stride * n); }
void nvc0_m2mf_push_linear(struct nouveau_context *nv, struct nouveau_bo *dst, unsigned offset, unsigned domain, unsigned size, const void *data) { struct nouveau_channel *chan = nv->screen->channel; uint32_t *src = (uint32_t *)data; unsigned count = (size + 3) / 4; while (count) { unsigned nr; MARK_RING (chan, 16, 2); nr = AVAIL_RING(chan) - 9; nr = MIN2(count, nr); nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN); BEGIN_RING(chan, RING_MF(OFFSET_OUT_HIGH), 2); OUT_RELOCh(chan, dst, offset, domain | NOUVEAU_BO_WR); OUT_RELOCl(chan, dst, offset, domain | NOUVEAU_BO_WR); BEGIN_RING(chan, RING_MF(LINE_LENGTH_IN), 2); OUT_RING (chan, nr * 4); OUT_RING (chan, 1); BEGIN_RING(chan, RING_MF(EXEC), 1); OUT_RING (chan, 0x100111); /* must not be interrupted (trap on QUERY fence, 0x50 works however) */ BEGIN_RING_NI(chan, RING_MF(DATA), nr); OUT_RINGp (chan, src, nr); count -= nr; src += nr; offset += nr * 4; } }
void nv50_constbufs_validate(struct nv50_context *nv50) { struct nouveau_channel *chan = nv50->screen->base.channel; unsigned s; for (s = 0; s < 3; ++s) { struct nv04_resource *res; int i; unsigned p, b; if (s == PIPE_SHADER_FRAGMENT) p = NV50_3D_SET_PROGRAM_CB_PROGRAM_FRAGMENT; else if (s == PIPE_SHADER_GEOMETRY) p = NV50_3D_SET_PROGRAM_CB_PROGRAM_GEOMETRY; else p = NV50_3D_SET_PROGRAM_CB_PROGRAM_VERTEX; while (nv50->constbuf_dirty[s]) { struct nouveau_bo *bo; unsigned start = 0; unsigned words = 0; i = ffs(nv50->constbuf_dirty[s]) - 1; nv50->constbuf_dirty[s] &= ~(1 << i); res = nv04_resource(nv50->constbuf[s][i]); if (!res) { if (i != 0) { BEGIN_RING(chan, RING_3D(SET_PROGRAM_CB), 1); OUT_RING (chan, (i << 8) | p | 0); } continue; } if (i == 0) { b = NV50_CB_PVP + s; /* always upload GL uniforms through CB DATA */ bo = nv50->screen->uniforms; words = res->base.width0 / 4; } else { b = s * 16 + i; assert(0); if (!nouveau_resource_mapped_by_gpu(&res->base)) { nouveau_buffer_migrate(&nv50->base, res, NOUVEAU_BO_VRAM); BEGIN_RING(chan, RING_3D(CODE_CB_FLUSH), 1); OUT_RING (chan, 0); } MARK_RING (chan, 6, 2); BEGIN_RING(chan, RING_3D(CB_DEF_ADDRESS_HIGH), 3); OUT_RESRCh(chan, res, 0, NOUVEAU_BO_RD); OUT_RESRCl(chan, res, 0, NOUVEAU_BO_RD); OUT_RING (chan, (b << 16) | (res->base.width0 & 0xffff)); BEGIN_RING(chan, RING_3D(SET_PROGRAM_CB), 1); OUT_RING (chan, (b << 12) | (i << 8) | p | 1); bo = res->bo; nv50_bufctx_add_resident(nv50, NV50_BUFCTX_CONSTANT, res, res->domain | NOUVEAU_BO_RD); } if (words) { MARK_RING(chan, 8, 1); nouveau_bo_validate(chan, bo, res->domain | NOUVEAU_BO_WR); } while (words) { unsigned nr = AVAIL_RING(chan); if (nr < 16) { FIRE_RING(chan); nouveau_bo_validate(chan, bo, res->domain | NOUVEAU_BO_WR); continue; } nr = MIN2(MIN2(nr - 3, words), NV04_PFIFO_MAX_PACKET_LEN); BEGIN_RING(chan, RING_3D(CB_ADDR), 1); OUT_RING (chan, (start << 8) | b); BEGIN_RING_NI(chan, RING_3D(CB_DATA(0)), nr); OUT_RINGp (chan, &res->data[start * 4], nr); start += nr; words -= nr; } } } }
static INLINE void nvfx_render_prim(struct draw_stage *stage, struct prim_header *prim, unsigned mode, unsigned count) { struct nvfx_render_stage *rs = nvfx_render_stage(stage); struct nvfx_context *nvfx = rs->nvfx; struct nvfx_screen *screen = nvfx->screen; struct nouveau_channel *chan = screen->base.channel; struct nouveau_grobj *eng3d = screen->eng3d; boolean no_elements = nvfx->vertprog->draw_no_elements; unsigned num_attribs = nvfx->vertprog->draw_elements; /* we need to account the flush as well here even if it is done afterthis * function */ if (AVAIL_RING(chan) < ((1 + count * num_attribs * 4) + 6 + 64)) { nvfx_render_flush(stage, 0); FIRE_RING(chan); nvfx_state_emit(nvfx); assert(AVAIL_RING(chan) >= ((1 + count * num_attribs * 4) + 6 + 64)); } /* Switch primitive modes if necessary */ if (rs->prim != mode) { if (rs->prim != NV30_3D_VERTEX_BEGIN_END_STOP) { BEGIN_RING(chan, eng3d, NV30_3D_VERTEX_BEGIN_END, 1); OUT_RING(chan, NV30_3D_VERTEX_BEGIN_END_STOP); } /* XXX: any command a lot of times seems to (mostly) fix corruption that would otherwise happen */ /* this seems to cause issues on nv3x, and also be unneeded there */ if(nvfx->is_nv4x) { int i; for(i = 0; i < 32; ++i) { BEGIN_RING(chan, eng3d, 0x1dac, 1); OUT_RING(chan, 0); } } BEGIN_RING(chan, eng3d, NV30_3D_VERTEX_BEGIN_END, 1); OUT_RING (chan, mode); rs->prim = mode; } if(no_elements) { BEGIN_RING_NI(chan, eng3d, NV30_3D_VERTEX_DATA, 4); OUT_RING(chan, 0); OUT_RING(chan, 0); OUT_RING(chan, 0); OUT_RING(chan, 0); } else { BEGIN_RING_NI(chan, eng3d, NV30_3D_VERTEX_DATA, num_attribs * 4 * count); for (unsigned i = 0; i < count; ++i) { struct vertex_header* v = prim->v[i]; /* TODO: disable divide where it's causing the problem, and remove this hack */ OUT_RING(chan, fui(v->data[0][0] / v->data[0][3])); OUT_RING(chan, fui(v->data[0][1] / v->data[0][3])); OUT_RING(chan, fui(v->data[0][2] / v->data[0][3])); OUT_RING(chan, fui(1.0f / v->data[0][3])); OUT_RINGp(chan, &v->data[1][0], 4 * (num_attribs - 1)); } } }