Merge branch 'mesa_7_5_branch'
[mesa.git] / src / gallium / drivers / nv50 / nv50_transfer.c
1
2 #include "pipe/p_context.h"
3 #include "pipe/p_inlines.h"
4
5 #include "nv50_context.h"
6
7 struct nv50_transfer {
8 struct pipe_transfer base;
9 struct nouveau_bo *bo;
10 unsigned level_offset;
11 int level_pitch;
12 int level_width;
13 int level_height;
14 int level_x;
15 int level_y;
16 };
17
18 static void
19 nv50_transfer_rect_m2mf(struct pipe_screen *pscreen, struct nouveau_bo *src_bo,
20 unsigned src_offset, int src_pitch, int sx, int sy,
21 int sw, int sh, struct nouveau_bo *dst_bo,
22 unsigned dst_offset, int dst_pitch, int dx, int dy,
23 int dw, int dh, int cpp, int width, int height,
24 unsigned src_reloc, unsigned dst_reloc)
25 {
26 struct nv50_screen *screen = nv50_screen(pscreen);
27 struct nouveau_channel *chan = screen->m2mf->channel;
28 struct nouveau_grobj *m2mf = screen->m2mf;
29
30 src_reloc |= NOUVEAU_BO_RD;
31 dst_reloc |= NOUVEAU_BO_WR;
32
33 WAIT_RING (chan, 14);
34
35 if (!src_bo->tile_flags) {
36 BEGIN_RING(chan, m2mf, 0x0200, 1);
37 OUT_RING (chan, 1);
38 BEGIN_RING(chan, m2mf, 0x0314, 1);
39 OUT_RING (chan, src_pitch);
40 src_offset += (sy * src_pitch) + (sx * cpp);
41 } else {
42 BEGIN_RING(chan, m2mf, 0x0200, 6);
43 OUT_RING (chan, 0);
44 OUT_RING (chan, src_bo->tile_mode << 4);
45 OUT_RING (chan, sw * cpp);
46 OUT_RING (chan, sh);
47 OUT_RING (chan, 1);
48 OUT_RING (chan, 0);
49 }
50
51 if (!dst_bo->tile_flags) {
52 BEGIN_RING(chan, m2mf, 0x021c, 1);
53 OUT_RING (chan, 1);
54 BEGIN_RING(chan, m2mf, 0x0318, 1);
55 OUT_RING (chan, dst_pitch);
56 dst_offset += (dy * dst_pitch) + (dx * cpp);
57 } else {
58 BEGIN_RING(chan, m2mf, 0x021c, 6);
59 OUT_RING (chan, 0);
60 OUT_RING (chan, dst_bo->tile_mode << 4);
61 OUT_RING (chan, dw * cpp);
62 OUT_RING (chan, dh);
63 OUT_RING (chan, 1);
64 OUT_RING (chan, 0);
65 }
66
67 while (height) {
68 int line_count = height > 2047 ? 2047 : height;
69
70 WAIT_RING (chan, 15);
71 BEGIN_RING(chan, m2mf, 0x0238, 2);
72 OUT_RELOCh(chan, src_bo, src_offset, src_reloc);
73 OUT_RELOCh(chan, dst_bo, dst_offset, dst_reloc);
74 BEGIN_RING(chan, m2mf, 0x030c, 2);
75 OUT_RELOCl(chan, src_bo, src_offset, src_reloc);
76 OUT_RELOCl(chan, dst_bo, dst_offset, dst_reloc);
77 if (src_bo->tile_flags) {
78 BEGIN_RING(chan, m2mf, 0x0218, 1);
79 OUT_RING (chan, (sy << 16) | sx);
80 } else {
81 src_offset += (line_count * src_pitch);
82 }
83 if (dst_bo->tile_flags) {
84 BEGIN_RING(chan, m2mf, 0x0234, 1);
85 OUT_RING (chan, (dy << 16) | dx);
86 } else {
87 dst_offset += (line_count * dst_pitch);
88 }
89 BEGIN_RING(chan, m2mf, 0x031c, 4);
90 OUT_RING (chan, width * cpp);
91 OUT_RING (chan, line_count);
92 OUT_RING (chan, 0x00000101);
93 OUT_RING (chan, 0);
94 FIRE_RING (chan);
95
96 height -= line_count;
97 sy += line_count;
98 dy += line_count;
99 }
100 }
101
102 static struct pipe_transfer *
103 nv50_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
104 unsigned face, unsigned level, unsigned zslice,
105 enum pipe_transfer_usage usage,
106 unsigned x, unsigned y, unsigned w, unsigned h)
107 {
108 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
109 struct nv50_miptree *mt = nv50_miptree(pt);
110 struct nv50_miptree_level *lvl = &mt->level[level];
111 struct nv50_transfer *tx;
112 unsigned image = 0;
113 int ret;
114
115 if (pt->target == PIPE_TEXTURE_CUBE)
116 image = face;
117 else
118 if (pt->target == PIPE_TEXTURE_3D)
119 image = zslice;
120
121 tx = CALLOC_STRUCT(nv50_transfer);
122 if (!tx)
123 return NULL;
124
125 pipe_texture_reference(&tx->base.texture, pt);
126 tx->base.format = pt->format;
127 tx->base.width = w;
128 tx->base.height = h;
129 tx->base.block = pt->block;
130 tx->base.nblocksx = pt->nblocksx[level];
131 tx->base.nblocksy = pt->nblocksy[level];
132 tx->base.stride = (w * pt->block.size);
133 tx->base.usage = usage;
134
135 tx->level_pitch = lvl->pitch;
136 tx->level_width = mt->base.width[level];
137 tx->level_height = mt->base.height[level];
138 tx->level_offset = lvl->image_offset[image];
139 tx->level_x = x;
140 tx->level_y = y;
141 ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
142 w * pt->block.size * h, &tx->bo);
143 if (ret) {
144 FREE(tx);
145 return NULL;
146 }
147
148 if (usage != PIPE_TRANSFER_WRITE) {
149 nv50_transfer_rect_m2mf(pscreen, mt->bo, tx->level_offset,
150 tx->level_pitch, x, y, tx->level_width,
151 tx->level_height, tx->bo, 0,
152 tx->base.stride, 0, 0,
153 tx->base.width, tx->base.height,
154 tx->base.block.size, w, h,
155 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART,
156 NOUVEAU_BO_GART);
157 }
158
159 return &tx->base;
160 }
161
162 static void
163 nv50_transfer_del(struct pipe_transfer *ptx)
164 {
165 struct nv50_transfer *tx = (struct nv50_transfer *)ptx;
166 struct nv50_miptree *mt = nv50_miptree(ptx->texture);
167
168 if (ptx->usage != PIPE_TRANSFER_READ) {
169 struct pipe_screen *pscreen = ptx->texture->screen;
170 nv50_transfer_rect_m2mf(pscreen, tx->bo, 0, tx->base.stride,
171 0, 0, tx->base.width, tx->base.height,
172 mt->bo, tx->level_offset,
173 tx->level_pitch, tx->level_x,
174 tx->level_y, tx->level_width,
175 tx->level_height, tx->base.block.size,
176 tx->base.width, tx->base.height,
177 NOUVEAU_BO_GART, NOUVEAU_BO_VRAM |
178 NOUVEAU_BO_GART);
179 }
180
181 nouveau_bo_ref(NULL, &tx->bo);
182 pipe_texture_reference(&ptx->texture, NULL);
183 FREE(ptx);
184 }
185
186 static void *
187 nv50_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
188 {
189 struct nv50_transfer *tx = (struct nv50_transfer *)ptx;
190 unsigned flags = 0;
191 int ret;
192
193 if (ptx->usage & PIPE_TRANSFER_WRITE)
194 flags |= NOUVEAU_BO_WR;
195 if (ptx->usage & PIPE_TRANSFER_READ)
196 flags |= NOUVEAU_BO_RD;
197
198 ret = nouveau_bo_map(tx->bo, flags);
199 if (ret)
200 return NULL;
201 return tx->bo->map;
202 }
203
204 static void
205 nv50_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
206 {
207 struct nv50_transfer *tx = (struct nv50_transfer *)ptx;
208
209 nouveau_bo_unmap(tx->bo);
210 }
211
212 void
213 nv50_transfer_init_screen_functions(struct pipe_screen *pscreen)
214 {
215 pscreen->get_tex_transfer = nv50_transfer_new;
216 pscreen->tex_transfer_destroy = nv50_transfer_del;
217 pscreen->transfer_map = nv50_transfer_map;
218 pscreen->transfer_unmap = nv50_transfer_unmap;
219 }