void nvc0_m2mf_copy_linear(struct nouveau_context *nv, struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom, struct nouveau_bo *src, unsigned srcoff, unsigned srcdom, unsigned size) { struct nouveau_channel *chan = nv->screen->channel; while (size) { unsigned bytes = MIN2(size, 1 << 17); MARK_RING (chan, 11, 4); BEGIN_RING(chan, RING_MF(OFFSET_OUT_HIGH), 2); OUT_RELOCh(chan, dst, dstoff, dstdom | NOUVEAU_BO_WR); OUT_RELOCl(chan, dst, dstoff, dstdom | NOUVEAU_BO_WR); BEGIN_RING(chan, RING_MF(OFFSET_IN_HIGH), 2); OUT_RELOCh(chan, src, srcoff, srcdom | NOUVEAU_BO_RD); OUT_RELOCl(chan, src, srcoff, srcdom | NOUVEAU_BO_RD); BEGIN_RING(chan, RING_MF(LINE_LENGTH_IN), 2); OUT_RING (chan, bytes); OUT_RING (chan, 1); BEGIN_RING(chan, RING_MF(EXEC), 1); OUT_RING (chan, (1 << NVC0_M2MF_EXEC_INC__SHIFT) | NVC0_M2MF_EXEC_LINEAR_IN | NVC0_M2MF_EXEC_LINEAR_OUT); srcoff += bytes; dstoff += bytes; size -= bytes; } }
static int nv50_surface_set(struct nv50_screen *screen, struct pipe_surface *ps, int dst) { struct nv50_miptree *mt = nv50_miptree(ps->texture); struct nouveau_channel *chan = screen->eng2d->channel; struct nouveau_grobj *eng2d = screen->eng2d; struct nouveau_bo *bo = nv50_miptree(ps->texture)->base.bo; int format, mthd = dst ? NV50_2D_DST_FORMAT : NV50_2D_SRC_FORMAT; int flags = NOUVEAU_BO_VRAM | (dst ? NOUVEAU_BO_WR : NOUVEAU_BO_RD); format = nv50_format(ps->format); if (format < 0) return 1; if (!bo->tile_flags) { BEGIN_RING(chan, eng2d, mthd, 2); OUT_RING (chan, format); OUT_RING (chan, 1); BEGIN_RING(chan, eng2d, mthd + 0x14, 5); OUT_RING (chan, mt->level[ps->level].pitch); OUT_RING (chan, ps->width); OUT_RING (chan, ps->height); OUT_RELOCh(chan, bo, ps->offset, flags); OUT_RELOCl(chan, bo, ps->offset, flags); } else { BEGIN_RING(chan, eng2d, mthd, 5); OUT_RING (chan, format); OUT_RING (chan, 0); OUT_RING (chan, mt->level[ps->level].tile_mode << 4); OUT_RING (chan, 1); OUT_RING (chan, 0); BEGIN_RING(chan, eng2d, mthd + 0x18, 4); OUT_RING (chan, ps->width); OUT_RING (chan, ps->height); OUT_RELOCh(chan, bo, ps->offset, flags); OUT_RELOCl(chan, bo, ps->offset, flags); } #if 0 if (dst) { BEGIN_RING(chan, eng2d, NV50_2D_CLIP_X, 4); OUT_RING (chan, 0); OUT_RING (chan, 0); OUT_RING (chan, surf->width); OUT_RING (chan, surf->height); } #endif return 0; }
static void nv50_render_condition(struct pipe_context *pipe, struct pipe_query *pq, uint mode) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_channel *chan = nv50->screen->base.channel; struct nouveau_grobj *tesla = nv50->screen->tesla; struct nv50_query *q; if (!pq) { BEGIN_RING(chan, tesla, NV50TCL_COND_MODE, 1); OUT_RING (chan, NV50TCL_COND_MODE_ALWAYS); return; } q = nv50_query(pq); if (mode == PIPE_RENDER_COND_WAIT || mode == PIPE_RENDER_COND_BY_REGION_WAIT) { /* XXX: big fence, FIFO semaphore might be better */ BEGIN_RING(chan, tesla, 0x0110, 1); OUT_RING (chan, 0); } BEGIN_RING(chan, tesla, NV50TCL_COND_ADDRESS_HIGH, 3); OUT_RELOCh(chan, q->bo, 0, NOUVEAU_BO_GART | NOUVEAU_BO_RD); OUT_RELOCl(chan, q->bo, 0, NOUVEAU_BO_GART | NOUVEAU_BO_RD); OUT_RING (chan, NV50TCL_COND_MODE_RES); }
static INLINE void nvc0_program_update_context_state(struct nvc0_context *nvc0, struct nvc0_program *prog, int stage) { struct nouveau_channel *chan = nvc0->screen->base.channel; if (prog->hdr[1]) nvc0->state.tls_required |= 1 << stage; else nvc0->state.tls_required &= ~(1 << stage); if (prog->immd_size) { const unsigned rl = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD; BEGIN_RING(chan, RING_3D(CB_SIZE), 3); /* NOTE: may overlap code of a different shader */ OUT_RING (chan, align(prog->immd_size, 0x100)); OUT_RELOCh(chan, nvc0->screen->text, prog->immd_base, rl); OUT_RELOCl(chan, nvc0->screen->text, prog->immd_base, rl); BEGIN_RING(chan, RING_3D(CB_BIND(stage)), 1); OUT_RING (chan, (14 << 4) | 1); nvc0->state.c14_bound |= 1 << stage; } else if (nvc0->state.c14_bound & (1 << stage)) { BEGIN_RING(chan, RING_3D(CB_BIND(stage)), 1); OUT_RING (chan, (14 << 4) | 0); nvc0->state.c14_bound &= ~(1 << stage); } }
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 void nv50_clear_depth_stencil(struct pipe_context *pipe, struct pipe_surface *dst, unsigned clear_flags, double depth, unsigned stencil, unsigned dstx, unsigned dsty, unsigned width, unsigned height) { struct nv50_context *nv50 = nv50_context(pipe); struct nv50_screen *screen = nv50->screen; struct nouveau_channel *chan = screen->base.channel; struct nv50_miptree *mt = nv50_miptree(dst->texture); struct nv50_surface *sf = nv50_surface(dst); struct nouveau_bo *bo = mt->base.bo; uint32_t mode = 0; if (clear_flags & PIPE_CLEAR_DEPTH) { BEGIN_RING(chan, RING_3D(CLEAR_DEPTH), 1); OUT_RINGf (chan, depth); mode |= NV50_3D_CLEAR_BUFFERS_Z; } if (clear_flags & PIPE_CLEAR_STENCIL) { BEGIN_RING(chan, RING_3D(CLEAR_STENCIL), 1); OUT_RING (chan, stencil & 0xff); mode |= NV50_3D_CLEAR_BUFFERS_S; } if (MARK_RING(chan, 17, 2)) return; BEGIN_RING(chan, RING_3D(ZETA_ADDRESS_HIGH), 5); OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RING (chan, nv50_format_table[dst->format].rt); OUT_RING (chan, mt->level[sf->base.u.tex.level].tile_mode << 4); OUT_RING (chan, 0); BEGIN_RING(chan, RING_3D(ZETA_ENABLE), 1); OUT_RING (chan, 1); BEGIN_RING(chan, RING_3D(ZETA_HORIZ), 3); OUT_RING (chan, sf->width); OUT_RING (chan, sf->height); OUT_RING (chan, (1 << 16) | 1); BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2); OUT_RING (chan, (width << 16) | dstx); OUT_RING (chan, (height << 16) | dsty); BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); OUT_RING (chan, mode); nv50->dirty |= NV50_NEW_FRAMEBUFFER; }
static void nv50_clear_render_target(struct pipe_context *pipe, struct pipe_surface *dst, const float *rgba, unsigned dstx, unsigned dsty, unsigned width, unsigned height) { struct nv50_context *nv50 = nv50_context(pipe); struct nv50_screen *screen = nv50->screen; struct nouveau_channel *chan = screen->base.channel; struct nv50_miptree *mt = nv50_miptree(dst->texture); struct nv50_surface *sf = nv50_surface(dst); struct nouveau_bo *bo = mt->base.bo; BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4); OUT_RINGf (chan, rgba[0]); OUT_RINGf (chan, rgba[1]); OUT_RINGf (chan, rgba[2]); OUT_RINGf (chan, rgba[3]); if (MARK_RING(chan, 18, 2)) return; BEGIN_RING(chan, RING_3D(RT_CONTROL), 1); OUT_RING (chan, 1); BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(0)), 5); OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RING (chan, nv50_format_table[dst->format].rt); OUT_RING (chan, mt->level[sf->base.u.tex.level].tile_mode << 4); OUT_RING (chan, 0); BEGIN_RING(chan, RING_3D(RT_HORIZ(0)), 2); OUT_RING (chan, sf->width); OUT_RING (chan, sf->height); BEGIN_RING(chan, RING_3D(RT_ARRAY_MODE), 1); OUT_RING (chan, 1); /* NOTE: only works with D3D clear flag (5097/0x143c bit 4) */ BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2); OUT_RING (chan, (width << 16) | dstx); OUT_RING (chan, (height << 16) | dsty); BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); OUT_RING (chan, 0x3c); nv50->dirty |= NV50_NEW_FRAMEBUFFER; }
static void nv50_query_end(struct pipe_context *pipe, struct pipe_query *pq) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_channel *chan = nv50->screen->base.channel; struct nouveau_grobj *tesla = nv50->screen->tesla; struct nv50_query *q = nv50_query(pq); WAIT_RING (chan, 5); BEGIN_RING(chan, tesla, NV50TCL_QUERY_ADDRESS_HIGH, 4); OUT_RELOCh(chan, q->bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RELOCl(chan, q->bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RING (chan, 0x00000000); OUT_RING (chan, 0x0100f002); FIRE_RING (chan); }
static void nv50_query_end(struct pipe_context *pipe, struct pipe_query *pq) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_channel *chan = nv50->screen->nvws->channel; struct nouveau_grobj *tesla = nv50->screen->tesla; struct nv50_query *q = nv50_query(pq); struct nouveau_bo *bo = nv50->screen->nvws->get_bo(q->buffer); WAIT_RING (chan, 5); BEGIN_RING(chan, tesla, 0x1b00, 4); OUT_RELOCh(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RING (chan, 0x00000000); OUT_RING (chan, 0x0100f002); FIRE_RING (chan); }
static void nv50_query_end(struct pipe_context *pipe, struct pipe_query *pq) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_channel *chan = nv50->screen->base.channel; struct nouveau_grobj *tesla = nv50->screen->tesla; struct nv50_query *q = nv50_query(pq); MARK_RING (chan, 5, 2); /* flush on lack of space or relocs */ BEGIN_RING(chan, tesla, NV50TCL_QUERY_ADDRESS_HIGH, 4); OUT_RELOCh(chan, q->bo, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR); OUT_RELOCl(chan, q->bo, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR); OUT_RING (chan, 0x00000000); OUT_RING (chan, 0x0100f002); BEGIN_RING(chan, tesla, NV50TCL_SAMPLECNT_ENABLE, 1); OUT_RING (chan, 0); }
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 void instance_step(struct nv50_context *nv50, struct instance *a) { struct nouveau_channel *chan = nv50->screen->tesla->channel; struct nouveau_grobj *tesla = nv50->screen->tesla; int i; for (i = 0; i < nv50->vtxelt->num_elements; i++) { if (!a[i].divisor) continue; BEGIN_RING(chan, tesla, NV50TCL_VERTEX_ARRAY_START_HIGH(i), 2); OUT_RELOCh(chan, a[i].bo, a[i].delta, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART); OUT_RELOCl(chan, a[i].bo, a[i].delta, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART); if (++a[i].step == a[i].divisor) { a[i].step = 0; a[i].delta += a[i].stride; } } }
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 nvc0_cb_push(struct nouveau_context *nv, struct nouveau_bo *bo, unsigned domain, unsigned base, unsigned size, unsigned offset, unsigned words, const uint32_t *data) { struct nouveau_channel *chan = nv->screen->channel; assert(!(offset & 3)); size = align(size, 0x100); MARK_RING (chan, 16, 2); BEGIN_RING(chan, RING_3D(CB_SIZE), 3); OUT_RING (chan, size); OUT_RELOCh(chan, bo, base, domain | NOUVEAU_BO_WR); OUT_RELOCl(chan, bo, base, domain | NOUVEAU_BO_WR); while (words) { unsigned nr = AVAIL_RING(chan); nr = MIN2(nr, words); nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN - 1); BEGIN_RING_1I(chan, RING_3D(CB_POS), nr + 1); OUT_RING (chan, offset); OUT_RINGp (chan, data, nr); words -= nr; data += nr; offset += nr * 4; if (words) { MARK_RING(chan, 6, 1); nouveau_bo_validate(chan, bo, domain | NOUVEAU_BO_WR); } } }
static inline Bool NVAccelDownloadM2MF(PixmapPtr pspix, int x, int y, int w, int h, char *dst, unsigned dst_pitch) { ScrnInfoPtr pScrn = xf86Screens[pspix->drawable.pScreen->myNum]; NVPtr pNv = NVPTR(pScrn); struct nouveau_channel *chan = pNv->chan; struct nouveau_grobj *m2mf = pNv->NvMemFormat; struct nouveau_bo *bo = nouveau_pixmap_bo(pspix); unsigned cpp = pspix->drawable.bitsPerPixel / 8; unsigned line_len = w * cpp; unsigned src_offset = 0, src_pitch = 0, linear = 0; /* Maximum DMA transfer */ unsigned line_count = pNv->GART->size / line_len; if (!nv50_style_tiled_pixmap(pspix)) { linear = 1; src_pitch = exaGetPixmapPitch(pspix); src_offset += (y * src_pitch) + (x * cpp); } /* HW limitations */ if (line_count > 2047) line_count = 2047; while (h) { int i; char *src; if (line_count > h) line_count = h; if (MARK_RING(chan, 32, 6)) return FALSE; BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2); if (OUT_RELOCo(chan, bo, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD) || OUT_RELOCo(chan, pNv->GART, NOUVEAU_BO_GART | NOUVEAU_BO_WR)) { MARK_UNDO(chan); return FALSE; } if (pNv->Architecture >= NV_ARCH_50) { if (!linear) { BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN, 7); OUT_RING (chan, 0); OUT_RING (chan, bo->tile_mode << 4); OUT_RING (chan, pspix->drawable.width * cpp); OUT_RING (chan, pspix->drawable.height); OUT_RING (chan, 1); OUT_RING (chan, 0); OUT_RING (chan, (y << 16) | (x * cpp)); } else { BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN, 1); OUT_RING (chan, 1); } BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT, 1); OUT_RING (chan, 1); BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN_HIGH, 2); if (OUT_RELOCh(chan, bo, src_offset, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD) || OUT_RELOCh(chan, pNv->GART, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR)) { MARK_UNDO(chan); return FALSE; } } BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); if (OUT_RELOCl(chan, bo, src_offset, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD) || OUT_RELOCl(chan, pNv->GART, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR)) { MARK_UNDO(chan); return FALSE; } OUT_RING (chan, src_pitch); OUT_RING (chan, line_len); OUT_RING (chan, line_len); OUT_RING (chan, line_count); OUT_RING (chan, (1<<8)|1); OUT_RING (chan, 0); if (nouveau_bo_map(pNv->GART, NOUVEAU_BO_RD)) { MARK_UNDO(chan); return FALSE; } src = pNv->GART->map; if (dst_pitch == line_len) { memcpy(dst, src, dst_pitch * line_count); dst += dst_pitch * line_count; } else { for (i = 0; i < line_count; i++) { memcpy(dst, src, line_len); src += line_len; dst += dst_pitch; } } nouveau_bo_unmap(pNv->GART); if (linear) src_offset += line_count * src_pitch; h -= line_count; y += line_count; } return TRUE; }
static int nv50_2d_texture_set(struct nouveau_channel *chan, int dst, struct nv50_miptree *mt, unsigned level, unsigned layer) { struct nouveau_bo *bo = mt->base.bo; uint32_t width, height, depth; uint32_t format; uint32_t mthd = dst ? NV50_2D_DST_FORMAT : NV50_2D_SRC_FORMAT; uint32_t flags = mt->base.domain | (dst ? NOUVEAU_BO_WR : NOUVEAU_BO_RD); uint32_t offset = mt->level[level].offset; format = nv50_2d_format(mt->base.base.format); if (!format) { NOUVEAU_ERR("invalid/unsupported surface format: %s\n", util_format_name(mt->base.base.format)); return 1; } width = u_minify(mt->base.base.width0, level) << mt->ms_x; height = u_minify(mt->base.base.height0, level) << mt->ms_y; offset = mt->level[level].offset; if (!mt->layout_3d) { offset += mt->layer_stride * layer; depth = 1; layer = 0; } else { depth = u_minify(mt->base.base.depth0, level); } if (!(bo->tile_flags & NOUVEAU_BO_TILE_LAYOUT_MASK)) { BEGIN_RING(chan, RING_2D_(mthd), 2); OUT_RING (chan, format); OUT_RING (chan, 1); BEGIN_RING(chan, RING_2D_(mthd + 0x14), 5); OUT_RING (chan, mt->level[level].pitch); OUT_RING (chan, width); OUT_RING (chan, height); OUT_RELOCh(chan, bo, offset, flags); OUT_RELOCl(chan, bo, offset, flags); } else { BEGIN_RING(chan, RING_2D_(mthd), 5); OUT_RING (chan, format); OUT_RING (chan, 0); OUT_RING (chan, mt->level[level].tile_mode << 4); OUT_RING (chan, depth); OUT_RING (chan, layer); BEGIN_RING(chan, RING_2D_(mthd + 0x18), 4); OUT_RING (chan, width); OUT_RING (chan, height); OUT_RELOCh(chan, bo, offset, flags); OUT_RELOCl(chan, bo, offset, flags); } #if 0 if (dst) { BEGIN_RING(chan, RING_2D_(NV50_2D_CLIP_X), 4); OUT_RING (chan, 0); OUT_RING (chan, 0); OUT_RING (chan, width); OUT_RING (chan, height); } #endif return 0; }
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; unsigned line_dwords = (w * cpp + 3) / 4; reloc |= NOUVEAU_BO_WR; MARK_RING (chan, 32, 2); /* flush on lack of space or relocs */ 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_BITMAP_ENABLE, 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 (AVAIL_RING(chan) <= 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(AVAIL_RING(chan) > nr); BEGIN_RING(chan, eng2d, NV50_2D_SIFC_DATA | (2 << 29), nr); OUT_RINGp (chan, p, nr); p += nr; count -= nr; } src = (uint8_t *) src + src_pitch; } }
static void nv50_transfer_rect_m2mf(struct pipe_screen *pscreen, struct nouveau_bo *src_bo, unsigned src_offset, int src_pitch, unsigned src_tile_mode, int sx, int sy, int sz, int sw, int sh, int sd, struct nouveau_bo *dst_bo, unsigned dst_offset, int dst_pitch, unsigned dst_tile_mode, int dx, int dy, int dz, int dw, int dh, int dd, int cpp, int width, int height, unsigned src_reloc, unsigned dst_reloc) { struct nv50_screen *screen = nv50_screen(pscreen); struct nouveau_channel *chan = screen->m2mf->channel; struct nouveau_grobj *m2mf = screen->m2mf; src_reloc |= NOUVEAU_BO_RD; dst_reloc |= NOUVEAU_BO_WR; WAIT_RING (chan, 14); if (!src_bo->tile_flags) { BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN, 1); OUT_RING (chan, 1); BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_PITCH_IN, 1); OUT_RING (chan, src_pitch); src_offset += (sy * src_pitch) + (sx * cpp); } else { BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN, 6); OUT_RING (chan, 0); OUT_RING (chan, src_tile_mode << 4); OUT_RING (chan, sw * cpp); OUT_RING (chan, sh); OUT_RING (chan, sd); OUT_RING (chan, sz); /* copying only 1 zslice per call */ } if (!dst_bo->tile_flags) { BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT, 1); OUT_RING (chan, 1); BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_PITCH_OUT, 1); OUT_RING (chan, dst_pitch); dst_offset += (dy * dst_pitch) + (dx * cpp); } else { BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT, 6); OUT_RING (chan, 0); OUT_RING (chan, dst_tile_mode << 4); OUT_RING (chan, dw * cpp); OUT_RING (chan, dh); OUT_RING (chan, dd); OUT_RING (chan, dz); /* copying only 1 zslice per call */ } while (height) { int line_count = height > 2047 ? 2047 : height; MARK_RING (chan, 15, 4); /* flush on lack of space or relocs */ BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN_HIGH, 2); OUT_RELOCh(chan, src_bo, src_offset, src_reloc); OUT_RELOCh(chan, dst_bo, dst_offset, dst_reloc); BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 2); OUT_RELOCl(chan, src_bo, src_offset, src_reloc); OUT_RELOCl(chan, dst_bo, dst_offset, dst_reloc); if (src_bo->tile_flags) { BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_TILING_POSITION_IN, 1); OUT_RING (chan, (sy << 16) | (sx * cpp)); } else { src_offset += (line_count * src_pitch); } if (dst_bo->tile_flags) { BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_TILING_POSITION_OUT, 1); OUT_RING (chan, (dy << 16) | (dx * cpp)); } else { dst_offset += (line_count * dst_pitch); } BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_LINE_LENGTH_IN, 4); OUT_RING (chan, width * cpp); OUT_RING (chan, line_count); OUT_RING (chan, 0x00000101); OUT_RING (chan, 0); FIRE_RING (chan); height -= line_count; sy += line_count; dy += line_count; } }
void nvc0_m2mf_transfer_rect(struct pipe_screen *pscreen, const struct nv50_m2mf_rect *dst, const struct nv50_m2mf_rect *src, uint32_t nblocksx, uint32_t nblocksy) { struct nouveau_channel *chan = nouveau_screen(pscreen)->channel; const int cpp = dst->cpp; uint32_t src_ofst = src->base; uint32_t dst_ofst = dst->base; uint32_t height = nblocksy; uint32_t sy = src->y; uint32_t dy = dst->y; uint32_t exec = (1 << 20); assert(dst->cpp == src->cpp); if (nouveau_bo_tile_layout(src->bo)) { BEGIN_RING(chan, RING_MF(TILING_MODE_IN), 5); OUT_RING (chan, src->tile_mode); OUT_RING (chan, src->width * cpp); OUT_RING (chan, src->height); OUT_RING (chan, src->depth); OUT_RING (chan, src->z); } else { src_ofst += src->y * src->pitch + src->x * cpp; BEGIN_RING(chan, RING_MF(PITCH_IN), 1); OUT_RING (chan, src->width * cpp); exec |= NVC0_M2MF_EXEC_LINEAR_IN; } if (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); } else { dst_ofst += dst->y * dst->pitch + dst->x * cpp; BEGIN_RING(chan, RING_MF(PITCH_OUT), 1); OUT_RING (chan, dst->width * cpp); exec |= NVC0_M2MF_EXEC_LINEAR_OUT; } while (height) { int line_count = height > 2047 ? 2047 : height; MARK_RING (chan, 17, 4); BEGIN_RING(chan, RING_MF(OFFSET_IN_HIGH), 2); OUT_RELOCh(chan, src->bo, src_ofst, src->domain | NOUVEAU_BO_RD); OUT_RELOCl(chan, src->bo, src_ofst, src->domain | NOUVEAU_BO_RD); BEGIN_RING(chan, RING_MF(OFFSET_OUT_HIGH), 2); OUT_RELOCh(chan, dst->bo, dst_ofst, dst->domain | NOUVEAU_BO_WR); OUT_RELOCl(chan, dst->bo, dst_ofst, dst->domain | NOUVEAU_BO_WR); if (!(exec & NVC0_M2MF_EXEC_LINEAR_IN)) { BEGIN_RING(chan, RING_MF(TILING_POSITION_IN_X), 2); OUT_RING (chan, src->x * cpp); OUT_RING (chan, sy); } else { src_ofst += line_count * src->pitch; } if (!(exec & NVC0_M2MF_EXEC_LINEAR_OUT)) { BEGIN_RING(chan, RING_MF(TILING_POSITION_OUT_X), 2); OUT_RING (chan, dst->x * cpp); OUT_RING (chan, dy); } else { dst_ofst += line_count * dst->pitch; } BEGIN_RING(chan, RING_MF(LINE_LENGTH_IN), 2); OUT_RING (chan, nblocksx * cpp); OUT_RING (chan, line_count); BEGIN_RING(chan, RING_MF(EXEC), 1); OUT_RING (chan, exec); height -= line_count; sy += line_count; dy += line_count; } }