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