static void nv50_dac_disconnect(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct drm_device *dev = encoder->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = dev_priv->evo; int ret; if (!nv_encoder->crtc) return; nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true); NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or); ret = RING_SPACE(evo, 4); if (ret) { NV_ERROR(dev, "no space while disconnecting DAC\n"); return; } BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1); OUT_RING (evo, 0); BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); OUT_RING (evo, 0); nv_encoder->crtc = NULL; }
static void nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update) { struct drm_nouveau_private *dev_priv = nv_crtc->base.dev->dev_private; struct nouveau_channel *evo = dev_priv->evo; struct drm_device *dev = nv_crtc->base.dev; int ret; NV_DEBUG_KMS(dev, "\n"); if (update && !nv_crtc->cursor.visible) return; ret = RING_SPACE(evo, (dev_priv->chipset != 0x50 ? 5 : 3) + update * 2); if (ret) { NV_ERROR(dev, "no space while hiding cursor\n"); return; } BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2); OUT_RING(evo, NV50_EVO_CRTC_CURSOR_CTRL_HIDE); OUT_RING(evo, 0); if (dev_priv->chipset != 0x50) { BEGIN_RING(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1); OUT_RING(evo, NV84_EVO_CRTC_CURSOR_DMA_HANDLE_NONE); } if (update) { BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); OUT_RING(evo, 0); FIRE_RING(evo); nv_crtc->cursor.visible = false; } }
void nvfx_state_viewport_validate(struct nvfx_context *nvfx) { struct nouveau_channel *chan = nvfx->screen->base.channel; struct nouveau_grobj *eng3d = nvfx->screen->eng3d; struct pipe_viewport_state *vpt = &nvfx->viewport; if(nvfx->render_mode == HW) { BEGIN_RING(chan, eng3d, NV30_3D_VIEWPORT_TRANSLATE_X, 8); OUT_RINGf(chan, vpt->translate[0]); OUT_RINGf(chan, vpt->translate[1]); OUT_RINGf(chan, vpt->translate[2]); OUT_RINGf(chan, vpt->translate[3]); OUT_RINGf(chan, vpt->scale[0]); OUT_RINGf(chan, vpt->scale[1]); OUT_RINGf(chan, vpt->scale[2]); OUT_RINGf(chan, vpt->scale[3]); BEGIN_RING(chan, eng3d, 0x1d78, 1); OUT_RING(chan, 1); } else { BEGIN_RING(chan, eng3d, NV30_3D_VIEWPORT_TRANSLATE_X, 8); OUT_RINGf(chan, 0.0f); OUT_RINGf(chan, 0.0f); OUT_RINGf(chan, 0.0f); OUT_RINGf(chan, 0.0f); OUT_RINGf(chan, 1.0f); OUT_RINGf(chan, 1.0f); OUT_RINGf(chan, 1.0f); OUT_RINGf(chan, 1.0f); BEGIN_RING(chan, eng3d, 0x1d78, 1); OUT_RING(chan, nvfx->is_nv4x ? 0x110 : 1); } }
boolean nv30_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start, unsigned count) { struct nv30_context *nv30 = nv30_context(pipe); struct nouveau_channel *chan = nv30->screen->base.channel; unsigned restart = 0; nv30_vbo_set_idxbuf(nv30, NULL, 0); if (FORCE_SWTNL || !nv30_state_validate(nv30)) { /*return nv30_draw_elements_swtnl(pipe, NULL, 0, mode, start, count);*/ return FALSE; } while (count) { unsigned vc, nr; nv30_state_emit(nv30); vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256, mode, start, count, &restart); if (!vc) { FIRE_RING(NULL); continue; } BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1); OUT_RING (nvgl_primitive(mode)); nr = (vc & 0xff); if (nr) { BEGIN_RING(rankine, NV34TCL_VB_VERTEX_BATCH, 1); OUT_RING (((nr - 1) << 24) | start); start += nr; } nr = vc >> 8; while (nr) { unsigned push = nr > 2047 ? 2047 : nr; nr -= push; BEGIN_RING_NI(rankine, NV34TCL_VB_VERTEX_BATCH, push); while (push--) { OUT_RING(((0x100 - 1) << 24) | start); start += 0x100; } } BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1); OUT_RING (0); count -= vc; start = restart; } pipe->flush(pipe, 0, NULL); return TRUE; }
static void nv40_query_begin(struct pipe_context *pipe, struct pipe_query *pq) { struct nv40_context *nv40 = nv40_context(pipe); struct nv40_query *q = nv40_query(pq); assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER); /* Happens when end_query() is called, then another begin_query() * without querying the result in-between. For now we'll wait for * the existing query to notify completion, but it could be better. */ if (q->object) { uint64_t tmp; pipe->get_query_result(pipe, pq, 1, &tmp); } if (nv40->nvws->res_alloc(nv40->screen->query_heap, 1, NULL, &q->object)) assert(0); nv40->nvws->notifier_reset(nv40->screen->query, q->object->start); BEGIN_RING(curie, NV40TCL_QUERY_RESET, 1); OUT_RING (1); BEGIN_RING(curie, NV40TCL_QUERY_UNK17CC, 1); OUT_RING (1); q->ready = FALSE; }
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 void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { 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; if (info->state != FBINFO_STATE_RUNNING) return; if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 7)) { nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { cfb_fillrect(info, rect); return; } BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1); OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3); BEGIN_RING(chan, NvSubGdiRect, 0x03fc, 1); if (info->fix.visual == FB_VISUAL_TRUECOLOR || info->fix.visual == FB_VISUAL_DIRECTCOLOR) OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]); else OUT_RING(chan, rect->color); BEGIN_RING(chan, NvSubGdiRect, 0x0400, 2); OUT_RING(chan, (rect->dx << 16) | rect->dy); OUT_RING(chan, (rect->width << 16) | rect->height); FIRE_RING(chan); }
static void nv17_zclear(struct gl_context *ctx, GLbitfield *buffers) { struct nouveau_context *nctx = to_nouveau_context(ctx); struct nouveau_channel *chan = context_chan(ctx); struct nouveau_grobj *celsius = context_eng3d(ctx); struct nouveau_framebuffer *nfb = to_nouveau_framebuffer( ctx->DrawBuffer); struct nouveau_surface *s = &to_nouveau_renderbuffer( nfb->base.Attachment[BUFFER_DEPTH].Renderbuffer)->surface; /* Clear the hierarchical depth buffer */ BEGIN_RING(chan, celsius, NV17_3D_HIERZ_FILL_VALUE, 1); OUT_RING(chan, pack_zs_f(s->format, ctx->Depth.Clear, 0)); BEGIN_RING(chan, celsius, NV17_3D_HIERZ_BUFFER_CLEAR, 1); OUT_RING(chan, 1); /* Mark the depth buffer as cleared */ if (use_fast_zclear(ctx, *buffers)) { if (nctx->hierz.clear_seq) *buffers &= ~BUFFER_BIT_DEPTH; nfb->hierz.clear_value = pack_zs_f(s->format, ctx->Depth.Clear, 0); nctx->hierz.clear_seq++; context_dirty(ctx, ZCLEAR); } }
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 nv40_fragtex_set(struct nvfx_context *nvfx, int unit) { struct nouveau_channel* chan = nvfx->screen->base.channel; struct nouveau_grobj *eng3d = nvfx->screen->eng3d; struct nvfx_sampler_state *ps = nvfx->tex_sampler[unit]; struct nvfx_sampler_view* sv = (struct nvfx_sampler_view*)nvfx->fragment_sampler_views[unit]; struct nouveau_bo *bo = ((struct nvfx_miptree *)sv->base.texture)->base.bo; unsigned tex_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD; unsigned txf; unsigned max_lod = MIN2(ps->max_lod + sv->lod_offset, sv->max_lod_limit); unsigned min_lod = MIN2(ps->min_lod + sv->lod_offset, max_lod); txf = sv->u.nv40.fmt[ps->compare] | ps->fmt; MARK_RING(chan, 11, 2); BEGIN_RING(chan, eng3d, NV30_3D_TEX_OFFSET(unit), 8); OUT_RELOC(chan, bo, sv->offset, tex_flags | NOUVEAU_BO_LOW, 0, 0); OUT_RELOC(chan, bo, txf, tex_flags | NOUVEAU_BO_OR, NV30_3D_TEX_FORMAT_DMA0, NV30_3D_TEX_FORMAT_DMA1); OUT_RING(chan, (ps->wrap & sv->wrap_mask) | sv->wrap); OUT_RING(chan, ps->en | (min_lod << 19) | (max_lod << 7)); OUT_RING(chan, sv->swizzle); OUT_RING(chan, ps->filt | sv->filt); OUT_RING(chan, sv->npot_size); OUT_RING(chan, ps->bcol); BEGIN_RING(chan, eng3d, NV40_3D_TEX_SIZE1(unit), 1); OUT_RING(chan, sv->u.nv40.npot_size2); nvfx->hw_txf[unit] = txf; nvfx->hw_samplers |= (1 << unit); }
void nvc0_vertprog_validate(struct nvc0_context *nvc0) { struct nouveau_channel *chan = nvc0->screen->base.channel; struct nvc0_program *vp = nvc0->vertprog; if (nvc0->clip.nr > vp->vp.num_ucps) { assert(nvc0->clip.nr <= 6); vp->vp.num_ucps = 6; if (vp->translated) nvc0_program_destroy(nvc0, vp); } if (!nvc0_program_validate(nvc0, vp)) return; nvc0_program_update_context_state(nvc0, vp, 0); BEGIN_RING(chan, RING_3D(SP_SELECT(1)), 2); OUT_RING (chan, 0x11); OUT_RING (chan, vp->code_base); BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(1)), 1); OUT_RING (chan, vp->max_gpr); if (!nvc0->gmtyprog && !nvc0->tevlprog) nvc0_program_validate_clip(nvc0, vp); // BEGIN_RING(chan, RING_3D_(0x163c), 1); // OUT_RING (chan, 0); }
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); } }
void nvc0_gmtyprog_validate(struct nvc0_context *nvc0) { struct nouveau_channel *chan = nvc0->screen->base.channel; struct nvc0_program *gp = nvc0->gmtyprog; if (gp) nvc0_program_validate(nvc0, gp); /* we allow GPs with no code for specifying stream output state only */ if (!gp || !gp->code_size) { BEGIN_RING(chan, RING_3D(GP_SELECT), 1); OUT_RING (chan, 0x40); IMMED_RING(chan, RING_3D(LAYER), 0); return; } nvc0_program_update_context_state(nvc0, gp, 3); BEGIN_RING(chan, RING_3D(GP_SELECT), 1); OUT_RING (chan, 0x41); BEGIN_RING(chan, RING_3D(SP_START_ID(4)), 1); OUT_RING (chan, gp->code_base); BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(4)), 1); OUT_RING (chan, gp->max_gpr); BEGIN_RING(chan, RING_3D(LAYER), 1); OUT_RING (chan, (gp->hdr[13] & (1 << 9)) ? NVC0_3D_LAYER_USE_GP : 0); nvc0_program_validate_clip(nvc0, gp); }
void nvc0_tevlprog_validate(struct nvc0_context *nvc0) { struct nouveau_channel *chan = nvc0->screen->base.channel; struct nvc0_program *tp = nvc0->tevlprog; if (!tp) { BEGIN_RING(chan, RING_3D(TEP_SELECT), 1); OUT_RING (chan, 0x30); return; } if (!nvc0_program_validate(nvc0, tp)) return; nvc0_program_update_context_state(nvc0, tp, 2); if (tp->tp.tess_mode != ~0) { BEGIN_RING(chan, RING_3D(TESS_MODE), 1); OUT_RING (chan, tp->tp.tess_mode); } BEGIN_RING(chan, RING_3D(TEP_SELECT), 1); OUT_RING (chan, 0x31); BEGIN_RING(chan, RING_3D(SP_START_ID(3)), 1); OUT_RING (chan, tp->code_base); BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(3)), 1); OUT_RING (chan, tp->max_gpr); if (!nvc0->gmtyprog) nvc0_program_validate_clip(nvc0, tp); }
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; } }
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); }
void nvc0_tctlprog_validate(struct nvc0_context *nvc0) { struct nouveau_channel *chan = nvc0->screen->base.channel; struct nvc0_program *tp = nvc0->tctlprog; if (!tp) { BEGIN_RING(chan, RING_3D(SP_SELECT(2)), 1); OUT_RING (chan, 0x20); return; } if (!nvc0_program_validate(nvc0, tp)) return; nvc0_program_update_context_state(nvc0, tp, 1); if (tp->tp.tess_mode != ~0) { BEGIN_RING(chan, RING_3D(TESS_MODE), 1); OUT_RING (chan, tp->tp.tess_mode); } BEGIN_RING(chan, RING_3D(SP_SELECT(2)), 2); OUT_RING (chan, 0x21); OUT_RING (chan, tp->code_base); BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(2)), 1); OUT_RING (chan, tp->max_gpr); if (tp->tp.input_patch_size <= 32) IMMED_RING(chan, RING_3D(PATCH_VERTICES), tp->tp.input_patch_size); }
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 void setup_blend_function(NVPtr pNv) { struct nouveau_channel *chan = pNv->chan; struct nouveau_grobj *celsius = pNv->Nv3D; struct pict_op *op = &nv10_pict_op[pNv->alu]; int src_factor = op->src; int dst_factor = op->dst; if (src_factor == SF(ONE_MINUS_DST_ALPHA) && !PICT_FORMAT_A(pNv->pdpict->format)) /* ONE_MINUS_DST_ALPHA doesn't always do the right thing for * framebuffers without alpha channel. But it's the same as * ZERO in that case. */ src_factor = SF(ZERO); if (effective_component_alpha(pNv->pmpict)) { if (dst_factor == DF(SRC_ALPHA)) dst_factor = DF(SRC_COLOR); else if (dst_factor == DF(ONE_MINUS_SRC_ALPHA)) dst_factor = DF(ONE_MINUS_SRC_COLOR); } BEGIN_RING(chan, celsius, NV10TCL_BLEND_FUNC_SRC, 2); OUT_RING (chan, src_factor); OUT_RING (chan, dst_factor); BEGIN_RING(chan, celsius, NV10TCL_BLEND_FUNC_ENABLE, 1); OUT_RING (chan, 1); }
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); } } }
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); }
/* Validate state derived from shaders and the rasterizer cso. */ void nv50_validate_derived_rs(struct nv50_context *nv50) { struct nouveau_channel *chan = nv50->screen->base.channel; uint32_t color, psize; nv50_sprite_coords_validate(nv50); if (nv50->dirty & NV50_NEW_FRAGPROG) return; psize = nv50->state.semantic_psize & ~NV50_3D_MAP_SEMANTIC_3_PTSZ_EN__MASK; color = nv50->state.semantic_color & ~NV50_3D_MAP_SEMANTIC_0_CLMP_EN; if (nv50->rast->pipe.clamp_vertex_color) color |= NV50_3D_MAP_SEMANTIC_0_CLMP_EN; if (color != nv50->state.semantic_color) { nv50->state.semantic_color = color; BEGIN_RING(chan, RING_3D(MAP_SEMANTIC_0), 1); OUT_RING (chan, color); } if (nv50->rast->pipe.point_size_per_vertex) psize |= NV50_3D_MAP_SEMANTIC_3_PTSZ_EN__MASK; if (psize != nv50->state.semantic_psize) { nv50->state.semantic_psize = psize; BEGIN_RING(chan, RING_3D(MAP_SEMANTIC_3), 1); OUT_RING (chan, psize); } }
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); }
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 int nouveau_card_channel_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan; int ret, oclass; ret = nouveau_channel_alloc(dev, &chan, NULL, NvDmaFB, NvDmaTT); dev_priv->channel = chan; if (ret) return ret; mutex_unlock(&dev_priv->channel->mutex); if (dev_priv->card_type <= NV_50) { if (dev_priv->card_type < NV_50) oclass = 0x0039; else oclass = 0x5039; ret = nouveau_gpuobj_gr_new(chan, NvM2MF, oclass); if (ret) goto error; ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000, &chan->m2mf_ntfy); if (ret) goto error; ret = RING_SPACE(chan, 6); if (ret) goto error; BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1); OUT_RING (chan, NvM2MF); BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3); OUT_RING (chan, NvNotify0); OUT_RING (chan, chan->vram_handle); OUT_RING (chan, chan->gart_handle); } else if (dev_priv->card_type <= NV_D0) { ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039); if (ret) goto error; ret = RING_SPACE(chan, 2); if (ret) goto error; BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1); OUT_RING (chan, 0x00009039); } FIRE_RING (chan); error: if (ret) nouveau_card_channel_fini(dev); return ret; }
static int nouveau_fbcon_sync(struct fb_info *info) { struct nouveau_fbdev *nfbdev = info->par; struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; int ret, i; if (!chan || !chan->accel_done || in_interrupt() || info->state != FBINFO_STATE_RUNNING || info->flags & FBINFO_HWACCEL_DISABLED) return 0; if (!mutex_trylock(&chan->mutex)) return 0; ret = RING_SPACE(chan, 4); if (ret) { mutex_unlock(&chan->mutex); nouveau_fbcon_gpu_lockup(info); return 0; } if (dev_priv->card_type >= NV_C0) { BEGIN_NVC0(chan, 2, NvSub2D, 0x010c, 1); OUT_RING (chan, 0); BEGIN_NVC0(chan, 2, NvSub2D, 0x0100, 1); OUT_RING (chan, 0); } else { BEGIN_RING(chan, 0, 0x0104, 1); OUT_RING (chan, 0); BEGIN_RING(chan, 0, 0x0100, 1); OUT_RING (chan, 0); } nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3, 0xffffffff); FIRE_RING(chan); mutex_unlock(&chan->mutex); ret = -EBUSY; for (i = 0; i < 100000; i++) { if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3)) { ret = 0; break; } DRM_UDELAY(1); } if (ret) { nouveau_fbcon_gpu_lockup(info); return 0; } chan->accel_done = false; return 0; }
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 void setup_combiners(NVPtr pNv, PicturePtr src, PicturePtr mask) { struct nouveau_channel *chan = pNv->chan; struct nouveau_grobj *celsius = pNv->Nv3D; uint32_t rc_in_alpha = 0, rc_in_rgb = 0; if (PICT_FORMAT_A(src->format)) rc_in_alpha |= RC_IN_TEX(A, ALPHA, 0); else rc_in_alpha |= RC_IN_ONE(A); if (mask && PICT_FORMAT_A(mask->format)) rc_in_alpha |= RC_IN_TEX(B, ALPHA, 1); else rc_in_alpha |= RC_IN_ONE(B); if (effective_component_alpha(mask)) { if (!needs_src_alpha(pNv->alu)) { /* The alpha channels won't be used for blending. Drop * them, as our pixels only have 4 components... * output_i = src_i * mask_i */ if (PICT_FORMAT_RGB(src->format)) rc_in_rgb |= RC_IN_TEX(A, RGB, 0); } else { /* The RGB channels won't be used for blending. Drop * them. * output_i = src_alpha * mask_i */ if (PICT_FORMAT_A(src->format)) rc_in_rgb |= RC_IN_TEX(A, ALPHA, 0); else rc_in_rgb |= RC_IN_ONE(A); } rc_in_rgb |= RC_IN_TEX(B, RGB, 1); } else { if (PICT_FORMAT_RGB(src->format)) rc_in_rgb |= RC_IN_TEX(A, RGB, 0); if (mask && PICT_FORMAT_A(mask->format)) rc_in_rgb |= RC_IN_TEX(B, ALPHA, 1); else rc_in_rgb |= RC_IN_ONE(B); } BEGIN_RING(chan, celsius, NV10TCL_RC_IN_ALPHA(0), 1); OUT_RING (chan, rc_in_alpha); BEGIN_RING(chan, celsius, NV10TCL_RC_IN_RGB(0), 1); OUT_RING (chan, rc_in_rgb); }
static int nv50_2d_texture_do_copy(struct nouveau_channel *chan, struct nv50_miptree *dst, unsigned dst_level, unsigned dx, unsigned dy, unsigned dz, struct nv50_miptree *src, unsigned src_level, unsigned sx, unsigned sy, unsigned sz, unsigned w, unsigned h) { static const uint32_t duvdxy[5] = { 0x40000000, 0x80000000, 0x00000001, 0x00000002, 0x00000004 }; int ret; uint32_t ctrl; ret = MARK_RING(chan, 2 * 16 + 32, 4); if (ret) return ret; ret = nv50_2d_texture_set(chan, 1, dst, dst_level, dz); if (ret) return ret; ret = nv50_2d_texture_set(chan, 0, src, src_level, sz); if (ret) return ret; /* NOTE: 2D engine doesn't work for MS8 */ if (src->ms_x) ctrl = 0x11; /* 0/1 = CENTER/CORNER, 00/10 = POINT/BILINEAR */ BEGIN_RING(chan, RING_2D(BLIT_CONTROL), 1); OUT_RING (chan, ctrl); BEGIN_RING(chan, RING_2D(BLIT_DST_X), 4); OUT_RING (chan, dx << dst->ms_x); OUT_RING (chan, dy << dst->ms_y); OUT_RING (chan, w << dst->ms_x); OUT_RING (chan, h << dst->ms_y); BEGIN_RING(chan, RING_2D(BLIT_DU_DX_FRACT), 4); OUT_RING (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0xf0000000); OUT_RING (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0x0000000f); OUT_RING (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0xf0000000); OUT_RING (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0x0000000f); BEGIN_RING(chan, RING_2D(BLIT_SRC_X_FRACT), 4); OUT_RING (chan, 0); OUT_RING (chan, sx << src->ms_x); OUT_RING (chan, 0); OUT_RING (chan, sy << src->ms_y); return 0; }