void nvc0_m2mf_push_linear(struct nouveau_context *nv, struct nouveau_bo *dst, unsigned offset, unsigned domain, unsigned size, const void *data) { struct nvc0_context *nvc0 = nvc0_context(&nv->pipe); struct nouveau_pushbuf *push = nv->pushbuf; uint32_t *src = (uint32_t *)data; unsigned count = (size + 3) / 4; nouveau_bufctx_refn(nvc0->bufctx, 0, dst, domain | NOUVEAU_BO_WR); nouveau_pushbuf_bufctx(push, nvc0->bufctx); nouveau_pushbuf_validate(push); while (count) { unsigned nr; if (!PUSH_SPACE(push, 16)) break; nr = PUSH_AVAIL(push); assert(nr >= 16); nr = MIN2(count, nr - 9); nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN); BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2); PUSH_DATAh(push, dst->offset + offset); PUSH_DATA (push, dst->offset + offset); BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2); PUSH_DATA (push, MIN2(size, nr * 4)); PUSH_DATA (push, 1); BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1); PUSH_DATA (push, 0x100111); /* must not be interrupted (trap on QUERY fence, 0x50 works however) */ BEGIN_NIC0(push, NVC0_M2MF(DATA), nr); PUSH_DATAp(push, src, nr); count -= nr; src += nr; offset += nr * 4; size -= nr * 4; } nouveau_bufctx_reset(nvc0->bufctx, 0); }
static boolean nvc0_validate_tsc(struct nvc0_context *nvc0, int s) { uint32_t commands[16]; struct nouveau_pushbuf *push = nvc0->base.pushbuf; unsigned i; unsigned n = 0; boolean need_flush = FALSE; for (i = 0; i < nvc0->num_samplers[s]; ++i) { struct nv50_tsc_entry *tsc = nv50_tsc_entry(nvc0->samplers[s][i]); if (!(nvc0->samplers_dirty[s] & (1 << i))) continue; if (!tsc) { commands[n++] = (i << 4) | 0; continue; } if (tsc->id < 0) { tsc->id = nvc0_screen_tsc_alloc(nvc0->screen, tsc); nvc0_m2mf_push_linear(&nvc0->base, nvc0->screen->txc, 65536 + tsc->id * 32, NOUVEAU_BO_VRAM, 32, tsc->tsc); need_flush = TRUE; } nvc0->screen->tsc.lock[tsc->id / 32] |= 1 << (tsc->id % 32); commands[n++] = (tsc->id << 12) | (i << 4) | 1; } for (; i < nvc0->state.num_samplers[s]; ++i) commands[n++] = (i << 4) | 0; nvc0->state.num_samplers[s] = nvc0->num_samplers[s]; if (n) { BEGIN_NIC0(push, NVC0_3D(BIND_TSC(s)), n); PUSH_DATAp(push, commands, n); } nvc0->samplers_dirty[s] = 0; return need_flush; }
static void nvc0_emit_string_marker(struct pipe_context *pipe, const char *str, int len) { struct nouveau_pushbuf *push = nvc0_context(pipe)->base.pushbuf; int string_words = len / 4; int data_words; if (len <= 0) return; string_words = MIN2(string_words, NV04_PFIFO_MAX_PACKET_LEN); if (string_words == NV04_PFIFO_MAX_PACKET_LEN) data_words = string_words; else data_words = string_words + !!(len & 3); BEGIN_NIC0(push, SUBC_3D(NV04_GRAPH_NOP), data_words); if (string_words) PUSH_DATAp(push, str, string_words); if (string_words != data_words) { int data = 0; memcpy(&data, &str[string_words * 4], len & 3); PUSH_DATA (push, data); } }
static boolean nvc0_validate_tic(struct nvc0_context *nvc0, int s) { uint32_t commands[32]; struct nouveau_pushbuf *push = nvc0->base.pushbuf; struct nouveau_bo *txc = nvc0->screen->txc; unsigned i; unsigned n = 0; boolean need_flush = FALSE; for (i = 0; i < nvc0->num_textures[s]; ++i) { struct nv50_tic_entry *tic = nv50_tic_entry(nvc0->textures[s][i]); struct nv04_resource *res; const boolean dirty = !!(nvc0->textures_dirty[s] & (1 << i)); if (!tic) { if (dirty) commands[n++] = (i << 1) | 0; continue; } res = nv04_resource(tic->pipe.texture); if (tic->id < 0) { tic->id = nvc0_screen_tic_alloc(nvc0->screen, tic); PUSH_SPACE(push, 17); BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2); PUSH_DATAh(push, txc->offset + (tic->id * 32)); PUSH_DATA (push, txc->offset + (tic->id * 32)); BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2); PUSH_DATA (push, 32); PUSH_DATA (push, 1); BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1); PUSH_DATA (push, 0x100111); BEGIN_NIC0(push, NVC0_M2MF(DATA), 8); PUSH_DATAp(push, &tic->tic[0], 8); need_flush = TRUE; } else if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) { BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1); PUSH_DATA (push, (tic->id << 4) | 1); } nvc0->screen->tic.lock[tic->id / 32] |= 1 << (tic->id % 32); res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING; res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING; if (!dirty) continue; commands[n++] = (tic->id << 9) | (i << 1) | 1; BCTX_REFN(nvc0->bufctx_3d, TEX(s, i), res, RD); } for (; i < nvc0->state.num_textures[s]; ++i) commands[n++] = (i << 1) | 0; nvc0->state.num_textures[s] = nvc0->num_textures[s]; if (n) { BEGIN_NIC0(push, NVC0_3D(BIND_TIC(s)), n); PUSH_DATAp(push, commands, n); } nvc0->textures_dirty[s] = 0; return need_flush; }
int nvc0_screen_compute_setup(struct nvc0_screen *screen, struct nouveau_pushbuf *push) { struct nouveau_object *chan = screen->base.channel; struct nouveau_device *dev = screen->base.device; uint32_t obj_class; int ret; int i; switch (dev->chipset & ~0xf) { case 0xc0: if (dev->chipset == 0xc8) obj_class = NVC8_COMPUTE_CLASS; else obj_class = NVC0_COMPUTE_CLASS; break; case 0xd0: obj_class = NVC0_COMPUTE_CLASS; break; default: NOUVEAU_ERR("unsupported chipset: NV%02x\n", dev->chipset); return -1; } ret = nouveau_object_new(chan, 0xbeef90c0, obj_class, NULL, 0, &screen->compute); if (ret) { NOUVEAU_ERR("Failed to allocate compute object: %d\n", ret); return ret; } ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 1 << 12, NULL, &screen->parm); if (ret) return ret; BEGIN_NVC0(push, SUBC_COMPUTE(NV01_SUBCHAN_OBJECT), 1); PUSH_DATA (push, screen->compute->oclass); /* hardware limit */ BEGIN_NVC0(push, NVC0_COMPUTE(MP_LIMIT), 1); PUSH_DATA (push, screen->mp_count); BEGIN_NVC0(push, NVC0_COMPUTE(CALL_LIMIT_LOG), 1); PUSH_DATA (push, 0xf); BEGIN_NVC0(push, SUBC_COMPUTE(0x02a0), 1); PUSH_DATA (push, 0x8000); /* global memory setup */ BEGIN_NVC0(push, SUBC_COMPUTE(0x02c4), 1); PUSH_DATA (push, 0); BEGIN_NIC0(push, NVC0_COMPUTE(GLOBAL_BASE), 0x100); for (i = 0; i <= 0xff; i++) PUSH_DATA (push, (0xc << 28) | (i << 16) | i); BEGIN_NVC0(push, SUBC_COMPUTE(0x02c4), 1); PUSH_DATA (push, 1); /* local memory and cstack setup */ BEGIN_NVC0(push, NVC0_COMPUTE(TEMP_ADDRESS_HIGH), 2); PUSH_DATAh(push, screen->tls->offset); PUSH_DATA (push, screen->tls->offset); BEGIN_NVC0(push, NVC0_COMPUTE(TEMP_SIZE_HIGH), 2); PUSH_DATAh(push, screen->tls->size); PUSH_DATA (push, screen->tls->size); BEGIN_NVC0(push, NVC0_COMPUTE(WARP_TEMP_ALLOC), 1); PUSH_DATA (push, 0); BEGIN_NVC0(push, NVC0_COMPUTE(LOCAL_BASE), 1); PUSH_DATA (push, 1 << 24); /* shared memory setup */ BEGIN_NVC0(push, NVC0_COMPUTE(CACHE_SPLIT), 1); PUSH_DATA (push, NVC0_COMPUTE_CACHE_SPLIT_48K_SHARED_16K_L1); BEGIN_NVC0(push, NVC0_COMPUTE(SHARED_BASE), 1); PUSH_DATA (push, 2 << 24); BEGIN_NVC0(push, NVC0_COMPUTE(SHARED_SIZE), 1); PUSH_DATA (push, 0); /* code segment setup */ BEGIN_NVC0(push, NVC0_COMPUTE(CODE_ADDRESS_HIGH), 2); PUSH_DATAh(push, screen->text->offset); PUSH_DATA (push, screen->text->offset); /* bind parameters buffer */ BEGIN_NVC0(push, NVC0_COMPUTE(CB_SIZE), 3); PUSH_DATA (push, screen->parm->size); PUSH_DATAh(push, screen->parm->offset); PUSH_DATA (push, screen->parm->offset); BEGIN_NVC0(push, NVC0_COMPUTE(CB_BIND), 1); PUSH_DATA (push, (0 << 8) | 1); /* TODO: textures & samplers */ return 0; }
int nvc0_screen_compute_setup(struct nvc0_screen *screen, struct nouveau_pushbuf *push) { struct nouveau_object *chan = screen->base.channel; struct nouveau_device *dev = screen->base.device; uint32_t obj_class; int ret; int i; switch (dev->chipset & ~0xf) { case 0xc0: case 0xd0: /* In theory, GF110+ should also support NVC8_COMPUTE_CLASS but, * in practice, a ILLEGAL_CLASS dmesg fail appears when using it. */ obj_class = NVC0_COMPUTE_CLASS; break; default: NOUVEAU_ERR("unsupported chipset: NV%02x\n", dev->chipset); return -1; } ret = nouveau_object_new(chan, 0xbeef90c0, obj_class, NULL, 0, &screen->compute); if (ret) { NOUVEAU_ERR("Failed to allocate compute object: %d\n", ret); return ret; } BEGIN_NVC0(push, SUBC_CP(NV01_SUBCHAN_OBJECT), 1); PUSH_DATA (push, screen->compute->oclass); /* hardware limit */ BEGIN_NVC0(push, NVC0_CP(MP_LIMIT), 1); PUSH_DATA (push, screen->mp_count); BEGIN_NVC0(push, NVC0_CP(CALL_LIMIT_LOG), 1); PUSH_DATA (push, 0xf); BEGIN_NVC0(push, SUBC_CP(0x02a0), 1); PUSH_DATA (push, 0x8000); /* global memory setup */ BEGIN_NVC0(push, SUBC_CP(0x02c4), 1); PUSH_DATA (push, 0); BEGIN_NIC0(push, NVC0_CP(GLOBAL_BASE), 0x100); for (i = 0; i <= 0xff; i++) PUSH_DATA (push, (0xc << 28) | (i << 16) | i); BEGIN_NVC0(push, SUBC_CP(0x02c4), 1); PUSH_DATA (push, 1); /* local memory and cstack setup */ BEGIN_NVC0(push, NVC0_CP(TEMP_ADDRESS_HIGH), 2); PUSH_DATAh(push, screen->tls->offset); PUSH_DATA (push, screen->tls->offset); BEGIN_NVC0(push, NVC0_CP(TEMP_SIZE_HIGH), 2); PUSH_DATAh(push, screen->tls->size); PUSH_DATA (push, screen->tls->size); BEGIN_NVC0(push, NVC0_CP(WARP_TEMP_ALLOC), 1); PUSH_DATA (push, 0); BEGIN_NVC0(push, NVC0_CP(LOCAL_BASE), 1); PUSH_DATA (push, 0xff << 24); /* shared memory setup */ BEGIN_NVC0(push, NVC0_CP(CACHE_SPLIT), 1); PUSH_DATA (push, NVC0_COMPUTE_CACHE_SPLIT_48K_SHARED_16K_L1); BEGIN_NVC0(push, NVC0_CP(SHARED_BASE), 1); PUSH_DATA (push, 0xfe << 24); BEGIN_NVC0(push, NVC0_CP(SHARED_SIZE), 1); PUSH_DATA (push, 0); /* code segment setup */ BEGIN_NVC0(push, NVC0_CP(CODE_ADDRESS_HIGH), 2); PUSH_DATAh(push, screen->text->offset); PUSH_DATA (push, screen->text->offset); /* textures */ BEGIN_NVC0(push, NVC0_CP(TIC_ADDRESS_HIGH), 3); PUSH_DATAh(push, screen->txc->offset); PUSH_DATA (push, screen->txc->offset); PUSH_DATA (push, NVC0_TIC_MAX_ENTRIES - 1); /* samplers */ BEGIN_NVC0(push, NVC0_CP(TSC_ADDRESS_HIGH), 3); PUSH_DATAh(push, screen->txc->offset + 65536); PUSH_DATA (push, screen->txc->offset + 65536); PUSH_DATA (push, NVC0_TSC_MAX_ENTRIES - 1); /* MS sample coordinate offsets */ BEGIN_NVC0(push, NVC0_CP(CB_SIZE), 3); PUSH_DATA (push, NVC0_CB_AUX_SIZE); PUSH_DATAh(push, screen->uniform_bo->offset + NVC0_CB_AUX_INFO(5)); PUSH_DATA (push, screen->uniform_bo->offset + NVC0_CB_AUX_INFO(5)); BEGIN_1IC0(push, NVC0_CP(CB_POS), 1 + 2 * 8); PUSH_DATA (push, NVC0_CB_AUX_MS_INFO); PUSH_DATA (push, 0); /* 0 */ PUSH_DATA (push, 0); PUSH_DATA (push, 1); /* 1 */ PUSH_DATA (push, 0); PUSH_DATA (push, 0); /* 2 */ PUSH_DATA (push, 1); PUSH_DATA (push, 1); /* 3 */ PUSH_DATA (push, 1); PUSH_DATA (push, 2); /* 4 */ PUSH_DATA (push, 0); PUSH_DATA (push, 3); /* 5 */ PUSH_DATA (push, 0); PUSH_DATA (push, 2); /* 6 */ PUSH_DATA (push, 1); PUSH_DATA (push, 3); /* 7 */ PUSH_DATA (push, 1); return 0; }