static void nvfx_ucp_validate(struct nvfx_context* nvfx) { struct nouveau_channel* chan = nvfx->screen->base.channel; struct nouveau_grobj *eng3d = nvfx->screen->eng3d; unsigned enables[7] = { 0, NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE0, NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE0 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE1, NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE0 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE1 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE2, NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE0 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE1 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE2 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE3, NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE0 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE1 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE2 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE3 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE4, NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE0 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE1 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE2 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE3 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE4 | NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE5, }; if(!nvfx->use_vp_clipping) { BEGIN_RING(chan, eng3d, NV30_3D_VP_CLIP_PLANES_ENABLE, 1); OUT_RING(chan, 0); BEGIN_RING(chan, eng3d, NV30_3D_VP_CLIP_PLANE(0, 0), nvfx->clip.nr * 4); OUT_RINGp(chan, &nvfx->clip.ucp[0][0], nvfx->clip.nr * 4); } BEGIN_RING(chan, eng3d, NV30_3D_VP_CLIP_PLANES_ENABLE, 1); OUT_RING(chan, enables[nvfx->clip.nr]); }
static INLINE void emit_elt32(void* priv, unsigned start, unsigned vc) { struct push_context* ctx = priv; struct nouveau_channel *chan = ctx->chan; uint32_t *elts = (uint32_t *)ctx->idxbuf + start; int idxbias = ctx->idxbias; while (vc) { unsigned push = MIN2(vc, 2047); OUT_RING(chan, RING_3D_NI(NV30_3D_VB_ELEMENT_U32, push)); assert(AVAIL_RING(chan) >= push); if(idxbias) { for(unsigned i = 0; i < push; ++i) OUT_RING(chan, elts[i] + idxbias); } else OUT_RINGp(chan, elts, push); vc -= push; elts += push; } }
void nv10_emit_viewport(struct gl_context *ctx, int emit) { struct nouveau_channel *chan = context_chan(ctx); struct nouveau_grobj *celsius = context_eng3d(ctx); struct gl_viewport_attrib *vp = &ctx->Viewport; struct gl_framebuffer *fb = ctx->DrawBuffer; float a[4] = {}; get_viewport_translate(ctx, a); a[0] -= 2048; a[1] -= 2048; if (nv10_use_viewport_zclear(ctx)) a[2] = nv10_transform_depth(ctx, (vp->Far + vp->Near) / 2); BEGIN_RING(chan, celsius, NV10_3D_VIEWPORT_TRANSLATE_X, 4); OUT_RINGp(chan, a, 4); BEGIN_RING(chan, celsius, NV10_3D_VIEWPORT_CLIP_HORIZ(0), 1); OUT_RING(chan, (fb->Width - 1) << 16 | 0x08000800); BEGIN_RING(chan, celsius, NV10_3D_VIEWPORT_CLIP_VERT(0), 1); OUT_RING(chan, (fb->Height - 1) << 16 | 0x08000800); context_dirty(ctx, PROJECTION); }
void nv50_gp_linkage_validate(struct nv50_context *nv50) { struct nouveau_channel *chan = nv50->screen->base.channel; struct nv50_program *vp = nv50->vertprog; struct nv50_program *gp = nv50->gmtyprog; int m = 0; int n; uint8_t map[64]; if (!gp) return; memset(map, 0, sizeof(map)); m = nv50_vp_gp_mapping(map, m, vp, gp); n = (m + 3) / 4; BEGIN_RING(chan, RING_3D(VP_GP_BUILTIN_ATTR_EN), 1); OUT_RING (chan, vp->vp.attrs[2] | gp->vp.attrs[2]); BEGIN_RING(chan, RING_3D(VP_RESULT_MAP_SIZE), 1); OUT_RING (chan, m); BEGIN_RING(chan, RING_3D(VP_RESULT_MAP(0)), n); OUT_RINGp (chan, map, n); }
static inline void nv10_render_line(GLcontext *ctx,GLuint v1,GLuint v2) { struct nouveau_context *nmesa = NOUVEAU_CONTEXT(ctx); GLubyte *vertptr = (GLubyte *)nmesa->verts; GLuint vertsize = nmesa->vertex_size; GLuint size_dword = vertsize*(2)/4; /* OUT_RINGp wants size in DWORDS */ vertsize >>= 2; nv10ExtendPrimitive(nmesa, size_dword); nv10StartPrimitive(nmesa,GL_LINES+1,size_dword); OUT_RINGp((nouveauVertex*)(vertptr+(v1*vertsize)),vertsize); OUT_RINGp((nouveauVertex*)(vertptr+(v2*vertsize)),vertsize); nv10FinishPrimitive(nmesa); }
void nv20_emit_tex_gen(GLcontext *ctx, int emit) { const int i = emit - NOUVEAU_STATE_TEX_GEN0; struct nouveau_context *nctx = to_nouveau_context(ctx); struct nouveau_channel *chan = context_chan(ctx); struct nouveau_grobj *kelvin = context_eng3d(ctx); struct gl_texture_unit *unit = &ctx->Texture.Unit[i]; int j; for (j = 0; j < 4; j++) { if (nctx->fallback == HWTNL && (unit->TexGenEnabled & 1 << j)) { struct gl_texgen *coord = get_texgen_coord(unit, j); float *k = get_texgen_coeff(coord); if (k) { BEGIN_RING(chan, kelvin, TX_GEN_COEFF(i, j), 4); OUT_RINGp(chan, k, 4); } BEGIN_RING(chan, kelvin, TX_GEN_MODE(i, j), 1); OUT_RING(chan, nvgl_texgen_mode(coord->Mode)); } else { BEGIN_RING(chan, kelvin, TX_GEN_MODE(i, j), 1); OUT_RING(chan, 0); } } }
void nvfx_state_stipple_validate(struct nvfx_context *nvfx) { struct nouveau_channel *chan = nvfx->screen->base.channel; struct nouveau_grobj *eng3d = nvfx->screen->eng3d; BEGIN_RING(chan, eng3d, NV30_3D_POLYGON_STIPPLE_PATTERN(0), 32); OUT_RINGp(chan, nvfx->stipple, 32); }
static void nv50_sprite_coords_validate(struct nv50_context *nv50) { struct nouveau_channel *chan = nv50->screen->base.channel; uint32_t pntc[8], mode; struct nv50_program *fp = nv50->fragprog; unsigned i, c; unsigned m = (nv50->state.interpolant_ctrl >> 8) & 0xff; if (!nv50->rast->pipe.point_quad_rasterization) { if (nv50->state.point_sprite) { BEGIN_RING(chan, RING_3D(POINT_COORD_REPLACE_MAP(0)), 8); for (i = 0; i < 8; ++i) OUT_RING(chan, 0); nv50->state.point_sprite = FALSE; } return; } else { nv50->state.point_sprite = TRUE; } memset(pntc, 0, sizeof(pntc)); for (i = 0; i < fp->in_nr; i++) { unsigned n = util_bitcount(fp->in[i].mask); if (fp->in[i].sn != TGSI_SEMANTIC_GENERIC) { m += n; continue; } if (!(nv50->rast->pipe.sprite_coord_enable & (1 << fp->in[i].si))) { m += n; continue; } for (c = 0; c < 4; ++c) { if (fp->in[i].mask & (1 << c)) { pntc[m / 8] |= (c + 1) << ((m % 8) * 4); ++m; } } } if (nv50->rast->pipe.sprite_coord_mode == PIPE_SPRITE_COORD_LOWER_LEFT) mode = 0x00; else mode = 0x10; BEGIN_RING(chan, RING_3D(POINT_SPRITE_CTRL), 1); OUT_RING (chan, mode); BEGIN_RING(chan, RING_3D(POINT_COORD_REPLACE_MAP(0)), 8); OUT_RINGp (chan, pntc, 8); }
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 inline void nv10_render_generic_primitive_verts(GLcontext *ctx,GLuint start,GLuint count,GLuint flags,GLuint prim) { struct nouveau_context *nmesa = NOUVEAU_CONTEXT(ctx); GLubyte *vertptr = (GLubyte *)nmesa->verts; GLuint vertsize = nmesa->vertex_size; GLuint size_dword = vertsize*(count-start)/4; nv10ExtendPrimitive(nmesa, size_dword); nv10StartPrimitive(nmesa,prim+1,size_dword); OUT_RINGp((nouveauVertex*)(vertptr+(start*vertsize)),size_dword); nv10FinishPrimitive(nmesa); }
static void nvfx_vertprog_ucp_validate(struct nvfx_context* nvfx) { struct nouveau_channel* chan = nvfx->screen->base.channel; struct nouveau_grobj *eng3d = nvfx->screen->eng3d; unsigned i; struct nvfx_vertex_program* vp = nvfx->hw_vertprog; if(nvfx->clip.nr != vp->clip_nr) { unsigned idx; /* remove last instruction bit */ if(vp->clip_nr >= 0) { idx = vp->nr_insns - 7 + vp->clip_nr; BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_FROM_ID, 1); OUT_RING(chan, vp->exec->start + idx); BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_INST(0), 4); OUT_RINGp (chan, vp->insns[idx].data, 4); } /* set last instruction bit */ idx = vp->nr_insns - 7 + nvfx->clip.nr; BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_FROM_ID, 1); OUT_RING(chan, vp->exec->start + idx); BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_INST(0), 4); OUT_RINGp(chan, vp->insns[idx].data, 3); OUT_RING(chan, vp->insns[idx].data[3] | 1); vp->clip_nr = nvfx->clip.nr; } // TODO: only do this for the ones changed for(i = 0; i < nvfx->clip.nr; ++i) { BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_CONST_ID, 5); OUT_RING(chan, vp->data->start + i); OUT_RINGp (chan, nvfx->clip.ucp[i], 4); } }
static inline void nv10_render_generic_primitive_elts(GLcontext *ctx,GLuint start,GLuint count,GLuint flags,GLuint prim) { struct nouveau_context *nmesa = NOUVEAU_CONTEXT(ctx); GLubyte *vertptr = (GLubyte *)nmesa->verts; GLuint vertsize = nmesa->vertex_size; GLuint size_dword = vertsize*(count-start)/4; const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; GLuint j; nv10ExtendPrimitive(nmesa, size_dword); nv10StartPrimitive(nmesa,prim+1,size_dword); for (j=start; j<count; j++ ) { OUT_RINGp((nouveauVertex*)(vertptr+(elt[j]*vertsize)),vertsize/4); } nv10FinishPrimitive(nmesa); }
void nv20_emit_viewport(GLcontext *ctx, int emit) { struct nouveau_channel *chan = context_chan(ctx); struct nouveau_grobj *kelvin = context_eng3d(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; float a[4] = {}; get_viewport_translate(ctx, a); BEGIN_RING(chan, kelvin, NV20TCL_VIEWPORT_TRANSLATE_X, 4); OUT_RINGp(chan, a, 4); BEGIN_RING(chan, kelvin, NV20TCL_VIEWPORT_CLIP_HORIZ(0), 1); OUT_RING(chan, (fb->Width - 1) << 16); BEGIN_RING(chan, kelvin, NV20TCL_VIEWPORT_CLIP_VERT(0), 1); OUT_RING(chan, (fb->Height - 1) << 16); context_dirty(ctx, PROJECTION); }
static INLINE void nv40_draw_elements_u32(struct nv40_context *nv40, void *ib, unsigned mode, unsigned start, unsigned count) { struct nouveau_channel *chan = nv40->nvws->channel; while (count) { uint32_t *elts = (uint32_t *)ib + start; unsigned vc, push, restart; nv40_state_emit(nv40); vc = nouveau_vbuf_split(chan->pushbuf->remaining, 5, 1, mode, start, count, &restart); if (vc == 0) { FIRE_RING(NULL); continue; } count -= vc; BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); OUT_RING (nvgl_primitive(mode)); while (vc) { push = MIN2(vc, 2047); BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U32, push); OUT_RINGp (elts, push); vc -= push; elts += push; } BEGIN_RING(curie, NV40TCL_BEGIN_END, 1); OUT_RING (0); start = restart; } }
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; } }
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); } } }
boolean nvfx_vbo_validate(struct nvfx_context *nvfx) { struct nouveau_channel* chan = nvfx->screen->base.channel; int i; int elements = MAX2(nvfx->vtxelt->num_elements, nvfx->hw_vtxelt_nr); unsigned vb_flags = nvfx->screen->vertex_buffer_reloc_flags | NOUVEAU_BO_RD; if (!elements) return TRUE; MARK_RING(chan, (5 + 2) * 16 + 2 + 11, 16 + 2); for(unsigned i = 0; i < nvfx->vtxelt->num_constant; ++i) { struct nvfx_low_frequency_element *ve = &nvfx->vtxelt->constant[i]; struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; struct nvfx_buffer* buffer = nvfx_buffer(vb->buffer); float v[4]; ve->fetch_rgba_float(v, buffer->data + vb->buffer_offset + ve->src_offset, 0, 0); nvfx_emit_vtx_attr(chan, ve->idx, v, ve->ncomp); } OUT_RING(chan, RING_3D(NV30_3D_VTXFMT(0), elements)); if(nvfx->use_vertex_buffers) { unsigned idx = 0; for (i = 0; i < nvfx->vtxelt->num_per_vertex; i++) { struct nvfx_per_vertex_element *ve = &nvfx->vtxelt->per_vertex[i]; struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; if(idx != ve->idx) { assert(idx < ve->idx); OUT_RINGp(chan, &nvfx->vtxelt->vtxfmt[idx], ve->idx - idx); idx = ve->idx; } OUT_RING(chan, nvfx->vtxelt->vtxfmt[idx] | (vb->stride << NV30_3D_VTXFMT_STRIDE__SHIFT)); ++idx; } if(idx != nvfx->vtxelt->num_elements) OUT_RINGp(chan, &nvfx->vtxelt->vtxfmt[idx], nvfx->vtxelt->num_elements - idx); } else OUT_RINGp(chan, nvfx->vtxelt->vtxfmt, nvfx->vtxelt->num_elements); for(i = nvfx->vtxelt->num_elements; 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)); if(nvfx->use_vertex_buffers) { unsigned idx = 0; for (i = 0; i < nvfx->vtxelt->num_per_vertex; i++) { struct nvfx_per_vertex_element *ve = &nvfx->vtxelt->per_vertex[i]; struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; struct nouveau_bo* bo = nvfx_resource(vb->buffer)->bo; for(; idx < ve->idx; ++idx) OUT_RING(chan, 0); OUT_RELOC(chan, bo, vb->buffer_offset + ve->src_offset + nvfx->base_vertex * vb->stride, vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR, 0, NV30_3D_VTXBUF_DMA1); ++idx; } for(; idx < elements; ++idx) OUT_RING(chan, 0); } else { for (i = 0; i < elements; i++) OUT_RING(chan, 0); } OUT_RING(chan, RING_3D(0x1710, 1)); OUT_RING(chan, 0); nvfx->hw_vtxelt_nr = nvfx->vtxelt->num_elements; nvfx->relocs_needed &=~ NVFX_RELOCATE_VTXBUF; return TRUE; }
void nv50_fp_linkage_validate(struct nv50_context *nv50) { struct nouveau_channel *chan = nv50->screen->base.channel; struct nv50_program *vp = nv50->gmtyprog ? nv50->gmtyprog : nv50->vertprog; struct nv50_program *fp = nv50->fragprog; struct nv50_varying dummy; int i, n, c, m; uint32_t primid = 0; uint32_t psiz = 0x000; uint32_t interp = fp->fp.interp; uint32_t colors = fp->fp.colors; uint32_t lin[4]; uint8_t map[64]; memset(lin, 0x00, sizeof(lin)); /* XXX: in buggy-endian mode, is the first element of map (u32)0x000000xx * or is it the first byte ? */ memset(map, nv50->gmtyprog ? 0x80 : 0x40, sizeof(map)); dummy.mask = 0xf; /* map all components of HPOS */ dummy.linear = 0; m = nv50_vec4_map(map, 0, lin, &dummy, &vp->out[0]); for (c = 0; c < vp->vp.clpd_nr; ++c) map[m++] = vp->vp.clpd + c; colors |= m << 8; /* adjust BFC0 id */ /* if light_twoside is active, FFC0_ID == BFC0_ID is invalid */ if (nv50->rast->pipe.light_twoside) { for (i = 0; i < 2; ++i) m = nv50_vec4_map(map, m, lin, &fp->in[fp->vp.bfc[i]], &vp->out[vp->vp.bfc[i]]); } colors += m - 4; /* adjust FFC0 id */ interp |= m << 8; /* set map id where 'normal' FP inputs start */ dummy.mask = 0x0; for (i = 0; i < fp->in_nr; ++i) { for (n = 0; n < vp->out_nr; ++n) if (vp->out[n].sn == fp->in[i].sn && vp->out[n].si == fp->in[i].si) break; m = nv50_vec4_map(map, m, lin, &fp->in[i], (n < vp->out_nr) ? &vp->out[n] : &dummy); } /* PrimitiveID either is replaced by the system value, or * written by the geometry shader into an output register */ if (fp->gp.primid < 0x40) { primid = m; map[m++] = vp->gp.primid; } if (nv50->rast->pipe.point_size_per_vertex) { psiz = (m << 4) | 1; map[m++] = vp->vp.psiz; } if (nv50->rast->pipe.clamp_vertex_color) colors |= NV50_3D_MAP_SEMANTIC_0_CLMP_EN; n = (m + 3) / 4; assert(m <= 64); if (unlikely(nv50->gmtyprog)) { BEGIN_RING(chan, RING_3D(GP_RESULT_MAP_SIZE), 1); OUT_RING (chan, m); BEGIN_RING(chan, RING_3D(GP_RESULT_MAP(0)), n); OUT_RINGp (chan, map, n); } else { BEGIN_RING(chan, RING_3D(VP_GP_BUILTIN_ATTR_EN), 1); OUT_RING (chan, vp->vp.attrs[2]); BEGIN_RING(chan, RING_3D(MAP_SEMANTIC_4), 1); OUT_RING (chan, primid); BEGIN_RING(chan, RING_3D(VP_RESULT_MAP_SIZE), 1); OUT_RING (chan, m); BEGIN_RING(chan, RING_3D(VP_RESULT_MAP(0)), n); OUT_RINGp (chan, map, n); } BEGIN_RING(chan, RING_3D(MAP_SEMANTIC_0), 4); OUT_RING (chan, colors); OUT_RING (chan, (vp->vp.clpd_nr << 8) | 4); OUT_RING (chan, 0); OUT_RING (chan, psiz); BEGIN_RING(chan, RING_3D(FP_INTERPOLANT_CTRL), 1); OUT_RING (chan, interp); nv50->state.interpolant_ctrl = interp; nv50->state.semantic_color = colors; nv50->state.semantic_psize = psiz; BEGIN_RING(chan, RING_3D(NOPERSPECTIVE_BITMAP(0)), 4); OUT_RINGp (chan, lin, 4); BEGIN_RING(chan, RING_3D(GP_ENABLE), 1); OUT_RING (chan, nv50->gmtyprog ? 1 : 0); }
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; } } } }
static void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbcon_par *par = info->par; struct drm_device *dev = par->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; uint32_t fg; uint32_t bg; uint32_t dsize; uint32_t width; uint32_t *data = (uint32_t *)image->data; if (info->state != FBINFO_STATE_RUNNING) return; if (image->depth != 1) { cfb_imageblit(info, image); return; } if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 8)) { nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { cfb_imageblit(info, image); return; } width = (image->width + 31) & ~31; dsize = (width * image->height) >> 5; if (info->fix.visual == FB_VISUAL_TRUECOLOR || info->fix.visual == FB_VISUAL_DIRECTCOLOR) { fg = ((uint32_t *) info->pseudo_palette)[image->fg_color]; bg = ((uint32_t *) info->pseudo_palette)[image->bg_color]; } else { fg = image->fg_color; bg = image->bg_color; } BEGIN_RING(chan, NvSubGdiRect, 0x0be4, 7); OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff)); OUT_RING(chan, ((image->dy + image->height) << 16) | ((image->dx + image->width) & 0xffff)); OUT_RING(chan, bg); OUT_RING(chan, fg); OUT_RING(chan, (image->height << 16) | image->width); OUT_RING(chan, (image->height << 16) | width); OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff)); while (dsize) { int iter_len = dsize > 128 ? 128 : dsize; if (RING_SPACE(chan, iter_len + 1)) { nouveau_fbcon_gpu_lockup(info); cfb_imageblit(info, image); return; } BEGIN_RING(chan, NvSubGdiRect, 0x0c00, iter_len); OUT_RINGp(chan, data, iter_len); data += iter_len; dsize -= iter_len; } FIRE_RING(chan); }
static boolean nv30_vertprog_validate(struct nv30_context *nv30) { struct pipe_screen *pscreen = nv30->pipe.screen; struct nouveau_grobj *rankine = nv30->screen->rankine; struct nv30_vertex_program *vp; struct pipe_buffer *constbuf; boolean upload_code = FALSE, upload_data = FALSE; int i; vp = nv30->vertprog; constbuf = nv30->constbuf[PIPE_SHADER_VERTEX]; /* Translate TGSI shader into hw bytecode */ if (!vp->translated) { nv30_vertprog_translate(nv30, vp); if (!vp->translated) return FALSE; } /* Allocate hw vtxprog exec slots */ if (!vp->exec) { struct nouveau_resource *heap = nv30->screen->vp_exec_heap; struct nouveau_stateobj *so; uint vplen = vp->nr_insns; if (nouveau_resource_alloc(heap, vplen, vp, &vp->exec)) { while (heap->next && heap->size < vplen) { struct nv30_vertex_program *evict; evict = heap->next->priv; nouveau_resource_free(&evict->exec); } if (nouveau_resource_alloc(heap, vplen, vp, &vp->exec)) assert(0); } so = so_new(2, 0); so_method(so, rankine, NV34TCL_VP_START_FROM_ID, 1); so_data (so, vp->exec->start); so_ref(so, &vp->so); so_ref(NULL, &so); upload_code = TRUE; } /* Allocate hw vtxprog const slots */ if (vp->nr_consts && !vp->data) { struct nouveau_resource *heap = nv30->screen->vp_data_heap; if (nouveau_resource_alloc(heap, vp->nr_consts, vp, &vp->data)) { while (heap->next && heap->size < vp->nr_consts) { struct nv30_vertex_program *evict; evict = heap->next->priv; nouveau_resource_free(&evict->data); } if (nouveau_resource_alloc(heap, vp->nr_consts, vp, &vp->data)) assert(0); } /*XXX: handle this some day */ assert(vp->data->start >= vp->data_start_min); upload_data = TRUE; if (vp->data_start != vp->data->start) upload_code = TRUE; } /* If exec or data segments moved we need to patch the program to * fixup offsets and register IDs. */ if (vp->exec_start != vp->exec->start) { for (i = 0; i < vp->nr_insns; i++) { struct nv30_vertex_program_exec *vpi = &vp->insns[i]; if (vpi->has_branch_offset) { assert(0); } } vp->exec_start = vp->exec->start; } if (vp->nr_consts && vp->data_start != vp->data->start) { for (i = 0; i < vp->nr_insns; i++) { struct nv30_vertex_program_exec *vpi = &vp->insns[i]; if (vpi->const_index >= 0) { vpi->data[1] &= ~NV30_VP_INST_CONST_SRC_MASK; vpi->data[1] |= (vpi->const_index + vp->data->start) << NV30_VP_INST_CONST_SRC_SHIFT; } } vp->data_start = vp->data->start; } /* Update + Upload constant values */ if (vp->nr_consts) { float *map = NULL; if (constbuf) { map = pipe_buffer_map(pscreen, constbuf, PIPE_BUFFER_USAGE_CPU_READ); } for (i = 0; i < vp->nr_consts; i++) { struct nv30_vertex_program_data *vpd = &vp->consts[i]; if (vpd->index >= 0) { if (!upload_data && !memcmp(vpd->value, &map[vpd->index * 4], 4 * sizeof(float))) continue; memcpy(vpd->value, &map[vpd->index * 4], 4 * sizeof(float)); } BEGIN_RING(rankine, NV34TCL_VP_UPLOAD_CONST_ID, 5); OUT_RING (i + vp->data->start); OUT_RINGp ((uint32_t *)vpd->value, 4); } if (constbuf) pipe_buffer_unmap(pscreen, constbuf); } /* Upload vtxprog */ if (upload_code) { #if 0 for (i = 0; i < vp->nr_insns; i++) { NOUVEAU_MSG("VP inst %d: 0x%08x 0x%08x 0x%08x 0x%08x\n", i, vp->insns[i].data[0], vp->insns[i].data[1], vp->insns[i].data[2], vp->insns[i].data[3]); } #endif BEGIN_RING(rankine, NV34TCL_VP_UPLOAD_FROM_ID, 1); OUT_RING (vp->exec->start); for (i = 0; i < vp->nr_insns; i++) { BEGIN_RING(rankine, NV34TCL_VP_UPLOAD_INST(0), 4); OUT_RINGp (vp->insns[i].data, 4); } } if (vp->so != nv30->state.hw[NV30_STATE_VERTPROG]) { so_ref(vp->so, &nv30->state.hw[NV30_STATE_VERTPROG]); return TRUE; } return FALSE; }
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 INLINE void nvfx_render_prim(struct draw_stage *stage, struct prim_header *prim, unsigned mode, unsigned count) { struct nvfx_render_stage *rs = nvfx_render_stage(stage); struct nvfx_context *nvfx = rs->nvfx; struct nvfx_screen *screen = nvfx->screen; struct nouveau_channel *chan = screen->base.channel; boolean no_elements = nvfx->vertprog->draw_no_elements; unsigned num_attribs = nvfx->vertprog->draw_elements; /* we need to account the flush as well here even if it is done afterthis * function */ if (AVAIL_RING(chan) < ((1 + count * num_attribs * 4) + 6 + 64)) { nvfx_render_flush(stage, 0); FIRE_RING(chan); nvfx_state_emit(nvfx); assert(AVAIL_RING(chan) >= ((1 + count * num_attribs * 4) + 6 + 64)); } /* Switch primitive modes if necessary */ if (rs->prim != mode) { if (rs->prim != NV30_3D_VERTEX_BEGIN_END_STOP) { OUT_RING(chan, RING_3D(NV30_3D_VERTEX_BEGIN_END, 1)); OUT_RING(chan, NV30_3D_VERTEX_BEGIN_END_STOP); } /* 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, mode); rs->prim = mode; } OUT_RING(chan, RING_3D_NI(NV30_3D_VERTEX_DATA, num_attribs * 4 * count)); if(no_elements) { OUT_RING(chan, 0); OUT_RING(chan, 0); OUT_RING(chan, 0); OUT_RING(chan, 0); } else { for (unsigned i = 0; i < count; ++i) { struct vertex_header* v = prim->v[i]; /* TODO: disable divide where it's causing the problem, and remove this hack */ OUT_RING(chan, fui(v->data[0][0] / v->data[0][3])); OUT_RING(chan, fui(v->data[0][1] / v->data[0][3])); OUT_RING(chan, fui(v->data[0][2] / v->data[0][3])); OUT_RING(chan, fui(1.0f / v->data[0][3])); OUT_RINGp(chan, &v->data[1][0], 4 * (num_attribs - 1)); } } }
void nvc0_tfb_validate(struct nvc0_context *nvc0) { struct nouveau_channel *chan = nvc0->screen->base.channel; struct nvc0_transform_feedback_state *tfb; unsigned b, n, i; if (nvc0->gmtyprog) tfb = nvc0->gmtyprog->tfb; else if (nvc0->tevlprog) tfb = nvc0->tevlprog->tfb; else tfb = nvc0->vertprog->tfb; IMMED_RING(chan, RING_3D(TFB_ENABLE), (tfb && nvc0->num_tfbbufs) ? 1 : 0); if (tfb && tfb != nvc0->state.tfb) { uint8_t var[128]; for (n = 0, b = 0; b < 4; n += tfb->varying_count[b++]) { if (tfb->varying_count[b]) { BEGIN_RING(chan, RING_3D(TFB_STREAM(b)), 3); OUT_RING (chan, 0); OUT_RING (chan, tfb->varying_count[b]); OUT_RING (chan, tfb->stride[b]); for (i = 0; i < tfb->varying_count[b]; ++i) var[i] = tfb->varying_index[n + i]; for (; i & 3; ++i) var[i] = 0; /* zero rest of method word bits */ BEGIN_RING(chan, RING_3D(TFB_VARYING_LOCS(b, 0)), i / 4); OUT_RINGp (chan, var, i / 4); if (nvc0->tfbbuf[b]) nvc0_so_target(nvc0->tfbbuf[b])->stride = tfb->stride[b]; } else { IMMED_RING(chan, RING_3D(TFB_VARYING_COUNT(b)), 0); } } } nvc0->state.tfb = tfb; if (!(nvc0->dirty & NVC0_NEW_TFB_TARGETS)) return; nvc0_bufctx_reset(nvc0, NVC0_BUFCTX_TFB); for (b = 0; b < nvc0->num_tfbbufs; ++b) { struct nvc0_so_target *targ = nvc0_so_target(nvc0->tfbbuf[b]); struct nv04_resource *buf = nv04_resource(targ->pipe.buffer); if (tfb) targ->stride = tfb->stride[b]; if (!(nvc0->tfbbuf_dirty & (1 << b))) continue; if (!targ->clean) nvc0_query_fifo_wait(chan, targ->pq); BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 5); OUT_RING (chan, 1); OUT_RESRCh(chan, buf, targ->pipe.buffer_offset, NOUVEAU_BO_WR); OUT_RESRCl(chan, buf, targ->pipe.buffer_offset, NOUVEAU_BO_WR); OUT_RING (chan, targ->pipe.buffer_size); if (!targ->clean) { nvc0_query_pushbuf_submit(chan, targ->pq, 0x4); } else { OUT_RING(chan, 0); /* TFB_BUFFER_OFFSET */ targ->clean = FALSE; } nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_TFB, buf, NOUVEAU_BO_WR); } for (; b < 4; ++b) IMMED_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 0); }