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
nv50_m2mf_rect_setup(struct nv50_m2mf_rect * rect,struct pipe_resource * restrict res,unsigned l,unsigned x,unsigned y,unsigned z)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
nv50_m2mf_transfer_rect(struct nv50_context * nv50,const struct nv50_m2mf_rect * dst,const struct nv50_m2mf_rect * src,uint32_t nblocksx,uint32_t nblocksy)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
nv50_sifc_linear_u8(struct nouveau_context * nv,struct nouveau_bo * dst,unsigned offset,unsigned domain,unsigned size,const void * data)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
nv50_m2mf_copy_linear(struct nouveau_context * nv,struct nouveau_bo * dst,unsigned dstoff,unsigned dstdom,struct nouveau_bo * src,unsigned srcoff,unsigned srcdom,unsigned size)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 struct pipe_transfer *
nv50_miptree_transfer_new(struct pipe_context * pctx,struct pipe_resource * res,unsigned level,unsigned usage,const struct pipe_box * box)250 nv50_miptree_transfer_new(struct pipe_context *pctx,
251 struct pipe_resource *res,
252 unsigned level,
253 unsigned usage,
254 const struct pipe_box *box)
255 {
256 struct nv50_context *nv50 = nv50_context(pctx);
257 struct nouveau_device *dev = nv50->screen->base.device;
258 const struct nv50_miptree *mt = nv50_miptree(res);
259 struct nv50_transfer *tx;
260 uint32_t size;
261 int ret;
262
263 if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
264 return NULL;
265
266 tx = CALLOC_STRUCT(nv50_transfer);
267 if (!tx)
268 return NULL;
269
270 pipe_resource_reference(&tx->base.resource, res);
271
272 tx->base.level = level;
273 tx->base.usage = usage;
274 tx->base.box = *box;
275
276 if (util_format_is_plain(res->format)) {
277 tx->nblocksx = box->width << mt->ms_x;
278 tx->nblocksy = box->height << mt->ms_x;
279 } else {
280 tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
281 tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
282 }
283
284 tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);
285 tx->base.layer_stride = tx->nblocksy * tx->base.stride;
286
287 nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z);
288
289 size = tx->base.layer_stride;
290
291 ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
292 size * tx->base.box.depth, NULL, &tx->rect[1].bo);
293 if (ret) {
294 FREE(tx);
295 return NULL;
296 }
297
298 tx->rect[1].cpp = tx->rect[0].cpp;
299 tx->rect[1].width = tx->nblocksx;
300 tx->rect[1].height = tx->nblocksy;
301 tx->rect[1].depth = 1;
302 tx->rect[1].pitch = tx->base.stride;
303 tx->rect[1].domain = NOUVEAU_BO_GART;
304
305 if (usage & PIPE_TRANSFER_READ) {
306 unsigned base = tx->rect[0].base;
307 unsigned z = tx->rect[0].z;
308 unsigned i;
309 for (i = 0; i < box->depth; ++i) {
310 nv50_m2mf_transfer_rect(nv50, &tx->rect[1], &tx->rect[0],
311 tx->nblocksx, tx->nblocksy);
312 if (mt->layout_3d)
313 tx->rect[0].z++;
314 else
315 tx->rect[0].base += mt->layer_stride;
316 tx->rect[1].base += size;
317 }
318 tx->rect[0].z = z;
319 tx->rect[0].base = base;
320 tx->rect[1].base = 0;
321 }
322
323 return &tx->base;
324 }
325
326 void
nv50_miptree_transfer_del(struct pipe_context * pctx,struct pipe_transfer * transfer)327 nv50_miptree_transfer_del(struct pipe_context *pctx,
328 struct pipe_transfer *transfer)
329 {
330 struct nv50_context *nv50 = nv50_context(pctx);
331 struct nv50_transfer *tx = (struct nv50_transfer *)transfer;
332 struct nv50_miptree *mt = nv50_miptree(tx->base.resource);
333 unsigned i;
334
335 if (tx->base.usage & PIPE_TRANSFER_WRITE) {
336 for (i = 0; i < tx->base.box.depth; ++i) {
337 nv50_m2mf_transfer_rect(nv50, &tx->rect[0], &tx->rect[1],
338 tx->nblocksx, tx->nblocksy);
339 if (mt->layout_3d)
340 tx->rect[0].z++;
341 else
342 tx->rect[0].base += mt->layer_stride;
343 tx->rect[1].base += tx->nblocksy * tx->base.stride;
344 }
345 }
346
347 nouveau_bo_ref(NULL, &tx->rect[1].bo);
348 pipe_resource_reference(&transfer->resource, NULL);
349
350 FREE(tx);
351 }
352
353 void *
nv50_miptree_transfer_map(struct pipe_context * pctx,struct pipe_transfer * transfer)354 nv50_miptree_transfer_map(struct pipe_context *pctx,
355 struct pipe_transfer *transfer)
356 {
357 struct nv50_screen *screen = nv50_screen(pctx->screen);
358 struct nv50_transfer *tx = (struct nv50_transfer *)transfer;
359 int ret;
360 unsigned flags = 0;
361
362 if (tx->rect[1].bo->map)
363 return tx->rect[1].bo->map;
364
365 if (transfer->usage & PIPE_TRANSFER_READ)
366 flags = NOUVEAU_BO_RD;
367 if (transfer->usage & PIPE_TRANSFER_WRITE)
368 flags |= NOUVEAU_BO_WR;
369
370 ret = nouveau_bo_map(tx->rect[1].bo, flags, screen->base.client);
371 if (ret)
372 return NULL;
373 return tx->rect[1].bo->map;
374 }
375
376 void
nv50_miptree_transfer_unmap(struct pipe_context * pctx,struct pipe_transfer * transfer)377 nv50_miptree_transfer_unmap(struct pipe_context *pctx,
378 struct pipe_transfer *transfer)
379 {
380 /* nothing to do */
381 }
382
383 void
nv50_cb_push(struct nouveau_context * nv,struct nouveau_bo * bo,unsigned domain,unsigned base,unsigned size,unsigned offset,unsigned words,const uint32_t * data)384 nv50_cb_push(struct nouveau_context *nv,
385 struct nouveau_bo *bo, unsigned domain,
386 unsigned base, unsigned size,
387 unsigned offset, unsigned words, const uint32_t *data)
388 {
389 struct nouveau_pushbuf *push = nv->pushbuf;
390 struct nouveau_bufctx *bctx = nv50_context(&nv->pipe)->bufctx;
391
392 assert(!(offset & 3));
393 size = align(size, 0x100);
394
395 nouveau_bufctx_refn(bctx, 0, bo, NOUVEAU_BO_WR | domain);
396 nouveau_pushbuf_bufctx(push, bctx);
397 nouveau_pushbuf_validate(push);
398
399 while (words) {
400 unsigned nr;
401
402 nr = PUSH_AVAIL(push);
403 nr = MIN2(nr - 7, words);
404 nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN - 1);
405
406 BEGIN_NV04(push, NV50_3D(CB_DEF_ADDRESS_HIGH), 3);
407 PUSH_DATAh(push, bo->offset + base);
408 PUSH_DATA (push, bo->offset + base);
409 PUSH_DATA (push, (NV50_CB_TMP << 16) | (size & 0xffff));
410 BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
411 PUSH_DATA (push, (offset << 6) | NV50_CB_TMP);
412 BEGIN_NI04(push, NV50_3D(CB_DATA(0)), nr);
413 PUSH_DATAp(push, data, nr);
414
415 words -= nr;
416 data += nr;
417 offset += nr * 4;
418 }
419
420 nouveau_bufctx_reset(bctx, 0);
421 }
422