1bf215546Sopenharmony_ci
2bf215546Sopenharmony_ci#include "util/format/u_format.h"
3bf215546Sopenharmony_ci
4bf215546Sopenharmony_ci#include "nv50/nv50_context.h"
5bf215546Sopenharmony_ci
6bf215546Sopenharmony_ci#include "nv50/g80_defs.xml.h"
7bf215546Sopenharmony_ci
8bf215546Sopenharmony_cistruct nv50_transfer {
9bf215546Sopenharmony_ci   struct pipe_transfer base;
10bf215546Sopenharmony_ci   struct nv50_m2mf_rect rect[2];
11bf215546Sopenharmony_ci   uint32_t nblocksx;
12bf215546Sopenharmony_ci   uint32_t nblocksy;
13bf215546Sopenharmony_ci};
14bf215546Sopenharmony_ci
15bf215546Sopenharmony_civoid
16bf215546Sopenharmony_cinv50_m2mf_rect_setup(struct nv50_m2mf_rect *rect,
17bf215546Sopenharmony_ci                     struct pipe_resource *restrict res, unsigned l,
18bf215546Sopenharmony_ci                     unsigned x, unsigned y, unsigned z)
19bf215546Sopenharmony_ci{
20bf215546Sopenharmony_ci   struct nv50_miptree *mt = nv50_miptree(res);
21bf215546Sopenharmony_ci   const unsigned w = u_minify(res->width0, l);
22bf215546Sopenharmony_ci   const unsigned h = u_minify(res->height0, l);
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci   rect->bo = mt->base.bo;
25bf215546Sopenharmony_ci   rect->domain = mt->base.domain;
26bf215546Sopenharmony_ci   rect->base = mt->level[l].offset;
27bf215546Sopenharmony_ci   if (mt->base.bo->offset != mt->base.address)
28bf215546Sopenharmony_ci      rect->base += mt->base.address - mt->base.bo->offset;
29bf215546Sopenharmony_ci   rect->pitch = mt->level[l].pitch;
30bf215546Sopenharmony_ci   if (util_format_is_plain(res->format)) {
31bf215546Sopenharmony_ci      rect->width = w << mt->ms_x;
32bf215546Sopenharmony_ci      rect->height = h << mt->ms_y;
33bf215546Sopenharmony_ci      rect->x = x << mt->ms_x;
34bf215546Sopenharmony_ci      rect->y = y << mt->ms_y;
35bf215546Sopenharmony_ci   } else {
36bf215546Sopenharmony_ci      rect->width = util_format_get_nblocksx(res->format, w);
37bf215546Sopenharmony_ci      rect->height = util_format_get_nblocksy(res->format, h);
38bf215546Sopenharmony_ci      rect->x = util_format_get_nblocksx(res->format, x);
39bf215546Sopenharmony_ci      rect->y = util_format_get_nblocksy(res->format, y);
40bf215546Sopenharmony_ci   }
41bf215546Sopenharmony_ci   rect->tile_mode = mt->level[l].tile_mode;
42bf215546Sopenharmony_ci   rect->cpp = util_format_get_blocksize(res->format);
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci   if (mt->layout_3d) {
45bf215546Sopenharmony_ci      rect->z = z;
46bf215546Sopenharmony_ci      rect->depth = u_minify(res->depth0, l);
47bf215546Sopenharmony_ci   } else {
48bf215546Sopenharmony_ci      rect->base += z * mt->layer_stride;
49bf215546Sopenharmony_ci      rect->z = 0;
50bf215546Sopenharmony_ci      rect->depth = 1;
51bf215546Sopenharmony_ci   }
52bf215546Sopenharmony_ci}
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci/* This is very similar to nv50_2d_texture_do_copy, but doesn't require
55bf215546Sopenharmony_ci * miptree objects. Maybe refactor? Although it's not straightforward.
56bf215546Sopenharmony_ci */
57bf215546Sopenharmony_cistatic void
58bf215546Sopenharmony_cinv50_2d_transfer_rect(struct nv50_context *nv50,
59bf215546Sopenharmony_ci                      const struct nv50_m2mf_rect *dst,
60bf215546Sopenharmony_ci                      const struct nv50_m2mf_rect *src,
61bf215546Sopenharmony_ci                      uint32_t nblocksx, uint32_t nblocksy)
62bf215546Sopenharmony_ci{
63bf215546Sopenharmony_ci   struct nouveau_pushbuf *push = nv50->base.pushbuf;
64bf215546Sopenharmony_ci   struct nouveau_bufctx *bctx = nv50->bufctx;
65bf215546Sopenharmony_ci   const int cpp = dst->cpp;
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD);
68bf215546Sopenharmony_ci   nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR);
69bf215546Sopenharmony_ci   nouveau_pushbuf_bufctx(push, bctx);
70bf215546Sopenharmony_ci   nouveau_pushbuf_validate(push);
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   uint32_t format;
73bf215546Sopenharmony_ci   switch (cpp) {
74bf215546Sopenharmony_ci   case 1:
75bf215546Sopenharmony_ci      format = G80_SURFACE_FORMAT_R8_UNORM;
76bf215546Sopenharmony_ci      break;
77bf215546Sopenharmony_ci   case 2:
78bf215546Sopenharmony_ci      format = G80_SURFACE_FORMAT_R16_UNORM;
79bf215546Sopenharmony_ci      break;
80bf215546Sopenharmony_ci   case 4:
81bf215546Sopenharmony_ci      format = G80_SURFACE_FORMAT_BGRA8_UNORM;
82bf215546Sopenharmony_ci      break;
83bf215546Sopenharmony_ci   case 8:
84bf215546Sopenharmony_ci      format = G80_SURFACE_FORMAT_RGBA16_FLOAT;
85bf215546Sopenharmony_ci      break;
86bf215546Sopenharmony_ci   case 16:
87bf215546Sopenharmony_ci      format = G80_SURFACE_FORMAT_RGBA32_FLOAT;
88bf215546Sopenharmony_ci      break;
89bf215546Sopenharmony_ci   default:
90bf215546Sopenharmony_ci      assert(!"Unexpected cpp");
91bf215546Sopenharmony_ci      format = G80_SURFACE_FORMAT_R8_UNORM;
92bf215546Sopenharmony_ci   }
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   if (nouveau_bo_memtype(src->bo)) {
95bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_2D(SRC_FORMAT), 5);
96bf215546Sopenharmony_ci      PUSH_DATA (push, format);
97bf215546Sopenharmony_ci      PUSH_DATA (push, 0);
98bf215546Sopenharmony_ci      PUSH_DATA (push, src->tile_mode);
99bf215546Sopenharmony_ci      PUSH_DATA (push, src->depth);
100bf215546Sopenharmony_ci      PUSH_DATA (push, src->z);
101bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_2D(SRC_WIDTH), 4);
102bf215546Sopenharmony_ci      PUSH_DATA (push, src->width);
103bf215546Sopenharmony_ci      PUSH_DATA (push, src->height);
104bf215546Sopenharmony_ci      PUSH_DATAh(push, src->bo->offset + src->base);
105bf215546Sopenharmony_ci      PUSH_DATA (push, src->bo->offset + src->base);
106bf215546Sopenharmony_ci   } else {
107bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_2D(SRC_FORMAT), 2);
108bf215546Sopenharmony_ci      PUSH_DATA (push, format);
109bf215546Sopenharmony_ci      PUSH_DATA (push, 1);
110bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_2D(SRC_PITCH), 5);
111bf215546Sopenharmony_ci      PUSH_DATA (push, src->pitch);
112bf215546Sopenharmony_ci      PUSH_DATA (push, src->width);
113bf215546Sopenharmony_ci      PUSH_DATA (push, src->height);
114bf215546Sopenharmony_ci      PUSH_DATAh(push, src->bo->offset + src->base);
115bf215546Sopenharmony_ci      PUSH_DATA (push, src->bo->offset + src->base);
116bf215546Sopenharmony_ci   }
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   if (nouveau_bo_memtype(dst->bo)) {
119bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_2D(DST_FORMAT), 5);
120bf215546Sopenharmony_ci      PUSH_DATA (push, format);
121bf215546Sopenharmony_ci      PUSH_DATA (push, 0);
122bf215546Sopenharmony_ci      PUSH_DATA (push, dst->tile_mode);
123bf215546Sopenharmony_ci      PUSH_DATA (push, dst->depth);
124bf215546Sopenharmony_ci      PUSH_DATA (push, dst->z);
125bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_2D(DST_WIDTH), 4);
126bf215546Sopenharmony_ci      PUSH_DATA (push, dst->width);
127bf215546Sopenharmony_ci      PUSH_DATA (push, dst->height);
128bf215546Sopenharmony_ci      PUSH_DATAh(push, dst->bo->offset + dst->base);
129bf215546Sopenharmony_ci      PUSH_DATA (push, dst->bo->offset + dst->base);
130bf215546Sopenharmony_ci   } else {
131bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_2D(DST_FORMAT), 2);
132bf215546Sopenharmony_ci      PUSH_DATA (push, format);
133bf215546Sopenharmony_ci      PUSH_DATA (push, 1);
134bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_2D(DST_PITCH), 5);
135bf215546Sopenharmony_ci      PUSH_DATA (push, dst->pitch);
136bf215546Sopenharmony_ci      PUSH_DATA (push, dst->width);
137bf215546Sopenharmony_ci      PUSH_DATA (push, dst->height);
138bf215546Sopenharmony_ci      PUSH_DATAh(push, dst->bo->offset + dst->base);
139bf215546Sopenharmony_ci      PUSH_DATA (push, dst->bo->offset + dst->base);
140bf215546Sopenharmony_ci   }
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_2D(BLIT_CONTROL), 1);
143bf215546Sopenharmony_ci   PUSH_DATA (push, NV50_2D_BLIT_CONTROL_FILTER_POINT_SAMPLE);
144bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_2D(BLIT_DST_X), 4);
145bf215546Sopenharmony_ci   PUSH_DATA (push, dst->x);
146bf215546Sopenharmony_ci   PUSH_DATA (push, dst->y);
147bf215546Sopenharmony_ci   PUSH_DATA (push, nblocksx);
148bf215546Sopenharmony_ci   PUSH_DATA (push, nblocksy);
149bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_2D(BLIT_DU_DX_FRACT), 4);
150bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
151bf215546Sopenharmony_ci   PUSH_DATA (push, 1);
152bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
153bf215546Sopenharmony_ci   PUSH_DATA (push, 1);
154bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_2D(BLIT_SRC_X_FRACT), 4);
155bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
156bf215546Sopenharmony_ci   PUSH_DATA (push, src->x);
157bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
158bf215546Sopenharmony_ci   PUSH_DATA (push, src->y);
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   nouveau_bufctx_reset(bctx, 0);
161bf215546Sopenharmony_ci}
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_civoid
164bf215546Sopenharmony_cinv50_m2mf_transfer_rect(struct nv50_context *nv50,
165bf215546Sopenharmony_ci                        const struct nv50_m2mf_rect *dst,
166bf215546Sopenharmony_ci                        const struct nv50_m2mf_rect *src,
167bf215546Sopenharmony_ci                        uint32_t nblocksx, uint32_t nblocksy)
168bf215546Sopenharmony_ci{
169bf215546Sopenharmony_ci   struct nouveau_pushbuf *push = nv50->base.pushbuf;
170bf215546Sopenharmony_ci   struct nouveau_bufctx *bctx = nv50->bufctx;
171bf215546Sopenharmony_ci   const int cpp = dst->cpp;
172bf215546Sopenharmony_ci   uint32_t src_ofst = src->base;
173bf215546Sopenharmony_ci   uint32_t dst_ofst = dst->base;
174bf215546Sopenharmony_ci   uint32_t height = nblocksy;
175bf215546Sopenharmony_ci   uint32_t sy = src->y;
176bf215546Sopenharmony_ci   uint32_t dy = dst->y;
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci   assert(dst->cpp == src->cpp);
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   /* Workaround: M2MF appears to break at the 64k boundary for tiled
181bf215546Sopenharmony_ci    * textures, which can really only happen with RGBA32 formats.
182bf215546Sopenharmony_ci    */
183bf215546Sopenharmony_ci   bool eng2d = false;
184bf215546Sopenharmony_ci   if (nouveau_bo_memtype(src->bo)) {
185bf215546Sopenharmony_ci      if (src->width * cpp > 65536)
186bf215546Sopenharmony_ci         eng2d = true;
187bf215546Sopenharmony_ci   }
188bf215546Sopenharmony_ci   if (nouveau_bo_memtype(dst->bo)) {
189bf215546Sopenharmony_ci      if (dst->width * cpp > 65536)
190bf215546Sopenharmony_ci         eng2d = true;
191bf215546Sopenharmony_ci   }
192bf215546Sopenharmony_ci   if (eng2d) {
193bf215546Sopenharmony_ci      nv50_2d_transfer_rect(nv50, dst, src, nblocksx, nblocksy);
194bf215546Sopenharmony_ci      return;
195bf215546Sopenharmony_ci   }
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci   nouveau_bufctx_refn(bctx, 0, src->bo, src->domain | NOUVEAU_BO_RD);
198bf215546Sopenharmony_ci   nouveau_bufctx_refn(bctx, 0, dst->bo, dst->domain | NOUVEAU_BO_WR);
199bf215546Sopenharmony_ci   nouveau_pushbuf_bufctx(push, bctx);
200bf215546Sopenharmony_ci   nouveau_pushbuf_validate(push);
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   if (nouveau_bo_memtype(src->bo)) {
203bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 6);
204bf215546Sopenharmony_ci      PUSH_DATA (push, 0);
205bf215546Sopenharmony_ci      PUSH_DATA (push, src->tile_mode);
206bf215546Sopenharmony_ci      PUSH_DATA (push, src->width * cpp);
207bf215546Sopenharmony_ci      PUSH_DATA (push, src->height);
208bf215546Sopenharmony_ci      PUSH_DATA (push, src->depth);
209bf215546Sopenharmony_ci      PUSH_DATA (push, src->z);
210bf215546Sopenharmony_ci   } else {
211bf215546Sopenharmony_ci      src_ofst += src->y * src->pitch + src->x * cpp;
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 1);
214bf215546Sopenharmony_ci      PUSH_DATA (push, 1);
215bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_PITCH_IN), 1);
216bf215546Sopenharmony_ci      PUSH_DATA (push, src->pitch);
217bf215546Sopenharmony_ci   }
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci   if (nouveau_bo_memtype(dst->bo)) {
220bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 6);
221bf215546Sopenharmony_ci      PUSH_DATA (push, 0);
222bf215546Sopenharmony_ci      PUSH_DATA (push, dst->tile_mode);
223bf215546Sopenharmony_ci      PUSH_DATA (push, dst->width * cpp);
224bf215546Sopenharmony_ci      PUSH_DATA (push, dst->height);
225bf215546Sopenharmony_ci      PUSH_DATA (push, dst->depth);
226bf215546Sopenharmony_ci      PUSH_DATA (push, dst->z);
227bf215546Sopenharmony_ci   } else {
228bf215546Sopenharmony_ci      dst_ofst += dst->y * dst->pitch + dst->x * cpp;
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 1);
231bf215546Sopenharmony_ci      PUSH_DATA (push, 1);
232bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_PITCH_OUT), 1);
233bf215546Sopenharmony_ci      PUSH_DATA (push, dst->pitch);
234bf215546Sopenharmony_ci   }
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   while (height) {
237bf215546Sopenharmony_ci      int line_count = height > 2047 ? 2047 : height;
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_M2MF(OFFSET_IN_HIGH), 2);
240bf215546Sopenharmony_ci      PUSH_DATAh(push, src->bo->offset + src_ofst);
241bf215546Sopenharmony_ci      PUSH_DATAh(push, dst->bo->offset + dst_ofst);
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_OFFSET_IN), 2);
244bf215546Sopenharmony_ci      PUSH_DATA (push, src->bo->offset + src_ofst);
245bf215546Sopenharmony_ci      PUSH_DATA (push, dst->bo->offset + dst_ofst);
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci      if (nouveau_bo_memtype(src->bo)) {
248bf215546Sopenharmony_ci         BEGIN_NV04(push, NV50_M2MF(TILING_POSITION_IN), 1);
249bf215546Sopenharmony_ci         PUSH_DATA (push, (sy << 16) | (src->x * cpp));
250bf215546Sopenharmony_ci      } else {
251bf215546Sopenharmony_ci         src_ofst += line_count * src->pitch;
252bf215546Sopenharmony_ci      }
253bf215546Sopenharmony_ci      if (nouveau_bo_memtype(dst->bo)) {
254bf215546Sopenharmony_ci         BEGIN_NV04(push, NV50_M2MF(TILING_POSITION_OUT), 1);
255bf215546Sopenharmony_ci         PUSH_DATA (push, (dy << 16) | (dst->x * cpp));
256bf215546Sopenharmony_ci      } else {
257bf215546Sopenharmony_ci         dst_ofst += line_count * dst->pitch;
258bf215546Sopenharmony_ci      }
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_LINE_LENGTH_IN), 4);
261bf215546Sopenharmony_ci      PUSH_DATA (push, nblocksx * cpp);
262bf215546Sopenharmony_ci      PUSH_DATA (push, line_count);
263bf215546Sopenharmony_ci      PUSH_DATA (push, (1 << 8) | (1 << 0));
264bf215546Sopenharmony_ci      PUSH_DATA (push, 0);
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci      height -= line_count;
267bf215546Sopenharmony_ci      sy += line_count;
268bf215546Sopenharmony_ci      dy += line_count;
269bf215546Sopenharmony_ci   }
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   nouveau_bufctx_reset(bctx, 0);
272bf215546Sopenharmony_ci}
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_civoid
275bf215546Sopenharmony_cinv50_sifc_linear_u8(struct nouveau_context *nv,
276bf215546Sopenharmony_ci                    struct nouveau_bo *dst, unsigned offset, unsigned domain,
277bf215546Sopenharmony_ci                    unsigned size, const void *data)
278bf215546Sopenharmony_ci{
279bf215546Sopenharmony_ci   struct nv50_context *nv50 = nv50_context(&nv->pipe);
280bf215546Sopenharmony_ci   struct nouveau_pushbuf *push = nv50->base.pushbuf;
281bf215546Sopenharmony_ci   uint32_t *src = (uint32_t *)data;
282bf215546Sopenharmony_ci   unsigned count = (size + 3) / 4;
283bf215546Sopenharmony_ci   unsigned xcoord = offset & 0xff;
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci   nouveau_bufctx_refn(nv50->bufctx, 0, dst, domain | NOUVEAU_BO_WR);
286bf215546Sopenharmony_ci   nouveau_pushbuf_bufctx(push, nv50->bufctx);
287bf215546Sopenharmony_ci   nouveau_pushbuf_validate(push);
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   offset &= ~0xff;
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_2D(DST_FORMAT), 2);
292bf215546Sopenharmony_ci   PUSH_DATA (push, G80_SURFACE_FORMAT_R8_UNORM);
293bf215546Sopenharmony_ci   PUSH_DATA (push, 1);
294bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_2D(DST_PITCH), 5);
295bf215546Sopenharmony_ci   PUSH_DATA (push, 262144);
296bf215546Sopenharmony_ci   PUSH_DATA (push, 65536);
297bf215546Sopenharmony_ci   PUSH_DATA (push, 1);
298bf215546Sopenharmony_ci   PUSH_DATAh(push, dst->offset + offset);
299bf215546Sopenharmony_ci   PUSH_DATA (push, dst->offset + offset);
300bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_2D(SIFC_BITMAP_ENABLE), 2);
301bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
302bf215546Sopenharmony_ci   PUSH_DATA (push, G80_SURFACE_FORMAT_R8_UNORM);
303bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_2D(SIFC_WIDTH), 10);
304bf215546Sopenharmony_ci   PUSH_DATA (push, size);
305bf215546Sopenharmony_ci   PUSH_DATA (push, 1);
306bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
307bf215546Sopenharmony_ci   PUSH_DATA (push, 1);
308bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
309bf215546Sopenharmony_ci   PUSH_DATA (push, 1);
310bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
311bf215546Sopenharmony_ci   PUSH_DATA (push, xcoord);
312bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
313bf215546Sopenharmony_ci   PUSH_DATA (push, 0);
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   while (count) {
316bf215546Sopenharmony_ci      unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci      BEGIN_NI04(push, NV50_2D(SIFC_DATA), nr);
319bf215546Sopenharmony_ci      PUSH_DATAp(push, src, nr);
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci      src += nr;
322bf215546Sopenharmony_ci      count -= nr;
323bf215546Sopenharmony_ci   }
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ci   nouveau_bufctx_reset(nv50->bufctx, 0);
326bf215546Sopenharmony_ci}
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_civoid
329bf215546Sopenharmony_cinv50_m2mf_copy_linear(struct nouveau_context *nv,
330bf215546Sopenharmony_ci                      struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom,
331bf215546Sopenharmony_ci                      struct nouveau_bo *src, unsigned srcoff, unsigned srcdom,
332bf215546Sopenharmony_ci                      unsigned size)
333bf215546Sopenharmony_ci{
334bf215546Sopenharmony_ci   struct nouveau_pushbuf *push = nv->pushbuf;
335bf215546Sopenharmony_ci   struct nouveau_bufctx *bctx = nv50_context(&nv->pipe)->bufctx;
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci   nouveau_bufctx_refn(bctx, 0, src, srcdom | NOUVEAU_BO_RD);
338bf215546Sopenharmony_ci   nouveau_bufctx_refn(bctx, 0, dst, dstdom | NOUVEAU_BO_WR);
339bf215546Sopenharmony_ci   nouveau_pushbuf_bufctx(push, bctx);
340bf215546Sopenharmony_ci   nouveau_pushbuf_validate(push);
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 1);
343bf215546Sopenharmony_ci   PUSH_DATA (push, 1);
344bf215546Sopenharmony_ci   BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 1);
345bf215546Sopenharmony_ci   PUSH_DATA (push, 1);
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   while (size) {
348bf215546Sopenharmony_ci      unsigned bytes = MIN2(size, 1 << 17);
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_M2MF(OFFSET_IN_HIGH), 2);
351bf215546Sopenharmony_ci      PUSH_DATAh(push, src->offset + srcoff);
352bf215546Sopenharmony_ci      PUSH_DATAh(push, dst->offset + dstoff);
353bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_OFFSET_IN), 2);
354bf215546Sopenharmony_ci      PUSH_DATA (push, src->offset + srcoff);
355bf215546Sopenharmony_ci      PUSH_DATA (push, dst->offset + dstoff);
356bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_M2MF(NV03_M2MF_LINE_LENGTH_IN), 4);
357bf215546Sopenharmony_ci      PUSH_DATA (push, bytes);
358bf215546Sopenharmony_ci      PUSH_DATA (push, 1);
359bf215546Sopenharmony_ci      PUSH_DATA (push, (1 << 8) | (1 << 0));
360bf215546Sopenharmony_ci      PUSH_DATA (push, 0);
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci      srcoff += bytes;
363bf215546Sopenharmony_ci      dstoff += bytes;
364bf215546Sopenharmony_ci      size -= bytes;
365bf215546Sopenharmony_ci   }
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci   nouveau_bufctx_reset(bctx, 0);
368bf215546Sopenharmony_ci}
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_civoid *
371bf215546Sopenharmony_cinv50_miptree_transfer_map(struct pipe_context *pctx,
372bf215546Sopenharmony_ci                          struct pipe_resource *res,
373bf215546Sopenharmony_ci                          unsigned level,
374bf215546Sopenharmony_ci                          unsigned usage,
375bf215546Sopenharmony_ci                          const struct pipe_box *box,
376bf215546Sopenharmony_ci                          struct pipe_transfer **ptransfer)
377bf215546Sopenharmony_ci{
378bf215546Sopenharmony_ci   struct nv50_context *nv50 = nv50_context(pctx);
379bf215546Sopenharmony_ci   struct nouveau_device *dev = nv50->screen->base.device;
380bf215546Sopenharmony_ci   const struct nv50_miptree *mt = nv50_miptree(res);
381bf215546Sopenharmony_ci   struct nv50_transfer *tx;
382bf215546Sopenharmony_ci   uint32_t size;
383bf215546Sopenharmony_ci   int ret;
384bf215546Sopenharmony_ci   unsigned flags = 0;
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   if (usage & PIPE_MAP_DIRECTLY)
387bf215546Sopenharmony_ci      return NULL;
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci   tx = CALLOC_STRUCT(nv50_transfer);
390bf215546Sopenharmony_ci   if (!tx)
391bf215546Sopenharmony_ci      return NULL;
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci   pipe_resource_reference(&tx->base.resource, res);
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_ci   tx->base.level = level;
396bf215546Sopenharmony_ci   tx->base.usage = usage;
397bf215546Sopenharmony_ci   tx->base.box = *box;
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_ci   if (util_format_is_plain(res->format)) {
400bf215546Sopenharmony_ci      tx->nblocksx = box->width << mt->ms_x;
401bf215546Sopenharmony_ci      tx->nblocksy = box->height << mt->ms_y;
402bf215546Sopenharmony_ci   } else {
403bf215546Sopenharmony_ci      tx->nblocksx = util_format_get_nblocksx(res->format, box->width);
404bf215546Sopenharmony_ci      tx->nblocksy = util_format_get_nblocksy(res->format, box->height);
405bf215546Sopenharmony_ci   }
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci   tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format);
408bf215546Sopenharmony_ci   tx->base.layer_stride = tx->nblocksy * tx->base.stride;
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_ci   nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z);
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci   size = tx->base.layer_stride;
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
415bf215546Sopenharmony_ci                        size * tx->base.box.depth, NULL, &tx->rect[1].bo);
416bf215546Sopenharmony_ci   if (ret) {
417bf215546Sopenharmony_ci      FREE(tx);
418bf215546Sopenharmony_ci      return NULL;
419bf215546Sopenharmony_ci   }
420bf215546Sopenharmony_ci
421bf215546Sopenharmony_ci   tx->rect[1].cpp = tx->rect[0].cpp;
422bf215546Sopenharmony_ci   tx->rect[1].width = tx->nblocksx;
423bf215546Sopenharmony_ci   tx->rect[1].height = tx->nblocksy;
424bf215546Sopenharmony_ci   tx->rect[1].depth = 1;
425bf215546Sopenharmony_ci   tx->rect[1].pitch = tx->base.stride;
426bf215546Sopenharmony_ci   tx->rect[1].domain = NOUVEAU_BO_GART;
427bf215546Sopenharmony_ci
428bf215546Sopenharmony_ci   if (usage & PIPE_MAP_READ) {
429bf215546Sopenharmony_ci      unsigned base = tx->rect[0].base;
430bf215546Sopenharmony_ci      unsigned z = tx->rect[0].z;
431bf215546Sopenharmony_ci      unsigned i;
432bf215546Sopenharmony_ci      for (i = 0; i < box->depth; ++i) {
433bf215546Sopenharmony_ci         nv50_m2mf_transfer_rect(nv50, &tx->rect[1], &tx->rect[0],
434bf215546Sopenharmony_ci                                 tx->nblocksx, tx->nblocksy);
435bf215546Sopenharmony_ci         if (mt->layout_3d)
436bf215546Sopenharmony_ci            tx->rect[0].z++;
437bf215546Sopenharmony_ci         else
438bf215546Sopenharmony_ci            tx->rect[0].base += mt->layer_stride;
439bf215546Sopenharmony_ci         tx->rect[1].base += size;
440bf215546Sopenharmony_ci      }
441bf215546Sopenharmony_ci      tx->rect[0].z = z;
442bf215546Sopenharmony_ci      tx->rect[0].base = base;
443bf215546Sopenharmony_ci      tx->rect[1].base = 0;
444bf215546Sopenharmony_ci   }
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci   if (tx->rect[1].bo->map) {
447bf215546Sopenharmony_ci      *ptransfer = &tx->base;
448bf215546Sopenharmony_ci      return tx->rect[1].bo->map;
449bf215546Sopenharmony_ci   }
450bf215546Sopenharmony_ci
451bf215546Sopenharmony_ci   if (usage & PIPE_MAP_READ)
452bf215546Sopenharmony_ci      flags = NOUVEAU_BO_RD;
453bf215546Sopenharmony_ci   if (usage & PIPE_MAP_WRITE)
454bf215546Sopenharmony_ci      flags |= NOUVEAU_BO_WR;
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   ret = nouveau_bo_map(tx->rect[1].bo, flags, nv50->base.client);
457bf215546Sopenharmony_ci   if (ret) {
458bf215546Sopenharmony_ci      nouveau_bo_ref(NULL, &tx->rect[1].bo);
459bf215546Sopenharmony_ci      FREE(tx);
460bf215546Sopenharmony_ci      return NULL;
461bf215546Sopenharmony_ci   }
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci   *ptransfer = &tx->base;
464bf215546Sopenharmony_ci   return tx->rect[1].bo->map;
465bf215546Sopenharmony_ci}
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_civoid
468bf215546Sopenharmony_cinv50_miptree_transfer_unmap(struct pipe_context *pctx,
469bf215546Sopenharmony_ci                            struct pipe_transfer *transfer)
470bf215546Sopenharmony_ci{
471bf215546Sopenharmony_ci   struct nv50_context *nv50 = nv50_context(pctx);
472bf215546Sopenharmony_ci   struct nv50_transfer *tx = (struct nv50_transfer *)transfer;
473bf215546Sopenharmony_ci   struct nv50_miptree *mt = nv50_miptree(tx->base.resource);
474bf215546Sopenharmony_ci   unsigned i;
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ci   if (tx->base.usage & PIPE_MAP_WRITE) {
477bf215546Sopenharmony_ci      for (i = 0; i < tx->base.box.depth; ++i) {
478bf215546Sopenharmony_ci         nv50_m2mf_transfer_rect(nv50, &tx->rect[0], &tx->rect[1],
479bf215546Sopenharmony_ci                                 tx->nblocksx, tx->nblocksy);
480bf215546Sopenharmony_ci         if (mt->layout_3d)
481bf215546Sopenharmony_ci            tx->rect[0].z++;
482bf215546Sopenharmony_ci         else
483bf215546Sopenharmony_ci            tx->rect[0].base += mt->layer_stride;
484bf215546Sopenharmony_ci         tx->rect[1].base += tx->nblocksy * tx->base.stride;
485bf215546Sopenharmony_ci      }
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci      /* Allow the copies above to finish executing before freeing the source */
488bf215546Sopenharmony_ci      nouveau_fence_work(nv50->screen->base.fence.current,
489bf215546Sopenharmony_ci                         nouveau_fence_unref_bo, tx->rect[1].bo);
490bf215546Sopenharmony_ci   } else {
491bf215546Sopenharmony_ci      nouveau_bo_ref(NULL, &tx->rect[1].bo);
492bf215546Sopenharmony_ci   }
493bf215546Sopenharmony_ci
494bf215546Sopenharmony_ci   pipe_resource_reference(&transfer->resource, NULL);
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci   FREE(tx);
497bf215546Sopenharmony_ci}
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_cistatic void
500bf215546Sopenharmony_cinv50_cb_bo_push(struct nouveau_context *nv,
501bf215546Sopenharmony_ci                struct nouveau_bo *bo, unsigned domain,
502bf215546Sopenharmony_ci                unsigned bufid,
503bf215546Sopenharmony_ci                unsigned offset, unsigned words,
504bf215546Sopenharmony_ci                const uint32_t *data)
505bf215546Sopenharmony_ci{
506bf215546Sopenharmony_ci   struct nouveau_pushbuf *push = nv->pushbuf;
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci   assert(!(offset & 3));
509bf215546Sopenharmony_ci
510bf215546Sopenharmony_ci   while (words) {
511bf215546Sopenharmony_ci      unsigned nr = MIN2(words, NV04_PFIFO_MAX_PACKET_LEN);
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci      PUSH_SPACE(push, nr + 3);
514bf215546Sopenharmony_ci      PUSH_REFN (push, bo, NOUVEAU_BO_WR | domain);
515bf215546Sopenharmony_ci      BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
516bf215546Sopenharmony_ci      PUSH_DATA (push, (offset << 6) | bufid);
517bf215546Sopenharmony_ci      BEGIN_NI04(push, NV50_3D(CB_DATA(0)), nr);
518bf215546Sopenharmony_ci      PUSH_DATAp(push, data, nr);
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci      words -= nr;
521bf215546Sopenharmony_ci      data += nr;
522bf215546Sopenharmony_ci      offset += nr * 4;
523bf215546Sopenharmony_ci   }
524bf215546Sopenharmony_ci}
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_civoid
527bf215546Sopenharmony_cinv50_cb_push(struct nouveau_context *nv,
528bf215546Sopenharmony_ci             struct nv04_resource *res,
529bf215546Sopenharmony_ci             unsigned offset, unsigned words, const uint32_t *data)
530bf215546Sopenharmony_ci{
531bf215546Sopenharmony_ci   struct nv50_context *nv50 = nv50_context(&nv->pipe);
532bf215546Sopenharmony_ci   struct nv50_constbuf *cb = NULL;
533bf215546Sopenharmony_ci   int s, bufid;
534bf215546Sopenharmony_ci   /* Go through all the constbuf binding points of this buffer and try to
535bf215546Sopenharmony_ci    * find one which contains the region to be updated.
536bf215546Sopenharmony_ci    */
537bf215546Sopenharmony_ci   for (s = 0; s < NV50_MAX_SHADER_STAGES && !cb; s++) {
538bf215546Sopenharmony_ci      uint16_t bindings = res->cb_bindings[s];
539bf215546Sopenharmony_ci      while (bindings) {
540bf215546Sopenharmony_ci         int i = ffs(bindings) - 1;
541bf215546Sopenharmony_ci         uint32_t cb_offset = nv50->constbuf[s][i].offset;
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_ci         bindings &= ~(1 << i);
544bf215546Sopenharmony_ci         if (cb_offset <= offset &&
545bf215546Sopenharmony_ci             cb_offset + nv50->constbuf[s][i].size >= offset + words * 4) {
546bf215546Sopenharmony_ci            cb = &nv50->constbuf[s][i];
547bf215546Sopenharmony_ci            bufid = s * 16 + i;
548bf215546Sopenharmony_ci            break;
549bf215546Sopenharmony_ci         }
550bf215546Sopenharmony_ci      }
551bf215546Sopenharmony_ci   }
552bf215546Sopenharmony_ci
553bf215546Sopenharmony_ci   if (cb) {
554bf215546Sopenharmony_ci      nv50_cb_bo_push(nv, res->bo, res->domain,
555bf215546Sopenharmony_ci                      bufid, offset - cb->offset, words, data);
556bf215546Sopenharmony_ci   } else {
557bf215546Sopenharmony_ci      nv->push_data(nv, res->bo, res->offset + offset, res->domain,
558bf215546Sopenharmony_ci                    words * 4, data);
559bf215546Sopenharmony_ci   }
560bf215546Sopenharmony_ci}
561