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 "util/u_inlines.h" 27bf215546Sopenharmony_ci#include "util/u_prim.h" 28bf215546Sopenharmony_ci#include "util/u_upload_mgr.h" 29bf215546Sopenharmony_ci#include "indices/u_indices.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "svga_cmd.h" 32bf215546Sopenharmony_ci#include "svga_draw.h" 33bf215546Sopenharmony_ci#include "svga_draw_private.h" 34bf215546Sopenharmony_ci#include "svga_resource_buffer.h" 35bf215546Sopenharmony_ci#include "svga_winsys.h" 36bf215546Sopenharmony_ci#include "svga_context.h" 37bf215546Sopenharmony_ci#include "svga_hw_reg.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci/** 41bf215546Sopenharmony_ci * Return a new index buffer which contains a translation of the original 42bf215546Sopenharmony_ci * index buffer. An example of a translation is converting from QUAD 43bf215546Sopenharmony_ci * primitives to TRIANGLE primitives. Each set of four indexes for a quad 44bf215546Sopenharmony_ci * will be converted to six indices for two triangles. 45bf215546Sopenharmony_ci * 46bf215546Sopenharmony_ci * Before generating the new index buffer we'll check if the incoming 47bf215546Sopenharmony_ci * buffer already has a translated buffer that can be re-used. 48bf215546Sopenharmony_ci * This benefits demos like Cinebench R15 which has many 49bf215546Sopenharmony_ci * glDrawElements(GL_QUADS) commands (we can't draw quads natively). 50bf215546Sopenharmony_ci * 51bf215546Sopenharmony_ci * \param offset offset in bytes to first index to translate in src buffer 52bf215546Sopenharmony_ci * \param orig_prim original primitive type (like PIPE_PRIM_QUADS) 53bf215546Sopenharmony_ci * \param gen_prim new/generated primitive type (like PIPE_PRIM_TRIANGLES) 54bf215546Sopenharmony_ci * \param orig_nr number of indexes to translate in source buffer 55bf215546Sopenharmony_ci * \param gen_nr number of indexes to write into new/dest buffer 56bf215546Sopenharmony_ci * \param index_size bytes per index (2 or 4) 57bf215546Sopenharmony_ci * \param translate the translation function from the u_translate module 58bf215546Sopenharmony_ci * \param out_buf returns the new/translated index buffer 59bf215546Sopenharmony_ci * \return error code to indicate success failure 60bf215546Sopenharmony_ci */ 61bf215546Sopenharmony_cistatic enum pipe_error 62bf215546Sopenharmony_citranslate_indices(struct svga_hwtnl *hwtnl, 63bf215546Sopenharmony_ci const struct pipe_draw_info *info, 64bf215546Sopenharmony_ci const struct pipe_draw_start_count_bias *draw, 65bf215546Sopenharmony_ci enum pipe_prim_type gen_prim, 66bf215546Sopenharmony_ci unsigned orig_nr, unsigned gen_nr, 67bf215546Sopenharmony_ci unsigned gen_size, 68bf215546Sopenharmony_ci u_translate_func translate, 69bf215546Sopenharmony_ci struct pipe_resource **out_buf, 70bf215546Sopenharmony_ci unsigned *out_offset) 71bf215546Sopenharmony_ci{ 72bf215546Sopenharmony_ci struct pipe_context *pipe = &hwtnl->svga->pipe; 73bf215546Sopenharmony_ci struct svga_screen *screen = svga_screen(pipe->screen); 74bf215546Sopenharmony_ci struct svga_buffer *src_sbuf = NULL; 75bf215546Sopenharmony_ci struct pipe_transfer *src_transfer = NULL; 76bf215546Sopenharmony_ci struct pipe_transfer *dst_transfer = NULL; 77bf215546Sopenharmony_ci const unsigned size = gen_size * gen_nr; 78bf215546Sopenharmony_ci const unsigned offset = draw->start * info->index_size; 79bf215546Sopenharmony_ci const void *src_map = NULL; 80bf215546Sopenharmony_ci struct pipe_resource *dst = NULL; 81bf215546Sopenharmony_ci void *dst_map = NULL; 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci assert(gen_size == 2 || gen_size == 4); 84bf215546Sopenharmony_ci if (!info->has_user_indices) 85bf215546Sopenharmony_ci src_sbuf = svga_buffer(info->index.resource); 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci /* If the draw_info provides us with a buffer rather than a 88bf215546Sopenharmony_ci * user pointer, Check to see if we've already translated that buffer 89bf215546Sopenharmony_ci */ 90bf215546Sopenharmony_ci if (src_sbuf && !screen->debug.no_cache_index_buffers) { 91bf215546Sopenharmony_ci /* Check if we already have a translated index buffer */ 92bf215546Sopenharmony_ci if (src_sbuf->translated_indices.buffer && 93bf215546Sopenharmony_ci src_sbuf->translated_indices.orig_prim == info->mode && 94bf215546Sopenharmony_ci src_sbuf->translated_indices.new_prim == gen_prim && 95bf215546Sopenharmony_ci src_sbuf->translated_indices.offset == offset && 96bf215546Sopenharmony_ci src_sbuf->translated_indices.count == orig_nr && 97bf215546Sopenharmony_ci src_sbuf->translated_indices.index_size == gen_size) { 98bf215546Sopenharmony_ci pipe_resource_reference(out_buf, src_sbuf->translated_indices.buffer); 99bf215546Sopenharmony_ci return PIPE_OK; 100bf215546Sopenharmony_ci } 101bf215546Sopenharmony_ci } 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci /* Need to trim vertex count to make sure we don't write too much data 104bf215546Sopenharmony_ci * to the dst buffer in the translate() call. 105bf215546Sopenharmony_ci */ 106bf215546Sopenharmony_ci u_trim_pipe_prim(gen_prim, &gen_nr); 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci if (src_sbuf) { 109bf215546Sopenharmony_ci /* If we have a source buffer, create a destination buffer in the 110bf215546Sopenharmony_ci * hope that we can reuse the translated data later. If not, 111bf215546Sopenharmony_ci * we'd probably be better off using the upload buffer. 112bf215546Sopenharmony_ci */ 113bf215546Sopenharmony_ci dst = pipe_buffer_create(pipe->screen, 114bf215546Sopenharmony_ci PIPE_BIND_INDEX_BUFFER, PIPE_USAGE_IMMUTABLE, 115bf215546Sopenharmony_ci size); 116bf215546Sopenharmony_ci if (!dst) 117bf215546Sopenharmony_ci goto fail; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci dst_map = pipe_buffer_map(pipe, dst, PIPE_MAP_WRITE, &dst_transfer); 120bf215546Sopenharmony_ci if (!dst_map) 121bf215546Sopenharmony_ci goto fail; 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci *out_offset = 0; 124bf215546Sopenharmony_ci src_map = pipe_buffer_map(pipe, info->index.resource, 125bf215546Sopenharmony_ci PIPE_MAP_READ | 126bf215546Sopenharmony_ci PIPE_MAP_UNSYNCHRONIZED, 127bf215546Sopenharmony_ci &src_transfer); 128bf215546Sopenharmony_ci if (!src_map) 129bf215546Sopenharmony_ci goto fail; 130bf215546Sopenharmony_ci } else { 131bf215546Sopenharmony_ci /* Allocate upload buffer space. Align to the index size. */ 132bf215546Sopenharmony_ci u_upload_alloc(pipe->stream_uploader, 0, size, gen_size, 133bf215546Sopenharmony_ci out_offset, &dst, &dst_map); 134bf215546Sopenharmony_ci if (!dst) 135bf215546Sopenharmony_ci goto fail; 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci src_map = info->index.user; 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci translate((const char *) src_map + offset, 0, 0, gen_nr, 0, dst_map); 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci if (src_transfer) 143bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, src_transfer); 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci if (dst_transfer) 146bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, dst_transfer); 147bf215546Sopenharmony_ci else 148bf215546Sopenharmony_ci u_upload_unmap(pipe->stream_uploader); 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci *out_buf = dst; 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci if (src_sbuf && !screen->debug.no_cache_index_buffers) { 153bf215546Sopenharmony_ci /* Save the new, translated index buffer in the hope we can use it 154bf215546Sopenharmony_ci * again in the future. 155bf215546Sopenharmony_ci */ 156bf215546Sopenharmony_ci pipe_resource_reference(&src_sbuf->translated_indices.buffer, dst); 157bf215546Sopenharmony_ci src_sbuf->translated_indices.orig_prim = info->mode; 158bf215546Sopenharmony_ci src_sbuf->translated_indices.new_prim = gen_prim; 159bf215546Sopenharmony_ci src_sbuf->translated_indices.offset = offset; 160bf215546Sopenharmony_ci src_sbuf->translated_indices.count = orig_nr; 161bf215546Sopenharmony_ci src_sbuf->translated_indices.index_size = gen_size; 162bf215546Sopenharmony_ci } 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci return PIPE_OK; 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci fail: 167bf215546Sopenharmony_ci if (src_transfer) 168bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, src_transfer); 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci if (dst_transfer) 171bf215546Sopenharmony_ci pipe_buffer_unmap(pipe, dst_transfer); 172bf215546Sopenharmony_ci else if (dst_map) 173bf215546Sopenharmony_ci u_upload_unmap(pipe->stream_uploader); 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci if (dst) 176bf215546Sopenharmony_ci pipe_resource_reference(&dst, NULL); 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci return PIPE_ERROR_OUT_OF_MEMORY; 179bf215546Sopenharmony_ci} 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_cienum pipe_error 183bf215546Sopenharmony_cisvga_hwtnl_simple_draw_range_elements(struct svga_hwtnl *hwtnl, 184bf215546Sopenharmony_ci struct pipe_resource *index_buffer, 185bf215546Sopenharmony_ci unsigned index_size, int index_bias, 186bf215546Sopenharmony_ci unsigned min_index, unsigned max_index, 187bf215546Sopenharmony_ci enum pipe_prim_type prim, unsigned start, 188bf215546Sopenharmony_ci unsigned count, 189bf215546Sopenharmony_ci unsigned start_instance, 190bf215546Sopenharmony_ci unsigned instance_count, 191bf215546Sopenharmony_ci ubyte vertices_per_patch) 192bf215546Sopenharmony_ci{ 193bf215546Sopenharmony_ci SVGA3dPrimitiveRange range; 194bf215546Sopenharmony_ci unsigned hw_prim; 195bf215546Sopenharmony_ci unsigned hw_count; 196bf215546Sopenharmony_ci unsigned index_offset = start * index_size; 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci hw_prim = svga_translate_prim(prim, count, &hw_count, vertices_per_patch); 199bf215546Sopenharmony_ci if (hw_count == 0) 200bf215546Sopenharmony_ci return PIPE_OK; /* nothing to draw */ 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci range.primType = hw_prim; 203bf215546Sopenharmony_ci range.primitiveCount = hw_count; 204bf215546Sopenharmony_ci range.indexArray.offset = index_offset; 205bf215546Sopenharmony_ci range.indexArray.stride = index_size; 206bf215546Sopenharmony_ci range.indexWidth = index_size; 207bf215546Sopenharmony_ci range.indexBias = index_bias; 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci return svga_hwtnl_prim(hwtnl, &range, count, 210bf215546Sopenharmony_ci min_index, max_index, index_buffer, 211bf215546Sopenharmony_ci start_instance, instance_count, 212bf215546Sopenharmony_ci NULL, NULL); 213bf215546Sopenharmony_ci} 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_cienum pipe_error 217bf215546Sopenharmony_cisvga_hwtnl_draw_range_elements(struct svga_hwtnl *hwtnl, 218bf215546Sopenharmony_ci const struct pipe_draw_info *info, 219bf215546Sopenharmony_ci const struct pipe_draw_start_count_bias *draw, 220bf215546Sopenharmony_ci unsigned count) 221bf215546Sopenharmony_ci{ 222bf215546Sopenharmony_ci struct pipe_context *pipe = &hwtnl->svga->pipe; 223bf215546Sopenharmony_ci enum pipe_prim_type gen_prim; 224bf215546Sopenharmony_ci unsigned gen_size, gen_nr; 225bf215546Sopenharmony_ci enum indices_mode gen_type; 226bf215546Sopenharmony_ci u_translate_func gen_func; 227bf215546Sopenharmony_ci enum pipe_error ret = PIPE_OK; 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), 230bf215546Sopenharmony_ci SVGA_STATS_TIME_HWTNLDRAWELEMENTS); 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci if (svga_need_unfilled_fallback(hwtnl, info->mode)) { 233bf215546Sopenharmony_ci gen_type = u_unfilled_translator(info->mode, 234bf215546Sopenharmony_ci info->index_size, 235bf215546Sopenharmony_ci count, 236bf215546Sopenharmony_ci hwtnl->api_fillmode, 237bf215546Sopenharmony_ci &gen_prim, 238bf215546Sopenharmony_ci &gen_size, &gen_nr, &gen_func); 239bf215546Sopenharmony_ci } 240bf215546Sopenharmony_ci else { 241bf215546Sopenharmony_ci unsigned hw_pv; 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci /* There is no geometry ordering with PATCH, so no need to 244bf215546Sopenharmony_ci * consider provoking vertex mode for the translation. 245bf215546Sopenharmony_ci * So use the same api_pv as the hw_pv. 246bf215546Sopenharmony_ci */ 247bf215546Sopenharmony_ci hw_pv = info->mode == PIPE_PRIM_PATCHES ? hwtnl->api_pv : 248bf215546Sopenharmony_ci hwtnl->hw_pv; 249bf215546Sopenharmony_ci gen_type = u_index_translator(svga_hw_prims, 250bf215546Sopenharmony_ci info->mode, 251bf215546Sopenharmony_ci info->index_size, 252bf215546Sopenharmony_ci count, 253bf215546Sopenharmony_ci hwtnl->api_pv, 254bf215546Sopenharmony_ci hw_pv, 255bf215546Sopenharmony_ci PR_DISABLE, 256bf215546Sopenharmony_ci &gen_prim, &gen_size, &gen_nr, &gen_func); 257bf215546Sopenharmony_ci } 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci if ((gen_type == U_TRANSLATE_MEMCPY) && (info->index_size == gen_size)) { 260bf215546Sopenharmony_ci /* No need for translation, just pass through to hardware: 261bf215546Sopenharmony_ci */ 262bf215546Sopenharmony_ci unsigned start_offset = draw->start * info->index_size; 263bf215546Sopenharmony_ci struct pipe_resource *index_buffer = NULL; 264bf215546Sopenharmony_ci unsigned index_offset; 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci if (info->has_user_indices) { 267bf215546Sopenharmony_ci u_upload_data(pipe->stream_uploader, 0, count * info->index_size, 268bf215546Sopenharmony_ci info->index_size, (char *) info->index.user + start_offset, 269bf215546Sopenharmony_ci &index_offset, &index_buffer); 270bf215546Sopenharmony_ci u_upload_unmap(pipe->stream_uploader); 271bf215546Sopenharmony_ci index_offset /= info->index_size; 272bf215546Sopenharmony_ci } else { 273bf215546Sopenharmony_ci pipe_resource_reference(&index_buffer, info->index.resource); 274bf215546Sopenharmony_ci index_offset = draw->start; 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci assert(index_buffer != NULL); 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci ret = svga_hwtnl_simple_draw_range_elements(hwtnl, index_buffer, 280bf215546Sopenharmony_ci info->index_size, 281bf215546Sopenharmony_ci draw->index_bias, 282bf215546Sopenharmony_ci info->index_bounds_valid ? info->min_index : 0, 283bf215546Sopenharmony_ci info->index_bounds_valid ? info->max_index : ~0, 284bf215546Sopenharmony_ci gen_prim, index_offset, count, 285bf215546Sopenharmony_ci info->start_instance, 286bf215546Sopenharmony_ci info->instance_count, 287bf215546Sopenharmony_ci hwtnl->svga->patch_vertices); 288bf215546Sopenharmony_ci pipe_resource_reference(&index_buffer, NULL); 289bf215546Sopenharmony_ci } 290bf215546Sopenharmony_ci else { 291bf215546Sopenharmony_ci struct pipe_resource *gen_buf = NULL; 292bf215546Sopenharmony_ci unsigned gen_offset = 0; 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci /* Need to allocate a new index buffer and run the translate 295bf215546Sopenharmony_ci * func to populate it. Could potentially cache this translated 296bf215546Sopenharmony_ci * index buffer with the original to avoid future 297bf215546Sopenharmony_ci * re-translations. Not much point if we're just accelerating 298bf215546Sopenharmony_ci * GL though, as index buffers are typically used only once 299bf215546Sopenharmony_ci * there. 300bf215546Sopenharmony_ci */ 301bf215546Sopenharmony_ci ret = translate_indices(hwtnl, info, draw, gen_prim, 302bf215546Sopenharmony_ci count, gen_nr, gen_size, 303bf215546Sopenharmony_ci gen_func, &gen_buf, &gen_offset); 304bf215546Sopenharmony_ci if (ret == PIPE_OK) { 305bf215546Sopenharmony_ci gen_offset /= gen_size; 306bf215546Sopenharmony_ci ret = svga_hwtnl_simple_draw_range_elements(hwtnl, 307bf215546Sopenharmony_ci gen_buf, 308bf215546Sopenharmony_ci gen_size, 309bf215546Sopenharmony_ci draw->index_bias, 310bf215546Sopenharmony_ci info->index_bounds_valid ? info->min_index : 0, 311bf215546Sopenharmony_ci info->index_bounds_valid ? info->max_index : ~0, 312bf215546Sopenharmony_ci gen_prim, gen_offset, 313bf215546Sopenharmony_ci gen_nr, 314bf215546Sopenharmony_ci info->start_instance, 315bf215546Sopenharmony_ci info->instance_count, 316bf215546Sopenharmony_ci hwtnl->svga->patch_vertices); 317bf215546Sopenharmony_ci } 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci if (gen_buf) { 320bf215546Sopenharmony_ci pipe_resource_reference(&gen_buf, NULL); 321bf215546Sopenharmony_ci } 322bf215546Sopenharmony_ci } 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci SVGA_STATS_TIME_POP(svga_sws(hwtnl->svga)); 325bf215546Sopenharmony_ci return ret; 326bf215546Sopenharmony_ci} 327