nvc0_tex.c revision 784f49e69624cba07616fd5a22ccb80ad3b5111b
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 NV50_TIC_0_SWIZZLE__MASK \ 30 (NV50_TIC_0_MAPA__MASK | NV50_TIC_0_MAPB__MASK | \ 31 NV50_TIC_0_MAPG__MASK | NV50_TIC_0_MAPR__MASK) 32 33static INLINE uint32_t 34nv50_tic_swizzle(uint32_t tc, unsigned swz, boolean tex_int) 35{ 36 switch (swz) { 37 case PIPE_SWIZZLE_RED: 38 return (tc & NV50_TIC_0_MAPR__MASK) >> NV50_TIC_0_MAPR__SHIFT; 39 case PIPE_SWIZZLE_GREEN: 40 return (tc & NV50_TIC_0_MAPG__MASK) >> NV50_TIC_0_MAPG__SHIFT; 41 case PIPE_SWIZZLE_BLUE: 42 return (tc & NV50_TIC_0_MAPB__MASK) >> NV50_TIC_0_MAPB__SHIFT; 43 case PIPE_SWIZZLE_ALPHA: 44 return (tc & NV50_TIC_0_MAPA__MASK) >> NV50_TIC_0_MAPA__SHIFT; 45 case PIPE_SWIZZLE_ONE: 46 return tex_int ? NV50_TIC_MAP_ONE_INT : NV50_TIC_MAP_ONE_FLOAT; 47 case PIPE_SWIZZLE_ZERO: 48 default: 49 return NV50_TIC_MAP_ZERO; 50 } 51} 52 53struct pipe_sampler_view * 54nvc0_create_sampler_view(struct pipe_context *pipe, 55 struct pipe_resource *texture, 56 const struct pipe_sampler_view *templ) 57{ 58 const struct util_format_description *desc; 59 uint64_t address; 60 uint32_t *tic; 61 uint32_t swz[4]; 62 uint32_t depth; 63 struct nv50_tic_entry *view; 64 struct nv50_miptree *mt; 65 boolean tex_int; 66 67 view = MALLOC_STRUCT(nv50_tic_entry); 68 if (!view) 69 return NULL; 70 mt = nv50_miptree(texture); 71 72 view->pipe = *templ; 73 view->pipe.reference.count = 1; 74 view->pipe.texture = NULL; 75 view->pipe.context = pipe; 76 77 view->id = -1; 78 79 pipe_resource_reference(&view->pipe.texture, texture); 80 81 tic = &view->tic[0]; 82 83 desc = util_format_description(view->pipe.format); 84 85 tic[0] = nvc0_format_table[view->pipe.format].tic; 86 87 tex_int = util_format_is_pure_integer(view->pipe.format); 88 89 swz[0] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_r, tex_int); 90 swz[1] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_g, tex_int); 91 swz[2] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_b, tex_int); 92 swz[3] = nv50_tic_swizzle(tic[0], view->pipe.swizzle_a, tex_int); 93 tic[0] = (tic[0] & ~NV50_TIC_0_SWIZZLE__MASK) | 94 (swz[0] << NV50_TIC_0_MAPR__SHIFT) | 95 (swz[1] << NV50_TIC_0_MAPG__SHIFT) | 96 (swz[2] << NV50_TIC_0_MAPB__SHIFT) | 97 (swz[3] << NV50_TIC_0_MAPA__SHIFT); 98 99 address = mt->base.address; 100 101 tic[2] = 0x10001000 | NV50_TIC_2_NO_BORDER; 102 103 if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) 104 tic[2] |= NV50_TIC_2_COLORSPACE_SRGB; 105 106 /* check for linear storage type */ 107 if (unlikely(!nouveau_bo_memtype(nv04_resource(texture)->bo))) { 108 if (texture->target == PIPE_BUFFER) { 109 address += 110 view->pipe.u.buf.first_element * desc->block.bits / 8; 111 tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_BUFFER; 112 tic[3] = 0; 113 tic[4] = /* width */ 114 view->pipe.u.buf.last_element - view->pipe.u.buf.first_element + 1; 115 tic[5] = 0; 116 } else { 117 /* must be 2D texture without mip maps */ 118 tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_RECT; 119 if (texture->target != PIPE_TEXTURE_RECT) 120 tic[2] |= NV50_TIC_2_NORMALIZED_COORDS; 121 tic[3] = mt->level[0].pitch; 122 tic[4] = mt->base.base.width0; 123 tic[5] = (1 << 16) | mt->base.base.height0; 124 } 125 tic[6] = 126 tic[7] = 0; 127 tic[1] = address; 128 tic[2] |= address >> 32; 129 return &view->pipe; 130 } 131 132 if (mt->base.base.target != PIPE_TEXTURE_RECT) 133 tic[2] |= NV50_TIC_2_NORMALIZED_COORDS; 134 135 tic[2] |= 136 ((mt->level[0].tile_mode & 0x0f0) << (22 - 4)) | 137 ((mt->level[0].tile_mode & 0xf00) << (25 - 8)); 138 139 depth = MAX2(mt->base.base.array_size, mt->base.base.depth0); 140 141 if (mt->base.base.array_size > 1) { 142 /* there doesn't seem to be a base layer field in TIC */ 143 address += view->pipe.u.tex.first_layer * mt->layer_stride; 144 depth = view->pipe.u.tex.last_layer - view->pipe.u.tex.first_layer + 1; 145 } 146 tic[1] = address; 147 tic[2] |= address >> 32; 148 149 switch (mt->base.base.target) { 150 case PIPE_TEXTURE_1D: 151 tic[2] |= NV50_TIC_2_TARGET_1D; 152 break; 153/* case PIPE_TEXTURE_2D_MS: */ 154 case PIPE_TEXTURE_2D: 155 tic[2] |= NV50_TIC_2_TARGET_2D; 156 break; 157 case PIPE_TEXTURE_RECT: 158 tic[2] |= NV50_TIC_2_TARGET_RECT; 159 break; 160 case PIPE_TEXTURE_3D: 161 tic[2] |= NV50_TIC_2_TARGET_3D; 162 break; 163 case PIPE_TEXTURE_CUBE: 164 depth /= 6; 165 if (depth > 1) 166 tic[2] |= NV50_TIC_2_TARGET_CUBE_ARRAY; 167 else 168 tic[2] |= NV50_TIC_2_TARGET_CUBE; 169 break; 170 case PIPE_TEXTURE_1D_ARRAY: 171 tic[2] |= NV50_TIC_2_TARGET_1D_ARRAY; 172 break; 173/* case PIPE_TEXTURE_2D_ARRAY_MS: */ 174 case PIPE_TEXTURE_2D_ARRAY: 175 tic[2] |= NV50_TIC_2_TARGET_2D_ARRAY; 176 break; 177 default: 178 NOUVEAU_ERR("invalid texture target: %d\n", mt->base.base.target); 179 return FALSE; 180 } 181 182 if (mt->base.base.target == PIPE_BUFFER) 183 tic[3] = mt->base.base.width0; 184 else 185 tic[3] = 0x00300000; 186 187 tic[4] = (1 << 31) | (mt->base.base.width0 << mt->ms_x); 188 189 tic[5] = (mt->base.base.height0 << mt->ms_y) & 0xffff; 190 tic[5] |= depth << 16; 191 tic[5] |= mt->base.base.last_level << 28; 192 193 tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; /* sampling points */ 194 195 tic[7] = (view->pipe.u.tex.last_level << 4) | view->pipe.u.tex.first_level; 196 197 /* 198 if (mt->base.base.target == PIPE_TEXTURE_2D_MS || 199 mt->base.base.target == PIPE_TEXTURE_2D_ARRAY_MS) 200 tic[7] |= mt->ms_mode << 12; 201 */ 202 203 return &view->pipe; 204} 205 206static boolean 207nvc0_validate_tic(struct nvc0_context *nvc0, int s) 208{ 209 uint32_t commands[32]; 210 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 211 struct nouveau_bo *txc = nvc0->screen->txc; 212 unsigned i; 213 unsigned n = 0; 214 boolean need_flush = FALSE; 215 216 for (i = 0; i < nvc0->num_textures[s]; ++i) { 217 struct nv50_tic_entry *tic = nv50_tic_entry(nvc0->textures[s][i]); 218 struct nv04_resource *res; 219 const boolean dirty = !!(nvc0->textures_dirty[s] & (1 << i)); 220 221 if (!tic) { 222 if (dirty) 223 commands[n++] = (i << 1) | 0; 224 continue; 225 } 226 res = nv04_resource(tic->pipe.texture); 227 228 if (tic->id < 0) { 229 tic->id = nvc0_screen_tic_alloc(nvc0->screen, tic); 230 231 PUSH_SPACE(push, 17); 232 BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2); 233 PUSH_DATAh(push, txc->offset + (tic->id * 32)); 234 PUSH_DATA (push, txc->offset + (tic->id * 32)); 235 BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2); 236 PUSH_DATA (push, 32); 237 PUSH_DATA (push, 1); 238 BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1); 239 PUSH_DATA (push, 0x100111); 240 BEGIN_NIC0(push, NVC0_M2MF(DATA), 8); 241 PUSH_DATAp(push, &tic->tic[0], 8); 242 243 need_flush = TRUE; 244 } else 245 if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) { 246 BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1); 247 PUSH_DATA (push, (tic->id << 4) | 1); 248 } 249 nvc0->screen->tic.lock[tic->id / 32] |= 1 << (tic->id % 32); 250 251 res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING; 252 res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING; 253 254 if (!dirty) 255 continue; 256 commands[n++] = (tic->id << 9) | (i << 1) | 1; 257 258 BCTX_REFN(nvc0->bufctx_3d, TEX(s, i), res, RD); 259 } 260 for (; i < nvc0->state.num_textures[s]; ++i) 261 commands[n++] = (i << 1) | 0; 262 263 nvc0->state.num_textures[s] = nvc0->num_textures[s]; 264 265 if (n) { 266 BEGIN_NIC0(push, NVC0_3D(BIND_TIC(s)), n); 267 PUSH_DATAp(push, commands, n); 268 } 269 nvc0->textures_dirty[s] = 0; 270 271 return need_flush; 272} 273 274void nvc0_validate_textures(struct nvc0_context *nvc0) 275{ 276 boolean need_flush; 277 278 need_flush = nvc0_validate_tic(nvc0, 0); 279 need_flush |= nvc0_validate_tic(nvc0, 3); 280 need_flush |= nvc0_validate_tic(nvc0, 4); 281 282 if (need_flush) { 283 BEGIN_NVC0(nvc0->base.pushbuf, NVC0_3D(TIC_FLUSH), 1); 284 PUSH_DATA (nvc0->base.pushbuf, 0); 285 } 286} 287 288static boolean 289nvc0_validate_tsc(struct nvc0_context *nvc0, int s) 290{ 291 uint32_t commands[16]; 292 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 293 unsigned i; 294 unsigned n = 0; 295 boolean need_flush = FALSE; 296 297 for (i = 0; i < nvc0->num_samplers[s]; ++i) { 298 struct nv50_tsc_entry *tsc = nv50_tsc_entry(nvc0->samplers[s][i]); 299 300 if (!(nvc0->samplers_dirty[s] & (1 << i))) 301 continue; 302 if (!tsc) { 303 commands[n++] = (i << 4) | 0; 304 continue; 305 } 306 if (tsc->id < 0) { 307 tsc->id = nvc0_screen_tsc_alloc(nvc0->screen, tsc); 308 309 nvc0_m2mf_push_linear(&nvc0->base, nvc0->screen->txc, 310 65536 + tsc->id * 32, NOUVEAU_BO_VRAM, 311 32, tsc->tsc); 312 need_flush = TRUE; 313 } 314 nvc0->screen->tsc.lock[tsc->id / 32] |= 1 << (tsc->id % 32); 315 316 commands[n++] = (tsc->id << 12) | (i << 4) | 1; 317 } 318 for (; i < nvc0->state.num_samplers[s]; ++i) 319 commands[n++] = (i << 4) | 0; 320 321 nvc0->state.num_samplers[s] = nvc0->num_samplers[s]; 322 323 if (n) { 324 BEGIN_NIC0(push, NVC0_3D(BIND_TSC(s)), n); 325 PUSH_DATAp(push, commands, n); 326 } 327 nvc0->samplers_dirty[s] = 0; 328 329 return need_flush; 330} 331 332void nvc0_validate_samplers(struct nvc0_context *nvc0) 333{ 334 boolean need_flush; 335 336 need_flush = nvc0_validate_tsc(nvc0, 0); 337 need_flush |= nvc0_validate_tsc(nvc0, 3); 338 need_flush |= nvc0_validate_tsc(nvc0, 4); 339 340 if (need_flush) { 341 BEGIN_NVC0(nvc0->base.pushbuf, NVC0_3D(TSC_FLUSH), 1); 342 PUSH_DATA (nvc0->base.pushbuf, 0); 343 } 344} 345