1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2007 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/**
29bf215546Sopenharmony_ci * \file
30bf215546Sopenharmony_ci * Build post-transformation, post-clipping vertex buffers and element
31bf215546Sopenharmony_ci * lists by hooking into the end of the primitive pipeline and
32bf215546Sopenharmony_ci * manipulating the vertex_id field in the vertex headers.
33bf215546Sopenharmony_ci *
34bf215546Sopenharmony_ci * XXX: work in progress
35bf215546Sopenharmony_ci *
36bf215546Sopenharmony_ci * \author José Fonseca <jfonseca@vmware.com>
37bf215546Sopenharmony_ci * \author Keith Whitwell <keithw@vmware.com>
38bf215546Sopenharmony_ci */
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci#include "draw/draw_context.h"
41bf215546Sopenharmony_ci#include "draw/draw_vbuf.h"
42bf215546Sopenharmony_ci#include "util/u_debug.h"
43bf215546Sopenharmony_ci#include "util/u_fifo.h"
44bf215546Sopenharmony_ci#include "util/u_inlines.h"
45bf215546Sopenharmony_ci#include "util/u_math.h"
46bf215546Sopenharmony_ci#include "util/u_memory.h"
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci#include "i915_batch.h"
49bf215546Sopenharmony_ci#include "i915_context.h"
50bf215546Sopenharmony_ci#include "i915_reg.h"
51bf215546Sopenharmony_ci#include "i915_state.h"
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci/**
54bf215546Sopenharmony_ci * Primitive renderer for i915.
55bf215546Sopenharmony_ci */
56bf215546Sopenharmony_cistruct i915_vbuf_render {
57bf215546Sopenharmony_ci   struct vbuf_render base;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   struct i915_context *i915;
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   /** Vertex size in bytes */
62bf215546Sopenharmony_ci   size_t vertex_size;
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci   /** Software primitive */
65bf215546Sopenharmony_ci   unsigned prim;
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   /** Hardware primitive */
68bf215546Sopenharmony_ci   unsigned hwprim;
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci   /** Genereate a vertex list */
71bf215546Sopenharmony_ci   unsigned fallback;
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci   /* Stuff for the vbo */
74bf215546Sopenharmony_ci   struct i915_winsys_buffer *vbo;
75bf215546Sopenharmony_ci   size_t vbo_size;       /**< current size of allocated buffer */
76bf215546Sopenharmony_ci   size_t vbo_alloc_size; /**< minimum buffer size to allocate */
77bf215546Sopenharmony_ci   size_t vbo_hw_offset;  /**< offset that we program the hardware with */
78bf215546Sopenharmony_ci   size_t vbo_sw_offset;  /**< offset that we work with */
79bf215546Sopenharmony_ci   size_t vbo_index;      /**< index offset to be added to all indices */
80bf215546Sopenharmony_ci   void *vbo_ptr;
81bf215546Sopenharmony_ci   size_t vbo_max_used;
82bf215546Sopenharmony_ci   size_t vbo_max_index; /**< index offset to be added to all indices */
83bf215546Sopenharmony_ci};
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci/**
86bf215546Sopenharmony_ci * Basically a cast wrapper.
87bf215546Sopenharmony_ci */
88bf215546Sopenharmony_cistatic inline struct i915_vbuf_render *
89bf215546Sopenharmony_cii915_vbuf_render(struct vbuf_render *render)
90bf215546Sopenharmony_ci{
91bf215546Sopenharmony_ci   assert(render);
92bf215546Sopenharmony_ci   return (struct i915_vbuf_render *)render;
93bf215546Sopenharmony_ci}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci/**
96bf215546Sopenharmony_ci * If vbo state differs between renderer and context
97bf215546Sopenharmony_ci * push state to the context. This function pushes
98bf215546Sopenharmony_ci * hw_offset to i915->vbo_offset and vbo to i915->vbo.
99bf215546Sopenharmony_ci *
100bf215546Sopenharmony_ci * Side effects:
101bf215546Sopenharmony_ci *    May updates context vbo_offset and vbo fields.
102bf215546Sopenharmony_ci */
103bf215546Sopenharmony_cistatic void
104bf215546Sopenharmony_cii915_vbuf_update_vbo_state(struct vbuf_render *render)
105bf215546Sopenharmony_ci{
106bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
107bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   if (i915->vbo != i915_render->vbo ||
110bf215546Sopenharmony_ci       i915->vbo_offset != i915_render->vbo_hw_offset) {
111bf215546Sopenharmony_ci      i915->vbo = i915_render->vbo;
112bf215546Sopenharmony_ci      i915->vbo_offset = i915_render->vbo_hw_offset;
113bf215546Sopenharmony_ci      i915->dirty |= I915_NEW_VBO;
114bf215546Sopenharmony_ci   }
115bf215546Sopenharmony_ci}
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci/**
118bf215546Sopenharmony_ci * Callback exported to the draw module.
119bf215546Sopenharmony_ci * Returns the current vertex_info.
120bf215546Sopenharmony_ci *
121bf215546Sopenharmony_ci * Side effects:
122bf215546Sopenharmony_ci *    If state is dirty update derived state.
123bf215546Sopenharmony_ci */
124bf215546Sopenharmony_cistatic const struct vertex_info *
125bf215546Sopenharmony_cii915_vbuf_render_get_vertex_info(struct vbuf_render *render)
126bf215546Sopenharmony_ci{
127bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
128bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   if (i915->dirty) {
131bf215546Sopenharmony_ci      /* make sure we have up to date vertex layout */
132bf215546Sopenharmony_ci      i915_update_derived(i915);
133bf215546Sopenharmony_ci   }
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   return &i915->current.vertex_info;
136bf215546Sopenharmony_ci}
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci/**
139bf215546Sopenharmony_ci * Reserve space in the vbo for vertices.
140bf215546Sopenharmony_ci *
141bf215546Sopenharmony_ci * Side effects:
142bf215546Sopenharmony_ci *    None.
143bf215546Sopenharmony_ci */
144bf215546Sopenharmony_cistatic bool
145bf215546Sopenharmony_cii915_vbuf_render_reserve(struct i915_vbuf_render *i915_render, size_t size)
146bf215546Sopenharmony_ci{
147bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   if (i915_render->vbo_size < size + i915_render->vbo_sw_offset)
150bf215546Sopenharmony_ci      return false;
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   if (i915->vbo_flushed)
153bf215546Sopenharmony_ci      return false;
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   return true;
156bf215546Sopenharmony_ci}
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci/**
159bf215546Sopenharmony_ci * Allocate a new vbo buffer should there not be enough space for
160bf215546Sopenharmony_ci * the requested number of vertices by the draw module.
161bf215546Sopenharmony_ci *
162bf215546Sopenharmony_ci * Side effects:
163bf215546Sopenharmony_ci *    Updates hw_offset, sw_offset, index and allocates a new buffer.
164bf215546Sopenharmony_ci *    Will set i915->vbo to null on buffer allocation.
165bf215546Sopenharmony_ci */
166bf215546Sopenharmony_cistatic void
167bf215546Sopenharmony_cii915_vbuf_render_new_buf(struct i915_vbuf_render *i915_render, size_t size)
168bf215546Sopenharmony_ci{
169bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
170bf215546Sopenharmony_ci   struct i915_winsys *iws = i915->iws;
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci   if (i915_render->vbo) {
173bf215546Sopenharmony_ci      iws->buffer_unmap(iws, i915_render->vbo);
174bf215546Sopenharmony_ci      iws->buffer_destroy(iws, i915_render->vbo);
175bf215546Sopenharmony_ci      /*
176bf215546Sopenharmony_ci       * XXX If buffers where referenced then this should be done in
177bf215546Sopenharmony_ci       * update_vbo_state but since they arn't and malloc likes to reuse
178bf215546Sopenharmony_ci       * memory we need to set it to null
179bf215546Sopenharmony_ci       */
180bf215546Sopenharmony_ci      i915->vbo = NULL;
181bf215546Sopenharmony_ci      i915_render->vbo = NULL;
182bf215546Sopenharmony_ci   }
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   i915->vbo_flushed = 0;
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   i915_render->vbo_size = MAX2(size, i915_render->vbo_alloc_size);
187bf215546Sopenharmony_ci   i915_render->vbo_hw_offset = 0;
188bf215546Sopenharmony_ci   i915_render->vbo_sw_offset = 0;
189bf215546Sopenharmony_ci   i915_render->vbo_index = 0;
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   i915_render->vbo =
192bf215546Sopenharmony_ci      iws->buffer_create(iws, i915_render->vbo_size, I915_NEW_VERTEX);
193bf215546Sopenharmony_ci   i915_render->vbo_ptr = iws->buffer_map(iws, i915_render->vbo, true);
194bf215546Sopenharmony_ci}
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci/**
197bf215546Sopenharmony_ci * Callback exported to the draw module.
198bf215546Sopenharmony_ci *
199bf215546Sopenharmony_ci * Side effects:
200bf215546Sopenharmony_ci *    Updates hw_offset, sw_offset, index and may allocate
201bf215546Sopenharmony_ci *    a new buffer. Also updates may update the vbo state
202bf215546Sopenharmony_ci *    on the i915 context.
203bf215546Sopenharmony_ci */
204bf215546Sopenharmony_cistatic boolean
205bf215546Sopenharmony_cii915_vbuf_render_allocate_vertices(struct vbuf_render *render,
206bf215546Sopenharmony_ci                                   ushort vertex_size, ushort nr_vertices)
207bf215546Sopenharmony_ci{
208bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
209bf215546Sopenharmony_ci   size_t size = (size_t)vertex_size * (size_t)nr_vertices;
210bf215546Sopenharmony_ci   size_t offset;
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci   /*
213bf215546Sopenharmony_ci    * Align sw_offset with first multiple of vertex size from hw_offset.
214bf215546Sopenharmony_ci    * Set index to be the multiples from from hw_offset to sw_offset.
215bf215546Sopenharmony_ci    * i915_vbuf_render_new_buf will reset index, sw_offset, hw_offset
216bf215546Sopenharmony_ci    * when it allocates a new buffer this is correct.
217bf215546Sopenharmony_ci    */
218bf215546Sopenharmony_ci   {
219bf215546Sopenharmony_ci      offset = i915_render->vbo_sw_offset - i915_render->vbo_hw_offset;
220bf215546Sopenharmony_ci      offset = util_align_npot(offset, vertex_size);
221bf215546Sopenharmony_ci      i915_render->vbo_sw_offset = i915_render->vbo_hw_offset + offset;
222bf215546Sopenharmony_ci      i915_render->vbo_index = offset / vertex_size;
223bf215546Sopenharmony_ci   }
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci   if (!i915_vbuf_render_reserve(i915_render, size))
226bf215546Sopenharmony_ci      i915_vbuf_render_new_buf(i915_render, size);
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci   /*
229bf215546Sopenharmony_ci    * If a new buffer has been alocated sw_offset,
230bf215546Sopenharmony_ci    * hw_offset & index will be reset by new_buf
231bf215546Sopenharmony_ci    */
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci   i915_render->vertex_size = vertex_size;
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   i915_vbuf_update_vbo_state(render);
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci   if (!i915_render->vbo)
238bf215546Sopenharmony_ci      return FALSE;
239bf215546Sopenharmony_ci   return TRUE;
240bf215546Sopenharmony_ci}
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_cistatic void *
243bf215546Sopenharmony_cii915_vbuf_render_map_vertices(struct vbuf_render *render)
244bf215546Sopenharmony_ci{
245bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
246bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   if (i915->vbo_flushed)
249bf215546Sopenharmony_ci      debug_printf("%s bad vbo flush occurred stalling on hw\n", __FUNCTION__);
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci   return (unsigned char *)i915_render->vbo_ptr + i915_render->vbo_sw_offset;
252bf215546Sopenharmony_ci}
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_cistatic void
255bf215546Sopenharmony_cii915_vbuf_render_unmap_vertices(struct vbuf_render *render, ushort min_index,
256bf215546Sopenharmony_ci                                ushort max_index)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   i915_render->vbo_max_index = max_index;
261bf215546Sopenharmony_ci   i915_render->vbo_max_used = MAX2(i915_render->vbo_max_used,
262bf215546Sopenharmony_ci                                    i915_render->vertex_size * (max_index + 1));
263bf215546Sopenharmony_ci}
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci/**
266bf215546Sopenharmony_ci * Ensure that the given max_index given is not larger ushort max.
267bf215546Sopenharmony_ci * If it is larger then ushort max it advanced the hw_offset to the
268bf215546Sopenharmony_ci * same position in the vbo as sw_offset and set index to zero.
269bf215546Sopenharmony_ci *
270bf215546Sopenharmony_ci * Side effects:
271bf215546Sopenharmony_ci *    On failure update hw_offset and index.
272bf215546Sopenharmony_ci */
273bf215546Sopenharmony_cistatic void
274bf215546Sopenharmony_cii915_vbuf_ensure_index_bounds(struct vbuf_render *render, unsigned max_index)
275bf215546Sopenharmony_ci{
276bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   if (max_index + i915_render->vbo_index < ((1 << 17) - 1))
279bf215546Sopenharmony_ci      return;
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   i915_render->vbo_hw_offset = i915_render->vbo_sw_offset;
282bf215546Sopenharmony_ci   i915_render->vbo_index = 0;
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci   i915_vbuf_update_vbo_state(render);
285bf215546Sopenharmony_ci}
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_cistatic void
288bf215546Sopenharmony_cii915_vbuf_render_set_primitive(struct vbuf_render *render,
289bf215546Sopenharmony_ci                               enum pipe_prim_type prim)
290bf215546Sopenharmony_ci{
291bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
292bf215546Sopenharmony_ci   i915_render->prim = prim;
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   switch (prim) {
295bf215546Sopenharmony_ci   case PIPE_PRIM_POINTS:
296bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_POINTLIST;
297bf215546Sopenharmony_ci      i915_render->fallback = 0;
298bf215546Sopenharmony_ci      break;
299bf215546Sopenharmony_ci   case PIPE_PRIM_LINES:
300bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_LINELIST;
301bf215546Sopenharmony_ci      i915_render->fallback = 0;
302bf215546Sopenharmony_ci      break;
303bf215546Sopenharmony_ci   case PIPE_PRIM_LINE_LOOP:
304bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_LINELIST;
305bf215546Sopenharmony_ci      i915_render->fallback = PIPE_PRIM_LINE_LOOP;
306bf215546Sopenharmony_ci      break;
307bf215546Sopenharmony_ci   case PIPE_PRIM_LINE_STRIP:
308bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_LINESTRIP;
309bf215546Sopenharmony_ci      i915_render->fallback = 0;
310bf215546Sopenharmony_ci      break;
311bf215546Sopenharmony_ci   case PIPE_PRIM_TRIANGLES:
312bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_TRILIST;
313bf215546Sopenharmony_ci      i915_render->fallback = 0;
314bf215546Sopenharmony_ci      break;
315bf215546Sopenharmony_ci   case PIPE_PRIM_TRIANGLE_STRIP:
316bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_TRISTRIP;
317bf215546Sopenharmony_ci      i915_render->fallback = 0;
318bf215546Sopenharmony_ci      break;
319bf215546Sopenharmony_ci   case PIPE_PRIM_TRIANGLE_FAN:
320bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_TRIFAN;
321bf215546Sopenharmony_ci      i915_render->fallback = 0;
322bf215546Sopenharmony_ci      break;
323bf215546Sopenharmony_ci   case PIPE_PRIM_QUADS:
324bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_TRILIST;
325bf215546Sopenharmony_ci      i915_render->fallback = PIPE_PRIM_QUADS;
326bf215546Sopenharmony_ci      break;
327bf215546Sopenharmony_ci   case PIPE_PRIM_QUAD_STRIP:
328bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_TRILIST;
329bf215546Sopenharmony_ci      i915_render->fallback = PIPE_PRIM_QUAD_STRIP;
330bf215546Sopenharmony_ci      break;
331bf215546Sopenharmony_ci   case PIPE_PRIM_POLYGON:
332bf215546Sopenharmony_ci      i915_render->hwprim = PRIM3D_POLY;
333bf215546Sopenharmony_ci      i915_render->fallback = 0;
334bf215546Sopenharmony_ci      break;
335bf215546Sopenharmony_ci   default:
336bf215546Sopenharmony_ci      /* FIXME: Actually, can handle a lot more just fine... */
337bf215546Sopenharmony_ci      assert(0 && "unexpected prim in i915_vbuf_render_set_primitive()");
338bf215546Sopenharmony_ci   }
339bf215546Sopenharmony_ci}
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci/**
342bf215546Sopenharmony_ci * Used for fallbacks in draw_arrays
343bf215546Sopenharmony_ci */
344bf215546Sopenharmony_cistatic void
345bf215546Sopenharmony_cidraw_arrays_generate_indices(struct vbuf_render *render, unsigned start,
346bf215546Sopenharmony_ci                             uint32_t nr, unsigned type)
347bf215546Sopenharmony_ci{
348bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
349bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
350bf215546Sopenharmony_ci   unsigned i;
351bf215546Sopenharmony_ci   unsigned end = start + nr + i915_render->vbo_index;
352bf215546Sopenharmony_ci   start += i915_render->vbo_index;
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci   switch (type) {
355bf215546Sopenharmony_ci   case 0:
356bf215546Sopenharmony_ci      for (i = start; i + 1 < end; i += 2)
357bf215546Sopenharmony_ci         OUT_BATCH((i + 0) | (i + 1) << 16);
358bf215546Sopenharmony_ci      if (i < end)
359bf215546Sopenharmony_ci         OUT_BATCH(i);
360bf215546Sopenharmony_ci      break;
361bf215546Sopenharmony_ci   case PIPE_PRIM_LINE_LOOP:
362bf215546Sopenharmony_ci      if (nr >= 2) {
363bf215546Sopenharmony_ci         for (i = start + 1; i < end; i++)
364bf215546Sopenharmony_ci            OUT_BATCH((i - 1) | (i + 0) << 16);
365bf215546Sopenharmony_ci         OUT_BATCH((i - 1) | (start) << 16);
366bf215546Sopenharmony_ci      }
367bf215546Sopenharmony_ci      break;
368bf215546Sopenharmony_ci   case PIPE_PRIM_QUADS:
369bf215546Sopenharmony_ci      for (i = start; i + 3 < end; i += 4) {
370bf215546Sopenharmony_ci         OUT_BATCH((i + 0) | (i + 1) << 16);
371bf215546Sopenharmony_ci         OUT_BATCH((i + 3) | (i + 1) << 16);
372bf215546Sopenharmony_ci         OUT_BATCH((i + 2) | (i + 3) << 16);
373bf215546Sopenharmony_ci      }
374bf215546Sopenharmony_ci      break;
375bf215546Sopenharmony_ci   case PIPE_PRIM_QUAD_STRIP:
376bf215546Sopenharmony_ci      for (i = start; i + 3 < end; i += 2) {
377bf215546Sopenharmony_ci         OUT_BATCH((i + 0) | (i + 1) << 16);
378bf215546Sopenharmony_ci         OUT_BATCH((i + 3) | (i + 2) << 16);
379bf215546Sopenharmony_ci         OUT_BATCH((i + 0) | (i + 3) << 16);
380bf215546Sopenharmony_ci      }
381bf215546Sopenharmony_ci      break;
382bf215546Sopenharmony_ci   default:
383bf215546Sopenharmony_ci      assert(0);
384bf215546Sopenharmony_ci   }
385bf215546Sopenharmony_ci}
386bf215546Sopenharmony_ci
387bf215546Sopenharmony_cistatic unsigned
388bf215546Sopenharmony_cidraw_arrays_calc_nr_indices(uint32_t nr, unsigned type)
389bf215546Sopenharmony_ci{
390bf215546Sopenharmony_ci   switch (type) {
391bf215546Sopenharmony_ci   case 0:
392bf215546Sopenharmony_ci      return nr;
393bf215546Sopenharmony_ci   case PIPE_PRIM_LINE_LOOP:
394bf215546Sopenharmony_ci      if (nr >= 2)
395bf215546Sopenharmony_ci         return nr * 2;
396bf215546Sopenharmony_ci      else
397bf215546Sopenharmony_ci         return 0;
398bf215546Sopenharmony_ci   case PIPE_PRIM_QUADS:
399bf215546Sopenharmony_ci      return (nr / 4) * 6;
400bf215546Sopenharmony_ci   case PIPE_PRIM_QUAD_STRIP:
401bf215546Sopenharmony_ci      return ((nr - 2) / 2) * 6;
402bf215546Sopenharmony_ci   default:
403bf215546Sopenharmony_ci      assert(0);
404bf215546Sopenharmony_ci      return 0;
405bf215546Sopenharmony_ci   }
406bf215546Sopenharmony_ci}
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_cistatic void
409bf215546Sopenharmony_cidraw_arrays_fallback(struct vbuf_render *render, unsigned start, uint32_t nr)
410bf215546Sopenharmony_ci{
411bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
412bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
413bf215546Sopenharmony_ci   unsigned nr_indices;
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci   nr_indices = draw_arrays_calc_nr_indices(nr, i915_render->fallback);
416bf215546Sopenharmony_ci   if (!nr_indices)
417bf215546Sopenharmony_ci      return;
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci   i915_vbuf_ensure_index_bounds(render, start + nr_indices);
420bf215546Sopenharmony_ci
421bf215546Sopenharmony_ci   if (i915->dirty)
422bf215546Sopenharmony_ci      i915_update_derived(i915);
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ci   if (i915->hardware_dirty)
425bf215546Sopenharmony_ci      i915_emit_hardware_state(i915);
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci   if (!BEGIN_BATCH(1 + (nr_indices + 1) / 2)) {
428bf215546Sopenharmony_ci      FLUSH_BATCH(NULL, I915_FLUSH_ASYNC);
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci      /* Make sure state is re-emitted after a flush:
431bf215546Sopenharmony_ci       */
432bf215546Sopenharmony_ci      i915_emit_hardware_state(i915);
433bf215546Sopenharmony_ci      i915->vbo_flushed = 1;
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci      if (!BEGIN_BATCH(1 + (nr_indices + 1) / 2)) {
436bf215546Sopenharmony_ci         mesa_loge("i915: Failed to allocate space for %d indices in fresh "
437bf215546Sopenharmony_ci                   "batch with %d bytes left\n",
438bf215546Sopenharmony_ci                   nr_indices, (int)i915_winsys_batchbuffer_space(i915->batch));
439bf215546Sopenharmony_ci         assert(0);
440bf215546Sopenharmony_ci         goto out;
441bf215546Sopenharmony_ci      }
442bf215546Sopenharmony_ci   }
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ci   OUT_BATCH(_3DPRIMITIVE | PRIM_INDIRECT | i915_render->hwprim |
445bf215546Sopenharmony_ci             PRIM_INDIRECT_ELTS | nr_indices);
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_ci   draw_arrays_generate_indices(render, start, nr, i915_render->fallback);
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_ciout:
450bf215546Sopenharmony_ci   return;
451bf215546Sopenharmony_ci}
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_cistatic void
454bf215546Sopenharmony_cii915_vbuf_render_draw_arrays(struct vbuf_render *render, unsigned start,
455bf215546Sopenharmony_ci                             uint32_t nr)
456bf215546Sopenharmony_ci{
457bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
458bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci   if (i915_render->fallback) {
461bf215546Sopenharmony_ci      draw_arrays_fallback(render, start, nr);
462bf215546Sopenharmony_ci      return;
463bf215546Sopenharmony_ci   }
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   i915_vbuf_ensure_index_bounds(render, start + nr);
466bf215546Sopenharmony_ci   start += i915_render->vbo_index;
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   if (i915->dirty)
469bf215546Sopenharmony_ci      i915_update_derived(i915);
470bf215546Sopenharmony_ci
471bf215546Sopenharmony_ci   if (i915->hardware_dirty)
472bf215546Sopenharmony_ci      i915_emit_hardware_state(i915);
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci   if (!BEGIN_BATCH(2)) {
475bf215546Sopenharmony_ci      FLUSH_BATCH(NULL, I915_FLUSH_ASYNC);
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci      /* Make sure state is re-emitted after a flush:
478bf215546Sopenharmony_ci       */
479bf215546Sopenharmony_ci      i915_emit_hardware_state(i915);
480bf215546Sopenharmony_ci      i915->vbo_flushed = 1;
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_ci      if (!BEGIN_BATCH(2)) {
483bf215546Sopenharmony_ci         assert(0);
484bf215546Sopenharmony_ci         goto out;
485bf215546Sopenharmony_ci      }
486bf215546Sopenharmony_ci   }
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_ci   OUT_BATCH(_3DPRIMITIVE | PRIM_INDIRECT | PRIM_INDIRECT_SEQUENTIAL |
489bf215546Sopenharmony_ci             i915_render->hwprim | nr);
490bf215546Sopenharmony_ci   OUT_BATCH(start); /* Beginning vertex index */
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ciout:
493bf215546Sopenharmony_ci   return;
494bf215546Sopenharmony_ci}
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci/**
497bf215546Sopenharmony_ci * Used for normal and fallback emitting of indices
498bf215546Sopenharmony_ci * If type is zero normal operation assumed.
499bf215546Sopenharmony_ci */
500bf215546Sopenharmony_cistatic void
501bf215546Sopenharmony_cidraw_generate_indices(struct vbuf_render *render, const ushort *indices,
502bf215546Sopenharmony_ci                      uint32_t nr_indices, unsigned type)
503bf215546Sopenharmony_ci{
504bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
505bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
506bf215546Sopenharmony_ci   unsigned i;
507bf215546Sopenharmony_ci   unsigned o = i915_render->vbo_index;
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_ci   switch (type) {
510bf215546Sopenharmony_ci   case 0:
511bf215546Sopenharmony_ci      for (i = 0; i + 1 < nr_indices; i += 2) {
512bf215546Sopenharmony_ci         OUT_BATCH((o + indices[i]) | (o + indices[i + 1]) << 16);
513bf215546Sopenharmony_ci      }
514bf215546Sopenharmony_ci      if (i < nr_indices) {
515bf215546Sopenharmony_ci         OUT_BATCH((o + indices[i]));
516bf215546Sopenharmony_ci      }
517bf215546Sopenharmony_ci      break;
518bf215546Sopenharmony_ci   case PIPE_PRIM_LINE_LOOP:
519bf215546Sopenharmony_ci      if (nr_indices >= 2) {
520bf215546Sopenharmony_ci         for (i = 1; i < nr_indices; i++)
521bf215546Sopenharmony_ci            OUT_BATCH((o + indices[i - 1]) | (o + indices[i]) << 16);
522bf215546Sopenharmony_ci         OUT_BATCH((o + indices[i - 1]) | (o + indices[0]) << 16);
523bf215546Sopenharmony_ci      }
524bf215546Sopenharmony_ci      break;
525bf215546Sopenharmony_ci   case PIPE_PRIM_QUADS:
526bf215546Sopenharmony_ci      for (i = 0; i + 3 < nr_indices; i += 4) {
527bf215546Sopenharmony_ci         OUT_BATCH((o + indices[i + 0]) | (o + indices[i + 1]) << 16);
528bf215546Sopenharmony_ci         OUT_BATCH((o + indices[i + 3]) | (o + indices[i + 1]) << 16);
529bf215546Sopenharmony_ci         OUT_BATCH((o + indices[i + 2]) | (o + indices[i + 3]) << 16);
530bf215546Sopenharmony_ci      }
531bf215546Sopenharmony_ci      break;
532bf215546Sopenharmony_ci   case PIPE_PRIM_QUAD_STRIP:
533bf215546Sopenharmony_ci      for (i = 0; i + 3 < nr_indices; i += 2) {
534bf215546Sopenharmony_ci         OUT_BATCH((o + indices[i + 0]) | (o + indices[i + 1]) << 16);
535bf215546Sopenharmony_ci         OUT_BATCH((o + indices[i + 3]) | (o + indices[i + 2]) << 16);
536bf215546Sopenharmony_ci         OUT_BATCH((o + indices[i + 0]) | (o + indices[i + 3]) << 16);
537bf215546Sopenharmony_ci      }
538bf215546Sopenharmony_ci      break;
539bf215546Sopenharmony_ci   default:
540bf215546Sopenharmony_ci      assert(0);
541bf215546Sopenharmony_ci      break;
542bf215546Sopenharmony_ci   }
543bf215546Sopenharmony_ci}
544bf215546Sopenharmony_ci
545bf215546Sopenharmony_cistatic unsigned
546bf215546Sopenharmony_cidraw_calc_nr_indices(uint32_t nr_indices, unsigned type)
547bf215546Sopenharmony_ci{
548bf215546Sopenharmony_ci   switch (type) {
549bf215546Sopenharmony_ci   case 0:
550bf215546Sopenharmony_ci      return nr_indices;
551bf215546Sopenharmony_ci   case PIPE_PRIM_LINE_LOOP:
552bf215546Sopenharmony_ci      if (nr_indices >= 2)
553bf215546Sopenharmony_ci         return nr_indices * 2;
554bf215546Sopenharmony_ci      else
555bf215546Sopenharmony_ci         return 0;
556bf215546Sopenharmony_ci   case PIPE_PRIM_QUADS:
557bf215546Sopenharmony_ci      return (nr_indices / 4) * 6;
558bf215546Sopenharmony_ci   case PIPE_PRIM_QUAD_STRIP:
559bf215546Sopenharmony_ci      return ((nr_indices - 2) / 2) * 6;
560bf215546Sopenharmony_ci   default:
561bf215546Sopenharmony_ci      assert(0);
562bf215546Sopenharmony_ci      return 0;
563bf215546Sopenharmony_ci   }
564bf215546Sopenharmony_ci}
565bf215546Sopenharmony_ci
566bf215546Sopenharmony_cistatic void
567bf215546Sopenharmony_cii915_vbuf_render_draw_elements(struct vbuf_render *render,
568bf215546Sopenharmony_ci                               const ushort *indices, uint32_t nr_indices)
569bf215546Sopenharmony_ci{
570bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
571bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
572bf215546Sopenharmony_ci   unsigned save_nr_indices;
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci   save_nr_indices = nr_indices;
575bf215546Sopenharmony_ci
576bf215546Sopenharmony_ci   nr_indices = draw_calc_nr_indices(nr_indices, i915_render->fallback);
577bf215546Sopenharmony_ci   if (!nr_indices)
578bf215546Sopenharmony_ci      return;
579bf215546Sopenharmony_ci
580bf215546Sopenharmony_ci   i915_vbuf_ensure_index_bounds(render, i915_render->vbo_max_index);
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci   if (i915->dirty)
583bf215546Sopenharmony_ci      i915_update_derived(i915);
584bf215546Sopenharmony_ci
585bf215546Sopenharmony_ci   if (i915->hardware_dirty)
586bf215546Sopenharmony_ci      i915_emit_hardware_state(i915);
587bf215546Sopenharmony_ci
588bf215546Sopenharmony_ci   if (!BEGIN_BATCH(1 + (nr_indices + 1) / 2)) {
589bf215546Sopenharmony_ci      FLUSH_BATCH(NULL, I915_FLUSH_ASYNC);
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci      /* Make sure state is re-emitted after a flush:
592bf215546Sopenharmony_ci       */
593bf215546Sopenharmony_ci      i915_emit_hardware_state(i915);
594bf215546Sopenharmony_ci      i915->vbo_flushed = 1;
595bf215546Sopenharmony_ci
596bf215546Sopenharmony_ci      if (!BEGIN_BATCH(1 + (nr_indices + 1) / 2)) {
597bf215546Sopenharmony_ci         mesa_loge("i915: Failed to allocate space for %d indices in fresh "
598bf215546Sopenharmony_ci                   "batch with %d bytes left\n",
599bf215546Sopenharmony_ci                   nr_indices, (int)i915_winsys_batchbuffer_space(i915->batch));
600bf215546Sopenharmony_ci         assert(0);
601bf215546Sopenharmony_ci         goto out;
602bf215546Sopenharmony_ci      }
603bf215546Sopenharmony_ci   }
604bf215546Sopenharmony_ci
605bf215546Sopenharmony_ci   OUT_BATCH(_3DPRIMITIVE | PRIM_INDIRECT | i915_render->hwprim |
606bf215546Sopenharmony_ci             PRIM_INDIRECT_ELTS | nr_indices);
607bf215546Sopenharmony_ci   draw_generate_indices(render, indices, save_nr_indices,
608bf215546Sopenharmony_ci                         i915_render->fallback);
609bf215546Sopenharmony_ci
610bf215546Sopenharmony_ciout:
611bf215546Sopenharmony_ci   return;
612bf215546Sopenharmony_ci}
613bf215546Sopenharmony_ci
614bf215546Sopenharmony_cistatic void
615bf215546Sopenharmony_cii915_vbuf_render_release_vertices(struct vbuf_render *render)
616bf215546Sopenharmony_ci{
617bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
618bf215546Sopenharmony_ci
619bf215546Sopenharmony_ci   i915_render->vbo_sw_offset += i915_render->vbo_max_used;
620bf215546Sopenharmony_ci   i915_render->vbo_max_used = 0;
621bf215546Sopenharmony_ci
622bf215546Sopenharmony_ci   /*
623bf215546Sopenharmony_ci    * Micro optimization, by calling update here we the offset change
624bf215546Sopenharmony_ci    * will be picked up on the next pipe_context::draw_*.
625bf215546Sopenharmony_ci    */
626bf215546Sopenharmony_ci   i915_vbuf_update_vbo_state(render);
627bf215546Sopenharmony_ci}
628bf215546Sopenharmony_ci
629bf215546Sopenharmony_cistatic void
630bf215546Sopenharmony_cii915_vbuf_render_destroy(struct vbuf_render *render)
631bf215546Sopenharmony_ci{
632bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
633bf215546Sopenharmony_ci   struct i915_context *i915 = i915_render->i915;
634bf215546Sopenharmony_ci   struct i915_winsys *iws = i915->iws;
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   if (i915_render->vbo) {
637bf215546Sopenharmony_ci      i915->vbo = NULL;
638bf215546Sopenharmony_ci      iws->buffer_unmap(iws, i915_render->vbo);
639bf215546Sopenharmony_ci      iws->buffer_destroy(iws, i915_render->vbo);
640bf215546Sopenharmony_ci   }
641bf215546Sopenharmony_ci
642bf215546Sopenharmony_ci   FREE(i915_render);
643bf215546Sopenharmony_ci}
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci/**
646bf215546Sopenharmony_ci * Create a new primitive render.
647bf215546Sopenharmony_ci */
648bf215546Sopenharmony_cistatic struct vbuf_render *
649bf215546Sopenharmony_cii915_vbuf_render_create(struct i915_context *i915)
650bf215546Sopenharmony_ci{
651bf215546Sopenharmony_ci   struct i915_vbuf_render *i915_render = CALLOC_STRUCT(i915_vbuf_render);
652bf215546Sopenharmony_ci
653bf215546Sopenharmony_ci   i915_render->i915 = i915;
654bf215546Sopenharmony_ci
655bf215546Sopenharmony_ci   i915_render->base.max_vertex_buffer_bytes = 4 * 4096;
656bf215546Sopenharmony_ci
657bf215546Sopenharmony_ci   /* NOTE: it must be such that state and vertices indices fit in a single
658bf215546Sopenharmony_ci    * batch buffer. 4096 is one batch buffer and 430 is the max amount of
659bf215546Sopenharmony_ci    * state in dwords. The result is the number of 16-bit indices which can
660bf215546Sopenharmony_ci    * fit in a single batch buffer.
661bf215546Sopenharmony_ci    */
662bf215546Sopenharmony_ci   i915_render->base.max_indices = (4096 - 430 * 4) / 2;
663bf215546Sopenharmony_ci
664bf215546Sopenharmony_ci   i915_render->base.get_vertex_info = i915_vbuf_render_get_vertex_info;
665bf215546Sopenharmony_ci   i915_render->base.allocate_vertices = i915_vbuf_render_allocate_vertices;
666bf215546Sopenharmony_ci   i915_render->base.map_vertices = i915_vbuf_render_map_vertices;
667bf215546Sopenharmony_ci   i915_render->base.unmap_vertices = i915_vbuf_render_unmap_vertices;
668bf215546Sopenharmony_ci   i915_render->base.set_primitive = i915_vbuf_render_set_primitive;
669bf215546Sopenharmony_ci   i915_render->base.draw_elements = i915_vbuf_render_draw_elements;
670bf215546Sopenharmony_ci   i915_render->base.draw_arrays = i915_vbuf_render_draw_arrays;
671bf215546Sopenharmony_ci   i915_render->base.release_vertices = i915_vbuf_render_release_vertices;
672bf215546Sopenharmony_ci   i915_render->base.destroy = i915_vbuf_render_destroy;
673bf215546Sopenharmony_ci
674bf215546Sopenharmony_ci   i915_render->vbo = NULL;
675bf215546Sopenharmony_ci   i915_render->vbo_ptr = NULL;
676bf215546Sopenharmony_ci   i915_render->vbo_size = 0;
677bf215546Sopenharmony_ci   i915_render->vbo_hw_offset = 0;
678bf215546Sopenharmony_ci   i915_render->vbo_sw_offset = 0;
679bf215546Sopenharmony_ci   i915_render->vbo_alloc_size = i915_render->base.max_vertex_buffer_bytes * 4;
680bf215546Sopenharmony_ci
681bf215546Sopenharmony_ci   return &i915_render->base;
682bf215546Sopenharmony_ci}
683bf215546Sopenharmony_ci
684bf215546Sopenharmony_ci/**
685bf215546Sopenharmony_ci * Create a new primitive vbuf/render stage.
686bf215546Sopenharmony_ci */
687bf215546Sopenharmony_cistruct draw_stage *
688bf215546Sopenharmony_cii915_draw_vbuf_stage(struct i915_context *i915)
689bf215546Sopenharmony_ci{
690bf215546Sopenharmony_ci   struct vbuf_render *render;
691bf215546Sopenharmony_ci   struct draw_stage *stage;
692bf215546Sopenharmony_ci
693bf215546Sopenharmony_ci   render = i915_vbuf_render_create(i915);
694bf215546Sopenharmony_ci   if (!render)
695bf215546Sopenharmony_ci      return NULL;
696bf215546Sopenharmony_ci
697bf215546Sopenharmony_ci   stage = draw_vbuf_stage(i915->draw, render);
698bf215546Sopenharmony_ci   if (!stage) {
699bf215546Sopenharmony_ci      render->destroy(render);
700bf215546Sopenharmony_ci      return NULL;
701bf215546Sopenharmony_ci   }
702bf215546Sopenharmony_ci   /** TODO JB: this shouldn't be here */
703bf215546Sopenharmony_ci   draw_set_render(i915->draw, render);
704bf215546Sopenharmony_ci
705bf215546Sopenharmony_ci   return stage;
706bf215546Sopenharmony_ci}
707