1/* 2 * Copyright © 2014-2017 Broadcom 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "util/u_pack_color.h" 25#include "util/u_upload_mgr.h" 26#include "util/format_srgb.h" 27 28#include "v3d_context.h" 29#include "compiler/v3d_compiler.h" 30 31/* We don't expect that the packets we use in this file change across across 32 * hw versions, so we just include directly the v33 header 33 */ 34#include "broadcom/cle/v3d_packet_v33_pack.h" 35 36static uint32_t 37get_texrect_scale(struct v3d_texture_stateobj *texstate, 38 enum quniform_contents contents, 39 uint32_t data) 40{ 41 struct pipe_sampler_view *texture = texstate->textures[data]; 42 uint32_t dim; 43 44 if (contents == QUNIFORM_TEXRECT_SCALE_X) 45 dim = texture->texture->width0; 46 else 47 dim = texture->texture->height0; 48 49 return fui(1.0f / dim); 50} 51 52static uint32_t 53get_texture_size(struct v3d_texture_stateobj *texstate, 54 enum quniform_contents contents, 55 uint32_t data) 56{ 57 struct pipe_sampler_view *texture = texstate->textures[data]; 58 59 switch (contents) { 60 case QUNIFORM_TEXTURE_WIDTH: 61 return u_minify(texture->texture->width0, 62 texture->u.tex.first_level); 63 case QUNIFORM_TEXTURE_HEIGHT: 64 return u_minify(texture->texture->height0, 65 texture->u.tex.first_level); 66 case QUNIFORM_TEXTURE_DEPTH: 67 return u_minify(texture->texture->depth0, 68 texture->u.tex.first_level); 69 case QUNIFORM_TEXTURE_ARRAY_SIZE: 70 return texture->texture->array_size; 71 case QUNIFORM_TEXTURE_LEVELS: 72 return (texture->u.tex.last_level - 73 texture->u.tex.first_level) + 1; 74 default: 75 unreachable("Bad texture size field"); 76 } 77} 78 79static uint32_t 80get_image_size(struct v3d_shaderimg_stateobj *shaderimg, 81 enum quniform_contents contents, 82 uint32_t data) 83{ 84 struct v3d_image_view *image = &shaderimg->si[data]; 85 86 switch (contents) { 87 case QUNIFORM_IMAGE_WIDTH: 88 return u_minify(image->base.resource->width0, 89 image->base.u.tex.level); 90 case QUNIFORM_IMAGE_HEIGHT: 91 return u_minify(image->base.resource->height0, 92 image->base.u.tex.level); 93 case QUNIFORM_IMAGE_DEPTH: 94 return u_minify(image->base.resource->depth0, 95 image->base.u.tex.level); 96 case QUNIFORM_IMAGE_ARRAY_SIZE: 97 return image->base.resource->array_size; 98 default: 99 unreachable("Bad texture size field"); 100 } 101} 102 103/** 104 * Writes the V3D 3.x P0 (CFG_MODE=1) texture parameter. 105 * 106 * Some bits of this field are dependent on the type of sample being done by 107 * the shader, while other bits are dependent on the sampler state. We OR the 108 * two together here. 109 */ 110static void 111write_texture_p0(struct v3d_job *job, 112 struct v3d_cl_out **uniforms, 113 struct v3d_texture_stateobj *texstate, 114 uint32_t unit, 115 uint32_t shader_data) 116{ 117 struct pipe_sampler_state *psampler = texstate->samplers[unit]; 118 struct v3d_sampler_state *sampler = v3d_sampler_state(psampler); 119 120 cl_aligned_u32(uniforms, shader_data | sampler->p0); 121} 122 123/** Writes the V3D 3.x P1 (CFG_MODE=1) texture parameter. */ 124static void 125write_texture_p1(struct v3d_job *job, 126 struct v3d_cl_out **uniforms, 127 struct v3d_texture_stateobj *texstate, 128 uint32_t data) 129{ 130 /* Extract the texture unit from the top bits, and the compiler's 131 * packed p1 from the bottom. 132 */ 133 uint32_t unit = data >> 5; 134 uint32_t p1 = data & 0x1f; 135 136 struct pipe_sampler_view *psview = texstate->textures[unit]; 137 struct v3d_sampler_view *sview = v3d_sampler_view(psview); 138 139 struct V3D33_TEXTURE_UNIFORM_PARAMETER_1_CFG_MODE1 unpacked = { 140 .texture_state_record_base_address = texstate->texture_state[unit], 141 }; 142 143 uint32_t packed; 144 V3D33_TEXTURE_UNIFORM_PARAMETER_1_CFG_MODE1_pack(&job->indirect, 145 (uint8_t *)&packed, 146 &unpacked); 147 148 cl_aligned_u32(uniforms, p1 | packed | sview->p1); 149} 150 151/** Writes the V3D 4.x TMU configuration parameter 0. */ 152static void 153write_tmu_p0(struct v3d_job *job, 154 struct v3d_cl_out **uniforms, 155 struct v3d_texture_stateobj *texstate, 156 uint32_t data) 157{ 158 int unit = v3d_unit_data_get_unit(data); 159 struct pipe_sampler_view *psview = texstate->textures[unit]; 160 struct v3d_sampler_view *sview = v3d_sampler_view(psview); 161 struct v3d_resource *rsc = v3d_resource(sview->texture); 162 163 cl_aligned_reloc(&job->indirect, uniforms, sview->bo, 164 v3d_unit_data_get_offset(data)); 165 v3d_job_add_bo(job, rsc->bo); 166} 167 168static void 169write_image_tmu_p0(struct v3d_job *job, 170 struct v3d_cl_out **uniforms, 171 struct v3d_shaderimg_stateobj *img, 172 uint32_t data) 173{ 174 /* Extract the image unit from the top bits, and the compiler's 175 * packed p0 from the bottom. 176 */ 177 uint32_t unit = data >> 24; 178 uint32_t p0 = data & 0x00ffffff; 179 180 struct v3d_image_view *iview = &img->si[unit]; 181 struct v3d_resource *rsc = v3d_resource(iview->base.resource); 182 183 cl_aligned_reloc(&job->indirect, uniforms, 184 v3d_resource(iview->tex_state)->bo, 185 iview->tex_state_offset | p0); 186 v3d_job_add_bo(job, rsc->bo); 187} 188 189/** Writes the V3D 4.x TMU configuration parameter 1. */ 190static void 191write_tmu_p1(struct v3d_job *job, 192 struct v3d_cl_out **uniforms, 193 struct v3d_texture_stateobj *texstate, 194 uint32_t data) 195{ 196 uint32_t unit = v3d_unit_data_get_unit(data); 197 struct pipe_sampler_state *psampler = texstate->samplers[unit]; 198 struct v3d_sampler_state *sampler = v3d_sampler_state(psampler); 199 struct pipe_sampler_view *psview = texstate->textures[unit]; 200 struct v3d_sampler_view *sview = v3d_sampler_view(psview); 201 int variant = 0; 202 203 if (sampler->border_color_variants) 204 variant = sview->sampler_variant; 205 206 cl_aligned_reloc(&job->indirect, uniforms, 207 v3d_resource(sampler->sampler_state)->bo, 208 sampler->sampler_state_offset[variant] | 209 v3d_unit_data_get_offset(data)); 210} 211 212struct v3d_cl_reloc 213v3d_write_uniforms(struct v3d_context *v3d, struct v3d_job *job, 214 struct v3d_compiled_shader *shader, 215 enum pipe_shader_type stage) 216{ 217 struct v3d_constbuf_stateobj *cb = &v3d->constbuf[stage]; 218 struct v3d_texture_stateobj *texstate = &v3d->tex[stage]; 219 struct v3d_uniform_list *uinfo = &shader->prog_data.base->uniforms; 220 const uint32_t *gallium_uniforms = cb->cb[0].user_buffer; 221 222 /* The hardware always pre-fetches the next uniform (also when there 223 * aren't any), so we always allocate space for an extra slot. This 224 * fixes MMU exceptions reported since Linux kernel 5.4 when the 225 * uniforms fill up the tail bytes of a page in the indirect 226 * BO. In that scenario, when the hardware pre-fetches after reading 227 * the last uniform it will read beyond the end of the page and trigger 228 * the MMU exception. 229 */ 230 v3d_cl_ensure_space(&job->indirect, (uinfo->count + 1) * 4, 4); 231 232 struct v3d_cl_reloc uniform_stream = cl_get_address(&job->indirect); 233 v3d_bo_reference(uniform_stream.bo); 234 235 struct v3d_cl_out *uniforms = 236 cl_start(&job->indirect); 237 238 for (int i = 0; i < uinfo->count; i++) { 239 uint32_t data = uinfo->data[i]; 240 241 switch (uinfo->contents[i]) { 242 case QUNIFORM_CONSTANT: 243 cl_aligned_u32(&uniforms, data); 244 break; 245 case QUNIFORM_UNIFORM: 246 cl_aligned_u32(&uniforms, gallium_uniforms[data]); 247 break; 248 case QUNIFORM_VIEWPORT_X_SCALE: 249 cl_aligned_f(&uniforms, v3d->viewport.scale[0] * 256.0f); 250 break; 251 case QUNIFORM_VIEWPORT_Y_SCALE: 252 cl_aligned_f(&uniforms, v3d->viewport.scale[1] * 256.0f); 253 break; 254 255 case QUNIFORM_VIEWPORT_Z_OFFSET: 256 cl_aligned_f(&uniforms, v3d->viewport.translate[2]); 257 break; 258 case QUNIFORM_VIEWPORT_Z_SCALE: 259 cl_aligned_f(&uniforms, v3d->viewport.scale[2]); 260 break; 261 262 case QUNIFORM_USER_CLIP_PLANE: 263 cl_aligned_f(&uniforms, 264 v3d->clip.ucp[data / 4][data % 4]); 265 break; 266 267 case QUNIFORM_TMU_CONFIG_P0: 268 write_tmu_p0(job, &uniforms, texstate, data); 269 break; 270 271 case QUNIFORM_TMU_CONFIG_P1: 272 write_tmu_p1(job, &uniforms, texstate, data); 273 break; 274 275 case QUNIFORM_IMAGE_TMU_CONFIG_P0: 276 write_image_tmu_p0(job, &uniforms, 277 &v3d->shaderimg[stage], data); 278 break; 279 280 case QUNIFORM_TEXTURE_CONFIG_P1: 281 write_texture_p1(job, &uniforms, texstate, 282 data); 283 break; 284 285 case QUNIFORM_TEXRECT_SCALE_X: 286 case QUNIFORM_TEXRECT_SCALE_Y: 287 cl_aligned_u32(&uniforms, 288 get_texrect_scale(texstate, 289 uinfo->contents[i], 290 data)); 291 break; 292 293 case QUNIFORM_TEXTURE_WIDTH: 294 case QUNIFORM_TEXTURE_HEIGHT: 295 case QUNIFORM_TEXTURE_DEPTH: 296 case QUNIFORM_TEXTURE_ARRAY_SIZE: 297 case QUNIFORM_TEXTURE_LEVELS: 298 cl_aligned_u32(&uniforms, 299 get_texture_size(texstate, 300 uinfo->contents[i], 301 data)); 302 break; 303 304 case QUNIFORM_IMAGE_WIDTH: 305 case QUNIFORM_IMAGE_HEIGHT: 306 case QUNIFORM_IMAGE_DEPTH: 307 case QUNIFORM_IMAGE_ARRAY_SIZE: 308 cl_aligned_u32(&uniforms, 309 get_image_size(&v3d->shaderimg[stage], 310 uinfo->contents[i], 311 data)); 312 break; 313 314 case QUNIFORM_LINE_WIDTH: 315 cl_aligned_f(&uniforms, 316 v3d->rasterizer->base.line_width); 317 break; 318 319 case QUNIFORM_AA_LINE_WIDTH: 320 cl_aligned_f(&uniforms, v3d_get_real_line_width(v3d)); 321 break; 322 323 case QUNIFORM_UBO_ADDR: { 324 uint32_t unit = v3d_unit_data_get_unit(data); 325 /* Constant buffer 0 may be a system memory pointer, 326 * in which case we want to upload a shadow copy to 327 * the GPU. 328 */ 329 if (!cb->cb[unit].buffer) { 330 u_upload_data(v3d->uploader, 0, 331 cb->cb[unit].buffer_size, 16, 332 cb->cb[unit].user_buffer, 333 &cb->cb[unit].buffer_offset, 334 &cb->cb[unit].buffer); 335 } 336 337 cl_aligned_reloc(&job->indirect, &uniforms, 338 v3d_resource(cb->cb[unit].buffer)->bo, 339 cb->cb[unit].buffer_offset + 340 v3d_unit_data_get_offset(data)); 341 break; 342 } 343 344 case QUNIFORM_SSBO_OFFSET: { 345 struct pipe_shader_buffer *sb = 346 &v3d->ssbo[stage].sb[data]; 347 348 cl_aligned_reloc(&job->indirect, &uniforms, 349 v3d_resource(sb->buffer)->bo, 350 sb->buffer_offset); 351 break; 352 } 353 354 case QUNIFORM_GET_SSBO_SIZE: 355 cl_aligned_u32(&uniforms, 356 v3d->ssbo[stage].sb[data].buffer_size); 357 break; 358 359 case QUNIFORM_TEXTURE_FIRST_LEVEL: 360 cl_aligned_f(&uniforms, 361 texstate->textures[data]->u.tex.first_level); 362 break; 363 364 case QUNIFORM_SPILL_OFFSET: 365 cl_aligned_reloc(&job->indirect, &uniforms, 366 v3d->prog.spill_bo, 0); 367 break; 368 369 case QUNIFORM_SPILL_SIZE_PER_THREAD: 370 cl_aligned_u32(&uniforms, 371 v3d->prog.spill_size_per_thread); 372 break; 373 374 case QUNIFORM_NUM_WORK_GROUPS: 375 cl_aligned_u32(&uniforms, 376 v3d->compute_num_workgroups[data]); 377 break; 378 379 case QUNIFORM_SHARED_OFFSET: 380 cl_aligned_reloc(&job->indirect, &uniforms, 381 v3d->compute_shared_memory, 0); 382 break; 383 384 case QUNIFORM_FB_LAYERS: 385 cl_aligned_u32(&uniforms, job->num_layers); 386 break; 387 388 default: 389 assert(quniform_contents_is_texture_p0(uinfo->contents[i])); 390 391 write_texture_p0(job, &uniforms, texstate, 392 uinfo->contents[i] - 393 QUNIFORM_TEXTURE_CONFIG_P0_0, 394 data); 395 break; 396 397 } 398#if 0 399 uint32_t written_val = *((uint32_t *)uniforms - 1); 400 fprintf(stderr, "shader %p[%d]: 0x%08x / 0x%08x (%f) ", 401 shader, i, __gen_address_offset(&uniform_stream) + i * 4, 402 written_val, uif(written_val)); 403 vir_dump_uniform(uinfo->contents[i], data); 404 fprintf(stderr, "\n"); 405#endif 406 } 407 408 cl_end(&job->indirect, uniforms); 409 410 return uniform_stream; 411} 412 413void 414v3d_set_shader_uniform_dirty_flags(struct v3d_compiled_shader *shader) 415{ 416 uint32_t dirty = 0; 417 418 for (int i = 0; i < shader->prog_data.base->uniforms.count; i++) { 419 switch (shader->prog_data.base->uniforms.contents[i]) { 420 case QUNIFORM_CONSTANT: 421 break; 422 case QUNIFORM_UNIFORM: 423 case QUNIFORM_UBO_ADDR: 424 dirty |= V3D_DIRTY_CONSTBUF; 425 break; 426 427 case QUNIFORM_VIEWPORT_X_SCALE: 428 case QUNIFORM_VIEWPORT_Y_SCALE: 429 case QUNIFORM_VIEWPORT_Z_OFFSET: 430 case QUNIFORM_VIEWPORT_Z_SCALE: 431 dirty |= V3D_DIRTY_VIEWPORT; 432 break; 433 434 case QUNIFORM_USER_CLIP_PLANE: 435 dirty |= V3D_DIRTY_CLIP; 436 break; 437 438 case QUNIFORM_TMU_CONFIG_P0: 439 case QUNIFORM_TMU_CONFIG_P1: 440 case QUNIFORM_TEXTURE_CONFIG_P1: 441 case QUNIFORM_TEXTURE_FIRST_LEVEL: 442 case QUNIFORM_TEXRECT_SCALE_X: 443 case QUNIFORM_TEXRECT_SCALE_Y: 444 case QUNIFORM_TEXTURE_WIDTH: 445 case QUNIFORM_TEXTURE_HEIGHT: 446 case QUNIFORM_TEXTURE_DEPTH: 447 case QUNIFORM_TEXTURE_ARRAY_SIZE: 448 case QUNIFORM_TEXTURE_LEVELS: 449 case QUNIFORM_SPILL_OFFSET: 450 case QUNIFORM_SPILL_SIZE_PER_THREAD: 451 /* We could flag this on just the stage we're 452 * compiling for, but it's not passed in. 453 */ 454 dirty |= V3D_DIRTY_FRAGTEX | V3D_DIRTY_VERTTEX | 455 V3D_DIRTY_GEOMTEX | V3D_DIRTY_COMPTEX; 456 break; 457 458 case QUNIFORM_SSBO_OFFSET: 459 case QUNIFORM_GET_SSBO_SIZE: 460 dirty |= V3D_DIRTY_SSBO; 461 break; 462 463 case QUNIFORM_IMAGE_TMU_CONFIG_P0: 464 case QUNIFORM_IMAGE_WIDTH: 465 case QUNIFORM_IMAGE_HEIGHT: 466 case QUNIFORM_IMAGE_DEPTH: 467 case QUNIFORM_IMAGE_ARRAY_SIZE: 468 dirty |= V3D_DIRTY_SHADER_IMAGE; 469 break; 470 471 case QUNIFORM_LINE_WIDTH: 472 case QUNIFORM_AA_LINE_WIDTH: 473 dirty |= V3D_DIRTY_RASTERIZER; 474 break; 475 476 case QUNIFORM_NUM_WORK_GROUPS: 477 case QUNIFORM_SHARED_OFFSET: 478 /* Compute always recalculates uniforms. */ 479 break; 480 481 case QUNIFORM_FB_LAYERS: 482 dirty |= V3D_DIRTY_FRAMEBUFFER; 483 break; 484 485 default: 486 assert(quniform_contents_is_texture_p0(shader->prog_data.base->uniforms.contents[i])); 487 dirty |= V3D_DIRTY_FRAGTEX | V3D_DIRTY_VERTTEX | 488 V3D_DIRTY_GEOMTEX | V3D_DIRTY_COMPTEX; 489 break; 490 } 491 } 492 493 shader->uniform_dirty_bits = dirty; 494} 495