1bf215546Sopenharmony_ci/********************************************************** 2bf215546Sopenharmony_ci * Copyright 2008-2009 VMware, Inc. All rights reserved. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person 5bf215546Sopenharmony_ci * obtaining a copy of this software and associated documentation 6bf215546Sopenharmony_ci * files (the "Software"), to deal in the Software without 7bf215546Sopenharmony_ci * restriction, including without limitation the rights to use, copy, 8bf215546Sopenharmony_ci * modify, merge, publish, distribute, sublicense, and/or sell copies 9bf215546Sopenharmony_ci * of the Software, and to permit persons to whom the Software is 10bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be 13bf215546Sopenharmony_ci * included in all copies or substantial portions of the Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18bf215546Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19bf215546Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20bf215546Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21bf215546Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22bf215546Sopenharmony_ci * SOFTWARE. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci **********************************************************/ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "svga_cmd.h" 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "util/u_inlines.h" 29bf215546Sopenharmony_ci#include "util/u_prim.h" 30bf215546Sopenharmony_ci#include "indices/u_indices.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "svga_hw_reg.h" 33bf215546Sopenharmony_ci#include "svga_draw.h" 34bf215546Sopenharmony_ci#include "svga_draw_private.h" 35bf215546Sopenharmony_ci#include "svga_context.h" 36bf215546Sopenharmony_ci#include "svga_shader.h" 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#define DBG 0 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_cistatic enum pipe_error 43bf215546Sopenharmony_cigenerate_indices(struct svga_hwtnl *hwtnl, 44bf215546Sopenharmony_ci unsigned nr, 45bf215546Sopenharmony_ci unsigned index_size, 46bf215546Sopenharmony_ci u_generate_func generate, struct pipe_resource **out_buf) 47bf215546Sopenharmony_ci{ 48bf215546Sopenharmony_ci struct pipe_context *pipe = &hwtnl->svga->pipe; 49bf215546Sopenharmony_ci struct pipe_transfer *transfer; 50bf215546Sopenharmony_ci unsigned size = index_size * nr; 51bf215546Sopenharmony_ci struct pipe_resource *dst = NULL; 52bf215546Sopenharmony_ci void *dst_map = NULL; 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci dst = pipe_buffer_create(pipe->screen, PIPE_BIND_INDEX_BUFFER, 55bf215546Sopenharmony_ci PIPE_USAGE_IMMUTABLE, size); 56bf215546Sopenharmony_ci if (!dst) 57bf215546Sopenharmony_ci goto fail; 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci dst_map = pipe_buffer_map(pipe, dst, PIPE_MAP_WRITE, &transfer); 60bf215546Sopenharmony_ci if (!dst_map) 61bf215546Sopenharmony_ci goto fail; 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci generate(0, nr, dst_map); 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, transfer); 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci *out_buf = dst; 68bf215546Sopenharmony_ci return PIPE_OK; 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_cifail: 71bf215546Sopenharmony_ci if (dst_map) 72bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, transfer); 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci if (dst) 75bf215546Sopenharmony_ci pipe->screen->resource_destroy(pipe->screen, dst); 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci return PIPE_ERROR_OUT_OF_MEMORY; 78bf215546Sopenharmony_ci} 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_cistatic boolean 82bf215546Sopenharmony_cicompare(unsigned cached_nr, unsigned nr, unsigned type) 83bf215546Sopenharmony_ci{ 84bf215546Sopenharmony_ci if (type == U_GENERATE_REUSABLE) 85bf215546Sopenharmony_ci return cached_nr >= nr; 86bf215546Sopenharmony_ci else 87bf215546Sopenharmony_ci return cached_nr == nr; 88bf215546Sopenharmony_ci} 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_cistatic enum pipe_error 92bf215546Sopenharmony_ciretrieve_or_generate_indices(struct svga_hwtnl *hwtnl, 93bf215546Sopenharmony_ci enum pipe_prim_type prim, 94bf215546Sopenharmony_ci unsigned gen_type, 95bf215546Sopenharmony_ci unsigned gen_nr, 96bf215546Sopenharmony_ci unsigned gen_size, 97bf215546Sopenharmony_ci u_generate_func generate, 98bf215546Sopenharmony_ci struct pipe_resource **out_buf) 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci enum pipe_error ret = PIPE_OK; 101bf215546Sopenharmony_ci int i; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), SVGA_STATS_TIME_GENERATEINDICES); 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci for (i = 0; i < IDX_CACHE_MAX; i++) { 106bf215546Sopenharmony_ci if (hwtnl->index_cache[prim][i].buffer != NULL && 107bf215546Sopenharmony_ci hwtnl->index_cache[prim][i].generate == generate) { 108bf215546Sopenharmony_ci if (compare(hwtnl->index_cache[prim][i].gen_nr, gen_nr, gen_type)) { 109bf215546Sopenharmony_ci pipe_resource_reference(out_buf, 110bf215546Sopenharmony_ci hwtnl->index_cache[prim][i].buffer); 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci if (DBG) 113bf215546Sopenharmony_ci debug_printf("%s retrieve %d/%d\n", __FUNCTION__, i, gen_nr); 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci goto done; 116bf215546Sopenharmony_ci } 117bf215546Sopenharmony_ci else if (gen_type == U_GENERATE_REUSABLE) { 118bf215546Sopenharmony_ci pipe_resource_reference(&hwtnl->index_cache[prim][i].buffer, 119bf215546Sopenharmony_ci NULL); 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci if (DBG) 122bf215546Sopenharmony_ci debug_printf("%s discard %d/%d\n", __FUNCTION__, 123bf215546Sopenharmony_ci i, hwtnl->index_cache[prim][i].gen_nr); 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci break; 126bf215546Sopenharmony_ci } 127bf215546Sopenharmony_ci } 128bf215546Sopenharmony_ci } 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci if (i == IDX_CACHE_MAX) { 131bf215546Sopenharmony_ci unsigned smallest = 0; 132bf215546Sopenharmony_ci unsigned smallest_size = ~0; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci for (i = 0; i < IDX_CACHE_MAX && smallest_size; i++) { 135bf215546Sopenharmony_ci if (hwtnl->index_cache[prim][i].buffer == NULL) { 136bf215546Sopenharmony_ci smallest = i; 137bf215546Sopenharmony_ci smallest_size = 0; 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci else if (hwtnl->index_cache[prim][i].gen_nr < smallest) { 140bf215546Sopenharmony_ci smallest = i; 141bf215546Sopenharmony_ci smallest_size = hwtnl->index_cache[prim][i].gen_nr; 142bf215546Sopenharmony_ci } 143bf215546Sopenharmony_ci } 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci assert(smallest != IDX_CACHE_MAX); 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci pipe_resource_reference(&hwtnl->index_cache[prim][smallest].buffer, 148bf215546Sopenharmony_ci NULL); 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci if (DBG) 151bf215546Sopenharmony_ci debug_printf("%s discard smallest %d/%d\n", __FUNCTION__, 152bf215546Sopenharmony_ci smallest, smallest_size); 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci i = smallest; 155bf215546Sopenharmony_ci } 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci ret = generate_indices(hwtnl, gen_nr, gen_size, generate, out_buf); 158bf215546Sopenharmony_ci if (ret != PIPE_OK) 159bf215546Sopenharmony_ci goto done; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci hwtnl->index_cache[prim][i].generate = generate; 162bf215546Sopenharmony_ci hwtnl->index_cache[prim][i].gen_nr = gen_nr; 163bf215546Sopenharmony_ci pipe_resource_reference(&hwtnl->index_cache[prim][i].buffer, *out_buf); 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci if (DBG) 166bf215546Sopenharmony_ci debug_printf("%s cache %d/%d\n", __FUNCTION__, 167bf215546Sopenharmony_ci i, hwtnl->index_cache[prim][i].gen_nr); 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_cidone: 170bf215546Sopenharmony_ci SVGA_STATS_TIME_POP(svga_sws(hwtnl->svga)); 171bf215546Sopenharmony_ci return ret; 172bf215546Sopenharmony_ci} 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_cistatic enum pipe_error 176bf215546Sopenharmony_cisimple_draw_arrays(struct svga_hwtnl *hwtnl, 177bf215546Sopenharmony_ci enum pipe_prim_type prim, unsigned start, unsigned count, 178bf215546Sopenharmony_ci unsigned start_instance, unsigned instance_count, 179bf215546Sopenharmony_ci ubyte vertices_per_patch) 180bf215546Sopenharmony_ci{ 181bf215546Sopenharmony_ci SVGA3dPrimitiveRange range; 182bf215546Sopenharmony_ci unsigned hw_prim; 183bf215546Sopenharmony_ci unsigned hw_count; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci hw_prim = svga_translate_prim(prim, count, &hw_count, vertices_per_patch); 186bf215546Sopenharmony_ci if (hw_count == 0) 187bf215546Sopenharmony_ci return PIPE_ERROR_BAD_INPUT; 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci range.primType = hw_prim; 190bf215546Sopenharmony_ci range.primitiveCount = hw_count; 191bf215546Sopenharmony_ci range.indexArray.surfaceId = SVGA3D_INVALID_ID; 192bf215546Sopenharmony_ci range.indexArray.offset = 0; 193bf215546Sopenharmony_ci range.indexArray.stride = 0; 194bf215546Sopenharmony_ci range.indexWidth = 0; 195bf215546Sopenharmony_ci range.indexBias = start; 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci /* Min/max index should be calculated prior to applying bias, so we 198bf215546Sopenharmony_ci * end up with min_index = 0, max_index = count - 1 and everybody 199bf215546Sopenharmony_ci * looking at those numbers knows to adjust them by 200bf215546Sopenharmony_ci * range.indexBias. 201bf215546Sopenharmony_ci */ 202bf215546Sopenharmony_ci return svga_hwtnl_prim(hwtnl, &range, count, 203bf215546Sopenharmony_ci 0, count - 1, NULL, 204bf215546Sopenharmony_ci start_instance, instance_count, 205bf215546Sopenharmony_ci NULL, NULL); 206bf215546Sopenharmony_ci} 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_cienum pipe_error 210bf215546Sopenharmony_cisvga_hwtnl_draw_arrays(struct svga_hwtnl *hwtnl, 211bf215546Sopenharmony_ci enum pipe_prim_type prim, unsigned start, unsigned count, 212bf215546Sopenharmony_ci unsigned start_instance, unsigned instance_count, 213bf215546Sopenharmony_ci ubyte vertices_per_patch) 214bf215546Sopenharmony_ci{ 215bf215546Sopenharmony_ci enum pipe_prim_type gen_prim; 216bf215546Sopenharmony_ci unsigned gen_size, gen_nr; 217bf215546Sopenharmony_ci enum indices_mode gen_type; 218bf215546Sopenharmony_ci u_generate_func gen_func; 219bf215546Sopenharmony_ci enum pipe_error ret = PIPE_OK; 220bf215546Sopenharmony_ci unsigned api_pv = hwtnl->api_pv; 221bf215546Sopenharmony_ci struct svga_context *svga = hwtnl->svga; 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_HWTNLDRAWARRAYS); 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci if (svga->curr.rast->templ.fill_front != 226bf215546Sopenharmony_ci svga->curr.rast->templ.fill_back) { 227bf215546Sopenharmony_ci assert(hwtnl->api_fillmode == PIPE_POLYGON_MODE_FILL); 228bf215546Sopenharmony_ci } 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci if (svga->curr.rast->templ.flatshade && 231bf215546Sopenharmony_ci svga_fs_variant(svga->state.hw_draw.fs)->constant_color_output) { 232bf215546Sopenharmony_ci /* The fragment color is a constant, not per-vertex so the whole 233bf215546Sopenharmony_ci * primitive will be the same color (except for possible blending). 234bf215546Sopenharmony_ci * We can ignore the current provoking vertex state and use whatever 235bf215546Sopenharmony_ci * the hardware wants. 236bf215546Sopenharmony_ci */ 237bf215546Sopenharmony_ci api_pv = hwtnl->hw_pv; 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci if (hwtnl->api_fillmode == PIPE_POLYGON_MODE_FILL) { 240bf215546Sopenharmony_ci /* Do some simple primitive conversions to avoid index buffer 241bf215546Sopenharmony_ci * generation below. Note that polygons and quads are not directly 242bf215546Sopenharmony_ci * supported by the svga device. Also note, we can only do this 243bf215546Sopenharmony_ci * for flat/constant-colored rendering because of provoking vertex. 244bf215546Sopenharmony_ci */ 245bf215546Sopenharmony_ci if (prim == PIPE_PRIM_POLYGON) { 246bf215546Sopenharmony_ci prim = PIPE_PRIM_TRIANGLE_FAN; 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci else if (prim == PIPE_PRIM_QUADS && count == 4) { 249bf215546Sopenharmony_ci prim = PIPE_PRIM_TRIANGLE_FAN; 250bf215546Sopenharmony_ci } 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci if (svga_need_unfilled_fallback(hwtnl, prim)) { 255bf215546Sopenharmony_ci /* Convert unfilled polygons into points, lines, triangles */ 256bf215546Sopenharmony_ci gen_type = u_unfilled_generator(prim, 257bf215546Sopenharmony_ci start, 258bf215546Sopenharmony_ci count, 259bf215546Sopenharmony_ci hwtnl->api_fillmode, 260bf215546Sopenharmony_ci &gen_prim, 261bf215546Sopenharmony_ci &gen_size, &gen_nr, &gen_func); 262bf215546Sopenharmony_ci } 263bf215546Sopenharmony_ci else { 264bf215546Sopenharmony_ci /* Convert PIPE_PRIM_LINE_LOOP to PIPE_PRIM_LINESTRIP, 265bf215546Sopenharmony_ci * convert PIPE_PRIM_POLYGON to PIPE_PRIM_TRIANGLE_FAN, 266bf215546Sopenharmony_ci * etc, if needed (as determined by svga_hw_prims mask). 267bf215546Sopenharmony_ci */ 268bf215546Sopenharmony_ci gen_type = u_index_generator(svga_hw_prims, 269bf215546Sopenharmony_ci prim, 270bf215546Sopenharmony_ci start, 271bf215546Sopenharmony_ci count, 272bf215546Sopenharmony_ci api_pv, 273bf215546Sopenharmony_ci hwtnl->hw_pv, 274bf215546Sopenharmony_ci &gen_prim, &gen_size, &gen_nr, &gen_func); 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci if (gen_type == U_GENERATE_LINEAR) { 278bf215546Sopenharmony_ci ret = simple_draw_arrays(hwtnl, gen_prim, start, count, 279bf215546Sopenharmony_ci start_instance, instance_count, 280bf215546Sopenharmony_ci vertices_per_patch); 281bf215546Sopenharmony_ci } 282bf215546Sopenharmony_ci else { 283bf215546Sopenharmony_ci struct pipe_resource *gen_buf = NULL; 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci /* Need to draw as indexed primitive. 286bf215546Sopenharmony_ci * Potentially need to run the gen func to build an index buffer. 287bf215546Sopenharmony_ci */ 288bf215546Sopenharmony_ci ret = retrieve_or_generate_indices(hwtnl, 289bf215546Sopenharmony_ci prim, 290bf215546Sopenharmony_ci gen_type, 291bf215546Sopenharmony_ci gen_nr, 292bf215546Sopenharmony_ci gen_size, gen_func, &gen_buf); 293bf215546Sopenharmony_ci if (ret == PIPE_OK) { 294bf215546Sopenharmony_ci util_debug_message(&svga->debug.callback, PERF_INFO, 295bf215546Sopenharmony_ci "generating temporary index buffer for drawing %s", 296bf215546Sopenharmony_ci u_prim_name(prim)); 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci ret = svga_hwtnl_simple_draw_range_elements(hwtnl, 299bf215546Sopenharmony_ci gen_buf, 300bf215546Sopenharmony_ci gen_size, 301bf215546Sopenharmony_ci start, 302bf215546Sopenharmony_ci 0, 303bf215546Sopenharmony_ci count - 1, 304bf215546Sopenharmony_ci gen_prim, 0, gen_nr, 305bf215546Sopenharmony_ci start_instance, 306bf215546Sopenharmony_ci instance_count, 307bf215546Sopenharmony_ci vertices_per_patch); 308bf215546Sopenharmony_ci } 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci if (gen_buf) { 311bf215546Sopenharmony_ci pipe_resource_reference(&gen_buf, NULL); 312bf215546Sopenharmony_ci } 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci SVGA_STATS_TIME_POP(svga_sws(svga)); 316bf215546Sopenharmony_ci return ret; 317bf215546Sopenharmony_ci} 318