nv50,nvc0: add new texture and render target formats
[mesa.git] / src / gallium / drivers / nv50 / nv50_transfer.c
1
2 #include "util/u_format.h"
3
4 #include "nv50_context.h"
5 #include "nv50_transfer.h"
6
7 #include "nv50_defs.xml.h"
8
9 struct nv50_transfer {
10 struct pipe_transfer base;
11 struct nv50_m2mf_rect rect[2];
12 uint32_t nblocksx;
13 uint32_t nblocksy;
14 };
15
16 static void
17 nv50_m2mf_transfer_rect(struct pipe_screen *pscreen,
18 const struct nv50_m2mf_rect *dst,
19 const struct nv50_m2mf_rect *src,
20 uint32_t nblocksx, uint32_t nblocksy)
21 {
22 struct nouveau_channel *chan = nouveau_screen(pscreen)->channel;
23 const int cpp = dst->cpp;
24 uint32_t src_ofst = src->base;
25 uint32_t dst_ofst = dst->base;
26 uint32_t height = nblocksy;
27 uint32_t sy = src->y;
28 uint32_t dy = dst->y;
29
30 assert(dst->cpp == src->cpp);
31
32 if (nouveau_bo_tile_layout(src->bo)) {
33 BEGIN_RING(chan, RING_MF(LINEAR_IN), 6);
34 OUT_RING (chan, 0);
35 OUT_RING (chan, src->tile_mode << 4);
36 OUT_RING (chan, src->width * cpp);
37 OUT_RING (chan, src->height);
38 OUT_RING (chan, src->depth);
39 OUT_RING (chan, src->z);
40 } else {
41 src_ofst += src->y * src->pitch + src->x * cpp;
42
43 BEGIN_RING(chan, RING_MF(LINEAR_IN), 1);
44 OUT_RING (chan, 1);
45 BEGIN_RING(chan, RING_MF_(NV04_M2MF_PITCH_IN), 1);
46 OUT_RING (chan, src->pitch);
47 }
48
49 if (nouveau_bo_tile_layout(dst->bo)) {
50 BEGIN_RING(chan, RING_MF(LINEAR_OUT), 6);
51 OUT_RING (chan, 0);
52 OUT_RING (chan, dst->tile_mode << 4);
53 OUT_RING (chan, dst->width * cpp);
54 OUT_RING (chan, dst->height);
55 OUT_RING (chan, dst->depth);
56 OUT_RING (chan, dst->z);
57 } else {
58 dst_ofst += dst->y * dst->pitch + dst->x * cpp;
59
60 BEGIN_RING(chan, RING_MF(LINEAR_OUT), 1);
61 OUT_RING (chan, 1);
62 BEGIN_RING(chan, RING_MF_(NV04_M2MF_PITCH_OUT), 1);
63 OUT_RING (chan, dst->pitch);
64 }
65
66 while (height) {
67 int line_count = height > 2047 ? 2047 : height;
68
69 MARK_RING (chan, 17, 4);
70
71 BEGIN_RING(chan, RING_MF(OFFSET_IN_HIGH), 2);
72 OUT_RELOCh(chan, src->bo, src_ofst, src->domain | NOUVEAU_BO_RD);
73 OUT_RELOCh(chan, dst->bo, dst_ofst, dst->domain | NOUVEAU_BO_WR);
74
75 BEGIN_RING(chan, RING_MF_(NV04_M2MF_OFFSET_IN), 2);
76 OUT_RELOCl(chan, src->bo, src_ofst, src->domain | NOUVEAU_BO_RD);
77 OUT_RELOCl(chan, dst->bo, dst_ofst, dst->domain | NOUVEAU_BO_WR);
78
79 if (nouveau_bo_tile_layout(src->bo)) {
80 BEGIN_RING(chan, RING_MF(TILING_POSITION_IN), 1);
81 OUT_RING (chan, (sy << 16) | (src->x * cpp));
82 } else {
83 src_ofst += line_count * src->pitch;
84 }
85 if (nouveau_bo_tile_layout(dst->bo)) {
86 BEGIN_RING(chan, RING_MF(TILING_POSITION_OUT), 1);
87 OUT_RING (chan, (dy << 16) | (dst->x * cpp));
88 } else {
89 dst_ofst += line_count * dst->pitch;
90 }
91
92 BEGIN_RING(chan, RING_MF_(NV04_M2MF_LINE_LENGTH_IN), 4);
93 OUT_RING (chan, nblocksx * cpp);
94 OUT_RING (chan, line_count);
95 OUT_RING (chan, (1 << 8) | (1 << 0));
96 OUT_RING (chan, 0);
97
98 height -= line_count;
99 sy += line_count;
100 dy += line_count;
101 }
102 }
103
104 void
105 nv50_sifc_linear_u8(struct nouveau_context *nv,
106 struct nouveau_bo *dst, unsigned offset, unsigned domain,
107 unsigned size, void *data)
108 {
109 struct nouveau_channel *chan = nv->screen->channel;
110 uint32_t *src = (uint32_t *)data;
111 unsigned count = (size + 3) / 4;
112 unsigned xcoord = offset & 0xff;
113
114 offset &= ~0xff;
115
116 MARK_RING (chan, 23, 4);
117 BEGIN_RING(chan, RING_2D(DST_FORMAT), 2);
118 OUT_RING (chan, NV50_SURFACE_FORMAT_R8_UNORM);
119 OUT_RING (chan, 1);
120 BEGIN_RING(chan, RING_2D(DST_PITCH), 5);
121 OUT_RING (chan, 262144);
122 OUT_RING (chan, 65536);
123 OUT_RING (chan, 1);
124 OUT_RELOCh(chan, dst, offset, domain | NOUVEAU_BO_WR);
125 OUT_RELOCl(chan, dst, offset, domain | NOUVEAU_BO_WR);
126 BEGIN_RING(chan, RING_2D(SIFC_BITMAP_ENABLE), 2);
127 OUT_RING (chan, 0);
128 OUT_RING (chan, NV50_SURFACE_FORMAT_R8_UNORM);
129 BEGIN_RING(chan, RING_2D(SIFC_WIDTH), 10);
130 OUT_RING (chan, size);
131 OUT_RING (chan, 1);
132 OUT_RING (chan, 0);
133 OUT_RING (chan, 1);
134 OUT_RING (chan, 0);
135 OUT_RING (chan, 1);
136 OUT_RING (chan, 0);
137 OUT_RING (chan, xcoord);
138 OUT_RING (chan, 0);
139 OUT_RING (chan, 0);
140
141 while (count) {
142 unsigned nr = AVAIL_RING(chan);
143
144 if (nr < 9) {
145 FIRE_RING(chan);
146 nouveau_bo_validate(chan, dst, NOUVEAU_BO_WR);
147 continue;
148 }
149 nr = MIN2(count, nr - 1);
150 nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN);
151
152 BEGIN_RING_NI(chan, RING_2D(SIFC_DATA), nr);
153 OUT_RINGp (chan, src, nr);
154
155 src += nr;
156 count -= nr;
157 }
158 }
159
160 void
161 nv50_m2mf_copy_linear(struct nouveau_context *nv,
162 struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom,
163 struct nouveau_bo *src, unsigned srcoff, unsigned srcdom,
164 unsigned size)
165 {
166 struct nouveau_channel *chan = nv->screen->channel;
167
168 BEGIN_RING(chan, RING_MF(LINEAR_IN), 1);
169 OUT_RING (chan, 1);
170 BEGIN_RING(chan, RING_MF(LINEAR_OUT), 1);
171 OUT_RING (chan, 1);
172
173 while (size) {
174 unsigned bytes = MIN2(size, 1 << 17);
175
176 MARK_RING (chan, 11, 4);
177 BEGIN_RING(chan, RING_MF(OFFSET_IN_HIGH), 2);
178 OUT_RELOCh(chan, src, srcoff, srcdom | NOUVEAU_BO_RD);
179 OUT_RELOCh(chan, dst, dstoff, dstdom | NOUVEAU_BO_WR);
180 BEGIN_RING(chan, RING_MF_(NV04_M2MF_OFFSET_IN), 2);
181 OUT_RELOCl(chan, src, srcoff, srcdom | NOUVEAU_BO_RD);
182 OUT_RELOCl(chan, dst, dstoff, dstdom | NOUVEAU_BO_WR);
183 BEGIN_RING(chan, RING_MF_(NV04_M2MF_LINE_LENGTH_IN), 4);
184 OUT_RING (chan, bytes);
185 OUT_RING (chan, 1);
186 OUT_RING (chan, (1 << 8) | (1 << 0));
187 OUT_RING (chan, 0);
188
189 srcoff += bytes;
190 dstoff += bytes;
191 size -= bytes;
192 }
193 }
194
195 struct pipe_transfer *
196 nv50_miptree_transfer_new(struct pipe_context *pctx,
197 struct pipe_resource *res,
198 unsigned level,
199 unsigned usage,
200 const struct pipe_box *box)
201 {
202 struct nv50_context *nv50 = nv50_context(pctx);
203 struct pipe_screen *pscreen = pctx->screen;
204 struct nouveau_device *dev = nv50->screen->base.device;
205 struct nv50_miptree *mt = nv50_miptree(res);
206 struct nv50_miptree_level *lvl = &mt->level[level];
207 struct nv50_transfer *tx;
208 uint32_t size;
209 uint32_t w, h, d, z, layer;
210 int ret;
211
212 if (mt->layout_3d) {
213 z = box->z;
214 d = u_minify(res->depth0, level);
215 layer = 0;
216 } else {
217 z = 0;
218 d = 1;
219 layer = box->z;
220 }
221
222 tx = CALLOC_STRUCT(nv50_transfer);
223 if (!tx)
224 return NULL;
225
226 pipe_resource_reference(&tx->base.resource, res);
227
228 tx->base.level = level;
229 tx->base.usage = usage;
230 tx->base.box = *box;
231
232 tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
233 tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
234
235 tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);
236 tx->base.layer_stride = tx->nblocksy * tx->base.stride;
237
238 w = u_minify(res->width0, level);
239 h = u_minify(res->height0, level);
240
241 tx->rect[0].cpp = tx->rect[1].cpp = util_format_get_blocksize(res->format);
242
243 tx->rect[0].bo = mt->base.bo;
244 tx->rect[0].base = lvl->offset + layer * mt->layer_stride;
245 tx->rect[0].tile_mode = lvl->tile_mode;
246 tx->rect[0].x = util_format_get_nblocksx(res->format, box->x);
247 tx->rect[0].y = util_format_get_nblocksy(res->format, box->y);
248 tx->rect[0].z = z;
249 tx->rect[0].width = util_format_get_nblocksx(res->format, w);
250 tx->rect[0].height = util_format_get_nblocksy(res->format, h);
251 tx->rect[0].depth = d;
252 tx->rect[0].pitch = lvl->pitch;
253 tx->rect[0].domain = NOUVEAU_BO_VRAM;
254
255 size = tx->base.layer_stride;
256
257 ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
258 size * tx->base.box.depth, &tx->rect[1].bo);
259 if (ret) {
260 FREE(tx);
261 return NULL;
262 }
263
264 tx->rect[1].width = tx->nblocksx;
265 tx->rect[1].height = tx->nblocksy;
266 tx->rect[1].depth = 1;
267 tx->rect[1].pitch = tx->base.stride;
268 tx->rect[1].domain = NOUVEAU_BO_GART;
269
270 if (usage & PIPE_TRANSFER_READ) {
271 unsigned base = tx->rect[0].base;
272 unsigned i;
273 for (i = 0; i < box->depth; ++i) {
274 nv50_m2mf_transfer_rect(pscreen, &tx->rect[1], &tx->rect[0],
275 tx->nblocksx, tx->nblocksy);
276 if (mt->layout_3d)
277 tx->rect[0].z++;
278 else
279 tx->rect[0].base += mt->layer_stride;
280 tx->rect[1].base += size;
281 }
282 tx->rect[0].z = z;
283 tx->rect[0].base = base;
284 tx->rect[1].base = 0;
285 }
286
287 return &tx->base;
288 }
289
290 void
291 nv50_miptree_transfer_del(struct pipe_context *pctx,
292 struct pipe_transfer *transfer)
293 {
294 struct pipe_screen *pscreen = pctx->screen;
295 struct nv50_transfer *tx = (struct nv50_transfer *)transfer;
296 struct nv50_miptree *mt = nv50_miptree(tx->base.resource);
297 unsigned i;
298
299 if (tx->base.usage & PIPE_TRANSFER_WRITE) {
300 for (i = 0; i < tx->base.box.depth; ++i) {
301 nv50_m2mf_transfer_rect(pscreen, &tx->rect[0], &tx->rect[1],
302 tx->nblocksx, tx->nblocksy);
303 if (mt->layout_3d)
304 tx->rect[0].z++;
305 else
306 tx->rect[0].base += mt->layer_stride;
307 tx->rect[1].base += tx->nblocksy * tx->base.stride;
308 }
309 }
310
311 nouveau_bo_ref(NULL, &tx->rect[1].bo);
312 pipe_resource_reference(&transfer->resource, NULL);
313
314 FREE(tx);
315 }
316
317 void *
318 nv50_miptree_transfer_map(struct pipe_context *pctx,
319 struct pipe_transfer *transfer)
320 {
321 struct nv50_transfer *tx = (struct nv50_transfer *)transfer;
322 int ret;
323 unsigned flags = 0;
324
325 if (tx->rect[1].bo->map)
326 return tx->rect[1].bo->map;
327
328 if (transfer->usage & PIPE_TRANSFER_READ)
329 flags = NOUVEAU_BO_RD;
330 if (transfer->usage & PIPE_TRANSFER_WRITE)
331 flags |= NOUVEAU_BO_WR;
332
333 ret = nouveau_bo_map(tx->rect[1].bo, flags);
334 if (ret)
335 return NULL;
336 return tx->rect[1].bo->map;
337 }
338
339 void
340 nv50_miptree_transfer_unmap(struct pipe_context *pctx,
341 struct pipe_transfer *transfer)
342 {
343 struct nv50_transfer *tx = (struct nv50_transfer *)transfer;
344
345 nouveau_bo_unmap(tx->rect[1].bo);
346 }
347