1/*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 *
24 */
25
26#define XFER_ARGS                                                              \
27   struct nv30_context *nv30, enum nv30_transfer_filter filter,                \
28   struct nv30_rect *src, struct nv30_rect *dst
29
30#include "util/u_math.h"
31
32#include "nv_object.xml.h"
33#include "nv_m2mf.xml.h"
34#include "nv30/nv01_2d.xml.h"
35#include "nv30/nv30-40_3d.xml.h"
36
37#include "nv30/nv30_context.h"
38#include "nv30/nv30_transfer.h"
39
40/* Various helper functions to transfer different types of data in a number
41 * of different ways.
42 */
43
44static inline bool
45nv30_transfer_scaled(struct nv30_rect *src, struct nv30_rect *dst)
46{
47   if (src->x1 - src->x0 != dst->x1 - dst->x0)
48      return true;
49   if (src->y1 - src->y0 != dst->y1 - dst->y0)
50      return true;
51   return false;
52}
53
54static inline bool
55nv30_transfer_blit(XFER_ARGS)
56{
57   if (nv30->screen->eng3d->oclass < NV40_3D_CLASS)
58      return false;
59   if (dst->offset & 63 || dst->pitch & 63 || dst->d > 1)
60      return false;
61   if (dst->w < 2 || dst->h < 2)
62      return false;
63   if (dst->cpp > 4 || (dst->cpp == 1 && !dst->pitch))
64      return false;
65   if (src->cpp > 4)
66      return false;
67   return true;
68}
69
70static inline struct nouveau_heap *
71nv30_transfer_rect_vertprog(struct nv30_context *nv30)
72{
73   struct nouveau_heap *heap = nv30->screen->vp_exec_heap;
74   struct nouveau_heap *vp;
75
76   vp = nv30->blit_vp;
77   if (!vp) {
78      if (nouveau_heap_alloc(heap, 2, &nv30->blit_vp, &nv30->blit_vp)) {
79         while (heap->next && heap->size < 2) {
80            struct nouveau_heap **evict = heap->next->priv;
81            nouveau_heap_free(evict);
82         }
83
84         if (nouveau_heap_alloc(heap, 2, &nv30->blit_vp, &nv30->blit_vp))
85            return NULL;
86      }
87
88      vp = nv30->blit_vp;
89      if (vp) {
90         struct nouveau_pushbuf *push = nv30->base.pushbuf;
91
92         BEGIN_NV04(push, NV30_3D(VP_UPLOAD_FROM_ID), 1);
93         PUSH_DATA (push, vp->start);
94         BEGIN_NV04(push, NV30_3D(VP_UPLOAD_INST(0)), 4);
95         PUSH_DATA (push, 0x401f9c6c); /* mov o[hpos], a[0]; */
96         PUSH_DATA (push, 0x0040000d);
97         PUSH_DATA (push, 0x8106c083);
98         PUSH_DATA (push, 0x6041ff80);
99         BEGIN_NV04(push, NV30_3D(VP_UPLOAD_INST(0)), 4);
100         PUSH_DATA (push, 0x401f9c6c); /* mov o[tex0], a[8]; end; */
101         PUSH_DATA (push, 0x0040080d);
102         PUSH_DATA (push, 0x8106c083);
103         PUSH_DATA (push, 0x6041ff9d);
104      }
105   }
106
107   return vp;
108}
109
110
111static inline struct nv04_resource *
112nv30_transfer_rect_fragprog(struct nv30_context *nv30)
113{
114   struct nv04_resource *fp = nv04_resource(nv30->blit_fp);
115   struct pipe_context *pipe = &nv30->base.pipe;
116
117   if (!fp) {
118      nv30->blit_fp =
119         pipe_buffer_create(pipe->screen, 0, PIPE_USAGE_STAGING, 12 * 4);
120      if (nv30->blit_fp) {
121         struct pipe_transfer *transfer;
122         u32 *map = pipe_buffer_map(pipe, nv30->blit_fp,
123                                    PIPE_TRANSFER_WRITE, &transfer);
124         if (map) {
125            map[0] = 0x17009e00; /* texr r0, i[tex0], texture[0]; end; */
126            map[1] = 0x1c9dc801;
127            map[2] = 0x0001c800;
128            map[3] = 0x3fe1c800;
129            map[4] = 0x01401e81; /* end; */
130            map[5] = 0x1c9dc800;
131            map[6] = 0x0001c800;
132            map[7] = 0x0001c800;
133            pipe_buffer_unmap(pipe, transfer);
134         }
135
136         fp = nv04_resource(nv30->blit_fp);
137         nouveau_buffer_migrate(&nv30->base, fp, NOUVEAU_BO_VRAM);
138      }
139   }
140
141   return fp;
142}
143
144static void
145nv30_transfer_rect_blit(XFER_ARGS)
146{
147   struct nv04_resource *fp = nv30_transfer_rect_fragprog(nv30);
148   struct nouveau_heap *vp = nv30_transfer_rect_vertprog(nv30);
149   struct nouveau_pushbuf *push = nv30->base.pushbuf;
150   struct nouveau_pushbuf_refn refs[] = {
151      { fp->bo, fp->domain | NOUVEAU_BO_RD },
152      { src->bo, src->domain | NOUVEAU_BO_RD },
153      { dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR },
154   };
155   u32 texfmt, texswz;
156   u32 format, stride;
157
158   if (nouveau_pushbuf_space(push, 512, 8, 0) ||
159       nouveau_pushbuf_refn (push, refs, ARRAY_SIZE(refs)))
160      return;
161
162   /* various switches depending on cpp of the transfer */
163   switch (dst->cpp) {
164   case 4:
165      format = NV30_3D_RT_FORMAT_COLOR_A8R8G8B8 |
166               NV30_3D_RT_FORMAT_ZETA_Z24S8;
167      texfmt = NV40_3D_TEX_FORMAT_FORMAT_A8R8G8B8;
168      texswz = 0x0000aae4;
169      break;
170   case 2:
171      format = NV30_3D_RT_FORMAT_COLOR_R5G6B5 |
172               NV30_3D_RT_FORMAT_ZETA_Z16;
173      texfmt = NV40_3D_TEX_FORMAT_FORMAT_R5G6B5;
174      texswz = 0x0000a9e4;
175      break;
176   case 1:
177      format = NV30_3D_RT_FORMAT_COLOR_B8 |
178               NV30_3D_RT_FORMAT_ZETA_Z16;
179      texfmt = NV40_3D_TEX_FORMAT_FORMAT_L8;
180      texswz = 0x0000aaff;
181      break;
182   default:
183      assert(0);
184      return;
185   }
186
187   /* render target */
188   if (!dst->pitch) {
189      format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
190      format |= util_logbase2(dst->w) << 16;
191      format |= util_logbase2(dst->h) << 24;
192      stride  = 64;
193   } else {
194      format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
195      stride  = dst->pitch;
196   }
197
198   BEGIN_NV04(push, NV30_3D(VIEWPORT_HORIZ), 2);
199   PUSH_DATA (push, dst->w << 16);
200   PUSH_DATA (push, dst->h << 16);
201   BEGIN_NV04(push, NV30_3D(RT_HORIZ), 5);
202   PUSH_DATA (push, dst->w << 16);
203   PUSH_DATA (push, dst->h << 16);
204   PUSH_DATA (push, format);
205   PUSH_DATA (push, stride);
206   PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
207   BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
208   PUSH_DATA (push, NV30_3D_RT_ENABLE_COLOR0);
209
210   nv30->dirty |= NV30_NEW_FRAMEBUFFER;
211
212   /* viewport state */
213   BEGIN_NV04(push, NV30_3D(VIEWPORT_TRANSLATE_X), 8);
214   PUSH_DATAf(push, 0.0);
215   PUSH_DATAf(push, 0.0);
216   PUSH_DATAf(push, 0.0);
217   PUSH_DATAf(push, 0.0);
218   PUSH_DATAf(push, 1.0);
219   PUSH_DATAf(push, 1.0);
220   PUSH_DATAf(push, 1.0);
221   PUSH_DATAf(push, 1.0);
222   BEGIN_NV04(push, NV30_3D(DEPTH_RANGE_NEAR), 2);
223   PUSH_DATAf(push, 0.0);
224   PUSH_DATAf(push, 1.0);
225
226   nv30->dirty |= NV30_NEW_VIEWPORT;
227
228   /* blend state */
229   BEGIN_NV04(push, NV30_3D(COLOR_LOGIC_OP_ENABLE), 1);
230   PUSH_DATA (push, 0);
231   BEGIN_NV04(push, NV30_3D(DITHER_ENABLE), 1);
232   PUSH_DATA (push, 0);
233   BEGIN_NV04(push, NV30_3D(BLEND_FUNC_ENABLE), 1);
234   PUSH_DATA (push, 0);
235   BEGIN_NV04(push, NV30_3D(COLOR_MASK), 1);
236   PUSH_DATA (push, 0x01010101);
237
238   nv30->dirty |= NV30_NEW_BLEND;
239
240   /* depth-stencil-alpha state */
241   BEGIN_NV04(push, NV30_3D(DEPTH_WRITE_ENABLE), 2);
242   PUSH_DATA (push, 0);
243   PUSH_DATA (push, 0);
244   BEGIN_NV04(push, NV30_3D(STENCIL_ENABLE(0)), 1);
245   PUSH_DATA (push, 0);
246   BEGIN_NV04(push, NV30_3D(STENCIL_ENABLE(1)), 1);
247   PUSH_DATA (push, 0);
248   BEGIN_NV04(push, NV30_3D(ALPHA_FUNC_ENABLE), 1);
249   PUSH_DATA (push, 0);
250
251   nv30->dirty |= NV30_NEW_ZSA;
252
253   /* rasterizer state */
254   BEGIN_NV04(push, NV30_3D(SHADE_MODEL), 1);
255   PUSH_DATA (push, NV30_3D_SHADE_MODEL_FLAT);
256   BEGIN_NV04(push, NV30_3D(CULL_FACE_ENABLE), 1);
257   PUSH_DATA (push, 0);
258   BEGIN_NV04(push, NV30_3D(POLYGON_MODE_FRONT), 2);
259   PUSH_DATA (push, NV30_3D_POLYGON_MODE_FRONT_FILL);
260   PUSH_DATA (push, NV30_3D_POLYGON_MODE_BACK_FILL);
261   BEGIN_NV04(push, NV30_3D(POLYGON_OFFSET_FILL_ENABLE), 1);
262   PUSH_DATA (push, 0);
263   BEGIN_NV04(push, NV30_3D(POLYGON_STIPPLE_ENABLE), 1);
264   PUSH_DATA (push, 0);
265
266   nv30->state.scissor_off = 0;
267   nv30->dirty |= NV30_NEW_RASTERIZER;
268
269   /* vertex program */
270   BEGIN_NV04(push, NV30_3D(VP_START_FROM_ID), 1);
271   PUSH_DATA (push, vp->start);
272   BEGIN_NV04(push, NV40_3D(VP_ATTRIB_EN), 2);
273   PUSH_DATA (push, 0x00000101); /* attrib: 0, 8 */
274   PUSH_DATA (push, 0x00004000); /* result: hpos, tex0 */
275   BEGIN_NV04(push, NV30_3D(ENGINE), 1);
276   PUSH_DATA (push, 0x00000103);
277   BEGIN_NV04(push, NV30_3D(VP_CLIP_PLANES_ENABLE), 1);
278   PUSH_DATA (push, 0x00000000);
279
280   nv30->dirty |= NV30_NEW_VERTPROG;
281   nv30->dirty |= NV30_NEW_CLIP;
282
283   /* fragment program */
284   BEGIN_NV04(push, NV30_3D(FP_ACTIVE_PROGRAM), 1);
285   PUSH_RELOC(push, fp->bo, fp->offset, fp->domain |
286                    NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
287                    NV30_3D_FP_ACTIVE_PROGRAM_DMA0,
288                    NV30_3D_FP_ACTIVE_PROGRAM_DMA1);
289   BEGIN_NV04(push, NV30_3D(FP_CONTROL), 1);
290   PUSH_DATA (push, 0x02000000);
291
292   nv30->state.fragprog = NULL;
293   nv30->dirty |= NV30_NEW_FRAGPROG;
294
295   /* texture */
296   texfmt |= 1 << NV40_3D_TEX_FORMAT_MIPMAP_COUNT__SHIFT;
297   texfmt |= NV30_3D_TEX_FORMAT_NO_BORDER;
298   texfmt |= NV40_3D_TEX_FORMAT_RECT;
299   texfmt |= 0x00008000;
300   if (src->d < 2)
301      texfmt |= NV30_3D_TEX_FORMAT_DIMS_2D;
302   else
303      texfmt |= NV30_3D_TEX_FORMAT_DIMS_3D;
304   if (src->pitch)
305      texfmt |= NV40_3D_TEX_FORMAT_LINEAR;
306
307   BEGIN_NV04(push, NV30_3D(TEX_OFFSET(0)), 8);
308   PUSH_RELOC(push, src->bo, src->offset, NOUVEAU_BO_LOW, 0, 0);
309   PUSH_RELOC(push, src->bo, texfmt, NOUVEAU_BO_OR,
310                    NV30_3D_TEX_FORMAT_DMA0, NV30_3D_TEX_FORMAT_DMA1);
311   PUSH_DATA (push, NV30_3D_TEX_WRAP_S_CLAMP_TO_EDGE |
312                    NV30_3D_TEX_WRAP_T_CLAMP_TO_EDGE |
313                    NV30_3D_TEX_WRAP_R_CLAMP_TO_EDGE);
314   PUSH_DATA (push, NV40_3D_TEX_ENABLE_ENABLE);
315   PUSH_DATA (push, texswz);
316   switch (filter) {
317   case BILINEAR:
318      PUSH_DATA (push, NV30_3D_TEX_FILTER_MIN_LINEAR |
319                       NV30_3D_TEX_FILTER_MAG_LINEAR | 0x00002000);
320      break;
321   default:
322      PUSH_DATA (push, NV30_3D_TEX_FILTER_MIN_NEAREST |
323                       NV30_3D_TEX_FILTER_MAG_NEAREST | 0x00002000);
324      break;
325   }
326   PUSH_DATA (push, (src->w << 16) | src->h);
327   PUSH_DATA (push, 0x00000000);
328   BEGIN_NV04(push, NV40_3D(TEX_SIZE1(0)), 1);
329   PUSH_DATA (push, 0x00100000 | src->pitch);
330   BEGIN_NV04(push, SUBC_3D(0x0b40), 1);
331   PUSH_DATA (push, src->d < 2 ? 0x00000001 : 0x00000000);
332   BEGIN_NV04(push, NV40_3D(TEX_CACHE_CTL), 1);
333   PUSH_DATA (push, 1);
334
335   nv30->fragprog.dirty_samplers |= 1;
336   nv30->dirty |= NV30_NEW_FRAGTEX;
337
338   /* blit! */
339   BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
340   PUSH_DATA (push, (dst->x1 - dst->x0) << 16 | dst->x0);
341   PUSH_DATA (push, (dst->y1 - dst->y0) << 16 | dst->y0);
342   BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
343   PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_QUADS);
344   BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(8)), 3);
345   PUSH_DATAf(push, src->x0);
346   PUSH_DATAf(push, src->y0);
347   PUSH_DATAf(push, src->z);
348   BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1);
349   PUSH_DATA (push, (dst->y0 << 16) | dst->x0);
350   BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(8)), 3);
351   PUSH_DATAf(push, src->x1);
352   PUSH_DATAf(push, src->y0);
353   PUSH_DATAf(push, src->z);
354   BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1);
355   PUSH_DATA (push, (dst->y0 << 16) | dst->x1);
356   BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(8)), 3);
357   PUSH_DATAf(push, src->x1);
358   PUSH_DATAf(push, src->y1);
359   PUSH_DATAf(push, src->z);
360   BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1);
361   PUSH_DATA (push, (dst->y1 << 16) | dst->x1);
362   BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(8)), 3);
363   PUSH_DATAf(push, src->x0);
364   PUSH_DATAf(push, src->y1);
365   PUSH_DATAf(push, src->z);
366   BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1);
367   PUSH_DATA (push, (dst->y1 << 16) | dst->x0);
368   BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
369   PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP);
370}
371
372static bool
373nv30_transfer_sifm(XFER_ARGS)
374{
375   if (!src->pitch || src->w > 1024 || src->h > 1024 || src->w < 2 || src->h < 2)
376      return false;
377
378   if (src->d > 1 || dst->d > 1)
379      return false;
380
381   if (dst->offset & 63)
382      return false;
383
384   if (!dst->pitch) {
385      if (dst->w > 2048 || dst->h > 2048 || dst->w < 2 || dst->h < 2)
386         return false;
387   } else {
388      if (dst->domain != NOUVEAU_BO_VRAM)
389         return false;
390      if (dst->pitch & 63)
391         return false;
392   }
393
394   return true;
395}
396
397static void
398nv30_transfer_rect_sifm(XFER_ARGS)
399
400{
401   struct nouveau_pushbuf *push = nv30->base.pushbuf;
402   struct nouveau_pushbuf_refn refs[] = {
403      { src->bo, src->domain | NOUVEAU_BO_RD },
404      { dst->bo, dst->domain | NOUVEAU_BO_WR },
405   };
406   struct nv04_fifo *fifo = push->channel->data;
407   unsigned si_fmt, si_arg;
408   unsigned ss_fmt;
409
410   switch (dst->cpp) {
411   case 4: ss_fmt = NV04_SURFACE_SWZ_FORMAT_COLOR_A8R8G8B8; break;
412   case 2: ss_fmt = NV04_SURFACE_SWZ_FORMAT_COLOR_R5G6B5; break;
413   default:
414      ss_fmt = NV04_SURFACE_SWZ_FORMAT_COLOR_Y8;
415      break;
416   }
417
418   switch (src->cpp) {
419   case 4: si_fmt = NV03_SIFM_COLOR_FORMAT_A8R8G8B8; break;
420   case 2: si_fmt = NV03_SIFM_COLOR_FORMAT_R5G6B5; break;
421   default:
422      si_fmt = NV03_SIFM_COLOR_FORMAT_AY8;
423      break;
424   }
425
426   if (filter == NEAREST) {
427      si_arg  = NV03_SIFM_FORMAT_ORIGIN_CENTER;
428      si_arg |= NV03_SIFM_FORMAT_FILTER_POINT_SAMPLE;
429   } else {
430      si_arg  = NV03_SIFM_FORMAT_ORIGIN_CORNER;
431      si_arg |= NV03_SIFM_FORMAT_FILTER_BILINEAR;
432   }
433
434   if (nouveau_pushbuf_space(push, 64, 6, 0) ||
435       nouveau_pushbuf_refn (push, refs, 2))
436      return;
437
438   if (dst->pitch) {
439      BEGIN_NV04(push, NV04_SF2D(DMA_IMAGE_SOURCE), 2);
440      PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
441      PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
442      BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
443      PUSH_DATA (push, ss_fmt);
444      PUSH_DATA (push, dst->pitch << 16 | dst->pitch);
445      PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
446      PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
447      BEGIN_NV04(push, NV05_SIFM(SURFACE), 1);
448      PUSH_DATA (push, nv30->screen->surf2d->handle);
449   } else {
450      BEGIN_NV04(push, NV04_SSWZ(DMA_IMAGE), 1);
451      PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
452      BEGIN_NV04(push, NV04_SSWZ(FORMAT), 2);
453      PUSH_DATA (push, ss_fmt | (util_logbase2(dst->w) << 16) |
454                                (util_logbase2(dst->h) << 24));
455      PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
456      BEGIN_NV04(push, NV05_SIFM(SURFACE), 1);
457      PUSH_DATA (push, nv30->screen->swzsurf->handle);
458   }
459
460   BEGIN_NV04(push, NV03_SIFM(DMA_IMAGE), 1);
461   PUSH_RELOC(push, src->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
462   BEGIN_NV04(push, NV03_SIFM(COLOR_FORMAT), 8);
463   PUSH_DATA (push, si_fmt);
464   PUSH_DATA (push, NV03_SIFM_OPERATION_SRCCOPY);
465   PUSH_DATA (push, (           dst->y0  << 16) |            dst->x0);
466   PUSH_DATA (push, ((dst->y1 - dst->y0) << 16) | (dst->x1 - dst->x0));
467   PUSH_DATA (push, (           dst->y0  << 16) |            dst->x0);
468   PUSH_DATA (push, ((dst->y1 - dst->y0) << 16) | (dst->x1 - dst->x0));
469   PUSH_DATA (push, ((src->x1 - src->x0) << 20) / (dst->x1 - dst->x0));
470   PUSH_DATA (push, ((src->y1 - src->y0) << 20) / (dst->y1 - dst->y0));
471   BEGIN_NV04(push, NV03_SIFM(SIZE), 4);
472   PUSH_DATA (push, align(src->h, 2) << 16 | align(src->w, 2));
473   PUSH_DATA (push, src->pitch | si_arg);
474   PUSH_RELOC(push, src->bo, src->offset, NOUVEAU_BO_LOW, 0, 0);
475   PUSH_DATA (push, (src->y0 << 20) | src->x0 << 4);
476}
477
478/* The NOP+OFFSET_OUT stuff after each M2MF transfer *is* actually required
479 * to prevent some odd things from happening, easily reproducible by
480 * attempting to do conditional rendering that has a M2MF transfer done
481 * some time before it.  0x1e98 will fail with a DMA_W_PROTECTION (assuming
482 * that name is still accurate on nv4x) error.
483 */
484
485static bool
486nv30_transfer_m2mf(XFER_ARGS)
487{
488   if (!src->pitch || !dst->pitch)
489      return false;
490   if (nv30_transfer_scaled(src, dst))
491      return false;
492   return true;
493}
494
495static void
496nv30_transfer_rect_m2mf(XFER_ARGS)
497{
498   struct nouveau_pushbuf *push = nv30->base.pushbuf;
499   struct nouveau_pushbuf_refn refs[] = {
500      { src->bo, src->domain | NOUVEAU_BO_RD },
501      { dst->bo, dst->domain | NOUVEAU_BO_WR },
502   };
503   struct nv04_fifo *fifo = push->channel->data;
504   unsigned src_offset = src->offset;
505   unsigned dst_offset = dst->offset;
506   unsigned w = dst->x1 - dst->x0;
507   unsigned h = dst->y1 - dst->y0;
508
509   src_offset += (src->y0 * src->pitch) + (src->x0 * src->cpp);
510   dst_offset += (dst->y0 * dst->pitch) + (dst->x0 * dst->cpp);
511
512   BEGIN_NV04(push, NV03_M2MF(DMA_BUFFER_IN), 2);
513   PUSH_DATA (push, (src->domain == NOUVEAU_BO_VRAM) ? fifo->vram : fifo->gart);
514   PUSH_DATA (push, (dst->domain == NOUVEAU_BO_VRAM) ? fifo->vram : fifo->gart);
515
516   while (h) {
517      unsigned lines = (h > 2047) ? 2047 : h;
518
519      if (nouveau_pushbuf_space(push, 32, 2, 0) ||
520          nouveau_pushbuf_refn (push, refs, 2))
521         return;
522
523      BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8);
524      PUSH_RELOC(push, src->bo, src_offset, NOUVEAU_BO_LOW, 0, 0);
525      PUSH_RELOC(push, dst->bo, dst_offset, NOUVEAU_BO_LOW, 0, 0);
526      PUSH_DATA (push, src->pitch);
527      PUSH_DATA (push, dst->pitch);
528      PUSH_DATA (push, w * src->cpp);
529      PUSH_DATA (push, lines);
530      PUSH_DATA (push, NV03_M2MF_FORMAT_INPUT_INC_1 |
531                       NV03_M2MF_FORMAT_OUTPUT_INC_1);
532      PUSH_DATA (push, 0x00000000);
533      BEGIN_NV04(push, NV04_GRAPH(M2MF, NOP), 1);
534      PUSH_DATA (push, 0x00000000);
535      BEGIN_NV04(push, NV03_M2MF(OFFSET_OUT), 1);
536      PUSH_DATA (push, 0x00000000);
537
538      h -= lines;
539      src_offset += src->pitch * lines;
540      dst_offset += dst->pitch * lines;
541   }
542}
543
544static bool
545nv30_transfer_cpu(XFER_ARGS)
546{
547   if (nv30_transfer_scaled(src, dst))
548      return false;
549   return true;
550}
551
552static char *
553linear_ptr(struct nv30_rect *rect, char *base, int x, int y, int z)
554{
555   return base + (y * rect->pitch) + (x * rect->cpp);
556}
557
558static inline unsigned
559swizzle2d(unsigned v, unsigned s)
560{
561   v = (v | (v << 8)) & 0x00ff00ff;
562   v = (v | (v << 4)) & 0x0f0f0f0f;
563   v = (v | (v << 2)) & 0x33333333;
564   v = (v | (v << 1)) & 0x55555555;
565   return v << s;
566}
567
568static char *
569swizzle2d_ptr(struct nv30_rect *rect, char *base, int x, int y, int z)
570{
571   unsigned k = util_logbase2(MIN2(rect->w, rect->h));
572   unsigned km = (1 << k) - 1;
573   unsigned nx = rect->w >> k;
574   unsigned tx = x >> k;
575   unsigned ty = y >> k;
576   unsigned m;
577
578   m  = swizzle2d(x & km, 0);
579   m |= swizzle2d(y & km, 1);
580   m += ((ty * nx) + tx) << k << k;
581
582   return base + (m * rect->cpp);
583}
584
585static char *
586swizzle3d_ptr(struct nv30_rect *rect, char *base, int x, int y, int z)
587{
588   unsigned w = rect->w >> 1;
589   unsigned h = rect->h >> 1;
590   unsigned d = rect->d >> 1;
591   unsigned i = 0, o;
592   unsigned v = 0;
593
594   do {
595      o = i;
596      if (w) {
597         v |= (x & 1) << i++;
598         x >>= 1;
599         w >>= 1;
600      }
601      if (h) {
602         v |= (y & 1) << i++;
603         y >>= 1;
604         h >>= 1;
605      }
606      if (d) {
607         v |= (z & 1) << i++;
608         z >>= 1;
609         d >>= 1;
610      }
611   } while(o != i);
612
613   return base + (v * rect->cpp);
614}
615
616typedef char *(*get_ptr_t)(struct nv30_rect *, char *, int, int, int);
617
618static inline get_ptr_t
619get_ptr(struct nv30_rect *rect)
620{
621   if (rect->pitch)
622      return linear_ptr;
623
624   if (rect->d <= 1)
625      return swizzle2d_ptr;
626
627   return swizzle3d_ptr;
628}
629
630static void
631nv30_transfer_rect_cpu(XFER_ARGS)
632{
633   get_ptr_t sp = get_ptr(src);
634   get_ptr_t dp = get_ptr(dst);
635   char *srcmap, *dstmap;
636   int x, y;
637
638   nouveau_bo_map(src->bo, NOUVEAU_BO_RD, nv30->base.client);
639   nouveau_bo_map(dst->bo, NOUVEAU_BO_WR, nv30->base.client);
640   srcmap = src->bo->map + src->offset;
641   dstmap = dst->bo->map + dst->offset;
642
643   for (y = 0; y < (dst->y1 - dst->y0); y++) {
644      for (x = 0; x < (dst->x1 - dst->x0); x++) {
645         memcpy(dp(dst, dstmap, dst->x0 + x, dst->y0 + y, dst->z),
646                sp(src, srcmap, src->x0 + x, src->y0 + y, src->z), dst->cpp);
647      }
648   }
649}
650
651void
652nv30_transfer_rect(struct nv30_context *nv30, enum nv30_transfer_filter filter,
653                   struct nv30_rect *src, struct nv30_rect *dst)
654{
655   static const struct {
656      char *name;
657      bool (*possible)(XFER_ARGS);
658      void (*execute)(XFER_ARGS);
659   } *method, methods[] = {
660      { "m2mf", nv30_transfer_m2mf, nv30_transfer_rect_m2mf },
661      { "sifm", nv30_transfer_sifm, nv30_transfer_rect_sifm },
662      { "blit", nv30_transfer_blit, nv30_transfer_rect_blit },
663      { "rect", nv30_transfer_cpu, nv30_transfer_rect_cpu },
664      {}
665   };
666
667   for (method = methods; method->possible; method++) {
668      if (method->possible(nv30, filter, src, dst)) {
669         method->execute(nv30, filter, src, dst);
670         return;
671      }
672   }
673
674   assert(0);
675}
676
677void
678nv30_transfer_push_data(struct nouveau_context *nv,
679                        struct nouveau_bo *bo, unsigned offset, unsigned domain,
680                        unsigned size, void *data)
681{
682   /* use ifc, or scratch + copy_data? */
683   fprintf(stderr, "nv30: push_data not implemented\n");
684}
685
686void
687nv30_transfer_copy_data(struct nouveau_context *nv,
688                        struct nouveau_bo *dst, unsigned d_off, unsigned d_dom,
689                        struct nouveau_bo *src, unsigned s_off, unsigned s_dom,
690                        unsigned size)
691{
692   struct nv04_fifo *fifo = nv->screen->channel->data;
693   struct nouveau_pushbuf_refn refs[] = {
694      { src, s_dom | NOUVEAU_BO_RD },
695      { dst, d_dom | NOUVEAU_BO_WR },
696   };
697   struct nouveau_pushbuf *push = nv->pushbuf;
698   unsigned pages, lines;
699
700   pages = size >> 12;
701   size -= (pages << 12);
702
703   BEGIN_NV04(push, NV03_M2MF(DMA_BUFFER_IN), 2);
704   PUSH_DATA (push, (s_dom == NOUVEAU_BO_VRAM) ? fifo->vram : fifo->gart);
705   PUSH_DATA (push, (d_dom == NOUVEAU_BO_VRAM) ? fifo->vram : fifo->gart);
706
707   while (pages) {
708      lines  = (pages > 2047) ? 2047 : pages;
709      pages -= lines;
710
711      if (nouveau_pushbuf_space(push, 32, 2, 0) ||
712          nouveau_pushbuf_refn (push, refs, 2))
713         return;
714
715      BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8);
716      PUSH_RELOC(push, src, s_off, NOUVEAU_BO_LOW, 0, 0);
717      PUSH_RELOC(push, dst, d_off, NOUVEAU_BO_LOW, 0, 0);
718      PUSH_DATA (push, 4096);
719      PUSH_DATA (push, 4096);
720      PUSH_DATA (push, 4096);
721      PUSH_DATA (push, lines);
722      PUSH_DATA (push, NV03_M2MF_FORMAT_INPUT_INC_1 |
723                       NV03_M2MF_FORMAT_OUTPUT_INC_1);
724      PUSH_DATA (push, 0x00000000);
725      BEGIN_NV04(push, NV04_GRAPH(M2MF, NOP), 1);
726      PUSH_DATA (push, 0x00000000);
727      BEGIN_NV04(push, NV03_M2MF(OFFSET_OUT), 1);
728      PUSH_DATA (push, 0x00000000);
729
730      s_off += (lines << 12);
731      d_off += (lines << 12);
732   }
733
734   if (size) {
735      if (nouveau_pushbuf_space(push, 32, 2, 0) ||
736          nouveau_pushbuf_refn (push, refs, 2))
737         return;
738
739      BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8);
740      PUSH_RELOC(push, src, s_off, NOUVEAU_BO_LOW, 0, 0);
741      PUSH_RELOC(push, dst, d_off, NOUVEAU_BO_LOW, 0, 0);
742      PUSH_DATA (push, size);
743      PUSH_DATA (push, size);
744      PUSH_DATA (push, size);
745      PUSH_DATA (push, 1);
746      PUSH_DATA (push, NV03_M2MF_FORMAT_INPUT_INC_1 |
747                       NV03_M2MF_FORMAT_OUTPUT_INC_1);
748      PUSH_DATA (push, 0x00000000);
749      BEGIN_NV04(push, NV04_GRAPH(M2MF, NOP), 1);
750      PUSH_DATA (push, 0x00000000);
751      BEGIN_NV04(push, NV03_M2MF(OFFSET_OUT), 1);
752      PUSH_DATA (push, 0x00000000);
753   }
754}
755