Adds a more generic SIFC transfer function.
extern void nv50_vertprog_validate(struct nv50_context *nv50);
extern void nv50_fragprog_validate(struct nv50_context *nv50);
extern void nv50_linkage_validate(struct nv50_context *nv50);
-extern void nv50_program_destroy(struct nv50_context *nv50, struct nv50_program *p);
+extern void nv50_program_destroy(struct nv50_context *nv50,
+ struct nv50_program *p);
/* nv50_state_validate.c */
extern boolean nv50_state_validate(struct nv50_context *nv50);
/* nv50_tex.c */
extern void nv50_tex_validate(struct nv50_context *);
+/* nv50_transfer.c */
+extern void
+nv50_upload_sifc(struct nv50_context *nv50,
+ struct nouveau_bo *bo, unsigned dst_offset, unsigned reloc,
+ unsigned dst_format, int dst_w, int dst_h, int dst_pitch,
+ void *src, unsigned src_format, int src_pitch,
+ int x, int y, int w, int h, int cpp);
+
#endif
nv50_program_validate_code(struct nv50_context *nv50, struct nv50_program *p)
{
struct nouveau_channel *chan = nv50->screen->base.channel;
- struct nouveau_grobj *tesla = nv50->screen->tesla;
struct nv50_program_exec *e;
- struct nouveau_stateobj *so;
- const unsigned flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
- unsigned start, count, *up, *ptr;
+ uint32_t *up, i;
boolean upload = FALSE;
if (!p->bo) {
if (!upload)
return;
- for (e = p->exec_head; e; e = e->next) {
+ up = MALLOC(p->exec_size * 4);
+
+ for (i = 0, e = p->exec_head; e; e = e->next) {
unsigned ei, ci, bs;
- if (e->param.index < 0)
- continue;
+ if (e->param.index >= 0 && e->param.mask) {
+ bs = (e->inst[1] >> 22) & 0x07;
+ assert(bs < 2);
+ ei = e->param.shift >> 5;
+ ci = e->param.index;
+ if (bs == 0)
+ ci += p->data[bs]->start;
- if (e->param.mask == 0) {
+ e->inst[ei] &= ~e->param.mask;
+ e->inst[ei] |= (ci << e->param.shift);
+ } else
+ if (e->param.index >= 0) {
+ /* zero mask means param is a jump/branch offset */
assert(!(e->param.index & 1));
/* seem to be 8 byte steps */
ei = (e->param.index >> 1) + 0 /* START_ID */;
e->inst[0] &= 0xf0000fff;
e->inst[0] |= ei << 12;
- continue;
}
- bs = (e->inst[1] >> 22) & 0x07;
- assert(bs < 2);
- ei = e->param.shift >> 5;
- ci = e->param.index;
- if (bs == 0)
- ci += p->data[bs]->start;
-
- e->inst[ei] &= ~e->param.mask;
- e->inst[ei] |= (ci << e->param.shift);
+ up[i++] = e->inst[0];
+ if (is_long(e))
+ up[i++] = e->inst[1];
}
+ assert(i == p->exec_size);
if (p->data[0])
p->data_start[0] = p->data[0]->start;
NOUVEAU_ERR("0x%08x\n", e->inst[1]);
}
#endif
-
- up = ptr = MALLOC(p->exec_size * 4);
- for (e = p->exec_head; e; e = e->next) {
- *(ptr++) = e->inst[0];
- if (is_long(e))
- *(ptr++) = e->inst[1];
- }
-
- so = so_new(4,2);
- so_method(so, nv50->screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3);
- so_reloc (so, p->bo, 0, flags | NOUVEAU_BO_HIGH, 0, 0);
- so_reloc (so, p->bo, 0, flags | NOUVEAU_BO_LOW, 0, 0);
- so_data (so, (NV50_CB_PUPLOAD << 16) | 0x0800); //(p->exec_size * 4));
-
- start = 0; count = p->exec_size;
- while (count) {
- struct nouveau_channel *chan = nv50->screen->base.channel;
- unsigned nr;
-
- so_emit(chan, so);
-
- nr = MIN2(count, 2047);
- nr = MIN2(chan->pushbuf->remaining, nr);
- if (chan->pushbuf->remaining < (nr + 3)) {
- FIRE_RING(chan);
- continue;
- }
-
- BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 1);
- OUT_RING (chan, (start << 8) | NV50_CB_PUPLOAD);
- BEGIN_RING(chan, tesla, NV50TCL_CB_DATA(0) | 0x40000000, nr);
- OUT_RINGp (chan, up + start, nr);
-
- start += nr;
- count -= nr;
- }
+ nv50_upload_sifc(nv50, p->bo, 0, NOUVEAU_BO_VRAM,
+ NV50_2D_DST_FORMAT_R8_UNORM, 65536, 1, 262144,
+ up, NV50_2D_SIFC_FORMAT_R8_UNORM, 0,
+ 0, 0, p->exec_size * 4, 1, 1);
FREE(up);
- so_ref(NULL, &so);
}
void
pscreen->transfer_map = nv50_transfer_map;
pscreen->transfer_unmap = nv50_transfer_unmap;
}
+
+void
+nv50_upload_sifc(struct nv50_context *nv50,
+ struct nouveau_bo *bo, unsigned dst_offset, unsigned reloc,
+ unsigned dst_format, int dst_w, int dst_h, int dst_pitch,
+ void *src, unsigned src_format, int src_pitch,
+ int x, int y, int w, int h, int cpp)
+{
+ struct nouveau_channel *chan = nv50->screen->base.channel;
+ struct nouveau_grobj *eng2d = nv50->screen->eng2d;
+ struct nouveau_grobj *tesla = nv50->screen->tesla;
+ unsigned line_dwords = (w * cpp + 3) / 4;
+
+ reloc |= NOUVEAU_BO_WR;
+
+ WAIT_RING (chan, 32);
+
+ if (bo->tile_flags) {
+ BEGIN_RING(chan, eng2d, NV50_2D_DST_FORMAT, 5);
+ OUT_RING (chan, dst_format);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, bo->tile_mode << 4);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ } else {
+ BEGIN_RING(chan, eng2d, NV50_2D_DST_FORMAT, 2);
+ OUT_RING (chan, dst_format);
+ OUT_RING (chan, 1);
+ BEGIN_RING(chan, eng2d, NV50_2D_DST_PITCH, 1);
+ OUT_RING (chan, dst_pitch);
+ }
+
+ BEGIN_RING(chan, eng2d, NV50_2D_DST_WIDTH, 4);
+ OUT_RING (chan, dst_w);
+ OUT_RING (chan, dst_h);
+ OUT_RELOCh(chan, bo, dst_offset, reloc);
+ OUT_RELOCl(chan, bo, dst_offset, reloc);
+
+ /* NV50_2D_OPERATION_SRCCOPY assumed already set */
+
+ BEGIN_RING(chan, eng2d, NV50_2D_SIFC_UNK0800, 2);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, src_format);
+ BEGIN_RING(chan, eng2d, NV50_2D_SIFC_WIDTH, 10);
+ OUT_RING (chan, w);
+ OUT_RING (chan, h);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, x);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, y);
+
+ while (h--) {
+ const uint32_t *p = src;
+ unsigned count = line_dwords;
+
+ while (count) {
+ unsigned nr = MIN2(count, 1792);
+
+ if (chan->pushbuf->remaining <= nr) {
+ FIRE_RING (chan);
+
+ BEGIN_RING(chan, eng2d,
+ NV50_2D_DST_ADDRESS_HIGH, 2);
+ OUT_RELOCh(chan, bo, dst_offset, reloc);
+ OUT_RELOCl(chan, bo, dst_offset, reloc);
+ }
+ assert(chan->pushbuf->remaining > nr);
+
+ BEGIN_RING(chan, eng2d,
+ NV50_2D_SIFC_DATA | (2 << 29), nr);
+ OUT_RINGp (chan, p, nr);
+
+ p += nr;
+ count -= nr;
+ }
+
+ src += src_pitch;
+ }
+
+ BEGIN_RING(chan, tesla, 0x1440, 1);
+ OUT_RING (chan, 0);
+}