1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2012 Red Hat Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 12bf215546Sopenharmony_ci * all copies or substantial portions of the Software. 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 21bf215546Sopenharmony_ci * 22bf215546Sopenharmony_ci * Authors: Ben Skeggs 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci */ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "util/format/u_format.h" 27bf215546Sopenharmony_ci#include "util/u_draw.h" 28bf215546Sopenharmony_ci#include "util/u_inlines.h" 29bf215546Sopenharmony_ci#include "util/u_prim.h" 30bf215546Sopenharmony_ci#include "translate/translate.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "nouveau_fence.h" 33bf215546Sopenharmony_ci#include "nv_object.xml.h" 34bf215546Sopenharmony_ci#include "nv30/nv30-40_3d.xml.h" 35bf215546Sopenharmony_ci#include "nv30/nv30_context.h" 36bf215546Sopenharmony_ci#include "nv30/nv30_format.h" 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_cistatic void 39bf215546Sopenharmony_cinv30_emit_vtxattr(struct nv30_context *nv30, struct pipe_vertex_buffer *vb, 40bf215546Sopenharmony_ci struct pipe_vertex_element *ve, unsigned attr) 41bf215546Sopenharmony_ci{ 42bf215546Sopenharmony_ci const unsigned nc = util_format_get_nr_components(ve->src_format); 43bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv30->base.pushbuf; 44bf215546Sopenharmony_ci struct nv04_resource *res = nv04_resource(vb->buffer.resource); 45bf215546Sopenharmony_ci const void *data; 46bf215546Sopenharmony_ci float v[4]; 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci data = nouveau_resource_map_offset(&nv30->base, res, vb->buffer_offset + 49bf215546Sopenharmony_ci ve->src_offset, NOUVEAU_BO_RD); 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci util_format_unpack_rgba(ve->src_format, v, data, 1); 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci switch (nc) { 54bf215546Sopenharmony_ci case 4: 55bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VTX_ATTR_4F(attr)), 4); 56bf215546Sopenharmony_ci PUSH_DATAf(push, v[0]); 57bf215546Sopenharmony_ci PUSH_DATAf(push, v[1]); 58bf215546Sopenharmony_ci PUSH_DATAf(push, v[2]); 59bf215546Sopenharmony_ci PUSH_DATAf(push, v[3]); 60bf215546Sopenharmony_ci break; 61bf215546Sopenharmony_ci case 3: 62bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(attr)), 3); 63bf215546Sopenharmony_ci PUSH_DATAf(push, v[0]); 64bf215546Sopenharmony_ci PUSH_DATAf(push, v[1]); 65bf215546Sopenharmony_ci PUSH_DATAf(push, v[2]); 66bf215546Sopenharmony_ci break; 67bf215546Sopenharmony_ci case 2: 68bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VTX_ATTR_2F(attr)), 2); 69bf215546Sopenharmony_ci PUSH_DATAf(push, v[0]); 70bf215546Sopenharmony_ci PUSH_DATAf(push, v[1]); 71bf215546Sopenharmony_ci break; 72bf215546Sopenharmony_ci case 1: 73bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VTX_ATTR_1F(attr)), 1); 74bf215546Sopenharmony_ci PUSH_DATAf(push, v[0]); 75bf215546Sopenharmony_ci break; 76bf215546Sopenharmony_ci default: 77bf215546Sopenharmony_ci assert(0); 78bf215546Sopenharmony_ci break; 79bf215546Sopenharmony_ci } 80bf215546Sopenharmony_ci} 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_cistatic inline void 83bf215546Sopenharmony_cinv30_vbuf_range(struct nv30_context *nv30, int vbi, 84bf215546Sopenharmony_ci uint32_t *base, uint32_t *size) 85bf215546Sopenharmony_ci{ 86bf215546Sopenharmony_ci assert(nv30->vbo_max_index != ~0); 87bf215546Sopenharmony_ci *base = nv30->vbo_min_index * nv30->vtxbuf[vbi].stride; 88bf215546Sopenharmony_ci *size = (nv30->vbo_max_index - 89bf215546Sopenharmony_ci nv30->vbo_min_index + 1) * nv30->vtxbuf[vbi].stride; 90bf215546Sopenharmony_ci} 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_cistatic void 93bf215546Sopenharmony_cinv30_prevalidate_vbufs(struct nv30_context *nv30) 94bf215546Sopenharmony_ci{ 95bf215546Sopenharmony_ci struct pipe_vertex_buffer *vb; 96bf215546Sopenharmony_ci struct nv04_resource *buf; 97bf215546Sopenharmony_ci int i; 98bf215546Sopenharmony_ci uint32_t base, size; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci nv30->vbo_fifo = nv30->vbo_user = 0; 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci for (i = 0; i < nv30->num_vtxbufs; i++) { 103bf215546Sopenharmony_ci vb = &nv30->vtxbuf[i]; 104bf215546Sopenharmony_ci if (!vb->stride || !vb->buffer.resource) /* NOTE: user_buffer not implemented */ 105bf215546Sopenharmony_ci continue; 106bf215546Sopenharmony_ci buf = nv04_resource(vb->buffer.resource); 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci /* NOTE: user buffers with temporary storage count as mapped by GPU */ 109bf215546Sopenharmony_ci if (!nouveau_resource_mapped_by_gpu(vb->buffer.resource)) { 110bf215546Sopenharmony_ci if (nv30->vbo_push_hint) { 111bf215546Sopenharmony_ci nv30->vbo_fifo = ~0; 112bf215546Sopenharmony_ci continue; 113bf215546Sopenharmony_ci } else { 114bf215546Sopenharmony_ci if (buf->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY) { 115bf215546Sopenharmony_ci nv30->vbo_user |= 1 << i; 116bf215546Sopenharmony_ci assert(vb->stride > vb->buffer_offset); 117bf215546Sopenharmony_ci nv30_vbuf_range(nv30, i, &base, &size); 118bf215546Sopenharmony_ci nouveau_user_buffer_upload(&nv30->base, buf, base, size); 119bf215546Sopenharmony_ci } else { 120bf215546Sopenharmony_ci nouveau_buffer_migrate(&nv30->base, buf, NOUVEAU_BO_GART); 121bf215546Sopenharmony_ci } 122bf215546Sopenharmony_ci nv30->base.vbo_dirty = true; 123bf215546Sopenharmony_ci } 124bf215546Sopenharmony_ci } 125bf215546Sopenharmony_ci } 126bf215546Sopenharmony_ci} 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_cistatic void 129bf215546Sopenharmony_cinv30_update_user_vbufs(struct nv30_context *nv30) 130bf215546Sopenharmony_ci{ 131bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv30->base.pushbuf; 132bf215546Sopenharmony_ci uint32_t base, offset, size; 133bf215546Sopenharmony_ci int i; 134bf215546Sopenharmony_ci uint32_t written = 0; 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci for (i = 0; i < nv30->vertex->num_elements; i++) { 137bf215546Sopenharmony_ci struct pipe_vertex_element *ve = &nv30->vertex->pipe[i]; 138bf215546Sopenharmony_ci const int b = ve->vertex_buffer_index; 139bf215546Sopenharmony_ci struct pipe_vertex_buffer *vb = &nv30->vtxbuf[b]; 140bf215546Sopenharmony_ci struct nv04_resource *buf = nv04_resource(vb->buffer.resource); 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci if (!(nv30->vbo_user & (1 << b))) 143bf215546Sopenharmony_ci continue; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci if (!vb->stride) { 146bf215546Sopenharmony_ci nv30_emit_vtxattr(nv30, vb, ve, i); 147bf215546Sopenharmony_ci continue; 148bf215546Sopenharmony_ci } 149bf215546Sopenharmony_ci nv30_vbuf_range(nv30, b, &base, &size); 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci if (!(written & (1 << b))) { 152bf215546Sopenharmony_ci written |= 1 << b; 153bf215546Sopenharmony_ci nouveau_user_buffer_upload(&nv30->base, buf, base, size); 154bf215546Sopenharmony_ci } 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci offset = vb->buffer_offset + ve->src_offset; 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VTXBUF(i)), 1); 159bf215546Sopenharmony_ci PUSH_RESRC(push, NV30_3D(VTXBUF(i)), BUFCTX_VTXTMP, buf, offset, 160bf215546Sopenharmony_ci NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 161bf215546Sopenharmony_ci 0, NV30_3D_VTXBUF_DMA1); 162bf215546Sopenharmony_ci } 163bf215546Sopenharmony_ci nv30->base.vbo_dirty = true; 164bf215546Sopenharmony_ci} 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_cistatic inline void 167bf215546Sopenharmony_cinv30_release_user_vbufs(struct nv30_context *nv30) 168bf215546Sopenharmony_ci{ 169bf215546Sopenharmony_ci uint32_t vbo_user = nv30->vbo_user; 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci while (vbo_user) { 172bf215546Sopenharmony_ci int i = ffs(vbo_user) - 1; 173bf215546Sopenharmony_ci vbo_user &= ~(1 << i); 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci nouveau_buffer_release_gpu_storage(nv04_resource(nv30->vtxbuf[i].buffer.resource)); 176bf215546Sopenharmony_ci } 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VTXTMP); 179bf215546Sopenharmony_ci} 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_civoid 182bf215546Sopenharmony_cinv30_vbo_validate(struct nv30_context *nv30) 183bf215546Sopenharmony_ci{ 184bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv30->base.pushbuf; 185bf215546Sopenharmony_ci struct nv30_vertex_stateobj *vertex = nv30->vertex; 186bf215546Sopenharmony_ci struct pipe_vertex_element *ve; 187bf215546Sopenharmony_ci struct pipe_vertex_buffer *vb; 188bf215546Sopenharmony_ci unsigned i, redefine; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VTXBUF); 191bf215546Sopenharmony_ci if (!nv30->vertex || nv30->draw_flags) 192bf215546Sopenharmony_ci return; 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci#if UTIL_ARCH_BIG_ENDIAN 195bf215546Sopenharmony_ci if (1) { /* Figure out where the buffers are getting messed up */ 196bf215546Sopenharmony_ci#else 197bf215546Sopenharmony_ci if (unlikely(vertex->need_conversion)) { 198bf215546Sopenharmony_ci#endif 199bf215546Sopenharmony_ci nv30->vbo_fifo = ~0; 200bf215546Sopenharmony_ci nv30->vbo_user = 0; 201bf215546Sopenharmony_ci } else { 202bf215546Sopenharmony_ci nv30_prevalidate_vbufs(nv30); 203bf215546Sopenharmony_ci } 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci if (!PUSH_SPACE(push, 128)) 206bf215546Sopenharmony_ci return; 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci redefine = MAX2(vertex->num_elements, nv30->state.num_vtxelts); 209bf215546Sopenharmony_ci if (redefine == 0) 210bf215546Sopenharmony_ci return; 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VTXFMT(0)), redefine); 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci for (i = 0; i < vertex->num_elements; i++) { 215bf215546Sopenharmony_ci ve = &vertex->pipe[i]; 216bf215546Sopenharmony_ci vb = &nv30->vtxbuf[ve->vertex_buffer_index]; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci if (likely(vb->stride) || nv30->vbo_fifo) 219bf215546Sopenharmony_ci PUSH_DATA (push, (vb->stride << 8) | vertex->element[i].state); 220bf215546Sopenharmony_ci else 221bf215546Sopenharmony_ci PUSH_DATA (push, NV30_3D_VTXFMT_TYPE_V32_FLOAT); 222bf215546Sopenharmony_ci } 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci for (; i < nv30->state.num_vtxelts; i++) { 225bf215546Sopenharmony_ci PUSH_DATA (push, NV30_3D_VTXFMT_TYPE_V32_FLOAT); 226bf215546Sopenharmony_ci } 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci for (i = 0; i < vertex->num_elements; i++) { 229bf215546Sopenharmony_ci struct nv04_resource *res; 230bf215546Sopenharmony_ci unsigned offset; 231bf215546Sopenharmony_ci bool user; 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci ve = &vertex->pipe[i]; 234bf215546Sopenharmony_ci vb = &nv30->vtxbuf[ve->vertex_buffer_index]; 235bf215546Sopenharmony_ci user = (nv30->vbo_user & (1 << ve->vertex_buffer_index)); 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci res = nv04_resource(vb->buffer.resource); 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci if (nv30->vbo_fifo || unlikely(vb->stride == 0)) { 240bf215546Sopenharmony_ci if (!nv30->vbo_fifo) 241bf215546Sopenharmony_ci nv30_emit_vtxattr(nv30, vb, ve, i); 242bf215546Sopenharmony_ci continue; 243bf215546Sopenharmony_ci } 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci offset = ve->src_offset + vb->buffer_offset; 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VTXBUF(i)), 1); 248bf215546Sopenharmony_ci PUSH_RESRC(push, NV30_3D(VTXBUF(i)), user ? BUFCTX_VTXTMP : BUFCTX_VTXBUF, 249bf215546Sopenharmony_ci res, offset, NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 250bf215546Sopenharmony_ci 0, NV30_3D_VTXBUF_DMA1); 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_ci nv30->state.num_vtxelts = vertex->num_elements; 254bf215546Sopenharmony_ci} 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_cistatic void * 257bf215546Sopenharmony_cinv30_vertex_state_create(struct pipe_context *pipe, unsigned num_elements, 258bf215546Sopenharmony_ci const struct pipe_vertex_element *elements) 259bf215546Sopenharmony_ci{ 260bf215546Sopenharmony_ci struct nv30_vertex_stateobj *so; 261bf215546Sopenharmony_ci struct translate_key transkey; 262bf215546Sopenharmony_ci unsigned i; 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci so = MALLOC(sizeof(*so) + sizeof(*so->element) * num_elements); 265bf215546Sopenharmony_ci if (!so) 266bf215546Sopenharmony_ci return NULL; 267bf215546Sopenharmony_ci memcpy(so->pipe, elements, sizeof(*elements) * num_elements); 268bf215546Sopenharmony_ci so->num_elements = num_elements; 269bf215546Sopenharmony_ci so->need_conversion = false; 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci transkey.nr_elements = 0; 272bf215546Sopenharmony_ci transkey.output_stride = 0; 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci for (i = 0; i < num_elements; i++) { 275bf215546Sopenharmony_ci const struct pipe_vertex_element *ve = &elements[i]; 276bf215546Sopenharmony_ci const unsigned vbi = ve->vertex_buffer_index; 277bf215546Sopenharmony_ci enum pipe_format fmt = ve->src_format; 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci so->element[i].state = nv30_vtxfmt(pipe->screen, fmt)->hw; 280bf215546Sopenharmony_ci if (!so->element[i].state) { 281bf215546Sopenharmony_ci switch (util_format_get_nr_components(fmt)) { 282bf215546Sopenharmony_ci case 1: fmt = PIPE_FORMAT_R32_FLOAT; break; 283bf215546Sopenharmony_ci case 2: fmt = PIPE_FORMAT_R32G32_FLOAT; break; 284bf215546Sopenharmony_ci case 3: fmt = PIPE_FORMAT_R32G32B32_FLOAT; break; 285bf215546Sopenharmony_ci case 4: fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; break; 286bf215546Sopenharmony_ci default: 287bf215546Sopenharmony_ci assert(0); 288bf215546Sopenharmony_ci FREE(so); 289bf215546Sopenharmony_ci return NULL; 290bf215546Sopenharmony_ci } 291bf215546Sopenharmony_ci so->element[i].state = nv30_vtxfmt(pipe->screen, fmt)->hw; 292bf215546Sopenharmony_ci so->need_conversion = true; 293bf215546Sopenharmony_ci } 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci if (1) { 296bf215546Sopenharmony_ci unsigned j = transkey.nr_elements++; 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci transkey.element[j].type = TRANSLATE_ELEMENT_NORMAL; 299bf215546Sopenharmony_ci transkey.element[j].input_format = ve->src_format; 300bf215546Sopenharmony_ci transkey.element[j].input_buffer = vbi; 301bf215546Sopenharmony_ci transkey.element[j].input_offset = ve->src_offset; 302bf215546Sopenharmony_ci transkey.element[j].instance_divisor = ve->instance_divisor; 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci transkey.element[j].output_format = fmt; 305bf215546Sopenharmony_ci transkey.element[j].output_offset = transkey.output_stride; 306bf215546Sopenharmony_ci transkey.output_stride += (util_format_get_stride(fmt, 1) + 3) & ~3; 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci } 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci so->translate = translate_create(&transkey); 311bf215546Sopenharmony_ci so->vtx_size = transkey.output_stride / 4; 312bf215546Sopenharmony_ci so->vtx_per_packet_max = NV04_PFIFO_MAX_PACKET_LEN / MAX2(so->vtx_size, 1); 313bf215546Sopenharmony_ci return so; 314bf215546Sopenharmony_ci} 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_cistatic void 317bf215546Sopenharmony_cinv30_vertex_state_delete(struct pipe_context *pipe, void *hwcso) 318bf215546Sopenharmony_ci{ 319bf215546Sopenharmony_ci struct nv30_vertex_stateobj *so = hwcso; 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci if (so->translate) 322bf215546Sopenharmony_ci so->translate->release(so->translate); 323bf215546Sopenharmony_ci FREE(hwcso); 324bf215546Sopenharmony_ci} 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_cistatic void 327bf215546Sopenharmony_cinv30_vertex_state_bind(struct pipe_context *pipe, void *hwcso) 328bf215546Sopenharmony_ci{ 329bf215546Sopenharmony_ci struct nv30_context *nv30 = nv30_context(pipe); 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci nv30->vertex = hwcso; 332bf215546Sopenharmony_ci nv30->dirty |= NV30_NEW_VERTEX; 333bf215546Sopenharmony_ci} 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_cistatic void 336bf215546Sopenharmony_cinv30_draw_arrays(struct nv30_context *nv30, 337bf215546Sopenharmony_ci unsigned mode, unsigned start, unsigned count, 338bf215546Sopenharmony_ci unsigned instance_count) 339bf215546Sopenharmony_ci{ 340bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv30->base.pushbuf; 341bf215546Sopenharmony_ci unsigned prim; 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_ci prim = nv30_prim_gl(mode); 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 346bf215546Sopenharmony_ci PUSH_DATA (push, prim); 347bf215546Sopenharmony_ci while (count) { 348bf215546Sopenharmony_ci const unsigned mpush = 2047 * 256; 349bf215546Sopenharmony_ci unsigned npush = (count > mpush) ? mpush : count; 350bf215546Sopenharmony_ci unsigned wpush = ((npush + 255) & ~255) >> 8; 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_ci count -= npush; 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci BEGIN_NI04(push, NV30_3D(VB_VERTEX_BATCH), wpush); 355bf215546Sopenharmony_ci while (npush >= 256) { 356bf215546Sopenharmony_ci PUSH_DATA (push, 0xff000000 | start); 357bf215546Sopenharmony_ci start += 256; 358bf215546Sopenharmony_ci npush -= 256; 359bf215546Sopenharmony_ci } 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci if (npush) 362bf215546Sopenharmony_ci PUSH_DATA (push, ((npush - 1) << 24) | start); 363bf215546Sopenharmony_ci } 364bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 365bf215546Sopenharmony_ci PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); 366bf215546Sopenharmony_ci} 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_cistatic void 369bf215546Sopenharmony_cinv30_draw_elements_inline_u08(struct nouveau_pushbuf *push, const uint8_t *map, 370bf215546Sopenharmony_ci unsigned start, unsigned count) 371bf215546Sopenharmony_ci{ 372bf215546Sopenharmony_ci map += start; 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_ci if (count & 1) { 375bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VB_ELEMENT_U32), 1); 376bf215546Sopenharmony_ci PUSH_DATA (push, *map++); 377bf215546Sopenharmony_ci } 378bf215546Sopenharmony_ci 379bf215546Sopenharmony_ci count >>= 1; 380bf215546Sopenharmony_ci while (count) { 381bf215546Sopenharmony_ci unsigned npush = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 382bf215546Sopenharmony_ci count -= npush; 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U16), npush); 385bf215546Sopenharmony_ci while (npush--) { 386bf215546Sopenharmony_ci PUSH_DATA (push, (map[1] << 16) | map[0]); 387bf215546Sopenharmony_ci map += 2; 388bf215546Sopenharmony_ci } 389bf215546Sopenharmony_ci } 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_ci} 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_cistatic void 394bf215546Sopenharmony_cinv30_draw_elements_inline_u16(struct nouveau_pushbuf *push, const uint16_t *map, 395bf215546Sopenharmony_ci unsigned start, unsigned count) 396bf215546Sopenharmony_ci{ 397bf215546Sopenharmony_ci map += start; 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci if (count & 1) { 400bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VB_ELEMENT_U32), 1); 401bf215546Sopenharmony_ci PUSH_DATA (push, *map++); 402bf215546Sopenharmony_ci } 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci count >>= 1; 405bf215546Sopenharmony_ci while (count) { 406bf215546Sopenharmony_ci unsigned npush = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 407bf215546Sopenharmony_ci count -= npush; 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U16), npush); 410bf215546Sopenharmony_ci while (npush--) { 411bf215546Sopenharmony_ci PUSH_DATA (push, (map[1] << 16) | map[0]); 412bf215546Sopenharmony_ci map += 2; 413bf215546Sopenharmony_ci } 414bf215546Sopenharmony_ci } 415bf215546Sopenharmony_ci} 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_cistatic void 418bf215546Sopenharmony_cinv30_draw_elements_inline_u32(struct nouveau_pushbuf *push, const uint32_t *map, 419bf215546Sopenharmony_ci unsigned start, unsigned count) 420bf215546Sopenharmony_ci{ 421bf215546Sopenharmony_ci map += start; 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci while (count) { 424bf215546Sopenharmony_ci const unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U32), nr); 427bf215546Sopenharmony_ci PUSH_DATAp(push, map, nr); 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci map += nr; 430bf215546Sopenharmony_ci count -= nr; 431bf215546Sopenharmony_ci } 432bf215546Sopenharmony_ci} 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_cistatic void 435bf215546Sopenharmony_cinv30_draw_elements_inline_u32_short(struct nouveau_pushbuf *push, 436bf215546Sopenharmony_ci const uint32_t *map, 437bf215546Sopenharmony_ci unsigned start, unsigned count) 438bf215546Sopenharmony_ci{ 439bf215546Sopenharmony_ci map += start; 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_ci if (count & 1) { 442bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VB_ELEMENT_U32), 1); 443bf215546Sopenharmony_ci PUSH_DATA (push, *map++); 444bf215546Sopenharmony_ci } 445bf215546Sopenharmony_ci 446bf215546Sopenharmony_ci count >>= 1; 447bf215546Sopenharmony_ci while (count) { 448bf215546Sopenharmony_ci unsigned npush = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 449bf215546Sopenharmony_ci count -= npush; 450bf215546Sopenharmony_ci 451bf215546Sopenharmony_ci BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U16), npush); 452bf215546Sopenharmony_ci while (npush--) { 453bf215546Sopenharmony_ci PUSH_DATA (push, (map[1] << 16) | map[0]); 454bf215546Sopenharmony_ci map += 2; 455bf215546Sopenharmony_ci } 456bf215546Sopenharmony_ci } 457bf215546Sopenharmony_ci} 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_cistatic void 460bf215546Sopenharmony_cinv30_draw_elements(struct nv30_context *nv30, bool shorten, 461bf215546Sopenharmony_ci const struct pipe_draw_info *info, 462bf215546Sopenharmony_ci unsigned mode, unsigned start, unsigned count, 463bf215546Sopenharmony_ci unsigned instance_count, int32_t index_bias, 464bf215546Sopenharmony_ci unsigned index_size) 465bf215546Sopenharmony_ci{ 466bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv30->base.pushbuf; 467bf215546Sopenharmony_ci struct nouveau_object *eng3d = nv30->screen->eng3d; 468bf215546Sopenharmony_ci unsigned prim = nv30_prim_gl(mode); 469bf215546Sopenharmony_ci 470bf215546Sopenharmony_ci if (eng3d->oclass >= NV40_3D_CLASS && index_bias != nv30->state.index_bias) { 471bf215546Sopenharmony_ci BEGIN_NV04(push, NV40_3D(VB_ELEMENT_BASE), 1); 472bf215546Sopenharmony_ci PUSH_DATA (push, index_bias); 473bf215546Sopenharmony_ci nv30->state.index_bias = index_bias; 474bf215546Sopenharmony_ci } 475bf215546Sopenharmony_ci 476bf215546Sopenharmony_ci if (eng3d->oclass == NV40_3D_CLASS && index_size > 1 && 477bf215546Sopenharmony_ci !info->has_user_indices) { 478bf215546Sopenharmony_ci struct nv04_resource *res = nv04_resource(info->index.resource); 479bf215546Sopenharmony_ci unsigned offset = 0; 480bf215546Sopenharmony_ci 481bf215546Sopenharmony_ci assert(nouveau_resource_mapped_by_gpu(&res->base)); 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(IDXBUF_OFFSET), 2); 484bf215546Sopenharmony_ci PUSH_RESRC(push, NV30_3D(IDXBUF_OFFSET), BUFCTX_IDXBUF, res, offset, 485bf215546Sopenharmony_ci NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 0, 0); 486bf215546Sopenharmony_ci PUSH_MTHD (push, NV30_3D(IDXBUF_FORMAT), BUFCTX_IDXBUF, res->bo, 487bf215546Sopenharmony_ci (index_size == 2) ? 0x00000010 : 0x00000000, 488bf215546Sopenharmony_ci res->domain | NOUVEAU_BO_RD, 489bf215546Sopenharmony_ci 0, NV30_3D_IDXBUF_FORMAT_DMA1); 490bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 491bf215546Sopenharmony_ci PUSH_DATA (push, prim); 492bf215546Sopenharmony_ci while (count) { 493bf215546Sopenharmony_ci const unsigned mpush = 2047 * 256; 494bf215546Sopenharmony_ci unsigned npush = (count > mpush) ? mpush : count; 495bf215546Sopenharmony_ci unsigned wpush = ((npush + 255) & ~255) >> 8; 496bf215546Sopenharmony_ci 497bf215546Sopenharmony_ci count -= npush; 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_ci BEGIN_NI04(push, NV30_3D(VB_INDEX_BATCH), wpush); 500bf215546Sopenharmony_ci while (npush >= 256) { 501bf215546Sopenharmony_ci PUSH_DATA (push, 0xff000000 | start); 502bf215546Sopenharmony_ci start += 256; 503bf215546Sopenharmony_ci npush -= 256; 504bf215546Sopenharmony_ci } 505bf215546Sopenharmony_ci 506bf215546Sopenharmony_ci if (npush) 507bf215546Sopenharmony_ci PUSH_DATA (push, ((npush - 1) << 24) | start); 508bf215546Sopenharmony_ci } 509bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 510bf215546Sopenharmony_ci PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); 511bf215546Sopenharmony_ci PUSH_RESET(push, BUFCTX_IDXBUF); 512bf215546Sopenharmony_ci } else { 513bf215546Sopenharmony_ci const void *data; 514bf215546Sopenharmony_ci if (!info->has_user_indices) 515bf215546Sopenharmony_ci data = nouveau_resource_map_offset(&nv30->base, 516bf215546Sopenharmony_ci nv04_resource(info->index.resource), 517bf215546Sopenharmony_ci 0, NOUVEAU_BO_RD); 518bf215546Sopenharmony_ci else 519bf215546Sopenharmony_ci data = info->index.user; 520bf215546Sopenharmony_ci if (!data) 521bf215546Sopenharmony_ci return; 522bf215546Sopenharmony_ci 523bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 524bf215546Sopenharmony_ci PUSH_DATA (push, prim); 525bf215546Sopenharmony_ci switch (index_size) { 526bf215546Sopenharmony_ci case 1: 527bf215546Sopenharmony_ci nv30_draw_elements_inline_u08(push, data, start, count); 528bf215546Sopenharmony_ci break; 529bf215546Sopenharmony_ci case 2: 530bf215546Sopenharmony_ci nv30_draw_elements_inline_u16(push, data, start, count); 531bf215546Sopenharmony_ci break; 532bf215546Sopenharmony_ci case 4: 533bf215546Sopenharmony_ci if (shorten) 534bf215546Sopenharmony_ci nv30_draw_elements_inline_u32_short(push, data, start, count); 535bf215546Sopenharmony_ci else 536bf215546Sopenharmony_ci nv30_draw_elements_inline_u32(push, data, start, count); 537bf215546Sopenharmony_ci break; 538bf215546Sopenharmony_ci default: 539bf215546Sopenharmony_ci assert(0); 540bf215546Sopenharmony_ci return; 541bf215546Sopenharmony_ci } 542bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 543bf215546Sopenharmony_ci PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); 544bf215546Sopenharmony_ci } 545bf215546Sopenharmony_ci} 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_cistatic void 548bf215546Sopenharmony_cinv30_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info, 549bf215546Sopenharmony_ci unsigned drawid_offset, 550bf215546Sopenharmony_ci const struct pipe_draw_indirect_info *indirect, 551bf215546Sopenharmony_ci const struct pipe_draw_start_count_bias *draws, 552bf215546Sopenharmony_ci unsigned num_draws) 553bf215546Sopenharmony_ci{ 554bf215546Sopenharmony_ci if (num_draws > 1) { 555bf215546Sopenharmony_ci util_draw_multi(pipe, info, drawid_offset, indirect, draws, num_draws); 556bf215546Sopenharmony_ci return; 557bf215546Sopenharmony_ci } 558bf215546Sopenharmony_ci 559bf215546Sopenharmony_ci if (!indirect && (!draws[0].count || !info->instance_count)) 560bf215546Sopenharmony_ci return; 561bf215546Sopenharmony_ci 562bf215546Sopenharmony_ci struct nv30_context *nv30 = nv30_context(pipe); 563bf215546Sopenharmony_ci struct nouveau_pushbuf *push = nv30->base.pushbuf; 564bf215546Sopenharmony_ci int i; 565bf215546Sopenharmony_ci 566bf215546Sopenharmony_ci if (!info->primitive_restart && 567bf215546Sopenharmony_ci !u_trim_pipe_prim(info->mode, (unsigned*)&draws[0].count)) 568bf215546Sopenharmony_ci return; 569bf215546Sopenharmony_ci 570bf215546Sopenharmony_ci /* For picking only a few vertices from a large user buffer, push is better, 571bf215546Sopenharmony_ci * if index count is larger and we expect repeated vertices, suggest upload. 572bf215546Sopenharmony_ci */ 573bf215546Sopenharmony_ci nv30->vbo_push_hint = /* the 64 is heuristic */ 574bf215546Sopenharmony_ci !(info->index_size && 575bf215546Sopenharmony_ci info->index_bounds_valid && 576bf215546Sopenharmony_ci ((info->max_index - info->min_index + 64) < draws[0].count)); 577bf215546Sopenharmony_ci 578bf215546Sopenharmony_ci if (info->index_bounds_valid) { 579bf215546Sopenharmony_ci nv30->vbo_min_index = info->min_index; 580bf215546Sopenharmony_ci nv30->vbo_max_index = info->max_index; 581bf215546Sopenharmony_ci } else { 582bf215546Sopenharmony_ci nv30->vbo_min_index = 0; 583bf215546Sopenharmony_ci nv30->vbo_max_index = ~0; 584bf215546Sopenharmony_ci } 585bf215546Sopenharmony_ci 586bf215546Sopenharmony_ci if (nv30->vbo_push_hint != !!nv30->vbo_fifo) 587bf215546Sopenharmony_ci nv30->dirty |= NV30_NEW_ARRAYS; 588bf215546Sopenharmony_ci 589bf215546Sopenharmony_ci push->user_priv = &nv30->bufctx; 590bf215546Sopenharmony_ci if (nv30->vbo_user && !(nv30->dirty & (NV30_NEW_VERTEX | NV30_NEW_ARRAYS))) 591bf215546Sopenharmony_ci nv30_update_user_vbufs(nv30); 592bf215546Sopenharmony_ci 593bf215546Sopenharmony_ci nv30_state_validate(nv30, ~0, true); 594bf215546Sopenharmony_ci if (nv30->draw_flags) { 595bf215546Sopenharmony_ci nv30_render_vbo(pipe, info, drawid_offset, &draws[0]); 596bf215546Sopenharmony_ci return; 597bf215546Sopenharmony_ci } else 598bf215546Sopenharmony_ci if (nv30->vbo_fifo) { 599bf215546Sopenharmony_ci nv30_push_vbo(nv30, info, &draws[0]); 600bf215546Sopenharmony_ci return; 601bf215546Sopenharmony_ci } 602bf215546Sopenharmony_ci 603bf215546Sopenharmony_ci for (i = 0; i < nv30->num_vtxbufs && !nv30->base.vbo_dirty; ++i) { 604bf215546Sopenharmony_ci if (!nv30->vtxbuf[i].buffer.resource) 605bf215546Sopenharmony_ci continue; 606bf215546Sopenharmony_ci if (nv30->vtxbuf[i].buffer.resource->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT) 607bf215546Sopenharmony_ci nv30->base.vbo_dirty = true; 608bf215546Sopenharmony_ci } 609bf215546Sopenharmony_ci 610bf215546Sopenharmony_ci if (!nv30->base.vbo_dirty && info->index_size && !info->has_user_indices && 611bf215546Sopenharmony_ci info->index.resource->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT) 612bf215546Sopenharmony_ci nv30->base.vbo_dirty = true; 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci if (nv30->base.vbo_dirty) { 615bf215546Sopenharmony_ci BEGIN_NV04(push, NV30_3D(VTX_CACHE_INVALIDATE_1710), 1); 616bf215546Sopenharmony_ci PUSH_DATA (push, 0); 617bf215546Sopenharmony_ci nv30->base.vbo_dirty = false; 618bf215546Sopenharmony_ci } 619bf215546Sopenharmony_ci 620bf215546Sopenharmony_ci if (!info->index_size) { 621bf215546Sopenharmony_ci nv30_draw_arrays(nv30, 622bf215546Sopenharmony_ci info->mode, draws[0].start, draws[0].count, 623bf215546Sopenharmony_ci info->instance_count); 624bf215546Sopenharmony_ci } else { 625bf215546Sopenharmony_ci bool shorten = info->index_bounds_valid && info->max_index <= 65535; 626bf215546Sopenharmony_ci 627bf215546Sopenharmony_ci if (info->primitive_restart != nv30->state.prim_restart) { 628bf215546Sopenharmony_ci if (info->primitive_restart) { 629bf215546Sopenharmony_ci BEGIN_NV04(push, NV40_3D(PRIM_RESTART_ENABLE), 2); 630bf215546Sopenharmony_ci PUSH_DATA (push, 1); 631bf215546Sopenharmony_ci PUSH_DATA (push, info->restart_index); 632bf215546Sopenharmony_ci 633bf215546Sopenharmony_ci if (info->restart_index > 65535) 634bf215546Sopenharmony_ci shorten = false; 635bf215546Sopenharmony_ci } else { 636bf215546Sopenharmony_ci BEGIN_NV04(push, NV40_3D(PRIM_RESTART_ENABLE), 1); 637bf215546Sopenharmony_ci PUSH_DATA (push, 0); 638bf215546Sopenharmony_ci } 639bf215546Sopenharmony_ci nv30->state.prim_restart = info->primitive_restart; 640bf215546Sopenharmony_ci } else 641bf215546Sopenharmony_ci if (info->primitive_restart) { 642bf215546Sopenharmony_ci BEGIN_NV04(push, NV40_3D(PRIM_RESTART_INDEX), 1); 643bf215546Sopenharmony_ci PUSH_DATA (push, info->restart_index); 644bf215546Sopenharmony_ci 645bf215546Sopenharmony_ci if (info->restart_index > 65535) 646bf215546Sopenharmony_ci shorten = false; 647bf215546Sopenharmony_ci } 648bf215546Sopenharmony_ci 649bf215546Sopenharmony_ci nv30_draw_elements(nv30, shorten, info, 650bf215546Sopenharmony_ci info->mode, draws[0].start, draws[0].count, 651bf215546Sopenharmony_ci info->instance_count, draws[0].index_bias, info->index_size); 652bf215546Sopenharmony_ci } 653bf215546Sopenharmony_ci 654bf215546Sopenharmony_ci nv30_state_release(nv30); 655bf215546Sopenharmony_ci nv30_release_user_vbufs(nv30); 656bf215546Sopenharmony_ci} 657bf215546Sopenharmony_ci 658bf215546Sopenharmony_civoid 659bf215546Sopenharmony_cinv30_vbo_init(struct pipe_context *pipe) 660bf215546Sopenharmony_ci{ 661bf215546Sopenharmony_ci pipe->create_vertex_elements_state = nv30_vertex_state_create; 662bf215546Sopenharmony_ci pipe->delete_vertex_elements_state = nv30_vertex_state_delete; 663bf215546Sopenharmony_ci pipe->bind_vertex_elements_state = nv30_vertex_state_bind; 664bf215546Sopenharmony_ci pipe->draw_vbo = nv30_draw_vbo; 665bf215546Sopenharmony_ci} 666