1/* 2 * Copyright 2013 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/** 27 * VGPU10 sampler and sampler view functions. 28 */ 29 30 31#include "pipe/p_defines.h" 32#include "util/u_bitmask.h" 33#include "util/u_format.h" 34#include "util/u_inlines.h" 35#include "util/u_math.h" 36#include "util/u_memory.h" 37 38#include "svga_cmd.h" 39#include "svga_context.h" 40#include "svga_format.h" 41#include "svga_resource_buffer.h" 42#include "svga_resource_texture.h" 43#include "svga_sampler_view.h" 44#include "svga_shader.h" 45#include "svga_state.h" 46#include "svga_surface.h" 47#include "svga3d_surfacedefs.h" 48 49/** Get resource handle for a texture or buffer */ 50static inline struct svga_winsys_surface * 51svga_resource_handle(struct pipe_resource *res) 52{ 53 if (res->target == PIPE_BUFFER) { 54 return svga_buffer(res)->handle; 55 } 56 else { 57 return svga_texture(res)->handle; 58 } 59} 60 61 62/** 63 * This helper function returns TRUE if the specified resource collides with 64 * any of the resources bound to any of the currently bound sampler views. 65 */ 66boolean 67svga_check_sampler_view_resource_collision(const struct svga_context *svga, 68 const struct svga_winsys_surface *res, 69 enum pipe_shader_type shader) 70{ 71 struct pipe_screen *screen = svga->pipe.screen; 72 unsigned i; 73 74 if (svga_screen(screen)->debug.no_surface_view) { 75 return FALSE; 76 } 77 78 for (i = 0; i < svga->curr.num_sampler_views[shader]; i++) { 79 struct svga_pipe_sampler_view *sv = 80 svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]); 81 82 if (sv && res == svga_resource_handle(sv->base.texture)) { 83 return TRUE; 84 } 85 } 86 87 return FALSE; 88} 89 90 91/** 92 * Check if there are any resources that are both bound to a render target 93 * and bound as a shader resource for the given type of shader. 94 */ 95boolean 96svga_check_sampler_framebuffer_resource_collision(struct svga_context *svga, 97 enum pipe_shader_type shader) 98{ 99 struct svga_surface *surf; 100 unsigned i; 101 102 for (i = 0; i < svga->curr.framebuffer.nr_cbufs; i++) { 103 surf = svga_surface(svga->curr.framebuffer.cbufs[i]); 104 if (surf && 105 svga_check_sampler_view_resource_collision(svga, surf->handle, 106 shader)) { 107 return TRUE; 108 } 109 } 110 111 surf = svga_surface(svga->curr.framebuffer.zsbuf); 112 if (surf && 113 svga_check_sampler_view_resource_collision(svga, surf->handle, shader)) { 114 return TRUE; 115 } 116 117 return FALSE; 118} 119 120 121/** 122 * Create a DX ShaderResourceSamplerView for the given pipe_sampler_view, 123 * if needed. 124 */ 125enum pipe_error 126svga_validate_pipe_sampler_view(struct svga_context *svga, 127 struct svga_pipe_sampler_view *sv) 128{ 129 enum pipe_error ret = PIPE_OK; 130 131 if (sv->id == SVGA3D_INVALID_ID) { 132 struct svga_screen *ss = svga_screen(svga->pipe.screen); 133 struct pipe_resource *texture = sv->base.texture; 134 struct svga_winsys_surface *surface = svga_resource_handle(texture); 135 SVGA3dSurfaceFormat format; 136 SVGA3dResourceType resourceDim; 137 SVGA3dShaderResourceViewDesc viewDesc; 138 enum pipe_format viewFormat = sv->base.format; 139 140 /* vgpu10 cannot create a BGRX view for a BGRA resource, so force it to 141 * create a BGRA view (and vice versa). 142 */ 143 if (viewFormat == PIPE_FORMAT_B8G8R8X8_UNORM && 144 svga_texture_device_format_has_alpha(texture)) { 145 viewFormat = PIPE_FORMAT_B8G8R8A8_UNORM; 146 } 147 else if (viewFormat == PIPE_FORMAT_B8G8R8A8_UNORM && 148 !svga_texture_device_format_has_alpha(texture)) { 149 viewFormat = PIPE_FORMAT_B8G8R8X8_UNORM; 150 } 151 152 if (texture->target == PIPE_BUFFER) { 153 unsigned pf_flags; 154 svga_translate_texture_buffer_view_format(viewFormat, 155 &format, 156 &pf_flags); 157 } 158 else { 159 format = svga_translate_format(ss, viewFormat, 160 PIPE_BIND_SAMPLER_VIEW); 161 162 /* Convert the format to a sampler-friendly format, if needed */ 163 format = svga_sampler_format(format); 164 } 165 166 assert(format != SVGA3D_FORMAT_INVALID); 167 168 if (texture->target == PIPE_BUFFER) { 169 unsigned elem_size = util_format_get_blocksize(sv->base.format); 170 171 viewDesc.buffer.firstElement = sv->base.u.buf.offset / elem_size; 172 viewDesc.buffer.numElements = sv->base.u.buf.size / elem_size; 173 } 174 else { 175 viewDesc.tex.mostDetailedMip = sv->base.u.tex.first_level; 176 viewDesc.tex.firstArraySlice = sv->base.u.tex.first_layer; 177 viewDesc.tex.mipLevels = (sv->base.u.tex.last_level - 178 sv->base.u.tex.first_level + 1); 179 } 180 181 /* arraySize in viewDesc specifies the number of array slices in a 182 * texture array. For 3D texture, last_layer in 183 * pipe_sampler_view specifies the last slice of the texture 184 * which is different from the last slice in a texture array, 185 * hence we need to set arraySize to 1 explicitly. 186 */ 187 viewDesc.tex.arraySize = 188 (texture->target == PIPE_TEXTURE_3D || 189 texture->target == PIPE_BUFFER) ? 1 : 190 (sv->base.u.tex.last_layer - sv->base.u.tex.first_layer + 1); 191 192 switch (texture->target) { 193 case PIPE_BUFFER: 194 resourceDim = SVGA3D_RESOURCE_BUFFER; 195 break; 196 case PIPE_TEXTURE_1D: 197 case PIPE_TEXTURE_1D_ARRAY: 198 resourceDim = SVGA3D_RESOURCE_TEXTURE1D; 199 break; 200 case PIPE_TEXTURE_RECT: 201 case PIPE_TEXTURE_2D: 202 case PIPE_TEXTURE_2D_ARRAY: 203 resourceDim = SVGA3D_RESOURCE_TEXTURE2D; 204 break; 205 case PIPE_TEXTURE_3D: 206 resourceDim = SVGA3D_RESOURCE_TEXTURE3D; 207 break; 208 case PIPE_TEXTURE_CUBE: 209 case PIPE_TEXTURE_CUBE_ARRAY: 210 resourceDim = SVGA3D_RESOURCE_TEXTURECUBE; 211 break; 212 213 default: 214 assert(!"Unexpected texture type"); 215 resourceDim = SVGA3D_RESOURCE_TEXTURE2D; 216 } 217 218 sv->id = util_bitmask_add(svga->sampler_view_id_bm); 219 220 ret = SVGA3D_vgpu10_DefineShaderResourceView(svga->swc, 221 sv->id, 222 surface, 223 format, 224 resourceDim, 225 &viewDesc); 226 if (ret != PIPE_OK) { 227 util_bitmask_clear(svga->sampler_view_id_bm, sv->id); 228 sv->id = SVGA3D_INVALID_ID; 229 } 230 } 231 232 return ret; 233} 234 235 236static enum pipe_error 237update_sampler_resources(struct svga_context *svga, unsigned dirty) 238{ 239 enum pipe_error ret = PIPE_OK; 240 enum pipe_shader_type shader; 241 242 if (!svga_have_vgpu10(svga)) 243 return PIPE_OK; 244 245 for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) { 246 SVGA3dShaderResourceViewId ids[PIPE_MAX_SAMPLERS]; 247 struct svga_winsys_surface *surfaces[PIPE_MAX_SAMPLERS]; 248 struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; 249 unsigned count; 250 unsigned nviews; 251 unsigned i; 252 253 count = svga->curr.num_sampler_views[shader]; 254 for (i = 0; i < count; i++) { 255 struct svga_pipe_sampler_view *sv = 256 svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]); 257 258 if (sv) { 259 surfaces[i] = svga_resource_handle(sv->base.texture); 260 261 ret = svga_validate_pipe_sampler_view(svga, sv); 262 if (ret != PIPE_OK) 263 return ret; 264 265 assert(sv->id != SVGA3D_INVALID_ID); 266 ids[i] = sv->id; 267 sampler_views[i] = &sv->base; 268 } 269 else { 270 surfaces[i] = NULL; 271 ids[i] = SVGA3D_INVALID_ID; 272 sampler_views[i] = NULL; 273 } 274 } 275 276 for (; i < svga->state.hw_draw.num_sampler_views[shader]; i++) { 277 ids[i] = SVGA3D_INVALID_ID; 278 surfaces[i] = NULL; 279 sampler_views[i] = NULL; 280 } 281 282 /* Number of ShaderResources that need to be modified. This includes 283 * the one that need to be unbound. 284 */ 285 nviews = MAX2(svga->state.hw_draw.num_sampler_views[shader], count); 286 if (nviews > 0) { 287 if (count != svga->state.hw_draw.num_sampler_views[shader] || 288 memcmp(sampler_views, svga->state.hw_draw.sampler_views[shader], 289 count * sizeof(sampler_views[0])) != 0) { 290 SVGA3dShaderResourceViewId *pIds = ids; 291 struct svga_winsys_surface **pSurf = surfaces; 292 unsigned numSR = 0; 293 294 /* Loop through the sampler view list to only emit 295 * the sampler views that are not already in the 296 * corresponding entries in the device's 297 * shader resource list. 298 */ 299 for (i = 0; i < nviews; i++) { 300 boolean emit; 301 302 emit = sampler_views[i] == 303 svga->state.hw_draw.sampler_views[shader][i]; 304 305 if (!emit && i == nviews-1) { 306 /* Include the last sampler view in the next emit 307 * if it is different. 308 */ 309 emit = TRUE; 310 numSR++; 311 i++; 312 } 313 314 if (emit) { 315 /* numSR can only be 0 if the first entry of the list 316 * is the same as the one in the device list. 317 * In this case, * there is nothing to send yet. 318 */ 319 if (numSR) { 320 ret = SVGA3D_vgpu10_SetShaderResources( 321 svga->swc, 322 svga_shader_type(shader), 323 i - numSR, /* startView */ 324 numSR, 325 pIds, 326 pSurf); 327 328 if (ret != PIPE_OK) 329 return ret; 330 } 331 pIds += (numSR + 1); 332 pSurf += (numSR + 1); 333 numSR = 0; 334 } 335 else 336 numSR++; 337 } 338 339 /* Save referenced sampler views in the hw draw state. */ 340 svga->state.hw_draw.num_sampler_views[shader] = count; 341 for (i = 0; i < nviews; i++) { 342 pipe_sampler_view_reference( 343 &svga->state.hw_draw.sampler_views[shader][i], 344 sampler_views[i]); 345 } 346 } 347 } 348 } 349 350 /* Handle polygon stipple sampler view */ 351 if (svga->curr.rast->templ.poly_stipple_enable) { 352 const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit; 353 struct svga_pipe_sampler_view *sv = svga->polygon_stipple.sampler_view; 354 struct svga_winsys_surface *surface; 355 356 assert(sv); 357 if (!sv) { 358 return PIPE_OK; /* probably out of memory */ 359 } 360 361 ret = svga_validate_pipe_sampler_view(svga, sv); 362 if (ret != PIPE_OK) 363 return ret; 364 365 surface = svga_resource_handle(sv->base.texture); 366 ret = SVGA3D_vgpu10_SetShaderResources( 367 svga->swc, 368 svga_shader_type(PIPE_SHADER_FRAGMENT), 369 unit, /* startView */ 370 1, 371 &sv->id, 372 &surface); 373 } 374 return ret; 375} 376 377 378struct svga_tracked_state svga_hw_sampler_bindings = { 379 "shader resources emit", 380 SVGA_NEW_STIPPLE | 381 SVGA_NEW_TEXTURE_BINDING, 382 update_sampler_resources 383}; 384 385 386 387static enum pipe_error 388update_samplers(struct svga_context *svga, unsigned dirty ) 389{ 390 enum pipe_error ret = PIPE_OK; 391 enum pipe_shader_type shader; 392 393 if (!svga_have_vgpu10(svga)) 394 return PIPE_OK; 395 396 for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) { 397 const unsigned count = svga->curr.num_samplers[shader]; 398 SVGA3dSamplerId ids[PIPE_MAX_SAMPLERS]; 399 unsigned i; 400 unsigned nsamplers; 401 402 for (i = 0; i < count; i++) { 403 bool fs_shadow = false; 404 405 /* _NEW_FS */ 406 if (shader == PIPE_SHADER_FRAGMENT) { 407 struct svga_shader_variant *fs = svga->state.hw_draw.fs; 408 /* If the fragment shader is doing the shadow comparison 409 * for this texture unit, don't enable shadow compare in 410 * the texture sampler state. 411 */ 412 if (fs && (fs->fs_shadow_compare_units & (1 << i))) { 413 fs_shadow = true; 414 } 415 } 416 417 if (svga->curr.sampler[shader][i]) { 418 ids[i] = svga->curr.sampler[shader][i]->id[fs_shadow]; 419 assert(ids[i] != SVGA3D_INVALID_ID); 420 } 421 else { 422 ids[i] = SVGA3D_INVALID_ID; 423 } 424 } 425 426 for (; i < svga->state.hw_draw.num_samplers[shader]; i++) { 427 ids[i] = SVGA3D_INVALID_ID; 428 } 429 430 nsamplers = MAX2(svga->state.hw_draw.num_samplers[shader], count); 431 if (nsamplers > 0) { 432 if (count != svga->state.hw_draw.num_samplers[shader] || 433 memcmp(ids, svga->state.hw_draw.samplers[shader], 434 count * sizeof(ids[0])) != 0) { 435 /* HW state is really changing */ 436 ret = SVGA3D_vgpu10_SetSamplers(svga->swc, 437 nsamplers, 438 0, /* start */ 439 svga_shader_type(shader), /* type */ 440 ids); 441 if (ret != PIPE_OK) 442 return ret; 443 memcpy(svga->state.hw_draw.samplers[shader], ids, 444 nsamplers * sizeof(ids[0])); 445 svga->state.hw_draw.num_samplers[shader] = count; 446 } 447 } 448 } 449 450 /* Handle polygon stipple sampler texture */ 451 if (svga->curr.rast->templ.poly_stipple_enable) { 452 const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit; 453 struct svga_sampler_state *sampler = svga->polygon_stipple.sampler; 454 455 assert(sampler); 456 if (!sampler) { 457 return PIPE_OK; /* probably out of memory */ 458 } 459 460 if (svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit] 461 != sampler->id[0]) { 462 ret = SVGA3D_vgpu10_SetSamplers(svga->swc, 463 1, /* count */ 464 unit, /* start */ 465 SVGA3D_SHADERTYPE_PS, 466 &sampler->id[0]); 467 if (ret != PIPE_OK) 468 return ret; 469 470 /* save the polygon stipple sampler in the hw draw state */ 471 svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit] = 472 sampler->id[0]; 473 } 474 } 475 476 return ret; 477} 478 479 480struct svga_tracked_state svga_hw_sampler = { 481 "texture sampler emit", 482 (SVGA_NEW_FS | 483 SVGA_NEW_SAMPLER | 484 SVGA_NEW_STIPPLE), 485 update_samplers 486}; 487