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