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