Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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 "nouveau/nv_object.xml.h"
  33. #include "nouveau/nv_m2mf.xml.h"
  34. #include "nv01_2d.xml.h"
  35. #include "nv30-40_3d.xml.h"
  36.  
  37. #include "nv30_context.h"
  38. #include "nv30_transfer.h"
  39.  
  40. /* Various helper functions to transfer different types of data in a number
  41.  * of different ways.
  42.  */
  43.  
  44. static INLINE boolean
  45. nv30_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.  
  54. static INLINE boolean
  55. nv30_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.  
  70. static INLINE struct nouveau_heap *
  71. nv30_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.  
  111. static INLINE struct nv04_resource *
  112. nv30_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 = pipe_buffer_create(pipe->screen, 0, 0, 12 * 4);
  119.       if (nv30->blit_fp) {
  120.          struct pipe_transfer *transfer;
  121.          u32 *map = pipe_buffer_map(pipe, nv30->blit_fp,
  122.                                     PIPE_TRANSFER_WRITE, &transfer);
  123.          if (map) {
  124.             map[0] = 0x17009e00; /* texr r0, i[tex0], texture[0]; end; */
  125.             map[1] = 0x1c9dc801;
  126.             map[2] = 0x0001c800;
  127.             map[3] = 0x3fe1c800;
  128.             map[4] = 0x01401e81; /* end; */
  129.             map[5] = 0x1c9dc800;
  130.             map[6] = 0x0001c800;
  131.             map[7] = 0x0001c800;
  132.             pipe_buffer_unmap(pipe, transfer);
  133.          }
  134.  
  135.          fp = nv04_resource(nv30->blit_fp);
  136.          nouveau_buffer_migrate(&nv30->base, fp, NOUVEAU_BO_VRAM);
  137.       }
  138.    }
  139.  
  140.    return fp;
  141. }
  142.  
  143. static void
  144. nv30_transfer_rect_blit(XFER_ARGS)
  145. {
  146.    struct nv04_resource *fp = nv30_transfer_rect_fragprog(nv30);
  147.    struct nouveau_heap *vp = nv30_transfer_rect_vertprog(nv30);
  148.    struct nouveau_pushbuf *push = nv30->base.pushbuf;
  149.    struct nouveau_pushbuf_refn refs[] = {
  150.       { fp->bo, fp->domain | NOUVEAU_BO_RD },
  151.       { src->bo, src->domain | NOUVEAU_BO_RD },
  152.       { dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR },
  153.    };
  154.    u32 texfmt, texswz;
  155.    u32 format, stride;
  156.  
  157.    if (nouveau_pushbuf_space(push, 512, 8, 0) ||
  158.        nouveau_pushbuf_refn (push, refs, sizeof(refs) / sizeof(refs[0])))
  159.       return;
  160.  
  161.    /* various switches depending on cpp of the transfer */
  162.    switch (dst->cpp) {
  163.    case 4:
  164.       format = NV30_3D_RT_FORMAT_COLOR_A8R8G8B8 |
  165.                NV30_3D_RT_FORMAT_ZETA_Z24S8;
  166.       texfmt = NV40_3D_TEX_FORMAT_FORMAT_A8R8G8B8;
  167.       texswz = 0x0000aae4;
  168.       break;
  169.    case 2:
  170.       format = NV30_3D_RT_FORMAT_COLOR_R5G6B5 |
  171.                NV30_3D_RT_FORMAT_ZETA_Z16;
  172.       texfmt = NV40_3D_TEX_FORMAT_FORMAT_R5G6B5;
  173.       texswz = 0x0000a9e4;
  174.       break;
  175.    case 1:
  176.       format = NV30_3D_RT_FORMAT_COLOR_B8 |
  177.                NV30_3D_RT_FORMAT_ZETA_Z16;
  178.       texfmt = NV40_3D_TEX_FORMAT_FORMAT_L8;
  179.       texswz = 0x0000aaff;
  180.       break;
  181.    default:
  182.       assert(0);
  183.       return;
  184.    }
  185.  
  186.    /* render target */
  187.    if (!dst->pitch) {
  188.       format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
  189.       format |= util_logbase2(dst->w) << 16;
  190.       format |= util_logbase2(dst->h) << 24;
  191.       stride  = 64;
  192.    } else {
  193.       format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
  194.       stride  = dst->pitch;
  195.    }
  196.  
  197.    BEGIN_NV04(push, NV30_3D(VIEWPORT_HORIZ), 2);
  198.    PUSH_DATA (push, dst->w << 16);
  199.    PUSH_DATA (push, dst->h << 16);
  200.    BEGIN_NV04(push, NV30_3D(RT_HORIZ), 5);
  201.    PUSH_DATA (push, dst->w << 16);
  202.    PUSH_DATA (push, dst->h << 16);
  203.    PUSH_DATA (push, format);
  204.    PUSH_DATA (push, stride);
  205.    PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
  206.    BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
  207.    PUSH_DATA (push, NV30_3D_RT_ENABLE_COLOR0);
  208.  
  209.    nv30->dirty |= NV30_NEW_FRAMEBUFFER;
  210.  
  211.    /* viewport state */
  212.    BEGIN_NV04(push, NV30_3D(VIEWPORT_TRANSLATE_X), 8);
  213.    PUSH_DATAf(push, 0.0);
  214.    PUSH_DATAf(push, 0.0);
  215.    PUSH_DATAf(push, 0.0);
  216.    PUSH_DATAf(push, 0.0);
  217.    PUSH_DATAf(push, 1.0);
  218.    PUSH_DATAf(push, 1.0);
  219.    PUSH_DATAf(push, 1.0);
  220.    PUSH_DATAf(push, 1.0);
  221.    BEGIN_NV04(push, NV30_3D(DEPTH_RANGE_NEAR), 2);
  222.    PUSH_DATAf(push, 0.0);
  223.    PUSH_DATAf(push, 1.0);
  224.  
  225.    nv30->dirty |= NV30_NEW_VIEWPORT;
  226.  
  227.    /* blend state */
  228.    BEGIN_NV04(push, NV30_3D(COLOR_LOGIC_OP_ENABLE), 1);
  229.    PUSH_DATA (push, 0);
  230.    BEGIN_NV04(push, NV30_3D(DITHER_ENABLE), 1);
  231.    PUSH_DATA (push, 0);
  232.    BEGIN_NV04(push, NV30_3D(BLEND_FUNC_ENABLE), 1);
  233.    PUSH_DATA (push, 0);
  234.    BEGIN_NV04(push, NV30_3D(COLOR_MASK), 1);
  235.    PUSH_DATA (push, 0x01010101);
  236.  
  237.    nv30->dirty |= NV30_NEW_BLEND;
  238.  
  239.    /* depth-stencil-alpha state */
  240.    BEGIN_NV04(push, NV30_3D(DEPTH_WRITE_ENABLE), 2);
  241.    PUSH_DATA (push, 0);
  242.    PUSH_DATA (push, 0);
  243.    BEGIN_NV04(push, NV30_3D(STENCIL_ENABLE(0)), 1);
  244.    PUSH_DATA (push, 0);
  245.    BEGIN_NV04(push, NV30_3D(STENCIL_ENABLE(1)), 1);
  246.    PUSH_DATA (push, 0);
  247.    BEGIN_NV04(push, NV30_3D(ALPHA_FUNC_ENABLE), 1);
  248.    PUSH_DATA (push, 0);
  249.  
  250.    nv30->dirty |= NV30_NEW_ZSA;
  251.  
  252.    /* rasterizer state */
  253.    BEGIN_NV04(push, NV30_3D(SHADE_MODEL), 1);
  254.    PUSH_DATA (push, NV30_3D_SHADE_MODEL_FLAT);
  255.    BEGIN_NV04(push, NV30_3D(CULL_FACE_ENABLE), 1);
  256.    PUSH_DATA (push, 0);
  257.    BEGIN_NV04(push, NV30_3D(POLYGON_MODE_FRONT), 2);
  258.    PUSH_DATA (push, NV30_3D_POLYGON_MODE_FRONT_FILL);
  259.    PUSH_DATA (push, NV30_3D_POLYGON_MODE_BACK_FILL);
  260.    BEGIN_NV04(push, NV30_3D(POLYGON_OFFSET_FILL_ENABLE), 1);
  261.    PUSH_DATA (push, 0);
  262.    BEGIN_NV04(push, NV30_3D(POLYGON_STIPPLE_ENABLE), 1);
  263.    PUSH_DATA (push, 0);
  264.  
  265.    nv30->state.scissor_off = 0;
  266.    nv30->dirty |= NV30_NEW_RASTERIZER;
  267.  
  268.    /* vertex program */
  269.    BEGIN_NV04(push, NV30_3D(VP_START_FROM_ID), 1);
  270.    PUSH_DATA (push, vp->start);
  271.    BEGIN_NV04(push, NV40_3D(VP_ATTRIB_EN), 2);
  272.    PUSH_DATA (push, 0x00000101); /* attrib: 0, 8 */
  273.    PUSH_DATA (push, 0x00004000); /* result: hpos, tex0 */
  274.    BEGIN_NV04(push, NV30_3D(ENGINE), 1);
  275.    PUSH_DATA (push, 0x00000103);
  276.    BEGIN_NV04(push, NV30_3D(VP_CLIP_PLANES_ENABLE), 1);
  277.    PUSH_DATA (push, 0x00000000);
  278.  
  279.    nv30->dirty |= NV30_NEW_VERTPROG;
  280.    nv30->dirty |= NV30_NEW_CLIP;
  281.  
  282.    /* fragment program */
  283.    BEGIN_NV04(push, NV30_3D(FP_ACTIVE_PROGRAM), 1);
  284.    PUSH_RELOC(push, fp->bo, fp->offset, fp->domain |
  285.                     NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
  286.                     NV30_3D_FP_ACTIVE_PROGRAM_DMA0,
  287.                     NV30_3D_FP_ACTIVE_PROGRAM_DMA1);
  288.    BEGIN_NV04(push, NV30_3D(FP_CONTROL), 1);
  289.    PUSH_DATA (push, 0x02000000);
  290.  
  291.    nv30->state.fragprog = NULL;
  292.    nv30->dirty |= NV30_NEW_FRAGPROG;
  293.  
  294.    /* texture */
  295.    texfmt |= 1 << NV40_3D_TEX_FORMAT_MIPMAP_COUNT__SHIFT;
  296.    texfmt |= NV30_3D_TEX_FORMAT_NO_BORDER;
  297.    texfmt |= NV40_3D_TEX_FORMAT_RECT;
  298.    texfmt |= 0x00008000;
  299.    if (src->d < 2)
  300.       texfmt |= NV30_3D_TEX_FORMAT_DIMS_2D;
  301.    else
  302.       texfmt |= NV30_3D_TEX_FORMAT_DIMS_3D;
  303.    if (src->pitch)
  304.       texfmt |= NV40_3D_TEX_FORMAT_LINEAR;
  305.  
  306.    BEGIN_NV04(push, NV30_3D(TEX_OFFSET(0)), 8);
  307.    PUSH_RELOC(push, src->bo, src->offset, NOUVEAU_BO_LOW, 0, 0);
  308.    PUSH_RELOC(push, src->bo, texfmt, NOUVEAU_BO_OR,
  309.                     NV30_3D_TEX_FORMAT_DMA0, NV30_3D_TEX_FORMAT_DMA1);
  310.    PUSH_DATA (push, NV30_3D_TEX_WRAP_S_CLAMP_TO_EDGE |
  311.                     NV30_3D_TEX_WRAP_T_CLAMP_TO_EDGE |
  312.                     NV30_3D_TEX_WRAP_R_CLAMP_TO_EDGE);
  313.    PUSH_DATA (push, NV40_3D_TEX_ENABLE_ENABLE);
  314.    PUSH_DATA (push, texswz);
  315.    switch (filter) {
  316.    case BILINEAR:
  317.       PUSH_DATA (push, NV30_3D_TEX_FILTER_MIN_LINEAR |
  318.                        NV30_3D_TEX_FILTER_MAG_LINEAR | 0x00002000);
  319.       break;
  320.    default:
  321.       PUSH_DATA (push, NV30_3D_TEX_FILTER_MIN_NEAREST |
  322.                        NV30_3D_TEX_FILTER_MAG_NEAREST | 0x00002000);
  323.       break;
  324.    }
  325.    PUSH_DATA (push, (src->w << 16) | src->h);
  326.    PUSH_DATA (push, 0x00000000);
  327.    BEGIN_NV04(push, NV40_3D(TEX_SIZE1(0)), 1);
  328.    PUSH_DATA (push, 0x00100000 | src->pitch);
  329.    BEGIN_NV04(push, SUBC_3D(0x0b40), 1);
  330.    PUSH_DATA (push, src->d < 2 ? 0x00000001 : 0x00000000);
  331.    BEGIN_NV04(push, NV40_3D(TEX_CACHE_CTL), 1);
  332.    PUSH_DATA (push, 1);
  333.  
  334.    nv30->fragprog.dirty_samplers |= 1;
  335.    nv30->dirty |= NV30_NEW_FRAGTEX;
  336.  
  337.    /* blit! */
  338.    BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
  339.    PUSH_DATA (push, (dst->x1 - dst->x0) << 16 | dst->x0);
  340.    PUSH_DATA (push, (dst->y1 - dst->y0) << 16 | dst->y0);
  341.    BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
  342.    PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_QUADS);
  343.    BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(8)), 3);
  344.    PUSH_DATAf(push, src->x0);
  345.    PUSH_DATAf(push, src->y0);
  346.    PUSH_DATAf(push, src->z);
  347.    BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1);
  348.    PUSH_DATA (push, (dst->y0 << 16) | dst->x0);
  349.    BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(8)), 3);
  350.    PUSH_DATAf(push, src->x1);
  351.    PUSH_DATAf(push, src->y0);
  352.    PUSH_DATAf(push, src->z);
  353.    BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1);
  354.    PUSH_DATA (push, (dst->y0 << 16) | dst->x1);
  355.    BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(8)), 3);
  356.    PUSH_DATAf(push, src->x1);
  357.    PUSH_DATAf(push, src->y1);
  358.    PUSH_DATAf(push, src->z);
  359.    BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1);
  360.    PUSH_DATA (push, (dst->y1 << 16) | dst->x1);
  361.    BEGIN_NV04(push, NV30_3D(VTX_ATTR_3F(8)), 3);
  362.    PUSH_DATAf(push, src->x0);
  363.    PUSH_DATAf(push, src->y1);
  364.    PUSH_DATAf(push, src->z);
  365.    BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1);
  366.    PUSH_DATA (push, (dst->y1 << 16) | dst->x0);
  367.    BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
  368.    PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP);
  369. }
  370.  
  371. static boolean
  372. nv30_transfer_sifm(XFER_ARGS)
  373. {
  374.    if (!src->pitch || (src->w | src->h) > 1024 || src->w < 2 || src->h < 2)
  375.       return FALSE;
  376.  
  377.    if (src->d > 1 || dst->d > 1)
  378.       return FALSE;
  379.  
  380.    if (dst->offset & 63)
  381.       return FALSE;
  382.  
  383.    if (!dst->pitch) {
  384.       if ((dst->w | dst->h) > 2048 || dst->w < 2 || dst->h < 2)
  385.          return FALSE;
  386.    } else {
  387.       if (dst->domain != NOUVEAU_BO_VRAM)
  388.          return FALSE;
  389.       if (dst->pitch & 63)
  390.          return FALSE;
  391.    }
  392.  
  393.    return TRUE;
  394. }
  395.  
  396. static void
  397. nv30_transfer_rect_sifm(XFER_ARGS)
  398.  
  399. {
  400.    struct nouveau_pushbuf *push = nv30->base.pushbuf;
  401.    struct nouveau_pushbuf_refn refs[] = {
  402.       { src->bo, src->domain | NOUVEAU_BO_RD },
  403.       { dst->bo, dst->domain | NOUVEAU_BO_WR },
  404.    };
  405.    struct nv04_fifo *fifo = push->channel->data;
  406.    unsigned si_fmt, si_arg;
  407.    unsigned ss_fmt;
  408.  
  409.    switch (dst->cpp) {
  410.    case 4: ss_fmt = NV04_SURFACE_SWZ_FORMAT_COLOR_A8R8G8B8; break;
  411.    case 2: ss_fmt = NV04_SURFACE_SWZ_FORMAT_COLOR_R5G6B5; break;
  412.    default:
  413.       ss_fmt = NV04_SURFACE_SWZ_FORMAT_COLOR_Y8;
  414.       break;
  415.    }
  416.  
  417.    switch (src->cpp) {
  418.    case 4: si_fmt = NV03_SIFM_COLOR_FORMAT_A8R8G8B8; break;
  419.    case 2: si_fmt = NV03_SIFM_COLOR_FORMAT_R5G6B5; break;
  420.    default:
  421.       si_fmt = NV03_SIFM_COLOR_FORMAT_AY8;
  422.       break;
  423.    }
  424.  
  425.    if (filter == NEAREST) {
  426.       si_arg  = NV03_SIFM_FORMAT_ORIGIN_CENTER;
  427.       si_arg |= NV03_SIFM_FORMAT_FILTER_POINT_SAMPLE;
  428.    } else {
  429.       si_arg  = NV03_SIFM_FORMAT_ORIGIN_CORNER;
  430.       si_arg |= NV03_SIFM_FORMAT_FILTER_BILINEAR;
  431.    }
  432.  
  433.    if (nouveau_pushbuf_space(push, 32, 6, 0) ||
  434.        nouveau_pushbuf_refn (push, refs, 2))
  435.       return;
  436.  
  437.    if (dst->pitch) {
  438.       BEGIN_NV04(push, NV04_SF2D(DMA_IMAGE_SOURCE), 2);
  439.       PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
  440.       PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
  441.       BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
  442.       PUSH_DATA (push, ss_fmt);
  443.       PUSH_DATA (push, dst->pitch << 16 | dst->pitch);
  444.       PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
  445.       PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
  446.       BEGIN_NV04(push, NV05_SIFM(SURFACE), 1);
  447.       PUSH_DATA (push, nv30->screen->surf2d->handle);
  448.    } else {
  449.       BEGIN_NV04(push, NV04_SSWZ(DMA_IMAGE), 1);
  450.       PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
  451.       BEGIN_NV04(push, NV04_SSWZ(FORMAT), 2);
  452.       PUSH_DATA (push, ss_fmt | (util_logbase2(dst->w) << 16) |
  453.                                 (util_logbase2(dst->h) << 24));
  454.       PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
  455.       BEGIN_NV04(push, NV05_SIFM(SURFACE), 1);
  456.       PUSH_DATA (push, nv30->screen->swzsurf->handle);
  457.    }
  458.  
  459.    BEGIN_NV04(push, NV03_SIFM(DMA_IMAGE), 1);
  460.    PUSH_RELOC(push, src->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
  461.    BEGIN_NV04(push, NV03_SIFM(COLOR_FORMAT), 8);
  462.    PUSH_DATA (push, si_fmt);
  463.    PUSH_DATA (push, NV03_SIFM_OPERATION_SRCCOPY);
  464.    PUSH_DATA (push, (           dst->y0  << 16) |            dst->x0);
  465.    PUSH_DATA (push, ((dst->y1 - dst->y0) << 16) | (dst->x1 - dst->x0));
  466.    PUSH_DATA (push, (           dst->y0  << 16) |            dst->x0);
  467.    PUSH_DATA (push, ((dst->y1 - dst->y0) << 16) | (dst->x1 - dst->x0));
  468.    PUSH_DATA (push, ((src->x1 - src->x0) << 20) / (dst->x1 - dst->x0));
  469.    PUSH_DATA (push, ((src->y1 - src->y0) << 20) / (dst->y1 - dst->y0));
  470.    BEGIN_NV04(push, NV03_SIFM(SIZE), 4);
  471.    PUSH_DATA (push, align(src->h, 2) << 16 | align(src->w, 2));
  472.    PUSH_DATA (push, src->pitch | si_arg);
  473.    PUSH_RELOC(push, src->bo, src->offset, NOUVEAU_BO_LOW, 0, 0);
  474.    PUSH_DATA (push, (src->y0 << 20) | src->x0 << 4);
  475. }
  476.  
  477. /* The NOP+OFFSET_OUT stuff after each M2MF transfer *is* actually required
  478.  * to prevent some odd things from happening, easily reproducible by
  479.  * attempting to do conditional rendering that has a M2MF transfer done
  480.  * some time before it.  0x1e98 will fail with a DMA_W_PROTECTION (assuming
  481.  * that name is still accurate on nv4x) error.
  482.  */
  483.  
  484. static boolean
  485. nv30_transfer_m2mf(XFER_ARGS)
  486. {
  487.    if (!src->pitch || !dst->pitch)
  488.       return FALSE;
  489.    if (nv30_transfer_scaled(src, dst))
  490.       return FALSE;
  491.    return TRUE;
  492. }
  493.  
  494. static void
  495. nv30_transfer_rect_m2mf(XFER_ARGS)
  496. {
  497.    struct nouveau_pushbuf *push = nv30->base.pushbuf;
  498.    struct nouveau_pushbuf_refn refs[] = {
  499.       { src->bo, src->domain | NOUVEAU_BO_RD },
  500.       { dst->bo, dst->domain | NOUVEAU_BO_WR },
  501.    };
  502.    struct nv04_fifo *fifo = push->channel->data;
  503.    unsigned src_offset = src->offset;
  504.    unsigned dst_offset = dst->offset;
  505.    unsigned w = dst->x1 - dst->x0;
  506.    unsigned h = dst->y1 - dst->y0;
  507.  
  508.    src_offset += (src->y0 * src->pitch) + (src->x0 * src->cpp);
  509.    dst_offset += (dst->y0 * dst->pitch) + (dst->x0 * dst->cpp);
  510.  
  511.    BEGIN_NV04(push, NV03_M2MF(DMA_BUFFER_IN), 2);
  512.    PUSH_DATA (push, (src->domain == NOUVEAU_BO_VRAM) ? fifo->vram : fifo->gart);
  513.    PUSH_DATA (push, (dst->domain == NOUVEAU_BO_VRAM) ? fifo->vram : fifo->gart);
  514.  
  515.    while (h) {
  516.       unsigned lines = (h > 2047) ? 2047 : h;
  517.  
  518.       if (nouveau_pushbuf_space(push, 13, 2, 0) ||
  519.           nouveau_pushbuf_refn (push, refs, 2))
  520.          return;
  521.  
  522.       BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8);
  523.       PUSH_RELOC(push, src->bo, src_offset, NOUVEAU_BO_LOW, 0, 0);
  524.       PUSH_RELOC(push, dst->bo, dst_offset, NOUVEAU_BO_LOW, 0, 0);
  525.       PUSH_DATA (push, src->pitch);
  526.       PUSH_DATA (push, dst->pitch);
  527.       PUSH_DATA (push, w * src->cpp);
  528.       PUSH_DATA (push, lines);
  529.       PUSH_DATA (push, NV03_M2MF_FORMAT_INPUT_INC_1 |
  530.                        NV03_M2MF_FORMAT_OUTPUT_INC_1);
  531.       PUSH_DATA (push, 0x00000000);
  532.       BEGIN_NV04(push, NV04_GRAPH(M2MF, NOP), 1);
  533.       PUSH_DATA (push, 0x00000000);
  534.       BEGIN_NV04(push, NV03_M2MF(OFFSET_OUT), 1);
  535.       PUSH_DATA (push, 0x00000000);
  536.  
  537.       h -= lines;
  538.       src_offset += src->pitch * lines;
  539.       dst_offset += dst->pitch * lines;
  540.    }
  541. }
  542.  
  543. static boolean
  544. nv30_transfer_cpu(XFER_ARGS)
  545. {
  546.    if (nv30_transfer_scaled(src, dst))
  547.       return FALSE;
  548.    return TRUE;
  549. }
  550.  
  551. static char *
  552. linear_ptr(struct nv30_rect *rect, char *base, int x, int y, int z)
  553. {
  554.    return base + (y * rect->pitch) + (x * rect->cpp);
  555. }
  556.  
  557. static INLINE unsigned
  558. swizzle2d(unsigned v, unsigned s)
  559. {
  560.    v = (v | (v << 8)) & 0x00ff00ff;
  561.    v = (v | (v << 4)) & 0x0f0f0f0f;
  562.    v = (v | (v << 2)) & 0x33333333;
  563.    v = (v | (v << 1)) & 0x55555555;
  564.    return v << s;
  565. }
  566.  
  567. static char *
  568. swizzle2d_ptr(struct nv30_rect *rect, char *base, int x, int y, int z)
  569. {
  570.    unsigned k = util_logbase2(MIN2(rect->w, rect->h));
  571.    unsigned km = (1 << k) - 1;
  572.    unsigned nx = rect->w >> k;
  573.    unsigned tx = x >> k;
  574.    unsigned ty = y >> k;
  575.    unsigned m;
  576.  
  577.    m  = swizzle2d(x & km, 0);
  578.    m |= swizzle2d(y & km, 1);
  579.    m += ((ty * nx) + tx) << k << k;
  580.  
  581.    return base + (m * rect->cpp);
  582. }
  583.  
  584. static char *
  585. swizzle3d_ptr(struct nv30_rect *rect, char *base, int x, int y, int z)
  586. {
  587.    unsigned w = rect->w >> 1;
  588.    unsigned h = rect->h >> 1;
  589.    unsigned d = rect->d >> 1;
  590.    unsigned i = 0, o;
  591.    unsigned v = 0;
  592.  
  593.    do {
  594.       o = i;
  595.       if (w) {
  596.          v |= (x & 1) << i++;
  597.          x >>= 1;
  598.          w >>= 1;
  599.       }
  600.       if (h) {
  601.          v |= (y & 1) << i++;
  602.          y >>= 1;
  603.          h >>= 1;
  604.       }
  605.       if (d) {
  606.          v |= (z & 1) << i++;
  607.          z >>= 1;
  608.          d >>= 1;
  609.       }
  610.    } while(o != i);
  611.  
  612.    return base + (v * rect->cpp);
  613. }
  614.  
  615. typedef char *(*get_ptr_t)(struct nv30_rect *, char *, int, int, int);
  616.  
  617. static INLINE get_ptr_t
  618. get_ptr(struct nv30_rect *rect)
  619. {
  620.    if (rect->pitch)
  621.       return linear_ptr;
  622.  
  623.    if (rect->d <= 1)
  624.       return swizzle2d_ptr;
  625.  
  626.    return swizzle3d_ptr;
  627. }
  628.  
  629. static void
  630. nv30_transfer_rect_cpu(XFER_ARGS)
  631. {
  632.    get_ptr_t sp = get_ptr(src);
  633.    get_ptr_t dp = get_ptr(dst);
  634.    char *srcmap, *dstmap;
  635.    int x, y;
  636.  
  637.    nouveau_bo_map(src->bo, NOUVEAU_BO_RD, nv30->base.client);
  638.    nouveau_bo_map(dst->bo, NOUVEAU_BO_WR, nv30->base.client);
  639.    srcmap = src->bo->map + src->offset;
  640.    dstmap = dst->bo->map + dst->offset;
  641.  
  642.    for (y = 0; y < (dst->y1 - dst->y0); y++) {
  643.       for (x = 0; x < (dst->x1 - dst->x0); x++) {
  644.          memcpy(dp(dst, dstmap, dst->x0 + x, dst->y0 + y, dst->z),
  645.                 sp(src, srcmap, src->x0 + x, src->y0 + y, src->z), dst->cpp);
  646.       }
  647.    }
  648. }
  649.  
  650. void
  651. nv30_transfer_rect(struct nv30_context *nv30, enum nv30_transfer_filter filter,
  652.                    struct nv30_rect *src, struct nv30_rect *dst)
  653. {
  654.    static const struct {
  655.       char *name;
  656.       boolean (*possible)(XFER_ARGS);
  657.       void (*execute)(XFER_ARGS);
  658.    } *method, methods[] = {
  659.       { "m2mf", nv30_transfer_m2mf, nv30_transfer_rect_m2mf },
  660.       { "sifm", nv30_transfer_sifm, nv30_transfer_rect_sifm },
  661.       { "blit", nv30_transfer_blit, nv30_transfer_rect_blit },
  662.       { "rect", nv30_transfer_cpu, nv30_transfer_rect_cpu },
  663.       {}
  664.    };
  665.  
  666.    method = methods - 1;
  667.    while ((++method)->possible) {
  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.  
  677. void
  678. nv30_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.  
  686. void
  687. nv30_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, 13, 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, 13, 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.