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