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