nouveau: switch to libdrm_nouveau-2.0
[mesa.git] / src / gallium / drivers / nvc0 / nvc0_tex.c
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
33 static INLINE uint32_t
34 nv50_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
53 struct pipe_sampler_view *
54 nvc0_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
206 static boolean
207 nvc0_validate_tic(struct nvc0_context *nvc0, int s)
208 {
209 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
210 struct nouveau_bo *txc = nvc0->screen->txc;
211 unsigned i;
212 boolean need_flush = FALSE;
213
214 for (i = 0; i < nvc0->num_textures[s]; ++i) {
215 struct nv50_tic_entry *tic = nv50_tic_entry(nvc0->textures[s][i]);
216 struct nv04_resource *res;
217
218 if (!tic) {
219 BEGIN_NVC0(push, NVC0_3D(BIND_TIC(s)), 1);
220 PUSH_DATA (push, (i << 1) | 0);
221 continue;
222 }
223 res = nv04_resource(tic->pipe.texture);
224
225 if (tic->id < 0) {
226 tic->id = nvc0_screen_tic_alloc(nvc0->screen, tic);
227
228 PUSH_SPACE(push, 17);
229 BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);
230 PUSH_DATAh(push, txc->offset + (tic->id * 32));
231 PUSH_DATA (push, txc->offset + (tic->id * 32));
232 BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);
233 PUSH_DATA (push, 32);
234 PUSH_DATA (push, 1);
235 BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);
236 PUSH_DATA (push, 0x100111);
237 BEGIN_NIC0(push, NVC0_M2MF(DATA), 8);
238 PUSH_DATAp(push, &tic->tic[0], 8);
239
240 need_flush = TRUE;
241 } else
242 if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) {
243 BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1);
244 PUSH_DATA (push, (tic->id << 4) | 1);
245 }
246 nvc0->screen->tic.lock[tic->id / 32] |= 1 << (tic->id % 32);
247
248 res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING;
249 res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING;
250
251 BCTX_REFN(nvc0->bufctx_3d, TEX, res, RD);
252
253 BEGIN_NVC0(push, NVC0_3D(BIND_TIC(s)), 1);
254 PUSH_DATA (push, (tic->id << 9) | (i << 1) | 1);
255 }
256 for (; i < nvc0->state.num_textures[s]; ++i) {
257 BEGIN_NVC0(push, NVC0_3D(BIND_TIC(s)), 1);
258 PUSH_DATA (push, (i << 1) | 0);
259 }
260 nvc0->state.num_textures[s] = nvc0->num_textures[s];
261
262 return need_flush;
263 }
264
265 void nvc0_validate_textures(struct nvc0_context *nvc0)
266 {
267 boolean need_flush;
268
269 need_flush = nvc0_validate_tic(nvc0, 0);
270 need_flush |= nvc0_validate_tic(nvc0, 3);
271 need_flush |= nvc0_validate_tic(nvc0, 4);
272
273 if (need_flush) {
274 BEGIN_NVC0(nvc0->base.pushbuf, NVC0_3D(TIC_FLUSH), 1);
275 PUSH_DATA (nvc0->base.pushbuf, 0);
276 }
277 }
278
279 static boolean
280 nvc0_validate_tsc(struct nvc0_context *nvc0, int s)
281 {
282 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
283 unsigned i;
284 boolean need_flush = FALSE;
285
286 for (i = 0; i < nvc0->num_samplers[s]; ++i) {
287 struct nv50_tsc_entry *tsc = nv50_tsc_entry(nvc0->samplers[s][i]);
288
289 if (!tsc) {
290 BEGIN_NVC0(push, NVC0_3D(BIND_TSC(s)), 1);
291 PUSH_DATA (push, (i << 4) | 0);
292 continue;
293 }
294 if (tsc->id < 0) {
295 tsc->id = nvc0_screen_tsc_alloc(nvc0->screen, tsc);
296
297 nvc0_m2mf_push_linear(&nvc0->base, nvc0->screen->txc,
298 65536 + tsc->id * 32, NOUVEAU_BO_VRAM,
299 32, tsc->tsc);
300 need_flush = TRUE;
301 }
302 nvc0->screen->tsc.lock[tsc->id / 32] |= 1 << (tsc->id % 32);
303
304 BEGIN_NVC0(push, NVC0_3D(BIND_TSC(s)), 1);
305 PUSH_DATA (push, (tsc->id << 12) | (i << 4) | 1);
306 }
307 for (; i < nvc0->state.num_samplers[s]; ++i) {
308 BEGIN_NVC0(push, NVC0_3D(BIND_TSC(s)), 1);
309 PUSH_DATA (push, (i << 4) | 0);
310 }
311 nvc0->state.num_samplers[s] = nvc0->num_samplers[s];
312
313 return need_flush;
314 }
315
316 void nvc0_validate_samplers(struct nvc0_context *nvc0)
317 {
318 boolean need_flush;
319
320 need_flush = nvc0_validate_tsc(nvc0, 0);
321 need_flush |= nvc0_validate_tsc(nvc0, 3);
322 need_flush |= nvc0_validate_tsc(nvc0, 4);
323
324 if (need_flush) {
325 BEGIN_NVC0(nvc0->base.pushbuf, NVC0_3D(TSC_FLUSH), 1);
326 PUSH_DATA (nvc0->base.pushbuf, 0);
327 }
328 }