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 48 49 /** Get resource handle for a texture or buffer */ 50 static inline struct svga_winsys_surface * 51 svga_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 */ 66 boolean 67 svga_check_sampler_view_resource_collision(struct svga_context *svga, 68 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 */ 95 boolean 96 svga_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 */ 125 enum pipe_error 126 svga_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 texture->format == PIPE_FORMAT_B8G8R8A8_UNORM) { 145 viewFormat = PIPE_FORMAT_B8G8R8A8_UNORM; 146 } 147 else if (viewFormat == PIPE_FORMAT_B8G8R8A8_UNORM && 148 texture->format == PIPE_FORMAT_B8G8R8X8_UNORM) { 149 viewFormat = PIPE_FORMAT_B8G8R8X8_UNORM; 150 } 151 152 format = svga_translate_format(ss, viewFormat, 153 PIPE_BIND_SAMPLER_VIEW); 154 assert(format != SVGA3D_FORMAT_INVALID); 155 156 /* Convert the format to a sampler-friendly format, if needed */ 157 format = svga_sampler_format(format); 158 159 if (texture->target == PIPE_BUFFER) { 160 unsigned elem_size = util_format_get_blocksize(sv->base.format); 161 162 viewDesc.buffer.firstElement = sv->base.u.buf.offset / elem_size; 163 viewDesc.buffer.numElements = sv->base.u.buf.size / elem_size; 164 } 165 else { 166 viewDesc.tex.mostDetailedMip = sv->base.u.tex.first_level; 167 viewDesc.tex.firstArraySlice = sv->base.u.tex.first_layer; 168 viewDesc.tex.mipLevels = (sv->base.u.tex.last_level - 169 sv->base.u.tex.first_level + 1); 170 } 171 172 /* arraySize in viewDesc specifies the number of array slices in a 173 * texture array. For 3D texture, last_layer in 174 * pipe_sampler_view specifies the last slice of the texture 175 * which is different from the last slice in a texture array, 176 * hence we need to set arraySize to 1 explicitly. 177 */ 178 viewDesc.tex.arraySize = 179 (texture->target == PIPE_TEXTURE_3D || 180 texture->target == PIPE_BUFFER) ? 1 : 181 (sv->base.u.tex.last_layer - sv->base.u.tex.first_layer + 1); 182 183 switch (texture->target) { 184 case PIPE_BUFFER: 185 resourceDim = SVGA3D_RESOURCE_BUFFER; 186 break; 187 case PIPE_TEXTURE_1D: 188 case PIPE_TEXTURE_1D_ARRAY: 189 resourceDim = SVGA3D_RESOURCE_TEXTURE1D; 190 break; 191 case PIPE_TEXTURE_RECT: 192 case PIPE_TEXTURE_2D: 193 case PIPE_TEXTURE_2D_ARRAY: 194 resourceDim = SVGA3D_RESOURCE_TEXTURE2D; 195 break; 196 case PIPE_TEXTURE_3D: 197 resourceDim = SVGA3D_RESOURCE_TEXTURE3D; 198 break; 199 case PIPE_TEXTURE_CUBE: 200 case PIPE_TEXTURE_CUBE_ARRAY: 201 resourceDim = SVGA3D_RESOURCE_TEXTURECUBE; 202 break; 203 204 default: 205 assert(!"Unexpected texture type"); 206 resourceDim = SVGA3D_RESOURCE_TEXTURE2D; 207 } 208 209 sv->id = util_bitmask_add(svga->sampler_view_id_bm); 210 211 ret = SVGA3D_vgpu10_DefineShaderResourceView(svga->swc, 212 sv->id, 213 surface, 214 format, 215 resourceDim, 216 &viewDesc); 217 if (ret != PIPE_OK) { 218 util_bitmask_clear(svga->sampler_view_id_bm, sv->id); 219 sv->id = SVGA3D_INVALID_ID; 220 } 221 } 222 223 return ret; 224 } 225 226 227 static enum pipe_error 228 update_sampler_resources(struct svga_context *svga, unsigned dirty) 229 { 230 enum pipe_error ret = PIPE_OK; 231 enum pipe_shader_type shader; 232 233 if (!svga_have_vgpu10(svga)) 234 return PIPE_OK; 235 236 for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) { 237 SVGA3dShaderResourceViewId ids[PIPE_MAX_SAMPLERS]; 238 struct svga_winsys_surface *surfaces[PIPE_MAX_SAMPLERS]; 239 struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; 240 unsigned count; 241 unsigned nviews; 242 unsigned i; 243 244 count = svga->curr.num_sampler_views[shader]; 245 for (i = 0; i < count; i++) { 246 struct svga_pipe_sampler_view *sv = 247 svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]); 248 249 if (sv) { 250 surfaces[i] = svga_resource_handle(sv->base.texture); 251 252 ret = svga_validate_pipe_sampler_view(svga, sv); 253 if (ret != PIPE_OK) 254 return ret; 255 256 assert(sv->id != SVGA3D_INVALID_ID); 257 ids[i] = sv->id; 258 sampler_views[i] = &sv->base; 259 } 260 else { 261 surfaces[i] = NULL; 262 ids[i] = SVGA3D_INVALID_ID; 263 sampler_views[i] = NULL; 264 } 265 } 266 267 for (; i < svga->state.hw_draw.num_sampler_views[shader]; i++) { 268 ids[i] = SVGA3D_INVALID_ID; 269 surfaces[i] = NULL; 270 sampler_views[i] = NULL; 271 } 272 273 /* Number of ShaderResources that need to be modified. This includes 274 * the one that need to be unbound. 275 */ 276 nviews = MAX2(svga->state.hw_draw.num_sampler_views[shader], count); 277 if (nviews > 0) { 278 if (count != svga->state.hw_draw.num_sampler_views[shader] || 279 memcmp(sampler_views, svga->state.hw_draw.sampler_views[shader], 280 count * sizeof(sampler_views[0])) != 0) { 281 ret = SVGA3D_vgpu10_SetShaderResources(svga->swc, 282 svga_shader_type(shader), 283 0, /* startView */ 284 nviews, 285 ids, 286 surfaces); 287 if (ret != PIPE_OK) 288 return ret; 289 290 /* Save referenced sampler views in the hw draw state. */ 291 svga->state.hw_draw.num_sampler_views[shader] = count; 292 for (i = 0; i < nviews; i++) { 293 pipe_sampler_view_reference( 294 &svga->state.hw_draw.sampler_views[shader][i], 295 sampler_views[i]); 296 } 297 } 298 } 299 } 300 301 /* Handle polygon stipple sampler view */ 302 if (svga->curr.rast->templ.poly_stipple_enable) { 303 const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit; 304 struct svga_pipe_sampler_view *sv = svga->polygon_stipple.sampler_view; 305 struct svga_winsys_surface *surface; 306 307 assert(sv); 308 if (!sv) { 309 return PIPE_OK; /* probably out of memory */ 310 } 311 312 ret = svga_validate_pipe_sampler_view(svga, sv); 313 if (ret != PIPE_OK) 314 return ret; 315 316 surface = svga_resource_handle(sv->base.texture); 317 ret = SVGA3D_vgpu10_SetShaderResources( 318 svga->swc, 319 svga_shader_type(PIPE_SHADER_FRAGMENT), 320 unit, /* startView */ 321 1, 322 &sv->id, 323 &surface); 324 } 325 return ret; 326 } 327 328 329 struct svga_tracked_state svga_hw_sampler_bindings = { 330 "shader resources emit", 331 SVGA_NEW_STIPPLE | 332 SVGA_NEW_TEXTURE_BINDING, 333 update_sampler_resources 334 }; 335 336 337 338 static enum pipe_error 339 update_samplers(struct svga_context *svga, unsigned dirty ) 340 { 341 enum pipe_error ret = PIPE_OK; 342 enum pipe_shader_type shader; 343 344 if (!svga_have_vgpu10(svga)) 345 return PIPE_OK; 346 347 for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) { 348 const unsigned count = svga->curr.num_samplers[shader]; 349 SVGA3dSamplerId ids[PIPE_MAX_SAMPLERS]; 350 unsigned i; 351 unsigned nsamplers; 352 353 for (i = 0; i < count; i++) { 354 if (svga->curr.sampler[shader][i]) { 355 ids[i] = svga->curr.sampler[shader][i]->id; 356 assert(ids[i] != SVGA3D_INVALID_ID); 357 } 358 else { 359 ids[i] = SVGA3D_INVALID_ID; 360 } 361 } 362 363 for (; i < svga->state.hw_draw.num_samplers[shader]; i++) { 364 ids[i] = SVGA3D_INVALID_ID; 365 } 366 367 nsamplers = MAX2(svga->state.hw_draw.num_samplers[shader], count); 368 if (nsamplers > 0) { 369 if (count != svga->state.hw_draw.num_samplers[shader] || 370 memcmp(ids, svga->state.hw_draw.samplers[shader], 371 count * sizeof(ids[0])) != 0) { 372 /* HW state is really changing */ 373 ret = SVGA3D_vgpu10_SetSamplers(svga->swc, 374 nsamplers, 375 0, /* start */ 376 svga_shader_type(shader), /* type */ 377 ids); 378 if (ret != PIPE_OK) 379 return ret; 380 memcpy(svga->state.hw_draw.samplers[shader], ids, 381 nsamplers * sizeof(ids[0])); 382 svga->state.hw_draw.num_samplers[shader] = count; 383 } 384 } 385 } 386 387 /* Handle polygon stipple sampler texture */ 388 if (svga->curr.rast->templ.poly_stipple_enable) { 389 const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit; 390 struct svga_sampler_state *sampler = svga->polygon_stipple.sampler; 391 392 assert(sampler); 393 if (!sampler) { 394 return PIPE_OK; /* probably out of memory */ 395 } 396 397 if (svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit] 398 != sampler->id) { 399 ret = SVGA3D_vgpu10_SetSamplers(svga->swc, 400 1, /* count */ 401 unit, /* start */ 402 SVGA3D_SHADERTYPE_PS, 403 &sampler->id); 404 if (ret != PIPE_OK) 405 return ret; 406 407 /* save the polygon stipple sampler in the hw draw state */ 408 svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit] = 409 sampler->id; 410 } 411 } 412 413 return ret; 414 } 415 416 417 struct svga_tracked_state svga_hw_sampler = { 418 "texture sampler emit", 419 (SVGA_NEW_SAMPLER | 420 SVGA_NEW_STIPPLE | 421 SVGA_NEW_TEXTURE_FLAGS), 422 update_samplers 423 }; 424