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_defines.h" 27 #include "util/u_bitmask.h" 28 #include "util/u_format.h" 29 #include "util/u_inlines.h" 30 #include "util/u_math.h" 31 #include "util/u_memory.h" 32 #include "tgsi/tgsi_parse.h" 33 34 #include "svga_context.h" 35 #include "svga_cmd.h" 36 #include "svga_debug.h" 37 #include "svga_resource_texture.h" 38 #include "svga_surface.h" 39 #include "svga_sampler_view.h" 40 41 42 static inline unsigned 43 translate_wrap_mode(unsigned wrap) 44 { 45 switch (wrap) { 46 case PIPE_TEX_WRAP_REPEAT: 47 return SVGA3D_TEX_ADDRESS_WRAP; 48 case PIPE_TEX_WRAP_CLAMP: 49 return SVGA3D_TEX_ADDRESS_CLAMP; 50 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 51 /* Unfortunately SVGA3D_TEX_ADDRESS_EDGE not respected by 52 * hardware. 53 */ 54 return SVGA3D_TEX_ADDRESS_CLAMP; 55 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 56 return SVGA3D_TEX_ADDRESS_BORDER; 57 case PIPE_TEX_WRAP_MIRROR_REPEAT: 58 return SVGA3D_TEX_ADDRESS_MIRROR; 59 case PIPE_TEX_WRAP_MIRROR_CLAMP: 60 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 61 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 62 return SVGA3D_TEX_ADDRESS_MIRRORONCE; 63 default: 64 assert(0); 65 return SVGA3D_TEX_ADDRESS_WRAP; 66 } 67 } 68 69 70 static inline unsigned 71 translate_img_filter(unsigned filter) 72 { 73 switch (filter) { 74 case PIPE_TEX_FILTER_NEAREST: 75 return SVGA3D_TEX_FILTER_NEAREST; 76 case PIPE_TEX_FILTER_LINEAR: 77 return SVGA3D_TEX_FILTER_LINEAR; 78 default: 79 assert(0); 80 return SVGA3D_TEX_FILTER_NEAREST; 81 } 82 } 83 84 85 static inline unsigned 86 translate_mip_filter(unsigned filter) 87 { 88 switch (filter) { 89 case PIPE_TEX_MIPFILTER_NONE: 90 return SVGA3D_TEX_FILTER_NONE; 91 case PIPE_TEX_MIPFILTER_NEAREST: 92 return SVGA3D_TEX_FILTER_NEAREST; 93 case PIPE_TEX_MIPFILTER_LINEAR: 94 return SVGA3D_TEX_FILTER_LINEAR; 95 default: 96 assert(0); 97 return SVGA3D_TEX_FILTER_NONE; 98 } 99 } 100 101 102 static uint8 103 translate_comparison_func(unsigned func) 104 { 105 switch (func) { 106 case PIPE_FUNC_NEVER: 107 return SVGA3D_COMPARISON_NEVER; 108 case PIPE_FUNC_LESS: 109 return SVGA3D_COMPARISON_LESS; 110 case PIPE_FUNC_EQUAL: 111 return SVGA3D_COMPARISON_EQUAL; 112 case PIPE_FUNC_LEQUAL: 113 return SVGA3D_COMPARISON_LESS_EQUAL; 114 case PIPE_FUNC_GREATER: 115 return SVGA3D_COMPARISON_GREATER; 116 case PIPE_FUNC_NOTEQUAL: 117 return SVGA3D_COMPARISON_NOT_EQUAL; 118 case PIPE_FUNC_GEQUAL: 119 return SVGA3D_COMPARISON_GREATER_EQUAL; 120 case PIPE_FUNC_ALWAYS: 121 return SVGA3D_COMPARISON_ALWAYS; 122 default: 123 assert(!"Invalid comparison function"); 124 return SVGA3D_COMPARISON_ALWAYS; 125 } 126 } 127 128 129 /** 130 * Translate filtering state to vgpu10 format. 131 */ 132 static SVGA3dFilter 133 translate_filter_mode(unsigned img_filter, 134 unsigned min_filter, 135 unsigned mag_filter, 136 boolean anisotropic, 137 boolean compare) 138 { 139 SVGA3dFilter mode = 0; 140 141 if (img_filter == PIPE_TEX_FILTER_LINEAR) 142 mode |= SVGA3D_FILTER_MIP_LINEAR; 143 if (min_filter == PIPE_TEX_FILTER_LINEAR) 144 mode |= SVGA3D_FILTER_MIN_LINEAR; 145 if (mag_filter == PIPE_TEX_FILTER_LINEAR) 146 mode |= SVGA3D_FILTER_MAG_LINEAR; 147 if (anisotropic) 148 mode |= SVGA3D_FILTER_ANISOTROPIC; 149 if (compare) 150 mode |= SVGA3D_FILTER_COMPARE; 151 152 return mode; 153 } 154 155 156 /** 157 * Define a vgpu10 sampler state. 158 */ 159 static void 160 define_sampler_state_object(struct svga_context *svga, 161 struct svga_sampler_state *ss, 162 const struct pipe_sampler_state *ps) 163 { 164 uint8_t max_aniso = (uint8_t) 255; /* XXX fix me */ 165 boolean anisotropic; 166 uint8 compare_func; 167 SVGA3dFilter filter; 168 SVGA3dRGBAFloat bcolor; 169 unsigned try; 170 float min_lod, max_lod; 171 172 assert(svga_have_vgpu10(svga)); 173 174 anisotropic = ss->aniso_level > 1.0f; 175 176 filter = translate_filter_mode(ps->min_mip_filter, 177 ps->min_img_filter, 178 ps->mag_img_filter, 179 anisotropic, 180 ss->compare_mode); 181 182 compare_func = translate_comparison_func(ss->compare_func); 183 184 COPY_4V(bcolor.value, ps->border_color.f); 185 186 ss->id = util_bitmask_add(svga->sampler_object_id_bm); 187 188 assert(ps->min_lod <= ps->max_lod); 189 190 if (ps->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) { 191 /* just use the base level image */ 192 min_lod = max_lod = 0.0f; 193 } 194 else { 195 min_lod = ps->min_lod; 196 max_lod = ps->max_lod; 197 } 198 199 /* Loop in case command buffer is full and we need to flush and retry */ 200 for (try = 0; try < 2; try++) { 201 enum pipe_error ret = 202 SVGA3D_vgpu10_DefineSamplerState(svga->swc, 203 ss->id, 204 filter, 205 ss->addressu, 206 ss->addressv, 207 ss->addressw, 208 ss->lod_bias, /* float */ 209 max_aniso, 210 compare_func, 211 bcolor, 212 min_lod, /* float */ 213 max_lod); /* float */ 214 if (ret == PIPE_OK) 215 return; 216 svga_context_flush(svga, NULL); 217 } 218 } 219 220 221 static void * 222 svga_create_sampler_state(struct pipe_context *pipe, 223 const struct pipe_sampler_state *sampler) 224 { 225 struct svga_context *svga = svga_context(pipe); 226 struct svga_sampler_state *cso = CALLOC_STRUCT( svga_sampler_state ); 227 228 if (!cso) 229 return NULL; 230 231 cso->mipfilter = translate_mip_filter(sampler->min_mip_filter); 232 cso->magfilter = translate_img_filter( sampler->mag_img_filter ); 233 cso->minfilter = translate_img_filter( sampler->min_img_filter ); 234 cso->aniso_level = MAX2( sampler->max_anisotropy, 1 ); 235 if (sampler->max_anisotropy) 236 cso->magfilter = cso->minfilter = SVGA3D_TEX_FILTER_ANISOTROPIC; 237 cso->lod_bias = sampler->lod_bias; 238 cso->addressu = translate_wrap_mode(sampler->wrap_s); 239 cso->addressv = translate_wrap_mode(sampler->wrap_t); 240 cso->addressw = translate_wrap_mode(sampler->wrap_r); 241 cso->normalized_coords = sampler->normalized_coords; 242 cso->compare_mode = sampler->compare_mode; 243 cso->compare_func = sampler->compare_func; 244 245 { 246 uint32 r = float_to_ubyte(sampler->border_color.f[0]); 247 uint32 g = float_to_ubyte(sampler->border_color.f[1]); 248 uint32 b = float_to_ubyte(sampler->border_color.f[2]); 249 uint32 a = float_to_ubyte(sampler->border_color.f[3]); 250 251 cso->bordercolor = (a << 24) | (r << 16) | (g << 8) | b; 252 } 253 254 /* No SVGA3D support for: 255 * - min/max LOD clamping 256 */ 257 cso->min_lod = 0; 258 cso->view_min_lod = MAX2((int) (sampler->min_lod + 0.5), 0); 259 cso->view_max_lod = MAX2((int) (sampler->max_lod + 0.5), 0); 260 261 /* Use min_mipmap */ 262 if (svga->debug.use_min_mipmap) { 263 if (cso->view_min_lod == cso->view_max_lod) { 264 cso->min_lod = cso->view_min_lod; 265 cso->view_min_lod = 0; 266 cso->view_max_lod = 1000; /* Just a high number */ 267 cso->mipfilter = SVGA3D_TEX_FILTER_NONE; 268 } 269 } 270 271 if (svga_have_vgpu10(svga)) { 272 define_sampler_state_object(svga, cso, sampler); 273 } 274 275 SVGA_DBG(DEBUG_VIEWS, "min %u, view(min %u, max %u) lod, mipfilter %s\n", 276 cso->min_lod, cso->view_min_lod, cso->view_max_lod, 277 cso->mipfilter == SVGA3D_TEX_FILTER_NONE ? "SVGA3D_TEX_FILTER_NONE" : "SOMETHING"); 278 279 svga->hud.num_sampler_objects++; 280 SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws, 281 SVGA_STATS_COUNT_SAMPLER); 282 283 return cso; 284 } 285 286 287 static void 288 svga_bind_sampler_states(struct pipe_context *pipe, 289 enum pipe_shader_type shader, 290 unsigned start, 291 unsigned num, 292 void **samplers) 293 { 294 struct svga_context *svga = svga_context(pipe); 295 unsigned i; 296 boolean any_change = FALSE; 297 298 assert(shader < PIPE_SHADER_TYPES); 299 assert(start + num <= PIPE_MAX_SAMPLERS); 300 301 /* Pre-VGPU10 only supports FS textures */ 302 if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT) 303 return; 304 305 for (i = 0; i < num; i++) { 306 if (svga->curr.sampler[shader][start + i] != samplers[i]) 307 any_change = TRUE; 308 svga->curr.sampler[shader][start + i] = samplers[i]; 309 } 310 311 if (!any_change) { 312 return; 313 } 314 315 /* find highest non-null sampler[] entry */ 316 { 317 unsigned j = MAX2(svga->curr.num_samplers[shader], start + num); 318 while (j > 0 && svga->curr.sampler[shader][j - 1] == NULL) 319 j--; 320 svga->curr.num_samplers[shader] = j; 321 } 322 323 svga->dirty |= SVGA_NEW_SAMPLER; 324 } 325 326 327 static void 328 svga_delete_sampler_state(struct pipe_context *pipe, void *sampler) 329 { 330 struct svga_sampler_state *ss = (struct svga_sampler_state *) sampler; 331 struct svga_context *svga = svga_context(pipe); 332 333 if (svga_have_vgpu10(svga)) { 334 enum pipe_error ret; 335 336 svga_hwtnl_flush_retry(svga); 337 338 ret = SVGA3D_vgpu10_DestroySamplerState(svga->swc, ss->id); 339 if (ret != PIPE_OK) { 340 svga_context_flush(svga, NULL); 341 ret = SVGA3D_vgpu10_DestroySamplerState(svga->swc, ss->id); 342 } 343 util_bitmask_clear(svga->sampler_object_id_bm, ss->id); 344 } 345 346 FREE(sampler); 347 svga->hud.num_sampler_objects--; 348 } 349 350 351 static struct pipe_sampler_view * 352 svga_create_sampler_view(struct pipe_context *pipe, 353 struct pipe_resource *texture, 354 const struct pipe_sampler_view *templ) 355 { 356 struct svga_context *svga = svga_context(pipe); 357 struct svga_pipe_sampler_view *sv = CALLOC_STRUCT(svga_pipe_sampler_view); 358 359 if (!sv) { 360 return NULL; 361 } 362 363 sv->base = *templ; 364 sv->base.reference.count = 1; 365 sv->base.texture = NULL; 366 pipe_resource_reference(&sv->base.texture, texture); 367 368 sv->base.context = pipe; 369 sv->id = SVGA3D_INVALID_ID; 370 371 svga->hud.num_samplerview_objects++; 372 SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws, 373 SVGA_STATS_COUNT_SAMPLERVIEW); 374 375 return &sv->base; 376 } 377 378 379 static void 380 svga_sampler_view_destroy(struct pipe_context *pipe, 381 struct pipe_sampler_view *view) 382 { 383 struct svga_context *svga = svga_context(pipe); 384 struct svga_pipe_sampler_view *sv = svga_pipe_sampler_view(view); 385 386 if (svga_have_vgpu10(svga) && sv->id != SVGA3D_INVALID_ID) { 387 if (view->context != pipe) { 388 /* The SVGA3D device will generate an error (and on Linux, cause 389 * us to abort) if we try to destroy a shader resource view from 390 * a context other than the one it was created with. Skip the 391 * SVGA3D_vgpu10_DestroyShaderResourceView() and leak the sampler 392 * view for now. This should only sometimes happen when a shared 393 * texture is deleted. 394 */ 395 _debug_printf("context mismatch in %s\n", __func__); 396 } 397 else { 398 enum pipe_error ret; 399 400 svga_hwtnl_flush_retry(svga); /* XXX is this needed? */ 401 402 ret = SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc, sv->id); 403 if (ret != PIPE_OK) { 404 svga_context_flush(svga, NULL); 405 ret = SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc, sv->id); 406 } 407 util_bitmask_clear(svga->sampler_view_id_bm, sv->id); 408 } 409 } 410 411 pipe_resource_reference(&sv->base.texture, NULL); 412 413 FREE(sv); 414 svga->hud.num_samplerview_objects--; 415 } 416 417 418 static void 419 svga_set_sampler_views(struct pipe_context *pipe, 420 enum pipe_shader_type shader, 421 unsigned start, 422 unsigned num, 423 struct pipe_sampler_view **views) 424 { 425 struct svga_context *svga = svga_context(pipe); 426 unsigned flag_1d = 0; 427 unsigned flag_srgb = 0; 428 unsigned flag_rect = 0; 429 unsigned flag_buf = 0; 430 uint i; 431 boolean any_change = FALSE; 432 433 assert(shader < PIPE_SHADER_TYPES); 434 assert(start + num <= ARRAY_SIZE(svga->curr.sampler_views[shader])); 435 436 /* Pre-VGPU10 only supports FS textures */ 437 if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT) 438 return; 439 440 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_SETSAMPLERVIEWS); 441 442 /* This bit of code works around a quirk in the CSO module. 443 * If start=num=0 it means all sampler views should be released. 444 * Note that the CSO module treats sampler views for fragment shaders 445 * differently than other shader types. 446 */ 447 if (start == 0 && num == 0 && svga->curr.num_sampler_views[shader] > 0) { 448 for (i = 0; i < svga->curr.num_sampler_views[shader]; i++) { 449 pipe_sampler_view_release(pipe, &svga->curr.sampler_views[shader][i]); 450 } 451 any_change = TRUE; 452 } 453 454 for (i = 0; i < num; i++) { 455 enum pipe_texture_target target; 456 457 if (svga->curr.sampler_views[shader][start + i] != views[i]) { 458 /* Note: we're using pipe_sampler_view_release() here to work around 459 * a possible crash when the old view belongs to another context that 460 * was already destroyed. 461 */ 462 pipe_sampler_view_release(pipe, &svga->curr.sampler_views[shader][start + i]); 463 pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i], 464 views[i]); 465 any_change = TRUE; 466 } 467 468 if (!views[i]) 469 continue; 470 471 if (util_format_is_srgb(views[i]->format)) 472 flag_srgb |= 1 << (start + i); 473 474 target = views[i]->texture->target; 475 if (target == PIPE_TEXTURE_1D) 476 flag_1d |= 1 << (start + i); 477 else if (target == PIPE_TEXTURE_RECT) 478 flag_rect |= 1 << (start + i); 479 else if (target == PIPE_BUFFER) 480 flag_buf |= 1 << (start + i); 481 } 482 483 if (!any_change) { 484 goto done; 485 } 486 487 /* find highest non-null sampler_views[] entry */ 488 { 489 unsigned j = MAX2(svga->curr.num_sampler_views[shader], start + num); 490 while (j > 0 && svga->curr.sampler_views[shader][j - 1] == NULL) 491 j--; 492 svga->curr.num_sampler_views[shader] = j; 493 } 494 495 svga->dirty |= SVGA_NEW_TEXTURE_BINDING; 496 497 if (flag_srgb != svga->curr.tex_flags.flag_srgb || 498 flag_1d != svga->curr.tex_flags.flag_1d) { 499 svga->dirty |= SVGA_NEW_TEXTURE_FLAGS; 500 svga->curr.tex_flags.flag_1d = flag_1d; 501 svga->curr.tex_flags.flag_srgb = flag_srgb; 502 } 503 504 if (flag_rect != svga->curr.tex_flags.flag_rect || 505 flag_buf != svga->curr.tex_flags.flag_buf) 506 { 507 /* Need to re-emit texture constants */ 508 svga->dirty |= SVGA_NEW_TEXTURE_CONSTS; 509 svga->curr.tex_flags.flag_rect = flag_rect; 510 svga->curr.tex_flags.flag_buf = flag_buf; 511 } 512 513 /* Check if any of the sampler view resources collide with the framebuffer 514 * color buffers or depth stencil resource. If so, set the NEW_FRAME_BUFFER 515 * dirty bit so that emit_framebuffer can be invoked to create backed view 516 * for the conflicted surface view. 517 */ 518 if (svga_check_sampler_framebuffer_resource_collision(svga, shader)) { 519 svga->dirty |= SVGA_NEW_FRAME_BUFFER; 520 } 521 522 done: 523 SVGA_STATS_TIME_POP(svga_sws(svga)); 524 } 525 526 /** 527 * Clean up sampler, sampler view state at context destruction time 528 */ 529 void 530 svga_cleanup_sampler_state(struct svga_context *svga) 531 { 532 enum pipe_shader_type shader; 533 534 for (shader = 0; shader <= PIPE_SHADER_GEOMETRY; shader++) { 535 unsigned i; 536 537 for (i = 0; i < svga->state.hw_draw.num_sampler_views[shader]; i++) { 538 pipe_sampler_view_release(&svga->pipe, 539 &svga->state.hw_draw.sampler_views[shader][i]); 540 } 541 } 542 543 /* free polygon stipple state */ 544 if (svga->polygon_stipple.sampler) { 545 svga->pipe.delete_sampler_state(&svga->pipe, svga->polygon_stipple.sampler); 546 } 547 548 if (svga->polygon_stipple.sampler_view) { 549 svga->pipe.sampler_view_destroy(&svga->pipe, 550 &svga->polygon_stipple.sampler_view->base); 551 } 552 pipe_resource_reference(&svga->polygon_stipple.texture, NULL); 553 } 554 555 void 556 svga_init_sampler_functions( struct svga_context *svga ) 557 { 558 svga->pipe.create_sampler_state = svga_create_sampler_state; 559 svga->pipe.bind_sampler_states = svga_bind_sampler_states; 560 svga->pipe.delete_sampler_state = svga_delete_sampler_state; 561 svga->pipe.set_sampler_views = svga_set_sampler_views; 562 svga->pipe.create_sampler_view = svga_create_sampler_view; 563 svga->pipe.sampler_view_destroy = svga_sampler_view_destroy; 564 } 565