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