a9906829fec2f6de4db5a1bff3e0eecb01ce9bca
[mesa.git] / src / gallium / drivers / nouveau / nv50 / nv50_transfer.c
1
2 #include "util/u_format.h"
3
4 #include "nv50/nv50_context.h"
5
6 #include "nv50/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 nv50_context *nv50,
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_pushbuf *push = nv50->base.pushbuf;
59 struct nouveau_bufctx *bctx = nv50->bufctx;
60 const int cpp = dst->cpp;
61 uint32_t src_ofst = src->base;
62 uint32_t dst_ofst = dst->base;
63 uint32_t height = nblocksy;
64 uint32_t sy = src->y;
65 uint32_t dy = dst->y;
66
67 assert(dst->cpp == src->cpp);
68
69 nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD);
70 nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR);
71 nouveau_pushbuf_bufctx(push, bctx);
72 nouveau_pushbuf_validate(push);
73
74 if (nouveau_bo_memtype(src->bo)) {
75 BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 6);
76 PUSH_DATA (push, 0);
77 PUSH_DATA (push, src->tile_mode);
78 PUSH_DATA (push, src->width * cpp);
79 PUSH_DATA (push, src->height);
80 PUSH_DATA (push, src->depth);
81 PUSH_DATA (push, src->z);
82 } else {
83 src_ofst += src->y * src->pitch + src->x * cpp;
84
85 BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 1);
86 PUSH_DATA (push, 1);
87 BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_PITCH_IN), 1);
88 PUSH_DATA (push, src->pitch);
89 }
90
91 if (nouveau_bo_memtype(dst->bo)) {
92 BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 6);
93 PUSH_DATA (push, 0);
94 PUSH_DATA (push, dst->tile_mode);
95 PUSH_DATA (push, dst->width * cpp);
96 PUSH_DATA (push, dst->height);
97 PUSH_DATA (push, dst->depth);
98 PUSH_DATA (push, dst->z);
99 } else {
100 dst_ofst += dst->y * dst->pitch + dst->x * cpp;
101
102 BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 1);
103 PUSH_DATA (push, 1);
104 BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_PITCH_OUT), 1);
105 PUSH_DATA (push, dst->pitch);
106 }
107
108 while (height) {
109 int line_count = height > 2047 ? 2047 : height;
110
111 BEGIN_NV04(push, NV50_M2MF(OFFSET_IN_HIGH), 2);
112 PUSH_DATAh(push, src->bo->offset + src_ofst);
113 PUSH_DATAh(push, dst->bo->offset + dst_ofst);
114
115 BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_OFFSET_IN), 2);
116 PUSH_DATA (push, src->bo->offset + src_ofst);
117 PUSH_DATA (push, dst->bo->offset + dst_ofst);
118
119 if (nouveau_bo_memtype(src->bo)) {
120 BEGIN_NV04(push, NV50_M2MF(TILING_POSITION_IN), 1);
121 PUSH_DATA (push, (sy << 16) | (src->x * cpp));
122 } else {
123 src_ofst += line_count * src->pitch;
124 }
125 if (nouveau_bo_memtype(dst->bo)) {
126 BEGIN_NV04(push, NV50_M2MF(TILING_POSITION_OUT), 1);
127 PUSH_DATA (push, (dy << 16) | (dst->x * cpp));
128 } else {
129 dst_ofst += line_count * dst->pitch;
130 }
131
132 BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_LINE_LENGTH_IN), 4);
133 PUSH_DATA (push, nblocksx * cpp);
134 PUSH_DATA (push, line_count);
135 PUSH_DATA (push, (1 << 8) | (1 << 0));
136 PUSH_DATA (push, 0);
137
138 height -= line_count;
139 sy += line_count;
140 dy += line_count;
141 }
142
143 nouveau_bufctx_reset(bctx, 0);
144 }
145
146 void
147 nv50_sifc_linear_u8(struct nouveau_context *nv,
148 struct nouveau_bo *dst, unsigned offset, unsigned domain,
149 unsigned size, const void *data)
150 {
151 struct nv50_context *nv50 = nv50_context(&nv->pipe);
152 struct nouveau_pushbuf *push = nv50->base.pushbuf;
153 uint32_t *src = (uint32_t *)data;
154 unsigned count = (size + 3) / 4;
155 unsigned xcoord = offset & 0xff;
156
157 nouveau_bufctx_refn(nv50->bufctx, 0, dst, domain | NOUVEAU_BO_WR);
158 nouveau_pushbuf_bufctx(push, nv50->bufctx);
159 nouveau_pushbuf_validate(push);
160
161 offset &= ~0xff;
162
163 BEGIN_NV04(push, NV50_2D(DST_FORMAT), 2);
164 PUSH_DATA (push, NV50_SURFACE_FORMAT_R8_UNORM);
165 PUSH_DATA (push, 1);
166 BEGIN_NV04(push, NV50_2D(DST_PITCH), 5);
167 PUSH_DATA (push, 262144);
168 PUSH_DATA (push, 65536);
169 PUSH_DATA (push, 1);
170 PUSH_DATAh(push, dst->offset + offset);
171 PUSH_DATA (push, dst->offset + offset);
172 BEGIN_NV04(push, NV50_2D(SIFC_BITMAP_ENABLE), 2);
173 PUSH_DATA (push, 0);
174 PUSH_DATA (push, NV50_SURFACE_FORMAT_R8_UNORM);
175 BEGIN_NV04(push, NV50_2D(SIFC_WIDTH), 10);
176 PUSH_DATA (push, size);
177 PUSH_DATA (push, 1);
178 PUSH_DATA (push, 0);
179 PUSH_DATA (push, 1);
180 PUSH_DATA (push, 0);
181 PUSH_DATA (push, 1);
182 PUSH_DATA (push, 0);
183 PUSH_DATA (push, xcoord);
184 PUSH_DATA (push, 0);
185 PUSH_DATA (push, 0);
186
187 while (count) {
188 unsigned nr;
189
190 if (!PUSH_SPACE(push, 16))
191 break;
192 nr = PUSH_AVAIL(push);
193 assert(nr >= 16);
194 nr = MIN2(count, nr - 1);
195 nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN);
196
197 BEGIN_NI04(push, NV50_2D(SIFC_DATA), nr);
198 PUSH_DATAp(push, src, nr);
199
200 src += nr;
201 count -= nr;
202 }
203
204 nouveau_bufctx_reset(nv50->bufctx, 0);
205 }
206
207 void
208 nv50_m2mf_copy_linear(struct nouveau_context *nv,
209 struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom,
210 struct nouveau_bo *src, unsigned srcoff, unsigned srcdom,
211 unsigned size)
212 {
213 struct nouveau_pushbuf *push = nv->pushbuf;
214 struct nouveau_bufctx *bctx = nv50_context(&nv->pipe)->bufctx;
215
216 nouveau_bufctx_refn(bctx, 0, src, srcdom | NOUVEAU_BO_RD);
217 nouveau_bufctx_refn(bctx, 0, dst, dstdom | NOUVEAU_BO_WR);
218 nouveau_pushbuf_bufctx(push, bctx);
219 nouveau_pushbuf_validate(push);
220
221 BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 1);
222 PUSH_DATA (push, 1);
223 BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 1);
224 PUSH_DATA (push, 1);
225
226 while (size) {
227 unsigned bytes = MIN2(size, 1 << 17);
228
229 BEGIN_NV04(push, NV50_M2MF(OFFSET_IN_HIGH), 2);
230 PUSH_DATAh(push, src->offset + srcoff);
231 PUSH_DATAh(push, dst->offset + dstoff);
232 BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_OFFSET_IN), 2);
233 PUSH_DATA (push, src->offset + srcoff);
234 PUSH_DATA (push, dst->offset + dstoff);
235 BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_LINE_LENGTH_IN), 4);
236 PUSH_DATA (push, bytes);
237 PUSH_DATA (push, 1);
238 PUSH_DATA (push, (1 << 8) | (1 << 0));
239 PUSH_DATA (push, 0);
240
241 srcoff += bytes;
242 dstoff += bytes;
243 size -= bytes;
244 }
245
246 nouveau_bufctx_reset(bctx, 0);
247 }
248
249 void *
250 nv50_miptree_transfer_map(struct pipe_context *pctx,
251 struct pipe_resource *res,
252 unsigned level,
253 unsigned usage,
254 const struct pipe_box *box,
255 struct pipe_transfer **ptransfer)
256 {
257 struct nv50_screen *screen = nv50_screen(pctx->screen);
258 struct nv50_context *nv50 = nv50_context(pctx);
259 struct nouveau_device *dev = nv50->screen->base.device;
260 const struct nv50_miptree *mt = nv50_miptree(res);
261 struct nv50_transfer *tx;
262 uint32_t size;
263 int ret;
264 unsigned flags = 0;
265
266 if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
267 return NULL;
268
269 tx = CALLOC_STRUCT(nv50_transfer);
270 if (!tx)
271 return NULL;
272
273 pipe_resource_reference(&tx->base.resource, res);
274
275 tx->base.level = level;
276 tx->base.usage = usage;
277 tx->base.box = *box;
278
279 if (util_format_is_plain(res->format)) {
280 tx->nblocksx = box->width << mt->ms_x;
281 tx->nblocksy = box->height << mt->ms_x;
282 } else {
283 tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
284 tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
285 }
286
287 tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);
288 tx->base.layer_stride = tx->nblocksy * tx->base.stride;
289
290 nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z);
291
292 size = tx->base.layer_stride;
293
294 ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
295 size * tx->base.box.depth, NULL, &tx->rect[1].bo);
296 if (ret) {
297 FREE(tx);
298 return NULL;
299 }
300
301 tx->rect[1].cpp = tx->rect[0].cpp;
302 tx->rect[1].width = tx->nblocksx;
303 tx->rect[1].height = tx->nblocksy;
304 tx->rect[1].depth = 1;
305 tx->rect[1].pitch = tx->base.stride;
306 tx->rect[1].domain = NOUVEAU_BO_GART;
307
308 if (usage & PIPE_TRANSFER_READ) {
309 unsigned base = tx->rect[0].base;
310 unsigned z = tx->rect[0].z;
311 unsigned i;
312 for (i = 0; i < box->depth; ++i) {
313 nv50_m2mf_transfer_rect(nv50, &tx->rect[1], &tx->rect[0],
314 tx->nblocksx, tx->nblocksy);
315 if (mt->layout_3d)
316 tx->rect[0].z++;
317 else
318 tx->rect[0].base += mt->layer_stride;
319 tx->rect[1].base += size;
320 }
321 tx->rect[0].z = z;
322 tx->rect[0].base = base;
323 tx->rect[1].base = 0;
324 }
325
326 if (tx->rect[1].bo->map) {
327 *ptransfer = &tx->base;
328 return tx->rect[1].bo->map;
329 }
330
331 if (usage & PIPE_TRANSFER_READ)
332 flags = NOUVEAU_BO_RD;
333 if (usage & PIPE_TRANSFER_WRITE)
334 flags |= NOUVEAU_BO_WR;
335
336 ret = nouveau_bo_map(tx->rect[1].bo, flags, screen->base.client);
337 if (ret) {
338 nouveau_bo_ref(NULL, &tx->rect[1].bo);
339 FREE(tx);
340 return NULL;
341 }
342
343 *ptransfer = &tx->base;
344 return tx->rect[1].bo->map;
345 }
346
347 void
348 nv50_miptree_transfer_unmap(struct pipe_context *pctx,
349 struct pipe_transfer *transfer)
350 {
351 struct nv50_context *nv50 = nv50_context(pctx);
352 struct nv50_transfer *tx = (struct nv50_transfer *)transfer;
353 struct nv50_miptree *mt = nv50_miptree(tx->base.resource);
354 unsigned i;
355
356 if (tx->base.usage & PIPE_TRANSFER_WRITE) {
357 for (i = 0; i < tx->base.box.depth; ++i) {
358 nv50_m2mf_transfer_rect(nv50, &tx->rect[0], &tx->rect[1],
359 tx->nblocksx, tx->nblocksy);
360 if (mt->layout_3d)
361 tx->rect[0].z++;
362 else
363 tx->rect[0].base += mt->layer_stride;
364 tx->rect[1].base += tx->nblocksy * tx->base.stride;
365 }
366 }
367
368 nouveau_bo_ref(NULL, &tx->rect[1].bo);
369 pipe_resource_reference(&transfer->resource, NULL);
370
371 FREE(tx);
372 }
373
374 void
375 nv50_cb_push(struct nouveau_context *nv,
376 struct nouveau_bo *bo, unsigned domain,
377 unsigned base, unsigned size,
378 unsigned offset, unsigned words, const uint32_t *data)
379 {
380 struct nouveau_pushbuf *push = nv->pushbuf;
381 struct nouveau_bufctx *bctx = nv50_context(&nv->pipe)->bufctx;
382
383 assert(!(offset & 3));
384 size = align(size, 0x100);
385
386 nouveau_bufctx_refn(bctx, 0, bo, NOUVEAU_BO_WR | domain);
387 nouveau_pushbuf_bufctx(push, bctx);
388 nouveau_pushbuf_validate(push);
389
390 while (words) {
391 unsigned nr;
392
393 nr = PUSH_AVAIL(push);
394 nr = MIN2(nr - 7, words);
395 nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN - 1);
396
397 BEGIN_NV04(push, NV50_3D(CB_DEF_ADDRESS_HIGH), 3);
398 PUSH_DATAh(push, bo->offset + base);
399 PUSH_DATA (push, bo->offset + base);
400 PUSH_DATA (push, (NV50_CB_TMP << 16) | (size & 0xffff));
401 BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
402 PUSH_DATA (push, (offset << 6) | NV50_CB_TMP);
403 BEGIN_NI04(push, NV50_3D(CB_DATA(0)), nr);
404 PUSH_DATAp(push, data, nr);
405
406 words -= nr;
407 data += nr;
408 offset += nr * 4;
409 }
410
411 nouveau_bufctx_reset(bctx, 0);
412 }