nv50: rework for texture_transfer changes
[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 struct nv50_miptree_level *level;
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 int src_pitch, int sx, int sy, int sw, int sh,
21 struct pipe_buffer *dst, int dst_pitch, int dx, int dy,
22 int dw, int dh, int cpp, int width, int height,
23 unsigned src_reloc, unsigned dst_reloc)
24 {
25 struct nv50_screen *screen = nv50_screen(pscreen);
26 struct nouveau_winsys *nvws = screen->nvws;
27 struct nouveau_channel *chan = nvws->channel;
28 struct nouveau_grobj *m2mf = screen->m2mf;
29 struct nouveau_bo *src_bo = nvws->get_bo(src);
30 struct nouveau_bo *dst_bo = nvws->get_bo(dst);
31 unsigned src_offset = 0, dst_offset = 0;
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 tx->base.refcount = 1;
127 pipe_texture_reference(&tx->base.texture, pt);
128 tx->base.format = pt->format;
129 tx->base.width = w;
130 tx->base.height = h;
131 tx->base.block = pt->block;
132 tx->base.nblocksx = pt->nblocksx[level];
133 tx->base.nblocksy = pt->nblocksy[level];
134 tx->base.stride = (w * pt->block.size);
135 tx->base.usage = usage;
136
137 tx->level = lvl;
138 tx->level_pitch = lvl->pitch;
139 tx->level_width = mt->base.width[level];
140 tx->level_height = mt->base.height[level];
141 tx->level_x = x;
142 tx->level_y = y;
143 tx->buffer =
144 pipe_buffer_create(pscreen, 0, NOUVEAU_BUFFER_USAGE_TRANSFER,
145 w * tx->base.block.size * h);
146
147 if (usage != PIPE_TRANSFER_WRITE) {
148 nv50_transfer_rect_m2mf(pscreen, mt->buffer, tx->level_pitch,
149 x, y, tx->level_width, tx->level_height,
150 tx->buffer, 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_screen *pscreen, struct pipe_transfer **pptx)
162 {
163 struct pipe_transfer *ptx = *pptx;
164 struct nv50_transfer *tx = (struct nv50_transfer *)ptx;
165
166 *pptx = NULL;
167 if (--ptx->refcount)
168 return;
169
170 pipe_buffer_reference(pscreen, &tx->buffer, NULL);
171 pipe_texture_reference(&ptx->texture, NULL);
172 FREE(ptx);
173 }
174
175 static void *
176 nv50_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
177 {
178 struct nv50_transfer *tx = (struct nv50_transfer *)ptx;
179 unsigned flags = 0;
180
181 if (ptx->usage & PIPE_TRANSFER_WRITE)
182 flags |= PIPE_BUFFER_USAGE_CPU_WRITE;
183 if (ptx->usage & PIPE_TRANSFER_READ)
184 flags |= PIPE_BUFFER_USAGE_CPU_READ;
185
186 return pipe_buffer_map(pscreen, tx->buffer, flags);
187 }
188
189 static void
190 nv50_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
191 {
192 struct nv50_transfer *tx = (struct nv50_transfer *)ptx;
193 struct nv50_miptree *mt = nv50_miptree(ptx->texture);
194
195 if (ptx->usage != PIPE_TRANSFER_READ) {
196 nv50_transfer_rect_m2mf(pscreen, tx->buffer, tx->base.stride,
197 0, 0, tx->base.width, tx->base.height,
198 mt->buffer, tx->level_pitch,
199 tx->level_x, tx->level_y,
200 tx->level_width, tx->level_height,
201 tx->base.block.size, tx->base.width,
202 tx->base.height, NOUVEAU_BO_GART,
203 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART);
204 }
205
206 pipe_buffer_unmap(pscreen, mt->buffer);
207 }
208
209 void
210 nv50_transfer_init_screen_functions(struct pipe_screen *pscreen)
211 {
212 pscreen->get_tex_transfer = nv50_transfer_new;
213 pscreen->tex_transfer_release = nv50_transfer_del;
214 pscreen->transfer_map = nv50_transfer_map;
215 pscreen->transfer_unmap = nv50_transfer_unmap;
216 }