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_format.h" 29 #include "util/u_inlines.h" 30 #include "util/u_prim.h" 31 #include "util/u_time.h" 32 #include "indices/u_indices.h" 33 34 #include "svga_hw_reg.h" 35 #include "svga_context.h" 36 #include "svga_screen.h" 37 #include "svga_draw.h" 38 #include "svga_state.h" 39 #include "svga_swtnl.h" 40 #include "svga_debug.h" 41 #include "svga_resource_buffer.h" 42 #include "util/u_upload_mgr.h" 43 44 /** 45 * Determine the ranges to upload for the user-buffers referenced 46 * by the next draw command. 47 * 48 * TODO: It might be beneficial to support multiple ranges. In that case, 49 * the struct svga_buffer::uploaded member should be made an array or a 50 * list, since we need to account for the possibility that different ranges 51 * may be uploaded to different hardware buffers chosen by the utility 52 * upload manager. 53 */ 54 55 static void 56 svga_user_buffer_range(struct svga_context *svga, 57 unsigned start, 58 unsigned count, 59 unsigned instance_count) 60 { 61 const struct pipe_vertex_element *ve = svga->curr.velems->velem; 62 int i; 63 64 /* 65 * Release old uploaded range (if not done already) and 66 * initialize new ranges. 67 */ 68 69 for (i=0; i < svga->curr.velems->count; i++) { 70 struct pipe_vertex_buffer *vb = 71 &svga->curr.vb[ve[i].vertex_buffer_index]; 72 73 if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) { 74 struct svga_buffer *buffer = svga_buffer(vb->buffer); 75 76 pipe_resource_reference(&buffer->uploaded.buffer, NULL); 77 buffer->uploaded.start = ~0; 78 buffer->uploaded.end = 0; 79 } 80 } 81 82 for (i=0; i < svga->curr.velems->count; i++) { 83 struct pipe_vertex_buffer *vb = 84 &svga->curr.vb[ve[i].vertex_buffer_index]; 85 86 if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) { 87 struct svga_buffer *buffer = svga_buffer(vb->buffer); 88 unsigned first, size; 89 unsigned instance_div = ve[i].instance_divisor; 90 unsigned elemSize = util_format_get_blocksize(ve[i].src_format); 91 92 svga->dirty |= SVGA_NEW_VBUFFER; 93 94 if (instance_div) { 95 first = ve[i].src_offset; 96 count = (instance_count + instance_div - 1) / instance_div; 97 size = vb->stride * (count - 1) + elemSize; 98 } else { 99 first = vb->stride * start + ve[i].src_offset; 100 size = vb->stride * (count - 1) + elemSize; 101 } 102 103 buffer->uploaded.start = MIN2(buffer->uploaded.start, first); 104 buffer->uploaded.end = MAX2(buffer->uploaded.end, first + size); 105 } 106 } 107 } 108 109 /** 110 * svga_upload_user_buffers - upload parts of user buffers 111 * 112 * This function streams a part of a user buffer to hw and fills 113 * svga_buffer::uploaded with information on the upload. 114 */ 115 116 static int 117 svga_upload_user_buffers(struct svga_context *svga, 118 unsigned start, 119 unsigned count, 120 unsigned instance_count) 121 { 122 const struct pipe_vertex_element *ve = svga->curr.velems->velem; 123 unsigned i; 124 int ret; 125 126 svga_user_buffer_range(svga, start, count, instance_count); 127 128 for (i=0; i < svga->curr.velems->count; i++) { 129 struct pipe_vertex_buffer *vb = 130 &svga->curr.vb[ve[i].vertex_buffer_index]; 131 132 if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) { 133 struct svga_buffer *buffer = svga_buffer(vb->buffer); 134 135 /* 136 * Check if already uploaded. Otherwise go ahead and upload. 137 */ 138 139 if (buffer->uploaded.buffer) 140 continue; 141 142 ret = u_upload_buffer( svga->upload_vb, 143 0, 144 buffer->uploaded.start, 145 buffer->uploaded.end - buffer->uploaded.start, 146 &buffer->b.b, 147 &buffer->uploaded.offset, 148 &buffer->uploaded.buffer); 149 150 if (ret) 151 return ret; 152 153 if (0) 154 debug_printf("%s: %d: orig buf %p upl buf %p ofs %d sofs %d" 155 " sz %d\n", 156 __FUNCTION__, 157 i, 158 buffer, 159 buffer->uploaded.buffer, 160 buffer->uploaded.offset, 161 buffer->uploaded.start, 162 buffer->uploaded.end - buffer->uploaded.start); 163 164 vb->buffer_offset = buffer->uploaded.offset; 165 } 166 } 167 168 return PIPE_OK; 169 } 170 171 /** 172 * svga_release_user_upl_buffers - release uploaded parts of user buffers 173 * 174 * This function releases the hw copy of the uploaded fraction of the 175 * user-buffer. It's important to do this as soon as all draw calls 176 * affecting the uploaded fraction are issued, as this allows for 177 * efficient reuse of the hardware surface backing the uploaded fraction. 178 * 179 * svga_buffer::source_offset is set to 0, and svga_buffer::uploaded::buffer 180 * is set to 0. 181 */ 182 183 static void 184 svga_release_user_upl_buffers(struct svga_context *svga) 185 { 186 unsigned i; 187 unsigned nr; 188 189 nr = svga->curr.num_vertex_buffers; 190 191 for (i = 0; i < nr; ++i) { 192 struct pipe_vertex_buffer *vb = &svga->curr.vb[i]; 193 194 if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) { 195 struct svga_buffer *buffer = svga_buffer(vb->buffer); 196 197 /* The buffer_offset is relative to the uploaded buffer. 198 * Since we're discarding that buffer we need to reset this offset 199 * so it's not inadvertantly applied to a subsequent draw. 200 * 201 * XXX a root problem here is that the svga->curr.vb[] information 202 * is getting set both by gallium API calls and by code in 203 * svga_upload_user_buffers(). We should instead have two copies 204 * of the vertex buffer information and choose between as needed. 205 */ 206 vb->buffer_offset = 0; 207 208 buffer->uploaded.start = ~0; 209 buffer->uploaded.end = 0; 210 if (buffer->uploaded.buffer) 211 pipe_resource_reference(&buffer->uploaded.buffer, NULL); 212 } 213 } 214 } 215 216 217 218 static enum pipe_error 219 retry_draw_range_elements( struct svga_context *svga, 220 struct pipe_resource *index_buffer, 221 unsigned index_size, 222 int index_bias, 223 unsigned min_index, 224 unsigned max_index, 225 unsigned prim, 226 unsigned start, 227 unsigned count, 228 unsigned instance_count, 229 boolean do_retry ) 230 { 231 enum pipe_error ret = PIPE_OK; 232 233 svga_hwtnl_set_unfilled( svga->hwtnl, 234 svga->curr.rast->hw_unfilled ); 235 236 svga_hwtnl_set_flatshade( svga->hwtnl, 237 svga->curr.rast->templ.flatshade, 238 svga->curr.rast->templ.flatshade_first ); 239 240 ret = svga_upload_user_buffers( svga, min_index + index_bias, 241 max_index - min_index + 1, instance_count ); 242 if (ret != PIPE_OK) 243 goto retry; 244 245 ret = svga_update_state( svga, SVGA_STATE_HW_DRAW ); 246 if (ret != PIPE_OK) 247 goto retry; 248 249 ret = svga_hwtnl_draw_range_elements( svga->hwtnl, 250 index_buffer, index_size, index_bias, 251 min_index, max_index, 252 prim, start, count ); 253 if (ret != PIPE_OK) 254 goto retry; 255 256 return PIPE_OK; 257 258 retry: 259 svga_context_flush( svga, NULL ); 260 261 if (do_retry) 262 { 263 return retry_draw_range_elements( svga, 264 index_buffer, index_size, index_bias, 265 min_index, max_index, 266 prim, start, count, 267 instance_count, FALSE ); 268 } 269 270 return ret; 271 } 272 273 274 static enum pipe_error 275 retry_draw_arrays( struct svga_context *svga, 276 unsigned prim, 277 unsigned start, 278 unsigned count, 279 unsigned instance_count, 280 boolean do_retry ) 281 { 282 enum pipe_error ret; 283 284 svga_hwtnl_set_unfilled( svga->hwtnl, 285 svga->curr.rast->hw_unfilled ); 286 287 svga_hwtnl_set_flatshade( svga->hwtnl, 288 svga->curr.rast->templ.flatshade, 289 svga->curr.rast->templ.flatshade_first ); 290 291 ret = svga_upload_user_buffers( svga, start, count, instance_count ); 292 293 if (ret != PIPE_OK) 294 goto retry; 295 296 ret = svga_update_state( svga, SVGA_STATE_HW_DRAW ); 297 if (ret != PIPE_OK) 298 goto retry; 299 300 ret = svga_hwtnl_draw_arrays( svga->hwtnl, prim, 301 start, count ); 302 if (ret != PIPE_OK) 303 goto retry; 304 305 return PIPE_OK; 306 307 retry: 308 if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry) 309 { 310 svga_context_flush( svga, NULL ); 311 312 return retry_draw_arrays( svga, 313 prim, 314 start, 315 count, 316 instance_count, 317 FALSE ); 318 } 319 320 return ret; 321 } 322 323 324 static void 325 svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) 326 { 327 struct svga_context *svga = svga_context( pipe ); 328 unsigned reduced_prim = u_reduced_prim( info->mode ); 329 unsigned count = info->count; 330 enum pipe_error ret = 0; 331 boolean needed_swtnl; 332 333 if (!u_trim_pipe_prim( info->mode, &count )) 334 return; 335 336 /* 337 * Mark currently bound target surfaces as dirty 338 * doesn't really matter if it is done before drawing. 339 * 340 * TODO If we ever normaly return something other then 341 * true we should not mark it as dirty then. 342 */ 343 svga_mark_surfaces_dirty(svga_context(pipe)); 344 345 if (svga->curr.reduced_prim != reduced_prim) { 346 svga->curr.reduced_prim = reduced_prim; 347 svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE; 348 } 349 350 needed_swtnl = svga->state.sw.need_swtnl; 351 352 svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL ); 353 354 #ifdef DEBUG 355 if (svga->curr.vs->base.id == svga->debug.disable_shader || 356 svga->curr.fs->base.id == svga->debug.disable_shader) 357 return; 358 #endif 359 360 if (svga->state.sw.need_swtnl) { 361 if (!needed_swtnl) { 362 /* 363 * We're switching from HW to SW TNL. SW TNL will require mapping all 364 * currently bound vertex buffers, some of which may already be 365 * referenced in the current command buffer as result of previous HW 366 * TNL. So flush now, to prevent the context to flush while a referred 367 * vertex buffer is mapped. 368 */ 369 370 svga_context_flush(svga, NULL); 371 } 372 373 /* Avoid leaking the previous hwtnl bias to swtnl */ 374 svga_hwtnl_set_index_bias( svga->hwtnl, 0 ); 375 ret = svga_swtnl_draw_vbo( svga, info ); 376 } 377 else { 378 if (info->indexed && svga->curr.ib.buffer) { 379 unsigned offset; 380 381 assert(svga->curr.ib.offset % svga->curr.ib.index_size == 0); 382 offset = svga->curr.ib.offset / svga->curr.ib.index_size; 383 384 ret = retry_draw_range_elements( svga, 385 svga->curr.ib.buffer, 386 svga->curr.ib.index_size, 387 info->index_bias, 388 info->min_index, 389 info->max_index, 390 info->mode, 391 info->start + offset, 392 info->count, 393 info->instance_count, 394 TRUE ); 395 } 396 else { 397 ret = retry_draw_arrays( svga, 398 info->mode, 399 info->start, 400 info->count, 401 info->instance_count, 402 TRUE ); 403 } 404 } 405 406 /* XXX: Silence warnings, do something sensible here? */ 407 (void)ret; 408 409 svga_release_user_upl_buffers( svga ); 410 411 if (SVGA_DEBUG & DEBUG_FLUSH) { 412 svga_hwtnl_flush_retry( svga ); 413 svga_context_flush(svga, NULL); 414 } 415 } 416 417 418 void svga_init_draw_functions( struct svga_context *svga ) 419 { 420 svga->pipe.draw_vbo = svga_draw_vbo; 421 } 422