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 "pipe/p_compiler.h" 27 #include "util/u_inlines.h" 28 #include "pipe/p_defines.h" 29 #include "util/u_memory.h" 30 #include "util/u_math.h" 31 #include "util/u_upload_mgr.h" 32 33 #include "svga_context.h" 34 #include "svga_draw.h" 35 #include "svga_draw_private.h" 36 #include "svga_debug.h" 37 #include "svga_screen.h" 38 #include "svga_resource_buffer.h" 39 #include "svga_resource_texture.h" 40 #include "svga_surface.h" 41 #include "svga_winsys.h" 42 #include "svga_cmd.h" 43 44 45 struct svga_hwtnl *svga_hwtnl_create( struct svga_context *svga, 46 struct u_upload_mgr *upload_ib, 47 struct svga_winsys_context *swc ) 48 { 49 struct svga_hwtnl *hwtnl = CALLOC_STRUCT(svga_hwtnl); 50 if (hwtnl == NULL) 51 goto fail; 52 53 hwtnl->svga = svga; 54 hwtnl->upload_ib = upload_ib; 55 56 hwtnl->cmd.swc = swc; 57 58 return hwtnl; 59 60 fail: 61 return NULL; 62 } 63 64 void svga_hwtnl_destroy( struct svga_hwtnl *hwtnl ) 65 { 66 int i, j; 67 68 for (i = 0; i < PIPE_PRIM_MAX; i++) { 69 for (j = 0; j < IDX_CACHE_MAX; j++) { 70 pipe_resource_reference( &hwtnl->index_cache[i][j].buffer, 71 NULL ); 72 } 73 } 74 75 for (i = 0; i < hwtnl->cmd.vdecl_count; i++) 76 pipe_resource_reference(&hwtnl->cmd.vdecl_vb[i], NULL); 77 78 for (i = 0; i < hwtnl->cmd.prim_count; i++) 79 pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL); 80 81 82 FREE(hwtnl); 83 } 84 85 86 void svga_hwtnl_set_flatshade( struct svga_hwtnl *hwtnl, 87 boolean flatshade, 88 boolean flatshade_first ) 89 { 90 hwtnl->hw_pv = PV_FIRST; 91 hwtnl->api_pv = (flatshade && !flatshade_first) ? PV_LAST : PV_FIRST; 92 } 93 94 void svga_hwtnl_set_unfilled( struct svga_hwtnl *hwtnl, 95 unsigned mode ) 96 { 97 hwtnl->api_fillmode = mode; 98 } 99 100 void svga_hwtnl_reset_vdecl( struct svga_hwtnl *hwtnl, 101 unsigned count ) 102 { 103 unsigned i; 104 105 assert(hwtnl->cmd.prim_count == 0); 106 107 for (i = count; i < hwtnl->cmd.vdecl_count; i++) { 108 pipe_resource_reference(&hwtnl->cmd.vdecl_vb[i], 109 NULL); 110 } 111 112 hwtnl->cmd.vdecl_count = count; 113 } 114 115 116 void svga_hwtnl_vdecl( struct svga_hwtnl *hwtnl, 117 unsigned i, 118 const SVGA3dVertexDecl *decl, 119 struct pipe_resource *vb) 120 { 121 assert(hwtnl->cmd.prim_count == 0); 122 123 assert( i < hwtnl->cmd.vdecl_count ); 124 125 hwtnl->cmd.vdecl[i] = *decl; 126 127 pipe_resource_reference(&hwtnl->cmd.vdecl_vb[i], vb); 128 } 129 130 131 /** 132 * Determine whether the specified buffer is referred in the primitive queue, 133 * for which no commands have been written yet. 134 */ 135 boolean 136 svga_hwtnl_is_buffer_referred( struct svga_hwtnl *hwtnl, 137 struct pipe_resource *buffer) 138 { 139 unsigned i; 140 141 if (svga_buffer_is_user_buffer(buffer)) { 142 return FALSE; 143 } 144 145 if (!hwtnl->cmd.prim_count) { 146 return FALSE; 147 } 148 149 for (i = 0; i < hwtnl->cmd.vdecl_count; ++i) { 150 if (hwtnl->cmd.vdecl_vb[i] == buffer) { 151 return TRUE; 152 } 153 } 154 155 for (i = 0; i < hwtnl->cmd.prim_count; ++i) { 156 if (hwtnl->cmd.prim_ib[i] == buffer) { 157 return TRUE; 158 } 159 } 160 161 return FALSE; 162 } 163 164 165 enum pipe_error 166 svga_hwtnl_flush( struct svga_hwtnl *hwtnl ) 167 { 168 struct svga_winsys_context *swc = hwtnl->cmd.swc; 169 struct svga_context *svga = hwtnl->svga; 170 enum pipe_error ret; 171 172 if (hwtnl->cmd.prim_count) { 173 struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX]; 174 struct svga_winsys_surface *ib_handle[QSZ]; 175 struct svga_winsys_surface *handle; 176 SVGA3dVertexDecl *vdecl; 177 SVGA3dPrimitiveRange *prim; 178 unsigned i; 179 180 /* Unmap upload manager vertex buffers */ 181 u_upload_unmap(svga->upload_vb); 182 183 for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { 184 handle = svga_buffer_handle(svga, hwtnl->cmd.vdecl_vb[i]); 185 if (handle == NULL) 186 return PIPE_ERROR_OUT_OF_MEMORY; 187 188 vb_handle[i] = handle; 189 } 190 191 /* Unmap upload manager index buffers */ 192 u_upload_unmap(svga->upload_ib); 193 194 for (i = 0; i < hwtnl->cmd.prim_count; i++) { 195 if (hwtnl->cmd.prim_ib[i]) { 196 handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i]); 197 if (handle == NULL) 198 return PIPE_ERROR_OUT_OF_MEMORY; 199 } 200 else 201 handle = NULL; 202 203 ib_handle[i] = handle; 204 } 205 206 if (svga->rebind.rendertargets) { 207 ret = svga_reemit_framebuffer_bindings(svga); 208 if (ret != PIPE_OK) { 209 return ret; 210 } 211 } 212 213 if (svga->rebind.texture_samplers) { 214 ret = svga_reemit_tss_bindings(svga); 215 if (ret != PIPE_OK) { 216 return ret; 217 } 218 } 219 220 SVGA_DBG(DEBUG_DMA, "draw to sid %p, %d prims\n", 221 svga->curr.framebuffer.cbufs[0] ? 222 svga_surface(svga->curr.framebuffer.cbufs[0])->handle : NULL, 223 hwtnl->cmd.prim_count); 224 225 ret = SVGA3D_BeginDrawPrimitives(swc, 226 &vdecl, 227 hwtnl->cmd.vdecl_count, 228 &prim, 229 hwtnl->cmd.prim_count); 230 if (ret != PIPE_OK) 231 return ret; 232 233 234 memcpy( vdecl, 235 hwtnl->cmd.vdecl, 236 hwtnl->cmd.vdecl_count * sizeof hwtnl->cmd.vdecl[0]); 237 238 for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { 239 /* Given rangeHint is considered to be relative to indexBias, and 240 * indexBias varies per primitive, we cannot accurately supply an 241 * rangeHint when emitting more than one primitive per draw command. 242 */ 243 if (hwtnl->cmd.prim_count == 1) { 244 vdecl[i].rangeHint.first = hwtnl->cmd.min_index[0]; 245 vdecl[i].rangeHint.last = hwtnl->cmd.max_index[0] + 1; 246 } 247 else { 248 vdecl[i].rangeHint.first = 0; 249 vdecl[i].rangeHint.last = 0; 250 } 251 252 swc->surface_relocation(swc, 253 &vdecl[i].array.surfaceId, 254 vb_handle[i], 255 SVGA_RELOC_READ); 256 } 257 258 memcpy( prim, 259 hwtnl->cmd.prim, 260 hwtnl->cmd.prim_count * sizeof hwtnl->cmd.prim[0]); 261 262 for (i = 0; i < hwtnl->cmd.prim_count; i++) { 263 swc->surface_relocation(swc, 264 &prim[i].indexArray.surfaceId, 265 ib_handle[i], 266 SVGA_RELOC_READ); 267 pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL); 268 } 269 270 SVGA_FIFOCommitAll( swc ); 271 hwtnl->cmd.prim_count = 0; 272 } 273 274 return PIPE_OK; 275 } 276 277 278 void svga_hwtnl_set_index_bias( struct svga_hwtnl *hwtnl, 279 int index_bias) 280 { 281 hwtnl->index_bias = index_bias; 282 } 283 284 285 286 /*********************************************************************** 287 * Internal functions: 288 */ 289 290 enum pipe_error svga_hwtnl_prim( struct svga_hwtnl *hwtnl, 291 const SVGA3dPrimitiveRange *range, 292 unsigned min_index, 293 unsigned max_index, 294 struct pipe_resource *ib ) 295 { 296 enum pipe_error ret = PIPE_OK; 297 298 #ifdef DEBUG 299 { 300 unsigned i; 301 for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { 302 struct pipe_resource *vb = hwtnl->cmd.vdecl_vb[i]; 303 unsigned size = vb ? vb->width0 : 0; 304 unsigned offset = hwtnl->cmd.vdecl[i].array.offset; 305 unsigned stride = hwtnl->cmd.vdecl[i].array.stride; 306 int index_bias = (int) range->indexBias + hwtnl->index_bias; 307 unsigned width; 308 309 assert(vb); 310 assert(size); 311 assert(offset < size); 312 assert(min_index <= max_index); 313 314 switch (hwtnl->cmd.vdecl[i].identity.type) { 315 case SVGA3D_DECLTYPE_FLOAT1: 316 width = 4; 317 break; 318 case SVGA3D_DECLTYPE_FLOAT2: 319 width = 4*2; 320 break; 321 case SVGA3D_DECLTYPE_FLOAT3: 322 width = 4*3; 323 break; 324 case SVGA3D_DECLTYPE_FLOAT4: 325 width = 4*4; 326 break; 327 case SVGA3D_DECLTYPE_D3DCOLOR: 328 width = 4; 329 break; 330 case SVGA3D_DECLTYPE_UBYTE4: 331 width = 1*4; 332 break; 333 case SVGA3D_DECLTYPE_SHORT2: 334 width = 2*2; 335 break; 336 case SVGA3D_DECLTYPE_SHORT4: 337 width = 2*4; 338 break; 339 case SVGA3D_DECLTYPE_UBYTE4N: 340 width = 1*4; 341 break; 342 case SVGA3D_DECLTYPE_SHORT2N: 343 width = 2*2; 344 break; 345 case SVGA3D_DECLTYPE_SHORT4N: 346 width = 2*4; 347 break; 348 case SVGA3D_DECLTYPE_USHORT2N: 349 width = 2*2; 350 break; 351 case SVGA3D_DECLTYPE_USHORT4N: 352 width = 2*4; 353 break; 354 case SVGA3D_DECLTYPE_UDEC3: 355 width = 4; 356 break; 357 case SVGA3D_DECLTYPE_DEC3N: 358 width = 4; 359 break; 360 case SVGA3D_DECLTYPE_FLOAT16_2: 361 width = 2*2; 362 break; 363 case SVGA3D_DECLTYPE_FLOAT16_4: 364 width = 2*4; 365 break; 366 default: 367 assert(0); 368 width = 0; 369 break; 370 } 371 372 if (index_bias >= 0) { 373 assert(offset + index_bias*stride + width <= size); 374 } 375 376 /* 377 * min_index/max_index are merely conservative guesses, so we can't 378 * make buffer overflow detection based on their values. 379 */ 380 } 381 382 assert(range->indexWidth == range->indexArray.stride); 383 384 if(ib) { 385 unsigned size = ib->width0; 386 unsigned offset = range->indexArray.offset; 387 unsigned stride = range->indexArray.stride; 388 unsigned count; 389 390 assert(size); 391 assert(offset < size); 392 assert(stride); 393 394 switch (range->primType) { 395 case SVGA3D_PRIMITIVE_POINTLIST: 396 count = range->primitiveCount; 397 break; 398 case SVGA3D_PRIMITIVE_LINELIST: 399 count = range->primitiveCount * 2; 400 break; 401 case SVGA3D_PRIMITIVE_LINESTRIP: 402 count = range->primitiveCount + 1; 403 break; 404 case SVGA3D_PRIMITIVE_TRIANGLELIST: 405 count = range->primitiveCount * 3; 406 break; 407 case SVGA3D_PRIMITIVE_TRIANGLESTRIP: 408 count = range->primitiveCount + 2; 409 break; 410 case SVGA3D_PRIMITIVE_TRIANGLEFAN: 411 count = range->primitiveCount + 2; 412 break; 413 default: 414 assert(0); 415 count = 0; 416 break; 417 } 418 419 assert(offset + count*stride <= size); 420 } 421 } 422 #endif 423 424 if (hwtnl->cmd.prim_count+1 >= QSZ) { 425 ret = svga_hwtnl_flush( hwtnl ); 426 if (ret != PIPE_OK) 427 return ret; 428 } 429 430 /* min/max indices are relative to bias */ 431 hwtnl->cmd.min_index[hwtnl->cmd.prim_count] = min_index; 432 hwtnl->cmd.max_index[hwtnl->cmd.prim_count] = max_index; 433 434 hwtnl->cmd.prim[hwtnl->cmd.prim_count] = *range; 435 hwtnl->cmd.prim[hwtnl->cmd.prim_count].indexBias += hwtnl->index_bias; 436 437 pipe_resource_reference(&hwtnl->cmd.prim_ib[hwtnl->cmd.prim_count], ib); 438 hwtnl->cmd.prim_count++; 439 440 return ret; 441 } 442