static void nv50_draw_arrays_instanced(struct pipe_context *pipe, unsigned mode, unsigned start, unsigned count, unsigned startInstance, unsigned instanceCount) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_channel *chan = nv50->screen->tesla->channel; struct nouveau_grobj *tesla = nv50->screen->tesla; struct instance a[16]; unsigned prim = nv50_prim(mode); instance_init(nv50, a, startInstance); if (!nv50_state_validate(nv50, 10 + 16*3)) return; if (nv50->vbo_fifo) { nv50_push_elements_instanced(pipe, NULL, 0, 0, mode, start, count, startInstance, instanceCount); return; } BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2); OUT_RING (chan, NV50_CB_AUX | (24 << 8)); OUT_RING (chan, startInstance); while (instanceCount--) { if (AVAIL_RING(chan) < (7 + 16*3)) { FIRE_RING(chan); if (!nv50_state_validate(nv50, 7 + 16*3)) { assert(0); return; } } instance_step(nv50, a); BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1); OUT_RING (chan, prim); BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2); OUT_RING (chan, start); OUT_RING (chan, count); BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1); OUT_RING (chan, 0); prim |= (1 << 28); } }
static bool nv50_state_validate_cp(struct nv50_context *nv50, uint32_t mask) { bool ret; /* TODO: validate textures, samplers, surfaces */ ret = nv50_state_validate(nv50, mask, validate_list_cp, ARRAY_SIZE(validate_list_cp), &nv50->dirty_cp, nv50->bufctx_cp); if (unlikely(nv50->state.flushed)) nv50_bufctx_fence(nv50->bufctx_cp, true); return ret; }
void nv50_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba, double depth, unsigned stencil) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_channel *chan = nv50->screen->base.channel; struct pipe_framebuffer_state *fb = &nv50->framebuffer; unsigned i; const unsigned dirty = nv50->dirty; uint32_t mode = 0; /* don't need NEW_BLEND, COLOR_MASK doesn't affect CLEAR_BUFFERS */ nv50->dirty &= NV50_NEW_FRAMEBUFFER; if (!nv50_state_validate(nv50, 9 + (fb->nr_cbufs * 2))) return; if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) { 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]); mode = NV50_3D_CLEAR_BUFFERS_R | NV50_3D_CLEAR_BUFFERS_G | NV50_3D_CLEAR_BUFFERS_B | NV50_3D_CLEAR_BUFFERS_A; } if (buffers & PIPE_CLEAR_DEPTH) { BEGIN_RING(chan, RING_3D(CLEAR_DEPTH), 1); OUT_RING (chan, fui(depth)); mode |= NV50_3D_CLEAR_BUFFERS_Z; } if (buffers & PIPE_CLEAR_STENCIL) { BEGIN_RING(chan, RING_3D(CLEAR_STENCIL), 1); OUT_RING (chan, stencil & 0xff); mode |= NV50_3D_CLEAR_BUFFERS_S; } BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); OUT_RING (chan, mode); for (i = 1; i < fb->nr_cbufs; i++) { BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); OUT_RING (chan, (i << 6) | 0x3c); } nv50->dirty = dirty & ~NV50_NEW_FRAMEBUFFER; }
void nv50_clear(struct pipe_context *pipe, unsigned buffers, const union pipe_color_union *color, double depth, unsigned stencil) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_pushbuf *push = nv50->base.pushbuf; struct pipe_framebuffer_state *fb = &nv50->framebuffer; unsigned i; uint32_t mode = 0; /* don't need NEW_BLEND, COLOR_MASK doesn't affect CLEAR_BUFFERS */ if (!nv50_state_validate(nv50, NV50_NEW_FRAMEBUFFER, 9 + (fb->nr_cbufs * 2))) return; if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) { BEGIN_NV04(push, NV50_3D(CLEAR_COLOR(0)), 4); PUSH_DATAf(push, color->f[0]); PUSH_DATAf(push, color->f[1]); PUSH_DATAf(push, color->f[2]); PUSH_DATAf(push, color->f[3]); mode = NV50_3D_CLEAR_BUFFERS_R | NV50_3D_CLEAR_BUFFERS_G | NV50_3D_CLEAR_BUFFERS_B | NV50_3D_CLEAR_BUFFERS_A; } if (buffers & PIPE_CLEAR_DEPTH) { BEGIN_NV04(push, NV50_3D(CLEAR_DEPTH), 1); PUSH_DATA (push, fui(depth)); mode |= NV50_3D_CLEAR_BUFFERS_Z; } if (buffers & PIPE_CLEAR_STENCIL) { BEGIN_NV04(push, NV50_3D(CLEAR_STENCIL), 1); PUSH_DATA (push, stencil & 0xff); mode |= NV50_3D_CLEAR_BUFFERS_S; } BEGIN_NV04(push, NV50_3D(CLEAR_BUFFERS), 1); PUSH_DATA (push, mode); for (i = 1; i < fb->nr_cbufs; i++) { BEGIN_NV04(push, NV50_3D(CLEAR_BUFFERS), 1); PUSH_DATA (push, (i << 6) | 0x3c); } }
void nv50_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba, double depth, unsigned stencil) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_channel *chan = nv50->screen->base.channel; struct nouveau_grobj *tesla = nv50->screen->tesla; struct pipe_framebuffer_state *fb = &nv50->framebuffer; unsigned mode = 0, i; const unsigned dirty = nv50->dirty; /* don't need NEW_BLEND, NV50TCL_COLOR_MASK doesn't affect CLEAR_BUFFERS */ nv50->dirty &= NV50_NEW_FRAMEBUFFER | NV50_NEW_SCISSOR; if (!nv50_state_validate(nv50, 64)) return; if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) { BEGIN_RING(chan, tesla, NV50TCL_CLEAR_COLOR(0), 4); OUT_RING (chan, fui(rgba[0])); OUT_RING (chan, fui(rgba[1])); OUT_RING (chan, fui(rgba[2])); OUT_RING (chan, fui(rgba[3])); mode |= 0x3c; } if (buffers & PIPE_CLEAR_DEPTH) { BEGIN_RING(chan, tesla, NV50TCL_CLEAR_DEPTH, 1); OUT_RING (chan, fui(depth)); mode |= NV50TCL_CLEAR_BUFFERS_Z; } if (buffers & PIPE_CLEAR_STENCIL) { BEGIN_RING(chan, tesla, NV50TCL_CLEAR_STENCIL, 1); OUT_RING (chan, stencil & 0xff); mode |= NV50TCL_CLEAR_BUFFERS_S; } BEGIN_RING(chan, tesla, NV50TCL_CLEAR_BUFFERS, 1); OUT_RING (chan, mode); for (i = 1; i < fb->nr_cbufs; i++) { BEGIN_RING(chan, tesla, NV50TCL_CLEAR_BUFFERS, 1); OUT_RING (chan, (i << 6) | 0x3c); } nv50->dirty = dirty; }
void nv50_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba, double depth, unsigned stencil) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_channel *chan = nv50->screen->nvws->channel; struct nouveau_grobj *tesla = nv50->screen->tesla; struct pipe_framebuffer_state *fb = &nv50->framebuffer; unsigned mode = 0, i; if (!nv50_state_validate(nv50)) return; if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) { BEGIN_RING(chan, tesla, NV50TCL_CLEAR_COLOR(0), 4); OUT_RING (chan, fui(rgba[0])); OUT_RING (chan, fui(rgba[1])); OUT_RING (chan, fui(rgba[2])); OUT_RING (chan, fui(rgba[3])); mode |= 0x3c; } if (buffers & PIPE_CLEAR_DEPTHSTENCIL) { BEGIN_RING(chan, tesla, NV50TCL_CLEAR_DEPTH, 1); OUT_RING (chan, fui(depth)); BEGIN_RING(chan, tesla, NV50TCL_CLEAR_STENCIL, 1); OUT_RING (chan, stencil & 0xff); mode |= 0x03; } BEGIN_RING(chan, tesla, NV50TCL_CLEAR_BUFFERS, 1); OUT_RING (chan, mode); for (i = 1; i < fb->nr_cbufs; i++) { BEGIN_RING(chan, tesla, NV50TCL_CLEAR_BUFFERS, 1); OUT_RING (chan, (i << 6) | 0x3c); } }
void nv50_push_elements_instanced(struct pipe_context *pipe, struct pipe_resource *idxbuf, unsigned idxsize, int idxbias, unsigned mode, unsigned start, unsigned count, unsigned i_start, unsigned i_count) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_grobj *tesla = nv50->screen->tesla; struct nouveau_channel *chan = tesla->channel; struct push_context ctx; const unsigned p_overhead = 4 + /* begin/end */ 4; /* potential edgeflag enable/disable */ const unsigned v_overhead = 1 + /* VERTEX_DATA packet header */ 2; /* potential edgeflag modification */ struct util_split_prim s; unsigned vtx_size; boolean nzi = FALSE; int i; ctx.nv50 = nv50; ctx.attr_nr = 0; ctx.idxbuf = NULL; ctx.vtx_size = 0; ctx.edgeflag = 0.5f; ctx.edgeflag_attr = nv50->vertprog->vp.edgeflag; /* map vertex buffers, determine vertex size */ for (i = 0; i < nv50->vtxelt->num_elements; i++) { struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i]; struct pipe_vertex_buffer *vb = &nv50->vtxbuf[ve->vertex_buffer_index]; struct nouveau_bo *bo = nv50_resource(vb->buffer)->bo; unsigned size, nr_components, n; if (!(nv50->vbo_fifo & (1 << i))) continue; n = ctx.attr_nr++; if (nouveau_bo_map(bo, NOUVEAU_BO_RD)) { assert(bo->map); return; } ctx.attr[n].map = (uint8_t *)bo->map + vb->buffer_offset + ve->src_offset; nouveau_bo_unmap(bo); ctx.attr[n].stride = vb->stride; ctx.attr[n].divisor = ve->instance_divisor; if (ctx.attr[n].divisor) { ctx.attr[n].step = i_start % ve->instance_divisor; ctx.attr[n].map = (uint8_t *)ctx.attr[n].map + i_start * vb->stride; } size = util_format_get_component_bits(ve->src_format, UTIL_FORMAT_COLORSPACE_RGB, 0); nr_components = util_format_get_nr_components(ve->src_format); switch (size) { case 8: switch (nr_components) { case 1: ctx.attr[n].push = emit_b08_1; break; case 2: ctx.attr[n].push = emit_b16_1; break; case 3: ctx.attr[n].push = emit_b08_3; break; case 4: ctx.attr[n].push = emit_b32_1; break; } ctx.vtx_size++; break; case 16: switch (nr_components) { case 1: ctx.attr[n].push = emit_b16_1; break; case 2: ctx.attr[n].push = emit_b32_1; break; case 3: ctx.attr[n].push = emit_b16_3; break; case 4: ctx.attr[n].push = emit_b32_2; break; } ctx.vtx_size += (nr_components + 1) >> 1; break; case 32: switch (nr_components) { case 1: ctx.attr[n].push = emit_b32_1; break; case 2: ctx.attr[n].push = emit_b32_2; break; case 3: ctx.attr[n].push = emit_b32_3; break; case 4: ctx.attr[n].push = emit_b32_4; break; } ctx.vtx_size += nr_components; break; default: assert(0); return; } } vtx_size = ctx.vtx_size + v_overhead; /* map index buffer, if present */ if (idxbuf) { struct nouveau_bo *bo = nv50_resource(idxbuf)->bo; if (nouveau_bo_map(bo, NOUVEAU_BO_RD)) { assert(bo->map); return; } ctx.idxbuf = bo->map; ctx.idxbias = idxbias; ctx.idxsize = idxsize; nouveau_bo_unmap(bo); } s.priv = &ctx; s.edge = emit_edgeflag; if (idxbuf) { if (idxsize == 1) s.emit = idxbias ? emit_elt08_biased : emit_elt08; else if (idxsize == 2) s.emit = idxbias ? emit_elt16_biased : emit_elt16; else s.emit = idxbias ? emit_elt32_biased : emit_elt32; } else s.emit = emit_verts; /* per-instance loop */ BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2); OUT_RING (chan, NV50_CB_AUX | (24 << 8)); OUT_RING (chan, i_start); while (i_count--) { unsigned max_verts; boolean done; for (i = 0; i < ctx.attr_nr; i++) { if (!ctx.attr[i].divisor || ctx.attr[i].divisor != ++ctx.attr[i].step) continue; ctx.attr[i].step = 0; ctx.attr[i].map = (uint8_t *)ctx.attr[i].map + ctx.attr[i].stride; } util_split_prim_init(&s, mode, start, count); do { if (AVAIL_RING(chan) < p_overhead + (6 * vtx_size)) { FIRE_RING(chan); if (!nv50_state_validate(nv50, p_overhead + (6 * vtx_size))) { assert(0); return; } } max_verts = AVAIL_RING(chan); max_verts -= p_overhead; max_verts /= vtx_size; BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1); OUT_RING (chan, nv50_prim(s.mode) | (nzi ? (1 << 28) : 0)); done = util_split_prim_next(&s, max_verts); BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1); OUT_RING (chan, 0); } while (!done); nzi = TRUE; } }
static void nv50_resource_resolve(struct pipe_context *pipe, const struct pipe_resolve_info *info) { struct nv50_context *nv50 = nv50_context(pipe); struct nv50_screen *screen = nv50->screen; struct nv50_blitctx *blit = screen->blitctx; struct nouveau_channel *chan = screen->base.channel; struct pipe_resource *src = info->src.res; struct pipe_resource *dst = info->dst.res; float x0, x1, y0, y1, z; float x_range, y_range; nv50_blitctx_get_color_mask_and_fp(blit, dst->format, info->mask); blit->filter = util_format_is_depth_or_stencil(dst->format) ? 0 : 1; nv50_blitctx_pre_blit(blit, nv50); nv50_blit_set_dst(nv50, dst, info->dst.level, info->dst.layer); nv50_blit_set_src(nv50, src, 0, info->src.layer); nv50_blitctx_prepare_state(blit); nv50_state_validate(nv50, 36); x_range = (float)(info->src.x1 - info->src.x0) / (float)(info->dst.x1 - info->dst.x0); y_range = (float)(info->src.y1 - info->src.y0) / (float)(info->dst.y1 - info->dst.y0); x0 = (float)info->src.x0 - x_range * (float)info->dst.x0; y0 = (float)info->src.y0 - y_range * (float)info->dst.y0; x1 = x0 + 16384.0f * x_range; y1 = y0 + 16384.0f * y_range; x0 *= (float)(1 << nv50_miptree(src)->ms_x); x1 *= (float)(1 << nv50_miptree(src)->ms_x); y0 *= (float)(1 << nv50_miptree(src)->ms_y); y1 *= (float)(1 << nv50_miptree(src)->ms_y); z = (float)info->src.layer; BEGIN_RING(chan, RING_3D(FP_START_ID), 1); OUT_RING (chan, blit->fp.code_base + blit->fp_offset); BEGIN_RING(chan, RING_3D(VIEWPORT_TRANSFORM_EN), 1); OUT_RING (chan, 0); /* Draw a large triangle in screen coordinates covering the whole * render target, with scissors defining the destination region. * The vertex is supplied with non-normalized texture coordinates * arranged in a way to yield the desired offset and scale. */ BEGIN_RING(chan, RING_3D(SCISSOR_HORIZ(0)), 2); OUT_RING (chan, (info->dst.x1 << 16) | info->dst.x0); OUT_RING (chan, (info->dst.y1 << 16) | info->dst.y0); BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1); OUT_RING (chan, NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_TRIANGLES); BEGIN_RING(chan, RING_3D(VTX_ATTR_3F_X(1)), 3); OUT_RINGf (chan, x0); OUT_RINGf (chan, y0); OUT_RINGf (chan, z); BEGIN_RING(chan, RING_3D(VTX_ATTR_2F_X(0)), 2); OUT_RINGf (chan, 0.0f); OUT_RINGf (chan, 0.0f); BEGIN_RING(chan, RING_3D(VTX_ATTR_3F_X(1)), 3); OUT_RINGf (chan, x1); OUT_RINGf (chan, y0); OUT_RINGf (chan, z); BEGIN_RING(chan, RING_3D(VTX_ATTR_2F_X(0)), 2); OUT_RINGf (chan, 16384 << nv50_miptree(dst)->ms_x); OUT_RINGf (chan, 0.0f); BEGIN_RING(chan, RING_3D(VTX_ATTR_3F_X(1)), 3); OUT_RINGf (chan, x0); OUT_RINGf (chan, y1); OUT_RINGf (chan, z); BEGIN_RING(chan, RING_3D(VTX_ATTR_2F_X(0)), 2); OUT_RINGf (chan, 0.0f); OUT_RINGf (chan, 16384 << nv50_miptree(dst)->ms_y); BEGIN_RING(chan, RING_3D(VERTEX_END_GL), 1); OUT_RING (chan, 0); /* re-enable normally constant state */ BEGIN_RING(chan, RING_3D(VIEWPORT_TRANSFORM_EN), 1); OUT_RING (chan, 1); nv50_blitctx_post_blit(nv50, blit); }