1/* 2 * Copyright 2008 Ben Skeggs 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 shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include "nvc0_context.h" 24#include "nvc0_resource.h" 25#include "nv50/nv50_texture.xml.h" 26 27#include "util/u_format.h" 28 29#define NVE4_TIC_ENTRY_INVALID 0x000fffff 30#define NVE4_TSC_ENTRY_INVALID 0xfff00000 31 32#define NV50_TIC_0_SWIZZLE__MASK \ 33 (NV50_TIC_0_MAPA__MASK | NV50_TIC_0_MAPB__MASK | \ 34 NV50_TIC_0_MAPG__MASK | NV50_TIC_0_MAPR__MASK) 35 36static INLINE uint32_t 37nv50_tic_swizzle(uint32_t tc, unsigned swz, boolean tex_int) 38{ 39 switch (swz) { 40 case PIPE_SWIZZLE_RED: 41 return (tc & NV50_TIC_0_MAPR__MASK) >> NV50_TIC_0_MAPR__SHIFT; 42 case PIPE_SWIZZLE_GREEN: 43 return (tc & NV50_TIC_0_MAPG__MASK) >> NV50_TIC_0_MAPG__SHIFT; 44 case PIPE_SWIZZLE_BLUE: 45 return (tc & NV50_TIC_0_MAPB__MASK) >> NV50_TIC_0_MAPB__SHIFT; 46 case PIPE_SWIZZLE_ALPHA: 47 return (tc & NV50_TIC_0_MAPA__MASK) >> NV50_TIC_0_MAPA__SHIFT; 48 case PIPE_SWIZZLE_ONE: 49 return tex_int ? NV50_TIC_MAP_ONE_INT : NV50_TIC_MAP_ONE_FLOAT; 50 case PIPE_SWIZZLE_ZERO: 51 default: 52 return NV50_TIC_MAP_ZERO; 53 } 54} 55 56struct pipe_sampler_view * 57nvc0_create_sampler_view(struct pipe_context *pipe, 58 struct pipe_resource *texture, 59 const struct pipe_sampler_view *templ) 60{ 61 const struct util_format_description *desc; 62 uint64_t address; 63 uint32_t *tic; 64 uint32_t swz[4]; 65 uint32_t depth; 66 struct nv50_tic_entry *view; 67 struct nv50_miptree *mt; 68 boolean tex_int; 69 70 view = MALLOC_STRUCT(nv50_tic_entry); 71 if (!view) 72 return NULL; 73 mt = nv50_miptree(texture); 74 75 view->pipe = *templ; 76 view->pipe.reference.count = 1; 77 view->pipe.texture = NULL; 78 view->pipe.context = pipe; 79 80 view->id = -1; 81 82 pipe_resource_reference(&view->pipe.texture, texture); 83 84 tic = &view->tic[0]; 85 86 desc = util_format_description(view->pipe.format); 87 88 tic[0] = nvc0_format_table[view->pipe.format].tic; 89 90 tex_int = util_format_is_pure_integer(view->pipe.format); 91 92 swz[0] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_r, tex_int); 93 swz[1] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_g, tex_int); 94 swz[2] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_b, tex_int); 95 swz[3] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_a, tex_int); 96 tic[0] = (tic[0] & ~NV50_TIC_0_SWIZZLE__MASK) | 97 (swz[0] << NV50_TIC_0_MAPR__SHIFT) | 98 (swz[1] << NV50_TIC_0_MAPG__SHIFT) | 99 (swz[2] << NV50_TIC_0_MAPB__SHIFT) | 100 (swz[3] << NV50_TIC_0_MAPA__SHIFT); 101 102 address = mt->base.address; 103 104 tic[2] = 0x10001000 | NV50_TIC_2_NO_BORDER; 105 106 if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) 107 tic[2] |= NV50_TIC_2_COLORSPACE_SRGB; 108 109 /* check for linear storage type */ 110 if (unlikely(!nouveau_bo_memtype(nv04_resource(texture)->bo))) { 111 if (texture->target == PIPE_BUFFER) { 112 address += 113 view->pipe.u.buf.first_element * desc->block.bits / 8; 114 tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_BUFFER; 115 tic[3] = 0; 116 tic[4] = /* width */ 117 view->pipe.u.buf.last_element - view->pipe.u.buf.first_element + 1; 118 tic[5] = 0; 119 } else { 120 /* must be 2D texture without mip maps */ 121 tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_RECT; 122 if (texture->target != PIPE_TEXTURE_RECT) 123 tic[2] |= NV50_TIC_2_NORMALIZED_COORDS; 124 tic[3] = mt->level[0].pitch; 125 tic[4] = mt->base.base.width0; 126 tic[5] = (1 << 16) | mt->base.base.height0; 127 } 128 tic[6] = 129 tic[7] = 0; 130 tic[1] = address; 131 tic[2] |= address >> 32; 132 return &view->pipe; 133 } 134 135 if (mt->base.base.target != PIPE_TEXTURE_RECT) 136 tic[2] |= NV50_TIC_2_NORMALIZED_COORDS; 137 138 tic[2] |= 139 ((mt->level[0].tile_mode & 0x0f0) << (22 - 4)) | 140 ((mt->level[0].tile_mode & 0xf00) << (25 - 8)); 141 142 depth = MAX2(mt->base.base.array_size, mt->base.base.depth0); 143 144 if (mt->base.base.array_size > 1) { 145 /* there doesn't seem to be a base layer field in TIC */ 146 address += view->pipe.u.tex.first_layer * mt->layer_stride; 147 depth = view->pipe.u.tex.last_layer - view->pipe.u.tex.first_layer + 1; 148 } 149 tic[1] = address; 150 tic[2] |= address >> 32; 151 152 switch (mt->base.base.target) { 153 case PIPE_TEXTURE_1D: 154 tic[2] |= NV50_TIC_2_TARGET_1D; 155 break; 156/* case PIPE_TEXTURE_2D_MS: */ 157 case PIPE_TEXTURE_2D: 158 tic[2] |= NV50_TIC_2_TARGET_2D; 159 break; 160 case PIPE_TEXTURE_RECT: 161 tic[2] |= NV50_TIC_2_TARGET_RECT; 162 break; 163 case PIPE_TEXTURE_3D: 164 tic[2] |= NV50_TIC_2_TARGET_3D; 165 break; 166 case PIPE_TEXTURE_CUBE: 167 depth /= 6; 168 if (depth > 1) 169 tic[2] |= NV50_TIC_2_TARGET_CUBE_ARRAY; 170 else 171 tic[2] |= NV50_TIC_2_TARGET_CUBE; 172 break; 173 case PIPE_TEXTURE_1D_ARRAY: 174 tic[2] |= NV50_TIC_2_TARGET_1D_ARRAY; 175 break; 176/* case PIPE_TEXTURE_2D_ARRAY_MS: */ 177 case PIPE_TEXTURE_2D_ARRAY: 178 tic[2] |= NV50_TIC_2_TARGET_2D_ARRAY; 179 break; 180 default: 181 NOUVEAU_ERR("invalid texture target: %d\n", mt->base.base.target); 182 return FALSE; 183 } 184 185 if (mt->base.base.target == PIPE_BUFFER) 186 tic[3] = mt->base.base.width0; 187 else 188 tic[3] = 0x00300000; 189 190 tic[4] = (1 << 31) | (mt->base.base.width0 << mt->ms_x); 191 192 tic[5] = (mt->base.base.height0 << mt->ms_y) & 0xffff; 193 tic[5] |= depth << 16; 194 tic[5] |= mt->base.base.last_level << 28; 195 196 tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; /* sampling points */ 197 198 tic[7] = (view->pipe.u.tex.last_level << 4) | view->pipe.u.tex.first_level; 199 200 /* 201 if (mt->base.base.target == PIPE_TEXTURE_2D_MS || 202 mt->base.base.target == PIPE_TEXTURE_2D_ARRAY_MS) 203 tic[7] |= mt->ms_mode << 12; 204 */ 205 206 return &view->pipe; 207} 208 209static boolean 210nvc0_validate_tic(struct nvc0_context *nvc0, int s) 211{ 212 uint32_t commands[32]; 213 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 214 struct nouveau_bo *txc = nvc0->screen->txc; 215 unsigned i; 216 unsigned n = 0; 217 boolean need_flush = FALSE; 218 219 for (i = 0; i < nvc0->num_textures[s]; ++i) { 220 struct nv50_tic_entry *tic = nv50_tic_entry(nvc0->textures[s][i]); 221 struct nv04_resource *res; 222 const boolean dirty = !!(nvc0->textures_dirty[s] & (1 << i)); 223 224 if (!tic) { 225 if (dirty) 226 commands[n++] = (i << 1) | 0; 227 continue; 228 } 229 res = nv04_resource(tic->pipe.texture); 230 231 if (tic->id < 0) { 232 tic->id = nvc0_screen_tic_alloc(nvc0->screen, tic); 233 234 PUSH_SPACE(push, 17); 235 BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2); 236 PUSH_DATAh(push, txc->offset + (tic->id * 32)); 237 PUSH_DATA (push, txc->offset + (tic->id * 32)); 238 BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2); 239 PUSH_DATA (push, 32); 240 PUSH_DATA (push, 1); 241 BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1); 242 PUSH_DATA (push, 0x100111); 243 BEGIN_NIC0(push, NVC0_M2MF(DATA), 8); 244 PUSH_DATAp(push, &tic->tic[0], 8); 245 246 need_flush = TRUE; 247 } else 248 if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) { 249 BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1); 250 PUSH_DATA (push, (tic->id << 4) | 1); 251 } 252 nvc0->screen->tic.lock[tic->id / 32] |= 1 << (tic->id % 32); 253 254 res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING; 255 res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING; 256 257 if (!dirty) 258 continue; 259 commands[n++] = (tic->id << 9) | (i << 1) | 1; 260 261 BCTX_REFN(nvc0->bufctx_3d, TEX(s, i), res, RD); 262 } 263 for (; i < nvc0->state.num_textures[s]; ++i) 264 commands[n++] = (i << 1) | 0; 265 266 nvc0->state.num_textures[s] = nvc0->num_textures[s]; 267 268 if (n) { 269 BEGIN_NIC0(push, NVC0_3D(BIND_TIC(s)), n); 270 PUSH_DATAp(push, commands, n); 271 } 272 nvc0->textures_dirty[s] = 0; 273 274 return need_flush; 275} 276 277static boolean 278nve4_validate_tic(struct nvc0_context *nvc0, unsigned s) 279{ 280 struct nouveau_bo *txc = nvc0->screen->txc; 281 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 282 unsigned i; 283 boolean need_flush = FALSE; 284 285 for (i = 0; i < nvc0->num_textures[s]; ++i) { 286 struct nv50_tic_entry *tic = nv50_tic_entry(nvc0->textures[s][i]); 287 struct nv04_resource *res; 288 const boolean dirty = !!(nvc0->textures_dirty[s] & (1 << i)); 289 290 if (!tic) { 291 nvc0->tex_handles[s][i] |= NVE4_TIC_ENTRY_INVALID; 292 continue; 293 } 294 res = nv04_resource(tic->pipe.texture); 295 296 if (tic->id < 0) { 297 tic->id = nvc0_screen_tic_alloc(nvc0->screen, tic); 298 299 PUSH_SPACE(push, 16); 300 BEGIN_NVC0(push, NVE4_P2MF(DST_ADDRESS_HIGH), 2); 301 PUSH_DATAh(push, txc->offset + (tic->id * 32)); 302 PUSH_DATA (push, txc->offset + (tic->id * 32)); 303 BEGIN_NVC0(push, NVE4_P2MF(LINE_LENGTH_IN), 2); 304 PUSH_DATA (push, 32); 305 PUSH_DATA (push, 1); 306 BEGIN_1IC0(push, NVE4_P2MF(EXEC), 9); 307 PUSH_DATA (push, 0x1001); 308 PUSH_DATAp(push, &tic->tic[0], 8); 309 310 need_flush = TRUE; 311 } else 312 if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) { 313 BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1); 314 PUSH_DATA (push, (tic->id << 4) | 1); 315 } 316 nvc0->screen->tic.lock[tic->id / 32] |= 1 << (tic->id % 32); 317 318 res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING; 319 res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING; 320 321 nvc0->tex_handles[s][i] &= ~NVE4_TIC_ENTRY_INVALID; 322 nvc0->tex_handles[s][i] |= tic->id; 323 if (dirty) 324 BCTX_REFN(nvc0->bufctx_3d, TEX(s, i), res, RD); 325 } 326 for (; i < nvc0->state.num_textures[s]; ++i) 327 nvc0->tex_handles[s][i] |= NVE4_TIC_ENTRY_INVALID; 328 329 nvc0->state.num_textures[s] = nvc0->num_textures[s]; 330 331 return need_flush; 332} 333 334void nvc0_validate_textures(struct nvc0_context *nvc0) 335{ 336 boolean need_flush; 337 338 if (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) { 339 need_flush = nve4_validate_tic(nvc0, 0); 340 need_flush |= nve4_validate_tic(nvc0, 3); 341 need_flush |= nve4_validate_tic(nvc0, 4); 342 } else { 343 need_flush = nvc0_validate_tic(nvc0, 0); 344 need_flush |= nvc0_validate_tic(nvc0, 3); 345 need_flush |= nvc0_validate_tic(nvc0, 4); 346 } 347 348 if (need_flush) { 349 BEGIN_NVC0(nvc0->base.pushbuf, NVC0_3D(TIC_FLUSH), 1); 350 PUSH_DATA (nvc0->base.pushbuf, 0); 351 } 352} 353 354static boolean 355nvc0_validate_tsc(struct nvc0_context *nvc0, int s) 356{ 357 uint32_t commands[16]; 358 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 359 unsigned i; 360 unsigned n = 0; 361 boolean need_flush = FALSE; 362 363 for (i = 0; i < nvc0->num_samplers[s]; ++i) { 364 struct nv50_tsc_entry *tsc = nv50_tsc_entry(nvc0->samplers[s][i]); 365 366 if (!(nvc0->samplers_dirty[s] & (1 << i))) 367 continue; 368 if (!tsc) { 369 commands[n++] = (i << 4) | 0; 370 continue; 371 } 372 if (tsc->id < 0) { 373 tsc->id = nvc0_screen_tsc_alloc(nvc0->screen, tsc); 374 375 nvc0_m2mf_push_linear(&nvc0->base, nvc0->screen->txc, 376 65536 + tsc->id * 32, NOUVEAU_BO_VRAM, 377 32, tsc->tsc); 378 need_flush = TRUE; 379 } 380 nvc0->screen->tsc.lock[tsc->id / 32] |= 1 << (tsc->id % 32); 381 382 commands[n++] = (tsc->id << 12) | (i << 4) | 1; 383 } 384 for (; i < nvc0->state.num_samplers[s]; ++i) 385 commands[n++] = (i << 4) | 0; 386 387 nvc0->state.num_samplers[s] = nvc0->num_samplers[s]; 388 389 if (n) { 390 BEGIN_NIC0(push, NVC0_3D(BIND_TSC(s)), n); 391 PUSH_DATAp(push, commands, n); 392 } 393 nvc0->samplers_dirty[s] = 0; 394 395 return need_flush; 396} 397 398static boolean 399nve4_validate_tsc(struct nvc0_context *nvc0, int s) 400{ 401 struct nouveau_bo *txc = nvc0->screen->txc; 402 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 403 unsigned i; 404 boolean need_flush = FALSE; 405 406 for (i = 0; i < nvc0->num_samplers[s]; ++i) { 407 struct nv50_tsc_entry *tsc = nv50_tsc_entry(nvc0->samplers[s][i]); 408 409 if (!tsc) { 410 nvc0->tex_handles[s][i] |= NVE4_TSC_ENTRY_INVALID; 411 continue; 412 } 413 if (tsc->id < 0) { 414 tsc->id = nvc0_screen_tsc_alloc(nvc0->screen, tsc); 415 416 PUSH_SPACE(push, 16); 417 BEGIN_NVC0(push, NVE4_P2MF(DST_ADDRESS_HIGH), 2); 418 PUSH_DATAh(push, txc->offset + 65536 + (tsc->id * 32)); 419 PUSH_DATA (push, txc->offset + 65536 + (tsc->id * 32)); 420 BEGIN_NVC0(push, NVE4_P2MF(LINE_LENGTH_IN), 2); 421 PUSH_DATA (push, 32); 422 PUSH_DATA (push, 1); 423 BEGIN_1IC0(push, NVE4_P2MF(EXEC), 9); 424 PUSH_DATA (push, 0x1001); 425 PUSH_DATAp(push, &tsc->tsc[0], 8); 426 427 need_flush = TRUE; 428 } 429 nvc0->screen->tsc.lock[tsc->id / 32] |= 1 << (tsc->id % 32); 430 431 nvc0->tex_handles[s][i] &= ~NVE4_TSC_ENTRY_INVALID; 432 nvc0->tex_handles[s][i] |= tsc->id << 20; 433 } 434 for (; i < nvc0->state.num_samplers[s]; ++i) 435 nvc0->tex_handles[s][i] |= NVE4_TSC_ENTRY_INVALID; 436 437 nvc0->state.num_samplers[s] = nvc0->num_samplers[s]; 438 439 return need_flush; 440} 441 442void nvc0_validate_samplers(struct nvc0_context *nvc0) 443{ 444 boolean need_flush; 445 446 if (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) { 447 need_flush = nve4_validate_tsc(nvc0, 0); 448 need_flush |= nve4_validate_tsc(nvc0, 3); 449 need_flush |= nve4_validate_tsc(nvc0, 4); 450 } else { 451 need_flush = nvc0_validate_tsc(nvc0, 0); 452 need_flush |= nvc0_validate_tsc(nvc0, 3); 453 need_flush |= nvc0_validate_tsc(nvc0, 4); 454 } 455 456 if (need_flush) { 457 BEGIN_NVC0(nvc0->base.pushbuf, NVC0_3D(TSC_FLUSH), 1); 458 PUSH_DATA (nvc0->base.pushbuf, 0); 459 } 460} 461 462/* Upload the "diagonal" entries for the possible texture sources ($t == $s). 463 * At some point we might want to get a list of the combinations used by a 464 * shader and fill in those entries instead of having it extract the handles. 465 */ 466void 467nve4_set_tex_handles(struct nvc0_context *nvc0) 468{ 469 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 470 uint64_t address; 471 unsigned s; 472 473 if (nvc0->screen->base.class_3d < NVE4_3D_CLASS) 474 return; 475 address = nvc0->screen->uniform_bo->offset + (5 << 16); 476 477 for (s = 0; s < 5; ++s, address += (1 << 9)) { 478 uint32_t dirty = nvc0->textures_dirty[s] | nvc0->samplers_dirty[s]; 479 if (!dirty) 480 continue; 481 BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3); 482 PUSH_DATA (push, 512); 483 PUSH_DATAh(push, address); 484 PUSH_DATA (push, address); 485 do { 486 int i = ffs(dirty) - 1; 487 dirty &= ~(1 << i); 488 489 BEGIN_NVC0(push, NVC0_3D(CB_POS), 2); 490 PUSH_DATA (push, (8 + i) * 4); 491 PUSH_DATA (push, nvc0->tex_handles[s][i]); 492 } while (dirty); 493 494 nvc0->textures_dirty[s] = 0; 495 nvc0->samplers_dirty[s] = 0; 496 } 497} 498