static void nv50_surface_fill(struct pipe_context *pipe, struct pipe_surface *dest, unsigned destx, unsigned desty, unsigned width, unsigned height, unsigned value) { struct nv50_context *nv50 = nv50_context(pipe); struct nv50_screen *screen = nv50->screen; struct nouveau_channel *chan = screen->eng2d->channel; struct nouveau_grobj *eng2d = screen->eng2d; int format, ret; format = nv50_format(dest->format); if (format < 0) return; WAIT_RING (chan, 32); ret = nv50_surface_set(screen, dest, 1); if (ret) return; BEGIN_RING(chan, eng2d, 0x0580, 3); OUT_RING (chan, 4); OUT_RING (chan, format); OUT_RING (chan, value); BEGIN_RING(chan, eng2d, NV50_2D_RECT_X1, 4); OUT_RING (chan, destx); OUT_RING (chan, desty); OUT_RING (chan, width); OUT_RING (chan, height); }
void NV10EXAComposite(PixmapPtr pix_dst, int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, int width, int height) { ScrnInfoPtr pScrn = xf86Screens[pix_dst->drawable.pScreen->myNum]; NVPtr pNv = NVPTR(pScrn); struct nouveau_channel *chan = pNv->chan; struct nouveau_grobj *celsius = pNv->Nv3D; PicturePtr mask = pNv->pmpict, src = pNv->pspict; PictVector dstq[4] = QUAD(dstX, dstY, width, height), maskq[4] = QUAD(maskX, maskY, width, height), srcq[4] = QUAD(srcX, srcY, width, height); MAP(transform_vertex, src->transform, srcq); if (mask) MAP(transform_vertex, mask->transform, maskq); WAIT_RING (chan, 64); BEGIN_RING(chan, celsius, NV10TCL_VERTEX_BEGIN_END, 1); OUT_RING (chan, NV10TCL_VERTEX_BEGIN_END_QUADS); MAP(emit_vertex, pNv, dstq, srcq, mask ? maskq : NULL); BEGIN_RING(chan, celsius, NV10TCL_VERTEX_BEGIN_END, 1); OUT_RING (chan, NV10TCL_VERTEX_BEGIN_END_STOP); }
static void setup_hierz_buffer(struct gl_context *ctx) { struct nouveau_channel *chan = context_chan(ctx); struct nouveau_grobj *celsius = context_eng3d(ctx); struct nouveau_bo_context *bctx = context_bctx(ctx, HIERZ); struct gl_framebuffer *fb = ctx->DrawBuffer; struct nouveau_framebuffer *nfb = to_nouveau_framebuffer(fb); unsigned pitch = align(fb->Width, 128), height = align(fb->Height, 2), size = pitch * height; if (!nfb->hierz.bo || nfb->hierz.bo->size != size) { nouveau_bo_ref(NULL, &nfb->hierz.bo); nouveau_bo_new_tile(context_dev(ctx), NOUVEAU_BO_VRAM, 0, size, 0, NOUVEAU_BO_TILE_ZETA, &nfb->hierz.bo); } nouveau_bo_markl(bctx, celsius, NV17_3D_HIERZ_OFFSET, nfb->hierz.bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR); WAIT_RING(chan, 9); BEGIN_RING(chan, celsius, NV17_3D_HIERZ_WINDOW_X, 4); OUT_RINGf(chan, - 1792); OUT_RINGf(chan, - 2304 + fb->Height); OUT_RINGf(chan, fb->_DepthMaxF / 2); OUT_RINGf(chan, 0); BEGIN_RING(chan, celsius, NV17_3D_HIERZ_PITCH, 1); OUT_RING(chan, pitch); BEGIN_RING(chan, celsius, NV17_3D_HIERZ_ENABLE, 1); OUT_RING(chan, 1); }
static inline void nv10ExtendPrimitive(struct nouveau_context* nmesa, int size) { /* make sure there's enough room. if not, wait */ if (RING_AVAILABLE()<size) { WAIT_RING(nmesa,size); } }
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); }
int nv50_surface_do_copy(struct nv50_screen *screen, struct pipe_surface *dst, int dx, int dy, struct pipe_surface *src, int sx, int sy, int w, int h) { struct nouveau_channel *chan = screen->eng2d->channel; struct nouveau_grobj *eng2d = screen->eng2d; int ret; WAIT_RING (chan, 32); ret = nv50_surface_set(screen, dst, 1); if (ret) return ret; ret = nv50_surface_set(screen, src, 0); if (ret) return ret; BEGIN_RING(chan, eng2d, 0x088c, 1); OUT_RING (chan, 0); BEGIN_RING(chan, eng2d, NV50_2D_BLIT_DST_X, 4); OUT_RING (chan, dx); OUT_RING (chan, dy); OUT_RING (chan, w); OUT_RING (chan, h); BEGIN_RING(chan, eng2d, 0x08c0, 4); OUT_RING (chan, 0); OUT_RING (chan, 1); OUT_RING (chan, 0); OUT_RING (chan, 1); BEGIN_RING(chan, eng2d, 0x08d0, 4); OUT_RING (chan, 0); OUT_RING (chan, sx); OUT_RING (chan, 0); OUT_RING (chan, sy); return 0; }
void nvfx_vbo_swtnl_validate(struct nvfx_context *nvfx) { struct nouveau_channel* chan = nvfx->screen->base.channel; unsigned num_outputs = nvfx->vertprog->draw_elements; int elements = MAX2(num_outputs, nvfx->hw_vtxelt_nr); if (!elements) return; WAIT_RING(chan, (1 + 6 + 1 + 2) + elements * 2); OUT_RING(chan, RING_3D(NV30_3D_VTXFMT(0), elements)); for(unsigned i = 0; i < num_outputs; ++i) OUT_RING(chan, (4 << NV30_3D_VTXFMT_SIZE__SHIFT) | NV30_3D_VTXFMT_TYPE_V32_FLOAT); for(unsigned i = num_outputs; i < elements; ++i) OUT_RING(chan, NV30_3D_VTXFMT_TYPE_V32_FLOAT); if(nvfx->is_nv4x) { unsigned i; /* seems to be some kind of cache flushing */ for(i = 0; i < 3; ++i) { OUT_RING(chan, RING_3D(0x1718, 1)); OUT_RING(chan, 0); } } OUT_RING(chan, RING_3D(NV30_3D_VTXBUF(0), elements)); for (unsigned i = 0; i < elements; i++) OUT_RING(chan, 0); OUT_RING(chan, RING_3D(0x1710, 1)); OUT_RING(chan, 0); nvfx->hw_vtxelt_nr = num_outputs; nvfx->relocs_needed &=~ NVFX_RELOCATE_VTXBUF; }
void NV40EXAComposite(PixmapPtr pdPix, int srcX , int srcY, int maskX, int maskY, int dstX , int dstY, int width, int height) { ScrnInfoPtr pScrn = xf86Screens[pdPix->drawable.pScreen->myNum]; NVPtr pNv = NVPTR(pScrn); struct nouveau_channel *chan = pNv->chan; struct nouveau_grobj *curie = pNv->Nv3D; float sX0, sX1, sX2, sY0, sY1, sY2; float mX0, mX1, mX2, mY0, mY1, mY2; NV40EXA_STATE; WAIT_RING(chan, 64); /* We're drawing a triangle, we need to scissor it to a quad. */ /* The scissors are here for a good reason, we don't get the full * image, but just a part. */ /* Handling the cliprects is done for us already. */ BEGIN_RING(chan, curie, NV40TCL_SCISSOR_HORIZ, 2); OUT_RING (chan, (width << 16) | dstX); OUT_RING (chan, (height << 16) | dstY); BEGIN_RING(chan, curie, NV40TCL_BEGIN_END, 1); OUT_RING (chan, NV40TCL_BEGIN_END_TRIANGLES); NV40EXATransformCoord(state->unit[0].transform, srcX, srcY - height, state->unit[0].width, state->unit[0].height, &sX0, &sY0); NV40EXATransformCoord(state->unit[0].transform, srcX, srcY + height, state->unit[0].width, state->unit[0].height, &sX1, &sY1); NV40EXATransformCoord(state->unit[0].transform, srcX + 2*width, srcY + height, state->unit[0].width, state->unit[0].height, &sX2, &sY2); if (state->have_mask) { NV40EXATransformCoord(state->unit[1].transform, maskX, maskY - height, state->unit[1].width, state->unit[1].height, &mX0, &mY0); NV40EXATransformCoord(state->unit[1].transform, maskX, maskY + height, state->unit[1].width, state->unit[1].height, &mX1, &mY1); NV40EXATransformCoord(state->unit[1].transform, maskX + 2*width, maskY + height, state->unit[1].width, state->unit[1].height, &mX2, &mY2); CV_OUTm(sX0, sY0, mX0, mY0, dstX, dstY - height); CV_OUTm(sX1, sY1, mX1, mY1, dstX, dstY + height); CV_OUTm(sX2, sY2, mX2, mY2, dstX + 2*width, dstY + height); } else { CV_OUT(sX0, sY0, dstX, dstY - height); CV_OUT(sX1, sY1, dstX, dstY + height); CV_OUT(sX2, sY2, dstX + 2*width, dstY + height); } BEGIN_RING(chan, curie, NV40TCL_BEGIN_END, 1); OUT_RING (chan, NV40TCL_BEGIN_END_STOP); }
void nvfx_push_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct nvfx_context *nvfx = nvfx_context(pipe); struct nouveau_channel *chan = nvfx->screen->base.channel; struct push_context ctx; struct util_split_prim s; unsigned instances_left = info->instance_count; int vtx_value; unsigned hw_mode = nvgl_primitive(info->mode); int i; struct { uint8_t* map; unsigned step; } per_instance[16]; unsigned p_overhead = 64 /* magic fix */ + 4 /* begin/end */ + 4; /* potential edgeflag enable/disable */ ctx.chan = nvfx->screen->base.channel; ctx.translate = nvfx->vtxelt->translate; ctx.idxbuf = NULL; ctx.vertex_length = nvfx->vtxelt->vertex_length; ctx.max_vertices_per_packet = nvfx->vtxelt->max_vertices_per_packet; ctx.edgeflag = 0.5f; // TODO: figure out if we really want to handle this, and do so in that case ctx.edgeflag_attr = 0xff; // nvfx->vertprog->cfg.edgeflag_in; if(!nvfx->use_vertex_buffers) { for(i = 0; i < nvfx->vtxelt->num_per_vertex_buffer_infos; ++i) { struct nvfx_per_vertex_buffer_info* vbi = &nvfx->vtxelt->per_vertex_buffer_info[i]; struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[vbi->vertex_buffer_index]; uint8_t* data = nvfx_buffer(vb->buffer)->data + vb->buffer_offset; if(info->indexed) data += info->index_bias * vb->stride; ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0); } if(ctx.edgeflag_attr < 16) vtx_value = -(ctx.vertex_length + 3); /* vertex data and edgeflag header and value */ else { p_overhead += 1; /* initial vertex_data header */ vtx_value = -ctx.vertex_length; /* vertex data and edgeflag header and value */ } if (info->indexed) { // XXX: this case and is broken and probably need a new VTX_ATTR push path if (nvfx->idxbuf.index_size == 1) s.emit = emit_vertices_lookup8; else if (nvfx->idxbuf.index_size == 2) s.emit = emit_vertices_lookup16; else s.emit = emit_vertices_lookup32; } else s.emit = emit_vertices; } else { if(!info->indexed || nvfx->use_index_buffer) { s.emit = info->indexed ? emit_ib_ranges : emit_vb_ranges; p_overhead += 3; vtx_value = 0; } else if (nvfx->idxbuf.index_size == 4) { s.emit = emit_elt32; p_overhead += 1; vtx_value = 8; } else { s.emit = (nvfx->idxbuf.index_size == 2) ? emit_elt16 : emit_elt8; p_overhead += 3; vtx_value = 7; } } ctx.idxbias = info->index_bias; if(nvfx->use_vertex_buffers) ctx.idxbias -= nvfx->base_vertex; /* map index buffer, if present */ if (info->indexed && !nvfx->use_index_buffer) ctx.idxbuf = nvfx_buffer(nvfx->idxbuf.buffer)->data + nvfx->idxbuf.offset; s.priv = &ctx; s.edge = emit_edgeflag; for (i = 0; i < nvfx->vtxelt->num_per_instance; ++i) { struct nvfx_per_instance_element *ve = &nvfx->vtxelt->per_instance[i]; struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->base.vertex_buffer_index]; float v[4]; per_instance[i].step = info->start_instance % ve->instance_divisor; per_instance[i].map = nvfx_buffer(vb->buffer)->data + vb->buffer_offset + ve->base.src_offset; nvfx->vtxelt->per_instance[i].base.fetch_rgba_float(v, per_instance[i].map, 0, 0); WAIT_RING(chan, 5); nvfx_emit_vtx_attr(chan, nvfx->vtxelt->per_instance[i].base.idx, v, nvfx->vtxelt->per_instance[i].base.ncomp); } /* per-instance loop */ while (instances_left--) { int max_verts; boolean done; util_split_prim_init(&s, info->mode, info->start, info->count); nvfx_state_emit(nvfx); for(;;) { max_verts = AVAIL_RING(chan); max_verts -= p_overhead; /* if vtx_value < 0, each vertex is -vtx_value words long * otherwise, each vertex is 2^(vtx_value) / 255 words long (this is an approximation) */ if(vtx_value < 0) { max_verts /= -vtx_value; max_verts -= (max_verts >> 10); /* vertex data headers */ } else { if(max_verts >= (1 << 23)) /* avoid overflow here */ max_verts = (1 << 23); max_verts = (max_verts * 255) >> vtx_value; } //printf("avail %u max_verts %u\n", AVAIL_RING(chan), max_verts); if(max_verts >= 16) { /* 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) { OUT_RING(chan, RING_3D(0x1dac, 1)); OUT_RING(chan, 0); } } OUT_RING(chan, RING_3D(NV30_3D_VERTEX_BEGIN_END, 1)); OUT_RING(chan, hw_mode); done = util_split_prim_next(&s, max_verts); OUT_RING(chan, RING_3D(NV30_3D_VERTEX_BEGIN_END, 1)); OUT_RING(chan, 0); if(done) break; } FIRE_RING(chan); nvfx_state_emit(nvfx); }
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; } }