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