static void nv30_prevalidate_vbufs(struct nv30_context *nv30) { struct pipe_vertex_buffer *vb; struct nv04_resource *buf; int i; uint32_t base, size; nv30->vbo_fifo = nv30->vbo_user = 0; for (i = 0; i < nv30->num_vtxbufs; i++) { vb = &nv30->vtxbuf[i]; if (!vb->stride || !vb->buffer) /* NOTE: user_buffer not implemented */ continue; buf = nv04_resource(vb->buffer); /* NOTE: user buffers with temporary storage count as mapped by GPU */ if (!nouveau_resource_mapped_by_gpu(vb->buffer)) { if (nv30->vbo_push_hint) { nv30->vbo_fifo = ~0; continue; } else { if (buf->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY) { nv30->vbo_user |= 1 << i; assert(vb->stride > vb->buffer_offset); nv30_vbuf_range(nv30, i, &base, &size); nouveau_user_buffer_upload(&nv30->base, buf, base, size); } else { nouveau_buffer_migrate(&nv30->base, buf, NOUVEAU_BO_GART); } nv30->base.vbo_dirty = TRUE; } } } }
static void nv30_draw_elements(struct nv30_context *nv30, boolean shorten, unsigned mode, unsigned start, unsigned count, unsigned instance_count, int32_t index_bias) { const unsigned index_size = nv30->idxbuf.index_size; struct nouveau_pushbuf *push = nv30->base.pushbuf; struct nouveau_object *eng3d = nv30->screen->eng3d; unsigned prim = nv30_prim_gl(mode); #if 0 /*XXX*/ if (index_bias != nv30->state.index_bias) { BEGIN_NV04(push, NV30_3D(VB_ELEMENT_BASE), 1); PUSH_DATA (push, index_bias); nv30->state.index_bias = index_bias; } #endif if (eng3d->oclass == NV40_3D_CLASS && index_size > 1 && nv30->idxbuf.buffer) { struct nv04_resource *res = nv04_resource(nv30->idxbuf.buffer); unsigned offset = nv30->idxbuf.offset; assert(nouveau_resource_mapped_by_gpu(&res->base)); BEGIN_NV04(push, NV30_3D(IDXBUF_OFFSET), 2); PUSH_RESRC(push, NV30_3D(IDXBUF_OFFSET), BUFCTX_IDXBUF, res, offset, NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 0, 0); PUSH_MTHD (push, NV30_3D(IDXBUF_FORMAT), BUFCTX_IDXBUF, res->bo, (index_size == 2) ? 0x00000010 : 0x00000000, res->domain | NOUVEAU_BO_RD, 0, NV30_3D_IDXBUF_FORMAT_DMA1); BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); PUSH_DATA (push, prim); while (count) { const unsigned mpush = 2047 * 256; unsigned npush = (count > mpush) ? mpush : count; unsigned wpush = ((npush + 255) & ~255) >> 8; count -= npush; BEGIN_NI04(push, NV30_3D(VB_INDEX_BATCH), wpush); while (npush >= 256) { PUSH_DATA (push, 0xff000000 | start); start += 256; npush -= 256; } if (npush) PUSH_DATA (push, ((npush - 1) << 24) | start); } BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); PUSH_RESET(push, BUFCTX_IDXBUF); } else {
void nv50_constbufs_validate(struct nv50_context *nv50) { struct nouveau_pushbuf *push = nv50->base.pushbuf; unsigned s; for (s = 0; s < 3; ++s) { unsigned p; 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]) { const unsigned i = (unsigned)ffs(nv50->constbuf_dirty[s]) - 1; assert(i < NV50_MAX_PIPE_CONSTBUFS); nv50->constbuf_dirty[s] &= ~(1 << i); if (nv50->constbuf[s][i].user) { const unsigned b = NV50_CB_PVP + s; unsigned start = 0; unsigned words = nv50->constbuf[s][0].size / 4; if (i) { NOUVEAU_ERR("user constbufs only supported in slot 0\n"); continue; } if (!nv50->state.uniform_buffer_bound[s]) { nv50->state.uniform_buffer_bound[s] = TRUE; BEGIN_NV04(push, NV50_3D(SET_PROGRAM_CB), 1); PUSH_DATA (push, (b << 12) | (i << 8) | p | 1); } while (words) { unsigned nr; if (!PUSH_SPACE(push, 16)) break; nr = PUSH_AVAIL(push); assert(nr >= 16); nr = MIN2(MIN2(nr - 3, words), NV04_PFIFO_MAX_PACKET_LEN); BEGIN_NV04(push, NV50_3D(CB_ADDR), 1); PUSH_DATA (push, (start << 8) | b); BEGIN_NI04(push, NV50_3D(CB_DATA(0)), nr); PUSH_DATAp(push, &nv50->constbuf[s][0].u.data[start * 4], nr); start += nr; words -= nr; } } else { struct nv04_resource *res = nv04_resource(nv50->constbuf[s][i].u.buf); if (res) { /* TODO: allocate persistent bindings */ const unsigned b = s * 16 + i; assert(nouveau_resource_mapped_by_gpu(&res->base)); if (!nv50->constbuf[s][i].offset) res->cb_slot = b; BEGIN_NV04(push, NV50_3D(CB_DEF_ADDRESS_HIGH), 3); PUSH_DATAh(push, res->address + nv50->constbuf[s][i].offset); PUSH_DATA (push, res->address + nv50->constbuf[s][i].offset); PUSH_DATA (push, (b << 16) | (align(nv50->constbuf[s][i].size, 0x100) & 0xffff)); BEGIN_NV04(push, NV50_3D(SET_PROGRAM_CB), 1); PUSH_DATA (push, (b << 12) | (i << 8) | p | 1); BCTX_REFN(nv50->bufctx_3d, CB(s, i), res, RD); } else { BEGIN_NV04(push, NV50_3D(SET_PROGRAM_CB), 1); PUSH_DATA (push, (i << 8) | p | 0); } if (i == 0) nv50->state.uniform_buffer_bound[s] = FALSE; } } } }
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; } } } }