Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c
4574 views
/*1* Copyright 2010 Christoph Bumiller2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#define NVC0_PUSH_EXPLICIT_SPACE_CHECKING2324#include "pipe/p_context.h"25#include "pipe/p_state.h"26#include "util/u_draw.h"27#include "util/u_inlines.h"28#include "util/format/u_format.h"29#include "translate/translate.h"3031#include "nvc0/nvc0_context.h"32#include "nvc0/nvc0_query_hw.h"33#include "nvc0/nvc0_resource.h"3435#include "nvc0/nvc0_3d.xml.h"3637void38nvc0_vertex_state_delete(struct pipe_context *pipe,39void *hwcso)40{41struct nvc0_vertex_stateobj *so = hwcso;4243if (so->translate)44so->translate->release(so->translate);45FREE(hwcso);46}4748void *49nvc0_vertex_state_create(struct pipe_context *pipe,50unsigned num_elements,51const struct pipe_vertex_element *elements)52{53struct nvc0_vertex_stateobj *so;54struct translate_key transkey;55unsigned i;56unsigned src_offset_max = 0;5758so = MALLOC(sizeof(*so) +59num_elements * sizeof(struct nvc0_vertex_element));60if (!so)61return NULL;62so->num_elements = num_elements;63so->instance_elts = 0;64so->instance_bufs = 0;65so->shared_slots = false;66so->need_conversion = false;6768memset(so->vb_access_size, 0, sizeof(so->vb_access_size));6970for (i = 0; i < PIPE_MAX_ATTRIBS; ++i)71so->min_instance_div[i] = 0xffffffff;7273transkey.nr_elements = 0;74transkey.output_stride = 0;7576for (i = 0; i < num_elements; ++i) {77const struct pipe_vertex_element *ve = &elements[i];78const unsigned vbi = ve->vertex_buffer_index;79unsigned size;80enum pipe_format fmt = ve->src_format;8182so->element[i].pipe = elements[i];83so->element[i].state = nvc0_vertex_format[fmt].vtx;8485if (!so->element[i].state) {86switch (util_format_get_nr_components(fmt)) {87case 1: fmt = PIPE_FORMAT_R32_FLOAT; break;88case 2: fmt = PIPE_FORMAT_R32G32_FLOAT; break;89case 3: fmt = PIPE_FORMAT_R32G32B32_FLOAT; break;90case 4: fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; break;91default:92assert(0);93FREE(so);94return NULL;95}96so->element[i].state = nvc0_vertex_format[fmt].vtx;97so->need_conversion = true;98pipe_debug_message(&nouveau_context(pipe)->debug, FALLBACK,99"Converting vertex element %d, no hw format %s",100i, util_format_name(ve->src_format));101}102size = util_format_get_blocksize(fmt);103104src_offset_max = MAX2(src_offset_max, ve->src_offset);105106if (so->vb_access_size[vbi] < (ve->src_offset + size))107so->vb_access_size[vbi] = ve->src_offset + size;108109if (unlikely(ve->instance_divisor)) {110so->instance_elts |= 1 << i;111so->instance_bufs |= 1 << vbi;112if (ve->instance_divisor < so->min_instance_div[vbi])113so->min_instance_div[vbi] = ve->instance_divisor;114}115116if (1) {117unsigned ca;118unsigned j = transkey.nr_elements++;119120ca = util_format_description(fmt)->channel[0].size / 8;121if (ca != 1 && ca != 2)122ca = 4;123124transkey.element[j].type = TRANSLATE_ELEMENT_NORMAL;125transkey.element[j].input_format = ve->src_format;126transkey.element[j].input_buffer = vbi;127transkey.element[j].input_offset = ve->src_offset;128transkey.element[j].instance_divisor = ve->instance_divisor;129130transkey.output_stride = align(transkey.output_stride, ca);131transkey.element[j].output_format = fmt;132transkey.element[j].output_offset = transkey.output_stride;133transkey.output_stride += size;134135so->element[i].state_alt = so->element[i].state;136so->element[i].state_alt |= transkey.element[j].output_offset << 7;137}138139so->element[i].state |= i << NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__SHIFT;140}141transkey.output_stride = align(transkey.output_stride, 4);142143so->size = transkey.output_stride;144so->translate = translate_create(&transkey);145146if (so->instance_elts || src_offset_max >= (1 << 14))147return so;148so->shared_slots = true;149150for (i = 0; i < num_elements; ++i) {151const unsigned b = elements[i].vertex_buffer_index;152const unsigned s = elements[i].src_offset;153so->element[i].state &= ~NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__MASK;154so->element[i].state |= b << NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__SHIFT;155so->element[i].state |= s << NVC0_3D_VERTEX_ATTRIB_FORMAT_OFFSET__SHIFT;156}157return so;158}159160#define NVC0_3D_VERTEX_ATTRIB_INACTIVE \161NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT | \162NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32 | NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST163164#define VTX_ATTR(a, c, t, s) \165((NVC0_3D_VTX_ATTR_DEFINE_TYPE_##t) | \166(NVC0_3D_VTX_ATTR_DEFINE_SIZE_##s) | \167((a) << NVC0_3D_VTX_ATTR_DEFINE_ATTR__SHIFT) | \168((c) << NVC0_3D_VTX_ATTR_DEFINE_COMP__SHIFT))169170static void171nvc0_set_constant_vertex_attrib(struct nvc0_context *nvc0, const unsigned a)172{173struct nouveau_pushbuf *push = nvc0->base.pushbuf;174struct pipe_vertex_element *ve = &nvc0->vertex->element[a].pipe;175struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[ve->vertex_buffer_index];176uint32_t mode;177const struct util_format_description *desc;178void *dst;179const void *src = (const uint8_t *)vb->buffer.user + ve->src_offset;180assert(vb->is_user_buffer);181182desc = util_format_description(ve->src_format);183184PUSH_SPACE(push, 6);185BEGIN_NVC0(push, NVC0_3D(VTX_ATTR_DEFINE), 5);186dst = &push->cur[1];187util_format_unpack_rgba(ve->src_format, dst, src, 1);188if (desc->channel[0].pure_integer) {189if (desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) {190mode = VTX_ATTR(a, 4, SINT, 32);191} else {192mode = VTX_ATTR(a, 4, UINT, 32);193}194} else {195mode = VTX_ATTR(a, 4, FLOAT, 32);196}197push->cur[0] = mode;198push->cur += 5;199}200201static inline void202nvc0_user_vbuf_range(struct nvc0_context *nvc0, int vbi,203uint32_t *base, uint32_t *size)204{205if (unlikely(nvc0->vertex->instance_bufs & (1 << vbi))) {206const uint32_t div = nvc0->vertex->min_instance_div[vbi];207*base = nvc0->instance_off * nvc0->vtxbuf[vbi].stride;208*size = (nvc0->instance_max / div) * nvc0->vtxbuf[vbi].stride +209nvc0->vertex->vb_access_size[vbi];210} else {211/* NOTE: if there are user buffers, we *must* have index bounds */212assert(nvc0->vb_elt_limit != ~0);213*base = nvc0->vb_elt_first * nvc0->vtxbuf[vbi].stride;214*size = nvc0->vb_elt_limit * nvc0->vtxbuf[vbi].stride +215nvc0->vertex->vb_access_size[vbi];216}217}218219static inline void220nvc0_release_user_vbufs(struct nvc0_context *nvc0)221{222if (nvc0->vbo_user) {223nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_VTX_TMP);224nouveau_scratch_done(&nvc0->base);225}226}227228static void229nvc0_update_user_vbufs(struct nvc0_context *nvc0)230{231uint64_t address[PIPE_MAX_ATTRIBS];232struct nouveau_pushbuf *push = nvc0->base.pushbuf;233int i;234uint32_t written = 0;235236PUSH_SPACE(push, nvc0->vertex->num_elements * 8);237for (i = 0; i < nvc0->vertex->num_elements; ++i) {238struct pipe_vertex_element *ve = &nvc0->vertex->element[i].pipe;239const unsigned b = ve->vertex_buffer_index;240struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[b];241uint32_t base, size;242243if (!(nvc0->vbo_user & (1 << b)))244continue;245if (nvc0->constant_vbos & (1 << b)) {246nvc0_set_constant_vertex_attrib(nvc0, i);247continue;248}249nvc0_user_vbuf_range(nvc0, b, &base, &size);250251if (!(written & (1 << b))) {252struct nouveau_bo *bo;253const uint32_t bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART;254written |= 1 << b;255address[b] = nouveau_scratch_data(&nvc0->base, vb->buffer.user,256base, size, &bo);257if (bo)258BCTX_REFN_bo(nvc0->bufctx_3d, 3D_VTX_TMP, bo_flags, bo);259260NOUVEAU_DRV_STAT(&nvc0->screen->base, user_buffer_upload_bytes, size);261}262263BEGIN_1IC0(push, NVC0_3D(MACRO_VERTEX_ARRAY_SELECT), 5);264PUSH_DATA (push, i);265PUSH_DATAh(push, address[b] + base + size - 1);266PUSH_DATA (push, address[b] + base + size - 1);267PUSH_DATAh(push, address[b] + ve->src_offset);268PUSH_DATA (push, address[b] + ve->src_offset);269}270nvc0->base.vbo_dirty = true;271}272273static void274nvc0_update_user_vbufs_shared(struct nvc0_context *nvc0)275{276struct nouveau_pushbuf *push = nvc0->base.pushbuf;277uint32_t mask = nvc0->vbo_user & ~nvc0->constant_vbos;278279PUSH_SPACE(push, nvc0->num_vtxbufs * 8);280while (mask) {281struct nouveau_bo *bo;282const uint32_t bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART;283uint64_t address;284uint32_t base, size;285const int b = ffs(mask) - 1;286mask &= ~(1 << b);287288nvc0_user_vbuf_range(nvc0, b, &base, &size);289290address = nouveau_scratch_data(&nvc0->base, nvc0->vtxbuf[b].buffer.user,291base, size, &bo);292if (bo)293BCTX_REFN_bo(nvc0->bufctx_3d, 3D_VTX_TMP, bo_flags, bo);294295BEGIN_1IC0(push, NVC0_3D(MACRO_VERTEX_ARRAY_SELECT), 5);296PUSH_DATA (push, b);297PUSH_DATAh(push, address + base + size - 1);298PUSH_DATA (push, address + base + size - 1);299PUSH_DATAh(push, address);300PUSH_DATA (push, address);301302NOUVEAU_DRV_STAT(&nvc0->screen->base, user_buffer_upload_bytes, size);303}304305mask = nvc0->state.constant_elts;306while (mask) {307int i = ffs(mask) - 1;308mask &= ~(1 << i);309nvc0_set_constant_vertex_attrib(nvc0, i);310}311}312313static void314nvc0_validate_vertex_buffers(struct nvc0_context *nvc0)315{316struct nouveau_pushbuf *push = nvc0->base.pushbuf;317const struct nvc0_vertex_stateobj *vertex = nvc0->vertex;318uint32_t refd = 0;319unsigned i;320321PUSH_SPACE(push, vertex->num_elements * 8);322for (i = 0; i < vertex->num_elements; ++i) {323const struct nvc0_vertex_element *ve;324const struct pipe_vertex_buffer *vb;325struct nv04_resource *res;326unsigned b;327unsigned limit, offset;328329if (nvc0->state.constant_elts & (1 << i))330continue;331ve = &vertex->element[i];332b = ve->pipe.vertex_buffer_index;333vb = &nvc0->vtxbuf[b];334335if (nvc0->vbo_user & (1 << b)) {336if (!(nvc0->constant_vbos & (1 << b))) {337if (ve->pipe.instance_divisor) {338BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_DIVISOR(i)), 1);339PUSH_DATA (push, ve->pipe.instance_divisor);340}341BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 1);342PUSH_DATA (push, (1 << 12) | vb->stride);343}344/* address/value set in nvc0_update_user_vbufs */345continue;346}347res = nv04_resource(vb->buffer.resource);348offset = ve->pipe.src_offset + vb->buffer_offset;349limit = vb->buffer.resource->width0 - 1;350351if (unlikely(ve->pipe.instance_divisor)) {352BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 4);353PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);354PUSH_DATAh(push, res->address + offset);355PUSH_DATA (push, res->address + offset);356PUSH_DATA (push, ve->pipe.instance_divisor);357} else {358BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 3);359PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);360PUSH_DATAh(push, res->address + offset);361PUSH_DATA (push, res->address + offset);362}363364if (nvc0->screen->eng3d->oclass < TU102_3D_CLASS)365BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_LIMIT_HIGH(i)), 2);366else367BEGIN_NVC0(push, SUBC_3D(TU102_3D_VERTEX_ARRAY_LIMIT_HIGH(i)), 2);368PUSH_DATAh(push, res->address + limit);369PUSH_DATA (push, res->address + limit);370371if (!(refd & (1 << b))) {372refd |= 1 << b;373BCTX_REFN(nvc0->bufctx_3d, 3D_VTX, res, RD);374}375}376if (nvc0->vbo_user)377nvc0_update_user_vbufs(nvc0);378}379380static void381nvc0_validate_vertex_buffers_shared(struct nvc0_context *nvc0)382{383struct nouveau_pushbuf *push = nvc0->base.pushbuf;384unsigned b;385const uint32_t mask = nvc0->vbo_user;386387PUSH_SPACE(push, nvc0->num_vtxbufs * 8 + nvc0->vertex->num_elements);388for (b = 0; b < nvc0->num_vtxbufs; ++b) {389struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[b];390struct nv04_resource *buf;391uint32_t offset, limit;392393if (mask & (1 << b)) {394if (!(nvc0->constant_vbos & (1 << b))) {395BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(b)), 1);396PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);397}398/* address/value set in nvc0_update_user_vbufs_shared */399continue;400} else if (!vb->buffer.resource) {401/* there can be holes in the vertex buffer lists */402IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(b)), 0);403continue;404}405buf = nv04_resource(vb->buffer.resource);406offset = vb->buffer_offset;407limit = buf->base.width0 - 1;408409BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(b)), 3);410PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);411PUSH_DATAh(push, buf->address + offset);412PUSH_DATA (push, buf->address + offset);413414if (nvc0->screen->eng3d->oclass < TU102_3D_CLASS)415BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_LIMIT_HIGH(b)), 2);416else417BEGIN_NVC0(push, SUBC_3D(TU102_3D_VERTEX_ARRAY_LIMIT_HIGH(b)), 2);418PUSH_DATAh(push, buf->address + limit);419PUSH_DATA (push, buf->address + limit);420421BCTX_REFN(nvc0->bufctx_3d, 3D_VTX, buf, RD);422}423/* If there are more elements than buffers, we might not have unset424* fetching on the later elements.425*/426for (; b < nvc0->vertex->num_elements; ++b)427IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(b)), 0);428429if (nvc0->vbo_user)430nvc0_update_user_vbufs_shared(nvc0);431}432433void434nvc0_vertex_arrays_validate(struct nvc0_context *nvc0)435{436struct nouveau_pushbuf *push = nvc0->base.pushbuf;437struct nvc0_vertex_stateobj *vertex = nvc0->vertex;438struct nvc0_vertex_element *ve;439uint32_t const_vbos;440unsigned i;441uint8_t vbo_mode;442bool update_vertex;443444nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_VTX);445446assert(vertex);447if (unlikely(vertex->need_conversion) ||448unlikely(nvc0->vertprog->vp.edgeflag < PIPE_MAX_ATTRIBS)) {449vbo_mode = 3;450} else if (nvc0->vbo_user & ~nvc0->constant_vbos) {451vbo_mode = nvc0->vbo_push_hint ? 1 : 0;452} else {453vbo_mode = 0;454}455const_vbos = vbo_mode ? 0 : nvc0->constant_vbos;456457update_vertex = (nvc0->dirty_3d & NVC0_NEW_3D_VERTEX) ||458(const_vbos != nvc0->state.constant_vbos) ||459(vbo_mode != nvc0->state.vbo_mode);460461if (update_vertex) {462const unsigned n = MAX2(vertex->num_elements, nvc0->state.num_vtxelts);463464nvc0->state.constant_vbos = const_vbos;465nvc0->state.constant_elts = 0;466nvc0->state.num_vtxelts = vertex->num_elements;467nvc0->state.vbo_mode = vbo_mode;468469if (unlikely(vbo_mode)) {470if (unlikely(nvc0->state.instance_elts & 3)) {471/* translate mode uses only 2 vertex buffers */472nvc0->state.instance_elts &= ~3;473PUSH_SPACE(push, 3);474BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_PER_INSTANCE(0)), 2);475PUSH_DATA (push, 0);476PUSH_DATA (push, 0);477}478479PUSH_SPACE(push, n * 2 + 4);480481BEGIN_NVC0(push, NVC0_3D(VERTEX_ATTRIB_FORMAT(0)), n);482for (i = 0; i < vertex->num_elements; ++i)483PUSH_DATA(push, vertex->element[i].state_alt);484for (; i < n; ++i)485PUSH_DATA(push, NVC0_3D_VERTEX_ATTRIB_INACTIVE);486487BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(0)), 1);488PUSH_DATA (push, (1 << 12) | vertex->size);489for (i = 1; i < n; ++i)490IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 0);491} else {492uint32_t *restrict data;493494if (unlikely(vertex->instance_elts != nvc0->state.instance_elts)) {495nvc0->state.instance_elts = vertex->instance_elts;496assert(n); /* if (n == 0), both masks should be 0 */497PUSH_SPACE(push, 3);498BEGIN_NVC0(push, NVC0_3D(MACRO_VERTEX_ARRAY_PER_INSTANCE), 2);499PUSH_DATA (push, n);500PUSH_DATA (push, vertex->instance_elts);501}502503PUSH_SPACE(push, n * 2 + 1);504BEGIN_NVC0(push, NVC0_3D(VERTEX_ATTRIB_FORMAT(0)), n);505data = push->cur;506push->cur += n;507for (i = 0; i < vertex->num_elements; ++i) {508ve = &vertex->element[i];509data[i] = ve->state;510if (unlikely(const_vbos & (1 << ve->pipe.vertex_buffer_index))) {511nvc0->state.constant_elts |= 1 << i;512data[i] |= NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST;513IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 0);514}515}516for (; i < n; ++i) {517data[i] = NVC0_3D_VERTEX_ATTRIB_INACTIVE;518IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 0);519}520}521}522if (nvc0->state.vbo_mode) /* using translate, don't set up arrays here */523return;524525if (vertex->shared_slots)526nvc0_validate_vertex_buffers_shared(nvc0);527else528nvc0_validate_vertex_buffers(nvc0);529}530531#define NVC0_PRIM_GL_CASE(n) \532case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n533534static inline unsigned535nvc0_prim_gl(unsigned prim)536{537switch (prim) {538NVC0_PRIM_GL_CASE(POINTS);539NVC0_PRIM_GL_CASE(LINES);540NVC0_PRIM_GL_CASE(LINE_LOOP);541NVC0_PRIM_GL_CASE(LINE_STRIP);542NVC0_PRIM_GL_CASE(TRIANGLES);543NVC0_PRIM_GL_CASE(TRIANGLE_STRIP);544NVC0_PRIM_GL_CASE(TRIANGLE_FAN);545NVC0_PRIM_GL_CASE(QUADS);546NVC0_PRIM_GL_CASE(QUAD_STRIP);547NVC0_PRIM_GL_CASE(POLYGON);548NVC0_PRIM_GL_CASE(LINES_ADJACENCY);549NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);550NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);551NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);552NVC0_PRIM_GL_CASE(PATCHES);553default:554return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;555}556}557558static void559nvc0_draw_vbo_kick_notify(struct nouveau_pushbuf *push)560{561struct nvc0_screen *screen = push->user_priv;562563nouveau_fence_update(&screen->base, true);564565NOUVEAU_DRV_STAT(&screen->base, pushbuf_count, 1);566}567568static void569nvc0_draw_arrays(struct nvc0_context *nvc0,570unsigned mode, unsigned start, unsigned count,571unsigned instance_count)572{573struct nouveau_pushbuf *push = nvc0->base.pushbuf;574unsigned prim;575576if (nvc0->state.index_bias) {577/* index_bias is implied 0 if !info->index_size (really ?) */578/* TODO: can we deactivate it for the VERTEX_BUFFER_FIRST command ? */579PUSH_SPACE(push, 2);580IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_BASE), 0);581IMMED_NVC0(push, NVC0_3D(VERTEX_ID_BASE), 0);582nvc0->state.index_bias = 0;583}584585prim = nvc0_prim_gl(mode);586587while (instance_count--) {588PUSH_SPACE(push, 6);589BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);590PUSH_DATA (push, prim);591BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2);592PUSH_DATA (push, start);593PUSH_DATA (push, count);594IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);595596prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;597}598NOUVEAU_DRV_STAT(&nvc0->screen->base, draw_calls_array, 1);599}600601static void602nvc0_draw_elements_inline_u08(struct nouveau_pushbuf *push, const uint8_t *map,603unsigned start, unsigned count)604{605map += start;606607if (count & 3) {608unsigned i;609PUSH_SPACE(push, 4);610BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U32), count & 3);611for (i = 0; i < (count & 3); ++i)612PUSH_DATA(push, *map++);613count &= ~3;614}615while (count) {616unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 4) / 4;617618PUSH_SPACE(push, nr + 1);619BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U8), nr);620for (i = 0; i < nr; ++i) {621PUSH_DATA(push,622(map[3] << 24) | (map[2] << 16) | (map[1] << 8) | map[0]);623map += 4;624}625count -= nr * 4;626}627}628629static void630nvc0_draw_elements_inline_u16(struct nouveau_pushbuf *push, const uint16_t *map,631unsigned start, unsigned count)632{633map += start;634635if (count & 1) {636count &= ~1;637PUSH_SPACE(push, 2);638BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);639PUSH_DATA (push, *map++);640}641while (count) {642unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;643644PUSH_SPACE(push, nr + 1);645BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U16), nr);646for (i = 0; i < nr; ++i) {647PUSH_DATA(push, (map[1] << 16) | map[0]);648map += 2;649}650count -= nr * 2;651}652}653654static void655nvc0_draw_elements_inline_u32(struct nouveau_pushbuf *push, const uint32_t *map,656unsigned start, unsigned count)657{658map += start;659660while (count) {661const unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);662663PUSH_SPACE(push, nr + 1);664BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U32), nr);665PUSH_DATAp(push, map, nr);666667map += nr;668count -= nr;669}670}671672static void673nvc0_draw_elements_inline_u32_short(struct nouveau_pushbuf *push,674const uint32_t *map,675unsigned start, unsigned count)676{677map += start;678679if (count & 1) {680count--;681PUSH_SPACE(push, 2);682BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);683PUSH_DATA (push, *map++);684}685while (count) {686unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;687688PUSH_SPACE(push, nr + 1);689BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U16), nr);690for (i = 0; i < nr; ++i) {691PUSH_DATA(push, (map[1] << 16) | map[0]);692map += 2;693}694count -= nr * 2;695}696}697698static void699nvc0_draw_elements(struct nvc0_context *nvc0, bool shorten,700const struct pipe_draw_info *info,701unsigned mode, unsigned start, unsigned count,702unsigned instance_count, int32_t index_bias,703unsigned index_size)704{705struct nouveau_pushbuf *push = nvc0->base.pushbuf;706unsigned prim;707708prim = nvc0_prim_gl(mode);709710if (index_bias != nvc0->state.index_bias) {711PUSH_SPACE(push, 4);712BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_BASE), 1);713PUSH_DATA (push, index_bias);714BEGIN_NVC0(push, NVC0_3D(VERTEX_ID_BASE), 1);715PUSH_DATA (push, index_bias);716nvc0->state.index_bias = index_bias;717}718719if (!info->has_user_indices) {720PUSH_SPACE(push, 1);721IMMED_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), prim);722do {723PUSH_SPACE(push, 7);724BEGIN_NVC0(push, NVC0_3D(INDEX_BATCH_FIRST), 2);725PUSH_DATA (push, start);726PUSH_DATA (push, count);727if (--instance_count) {728BEGIN_NVC0(push, NVC0_3D(VERTEX_END_GL), 2);729PUSH_DATA (push, 0);730PUSH_DATA (push, prim | NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT);731}732} while (instance_count);733IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);734} else {735const void *data = info->index.user;736737while (instance_count--) {738PUSH_SPACE(push, 2);739BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);740PUSH_DATA (push, prim);741switch (index_size) {742case 1:743nvc0_draw_elements_inline_u08(push, data, start, count);744break;745case 2:746nvc0_draw_elements_inline_u16(push, data, start, count);747break;748case 4:749if (shorten)750nvc0_draw_elements_inline_u32_short(push, data, start, count);751else752nvc0_draw_elements_inline_u32(push, data, start, count);753break;754default:755assert(0);756return;757}758PUSH_SPACE(push, 1);759IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);760761prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;762}763}764NOUVEAU_DRV_STAT(&nvc0->screen->base, draw_calls_indexed, 1);765}766767static void768nvc0_draw_stream_output(struct nvc0_context *nvc0,769const struct pipe_draw_info *info,770const struct pipe_draw_indirect_info *indirect)771{772struct nouveau_pushbuf *push = nvc0->base.pushbuf;773struct nvc0_so_target *so = nvc0_so_target(indirect->count_from_stream_output);774struct nv04_resource *res = nv04_resource(so->pipe.buffer);775unsigned mode = nvc0_prim_gl(info->mode);776unsigned num_instances = info->instance_count;777778if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) {779res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING;780PUSH_SPACE(push, 2);781IMMED_NVC0(push, NVC0_3D(SERIALIZE), 0);782nvc0_hw_query_fifo_wait(nvc0, nvc0_query(so->pq));783if (nvc0->screen->eng3d->oclass < GM107_3D_CLASS)784IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FLUSH), 0);785786NOUVEAU_DRV_STAT(&nvc0->screen->base, gpu_serialize_count, 1);787}788789while (num_instances--) {790nouveau_pushbuf_space(push, 16, 0, 1);791BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);792PUSH_DATA (push, mode);793BEGIN_NVC0(push, NVC0_3D(DRAW_TFB_BASE), 1);794PUSH_DATA (push, 0);795BEGIN_NVC0(push, NVC0_3D(DRAW_TFB_STRIDE), 1);796PUSH_DATA (push, so->stride);797BEGIN_NVC0(push, NVC0_3D(DRAW_TFB_BYTES), 1);798nvc0_hw_query_pushbuf_submit(push, nvc0_query(so->pq), 0x4);799IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);800801mode |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;802}803}804805static void806nvc0_draw_indirect(struct nvc0_context *nvc0, const struct pipe_draw_info *info,807unsigned drawid_offset,808const struct pipe_draw_indirect_info *indirect)809{810struct nouveau_pushbuf *push = nvc0->base.pushbuf;811struct nv04_resource *buf = nv04_resource(indirect->buffer);812struct nv04_resource *buf_count = nv04_resource(indirect->indirect_draw_count);813unsigned size, macro, count = indirect->draw_count, drawid = drawid_offset;814uint32_t offset = buf->offset + indirect->offset;815struct nvc0_screen *screen = nvc0->screen;816817PUSH_SPACE(push, 7);818819/* must make FIFO wait for engines idle before continuing to process */820if ((buf->fence_wr && !nouveau_fence_signalled(buf->fence_wr)) ||821(buf_count && buf_count->fence_wr &&822!nouveau_fence_signalled(buf_count->fence_wr))) {823IMMED_NVC0(push, SUBC_3D(NV10_SUBCHAN_REF_CNT), 0);824}825826/* Queue things up to let the macros write params to the driver constbuf */827BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);828PUSH_DATA (push, NVC0_CB_AUX_SIZE);829PUSH_DATAh(push, screen->uniform_bo->offset + NVC0_CB_AUX_INFO(0));830PUSH_DATA (push, screen->uniform_bo->offset + NVC0_CB_AUX_INFO(0));831BEGIN_NVC0(push, NVC0_3D(CB_POS), 1);832PUSH_DATA (push, NVC0_CB_AUX_DRAW_INFO);833834if (info->index_size) {835assert(!info->has_user_indices);836assert(nouveau_resource_mapped_by_gpu(info->index.resource));837size = 5;838if (buf_count)839macro = NVC0_3D_MACRO_DRAW_ELEMENTS_INDIRECT_COUNT;840else841macro = NVC0_3D_MACRO_DRAW_ELEMENTS_INDIRECT;842} else {843if (nvc0->state.index_bias) {844/* index_bias is implied 0 if !info->index_size (really ?) */845IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_BASE), 0);846IMMED_NVC0(push, NVC0_3D(VERTEX_ID_BASE), 0);847nvc0->state.index_bias = 0;848}849size = 4;850if (buf_count)851macro = NVC0_3D_MACRO_DRAW_ARRAYS_INDIRECT_COUNT;852else853macro = NVC0_3D_MACRO_DRAW_ARRAYS_INDIRECT;854}855856/* If the stride is not the natural stride, we have to stick a separate857* push data reference for each draw. Otherwise it can all go in as one.858* Of course there is a maximum packet size, so we have to break things up859* along those borders as well.860*/861while (count) {862unsigned draws = count, pushes, i;863if (indirect->stride == size * 4) {864draws = MIN2(draws, (NV04_PFIFO_MAX_PACKET_LEN - 4) / size);865pushes = 1;866} else {867draws = MIN2(draws, 32);868pushes = draws;869}870871nouveau_pushbuf_space(push, 16, 0, pushes + !!buf_count);872PUSH_REFN(push, buf->bo, NOUVEAU_BO_RD | buf->domain);873if (buf_count)874PUSH_REFN(push, buf_count->bo, NOUVEAU_BO_RD | buf_count->domain);875PUSH_DATA(push,876NVC0_FIFO_PKHDR_1I(0, macro, 3 + !!buf_count + draws * size));877PUSH_DATA(push, nvc0_prim_gl(info->mode));878PUSH_DATA(push, drawid);879PUSH_DATA(push, draws);880if (buf_count) {881nouveau_pushbuf_data(push,882buf_count->bo,883buf_count->offset + indirect->indirect_draw_count_offset,884NVC0_IB_ENTRY_1_NO_PREFETCH | 4);885}886if (pushes == 1) {887nouveau_pushbuf_data(push,888buf->bo, offset,889NVC0_IB_ENTRY_1_NO_PREFETCH | (size * 4 * draws));890offset += draws * indirect->stride;891} else {892for (i = 0; i < pushes; i++) {893nouveau_pushbuf_data(push,894buf->bo, offset,895NVC0_IB_ENTRY_1_NO_PREFETCH | (size * 4));896offset += indirect->stride;897}898}899count -= draws;900drawid += draws;901}902}903904static inline void905nvc0_update_prim_restart(struct nvc0_context *nvc0, bool en, uint32_t index)906{907struct nouveau_pushbuf *push = nvc0->base.pushbuf;908909if (en != nvc0->state.prim_restart) {910if (en) {911BEGIN_NVC0(push, NVC0_3D(PRIM_RESTART_ENABLE), 2);912PUSH_DATA (push, 1);913PUSH_DATA (push, index);914} else {915IMMED_NVC0(push, NVC0_3D(PRIM_RESTART_ENABLE), 0);916}917nvc0->state.prim_restart = en;918} else919if (en) {920BEGIN_NVC0(push, NVC0_3D(PRIM_RESTART_INDEX), 1);921PUSH_DATA (push, index);922}923}924925void926nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info,927unsigned drawid_offset,928const struct pipe_draw_indirect_info *indirect,929const struct pipe_draw_start_count_bias *draws,930unsigned num_draws)931{932if (num_draws > 1) {933util_draw_multi(pipe, info, drawid_offset, indirect, draws, num_draws);934return;935}936937if (!indirect && (!draws[0].count || !info->instance_count))938return;939940struct nvc0_context *nvc0 = nvc0_context(pipe);941struct nouveau_pushbuf *push = nvc0->base.pushbuf;942struct nvc0_screen *screen = nvc0->screen;943unsigned vram_domain = NV_VRAM_DOMAIN(&screen->base);944int s;945946/* NOTE: caller must ensure that (min_index + index_bias) is >= 0 */947if (info->index_bounds_valid) {948nvc0->vb_elt_first = info->min_index + (info->index_size ? draws->index_bias : 0);949nvc0->vb_elt_limit = info->max_index - info->min_index;950} else {951nvc0->vb_elt_first = 0;952nvc0->vb_elt_limit = ~0;953}954nvc0->instance_off = info->start_instance;955nvc0->instance_max = info->instance_count - 1;956957/* For picking only a few vertices from a large user buffer, push is better,958* if index count is larger and we expect repeated vertices, suggest upload.959*/960nvc0->vbo_push_hint =961(!indirect || indirect->count_from_stream_output) && info->index_size &&962(nvc0->vb_elt_limit >= (draws[0].count * 2));963964/* Check whether we want to switch vertex-submission mode. */965if (nvc0->vbo_user && !(nvc0->dirty_3d & (NVC0_NEW_3D_ARRAYS | NVC0_NEW_3D_VERTEX))) {966if (nvc0->vbo_push_hint != !!nvc0->state.vbo_mode)967if (nvc0->state.vbo_mode != 3)968nvc0->dirty_3d |= NVC0_NEW_3D_ARRAYS;969970if (!(nvc0->dirty_3d & NVC0_NEW_3D_ARRAYS) && nvc0->state.vbo_mode == 0) {971if (nvc0->vertex->shared_slots)972nvc0_update_user_vbufs_shared(nvc0);973else974nvc0_update_user_vbufs(nvc0);975}976}977978if (info->mode == PIPE_PRIM_PATCHES &&979nvc0->state.patch_vertices != info->vertices_per_patch) {980nvc0->state.patch_vertices = info->vertices_per_patch;981PUSH_SPACE(push, 1);982IMMED_NVC0(push, NVC0_3D(PATCH_VERTICES), nvc0->state.patch_vertices);983}984985if (info->index_size && !info->has_user_indices) {986struct nv04_resource *buf = nv04_resource(info->index.resource);987988assert(buf);989assert(nouveau_resource_mapped_by_gpu(&buf->base));990991PUSH_SPACE(push, 6);992if (nvc0->screen->eng3d->oclass < TU102_3D_CLASS) {993BEGIN_NVC0(push, NVC0_3D(INDEX_ARRAY_START_HIGH), 5);994PUSH_DATAh(push, buf->address);995PUSH_DATA (push, buf->address);996PUSH_DATAh(push, buf->address + buf->base.width0 - 1);997PUSH_DATA (push, buf->address + buf->base.width0 - 1);998PUSH_DATA (push, info->index_size >> 1);999} else {1000BEGIN_NVC0(push, NVC0_3D(INDEX_ARRAY_START_HIGH), 2);1001PUSH_DATAh(push, buf->address);1002PUSH_DATA (push, buf->address);1003BEGIN_NVC0(push, SUBC_3D(TU102_3D_INDEX_ARRAY_LIMIT_HIGH), 2);1004PUSH_DATAh(push, buf->address + buf->base.width0 - 1);1005PUSH_DATA (push, buf->address + buf->base.width0 - 1);1006BEGIN_NVC0(push, NVC0_3D(INDEX_FORMAT), 1);1007PUSH_DATA (push, info->index_size >> 1);1008}10091010BCTX_REFN(nvc0->bufctx_3d, 3D_IDX, buf, RD);1011}10121013list_for_each_entry(struct nvc0_resident, resident, &nvc0->tex_head, list) {1014nvc0_add_resident(nvc0->bufctx_3d, NVC0_BIND_3D_BINDLESS, resident->buf,1015resident->flags);1016}10171018list_for_each_entry(struct nvc0_resident, resident, &nvc0->img_head, list) {1019nvc0_add_resident(nvc0->bufctx_3d, NVC0_BIND_3D_BINDLESS, resident->buf,1020resident->flags);1021}10221023BCTX_REFN_bo(nvc0->bufctx_3d, 3D_TEXT, vram_domain | NOUVEAU_BO_RD,1024screen->text);10251026nvc0_state_validate_3d(nvc0, ~0);10271028if (nvc0->vertprog->vp.need_draw_parameters && (!indirect || indirect->count_from_stream_output)) {1029PUSH_SPACE(push, 9);1030BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);1031PUSH_DATA (push, NVC0_CB_AUX_SIZE);1032PUSH_DATAh(push, screen->uniform_bo->offset + NVC0_CB_AUX_INFO(0));1033PUSH_DATA (push, screen->uniform_bo->offset + NVC0_CB_AUX_INFO(0));1034BEGIN_1IC0(push, NVC0_3D(CB_POS), 1 + 3);1035PUSH_DATA (push, NVC0_CB_AUX_DRAW_INFO);1036PUSH_DATA (push, info->index_size ? draws->index_bias : 0);1037PUSH_DATA (push, info->start_instance);1038PUSH_DATA (push, drawid_offset);1039}10401041if (nvc0->screen->base.class_3d < NVE4_3D_CLASS &&1042nvc0->seamless_cube_map != nvc0->state.seamless_cube_map) {1043nvc0->state.seamless_cube_map = nvc0->seamless_cube_map;1044PUSH_SPACE(push, 1);1045IMMED_NVC0(push, NVC0_3D(TEX_MISC),1046nvc0->seamless_cube_map ? NVC0_3D_TEX_MISC_SEAMLESS_CUBE_MAP : 0);1047}10481049push->kick_notify = nvc0_draw_vbo_kick_notify;10501051for (s = 0; s < 5 && !nvc0->cb_dirty; ++s) {1052if (nvc0->constbuf_coherent[s])1053nvc0->cb_dirty = true;1054}10551056if (nvc0->cb_dirty) {1057PUSH_SPACE(push, 1);1058IMMED_NVC0(push, NVC0_3D(MEM_BARRIER), 0x1011);1059nvc0->cb_dirty = false;1060}10611062for (s = 0; s < 5; ++s) {1063if (!nvc0->textures_coherent[s])1064continue;10651066PUSH_SPACE(push, nvc0->num_textures[s] * 2);10671068for (int i = 0; i < nvc0->num_textures[s]; ++i) {1069struct nv50_tic_entry *tic = nv50_tic_entry(nvc0->textures[s][i]);1070if (!(nvc0->textures_coherent[s] & (1 << i)))1071continue;10721073BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1);1074PUSH_DATA (push, (tic->id << 4) | 1);1075NOUVEAU_DRV_STAT(&nvc0->screen->base, tex_cache_flush_count, 1);1076}1077}10781079if (nvc0->state.vbo_mode) {1080if (indirect && indirect->buffer)1081nvc0_push_vbo_indirect(nvc0, info, drawid_offset, indirect, &draws[0]);1082else1083nvc0_push_vbo(nvc0, info, indirect, &draws[0]);1084goto cleanup;1085}10861087/* space for base instance, flush, and prim restart */1088PUSH_SPACE(push, 8);10891090if (nvc0->state.instance_base != info->start_instance) {1091nvc0->state.instance_base = info->start_instance;1092/* NOTE: this does not affect the shader input, should it ? */1093BEGIN_NVC0(push, NVC0_3D(VB_INSTANCE_BASE), 1);1094PUSH_DATA (push, info->start_instance);1095}10961097nvc0->base.vbo_dirty |= !!nvc0->vtxbufs_coherent;10981099if (!nvc0->base.vbo_dirty && info->index_size && !info->has_user_indices &&1100info->index.resource->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT)1101nvc0->base.vbo_dirty = true;11021103nvc0_update_prim_restart(nvc0, info->primitive_restart, info->restart_index);11041105if (nvc0->base.vbo_dirty) {1106if (nvc0->screen->eng3d->oclass < GM107_3D_CLASS)1107IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FLUSH), 0);1108nvc0->base.vbo_dirty = false;1109}11101111if (unlikely(indirect && indirect->buffer)) {1112nvc0_draw_indirect(nvc0, info, drawid_offset, indirect);1113} else1114if (unlikely(indirect && indirect->count_from_stream_output)) {1115nvc0_draw_stream_output(nvc0, info, indirect);1116} else1117if (info->index_size) {1118bool shorten = info->index_bounds_valid && info->max_index <= 65535;11191120if (info->primitive_restart && info->restart_index > 65535)1121shorten = false;11221123nvc0_draw_elements(nvc0, shorten, info,1124info->mode, draws[0].start, draws[0].count,1125info->instance_count, draws->index_bias, info->index_size);1126} else {1127nvc0_draw_arrays(nvc0,1128info->mode, draws[0].start, draws[0].count,1129info->instance_count);1130}11311132cleanup:1133push->kick_notify = nvc0_default_kick_notify;11341135nvc0_release_user_vbufs(nvc0);11361137nouveau_pushbuf_bufctx(push, NULL);11381139nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_TEXT);1140nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_IDX);1141nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_BINDLESS);1142}114311441145