2 #include "pipe/p_context.h"
3 #include "util/u_inlines.h"
4 #include "util/u_format.h"
5 #include "util/u_math.h"
7 #include "nv50_context.h"
10 struct pipe_transfer base
;
11 struct nouveau_bo
*bo
;
13 unsigned level_offset
;
14 unsigned level_tiling
;
27 nv50_transfer_rect_m2mf(struct pipe_screen
*pscreen
,
28 struct nouveau_bo
*src_bo
, unsigned src_offset
,
29 int src_pitch
, unsigned src_tile_mode
,
30 int sx
, int sy
, int sz
, int sw
, int sh
, int sd
,
31 struct nouveau_bo
*dst_bo
, unsigned dst_offset
,
32 int dst_pitch
, unsigned dst_tile_mode
,
33 int dx
, int dy
, int dz
, int dw
, int dh
, int dd
,
34 int cpp
, int width
, int height
,
35 unsigned src_reloc
, unsigned dst_reloc
)
37 struct nv50_screen
*screen
= nv50_screen(pscreen
);
38 struct nouveau_channel
*chan
= screen
->m2mf
->channel
;
39 struct nouveau_grobj
*m2mf
= screen
->m2mf
;
41 src_reloc
|= NOUVEAU_BO_RD
;
42 dst_reloc
|= NOUVEAU_BO_WR
;
46 if (!src_bo
->tile_flags
) {
47 BEGIN_RING(chan
, m2mf
,
48 NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN
, 1);
50 BEGIN_RING(chan
, m2mf
,
51 NV04_MEMORY_TO_MEMORY_FORMAT_PITCH_IN
, 1);
52 OUT_RING (chan
, src_pitch
);
53 src_offset
+= (sy
* src_pitch
) + (sx
* cpp
);
55 BEGIN_RING(chan
, m2mf
,
56 NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN
, 6);
58 OUT_RING (chan
, src_tile_mode
<< 4);
59 OUT_RING (chan
, sw
* cpp
);
62 OUT_RING (chan
, sz
); /* copying only 1 zslice per call */
65 if (!dst_bo
->tile_flags
) {
66 BEGIN_RING(chan
, m2mf
,
67 NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT
, 1);
69 BEGIN_RING(chan
, m2mf
,
70 NV04_MEMORY_TO_MEMORY_FORMAT_PITCH_OUT
, 1);
71 OUT_RING (chan
, dst_pitch
);
72 dst_offset
+= (dy
* dst_pitch
) + (dx
* cpp
);
74 BEGIN_RING(chan
, m2mf
,
75 NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT
, 6);
77 OUT_RING (chan
, dst_tile_mode
<< 4);
78 OUT_RING (chan
, dw
* cpp
);
81 OUT_RING (chan
, dz
); /* copying only 1 zslice per call */
85 int line_count
= height
> 2047 ? 2047 : height
;
87 MARK_RING (chan
, 15, 4); /* flush on lack of space or relocs */
88 BEGIN_RING(chan
, m2mf
,
89 NV50_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN_HIGH
, 2);
90 OUT_RELOCh(chan
, src_bo
, src_offset
, src_reloc
);
91 OUT_RELOCh(chan
, dst_bo
, dst_offset
, dst_reloc
);
92 BEGIN_RING(chan
, m2mf
,
93 NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN
, 2);
94 OUT_RELOCl(chan
, src_bo
, src_offset
, src_reloc
);
95 OUT_RELOCl(chan
, dst_bo
, dst_offset
, dst_reloc
);
96 if (src_bo
->tile_flags
) {
97 BEGIN_RING(chan
, m2mf
,
98 NV50_MEMORY_TO_MEMORY_FORMAT_TILING_POSITION_IN
, 1);
99 OUT_RING (chan
, (sy
<< 16) | (sx
* cpp
));
101 src_offset
+= (line_count
* src_pitch
);
103 if (dst_bo
->tile_flags
) {
104 BEGIN_RING(chan
, m2mf
,
105 NV50_MEMORY_TO_MEMORY_FORMAT_TILING_POSITION_OUT
, 1);
106 OUT_RING (chan
, (dy
<< 16) | (dx
* cpp
));
108 dst_offset
+= (line_count
* dst_pitch
);
110 BEGIN_RING(chan
, m2mf
,
111 NV04_MEMORY_TO_MEMORY_FORMAT_LINE_LENGTH_IN
, 4);
112 OUT_RING (chan
, width
* cpp
);
113 OUT_RING (chan
, line_count
);
114 OUT_RING (chan
, 0x00000101);
118 height
-= line_count
;
124 static struct pipe_transfer
*
125 nv50_transfer_new(struct pipe_context
*pcontext
, struct pipe_texture
*pt
,
126 unsigned face
, unsigned level
, unsigned zslice
,
127 enum pipe_transfer_usage usage
,
128 unsigned x
, unsigned y
, unsigned w
, unsigned h
)
130 struct pipe_screen
*pscreen
= pcontext
->screen
;
131 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
132 struct nv50_miptree
*mt
= nv50_miptree(pt
);
133 struct nv50_miptree_level
*lvl
= &mt
->level
[level
];
134 struct nv50_transfer
*tx
;
135 unsigned nx
, ny
, image
= 0;
138 if (pt
->target
== PIPE_TEXTURE_CUBE
)
141 tx
= CALLOC_STRUCT(nv50_transfer
);
145 pipe_texture_reference(&tx
->base
.texture
, pt
);
146 tx
->nblocksx
= util_format_get_nblocksx(pt
->format
, u_minify(pt
->width0
, level
));
147 tx
->nblocksy
= util_format_get_nblocksy(pt
->format
, u_minify(pt
->height0
, level
));
150 tx
->base
.stride
= tx
->nblocksx
* util_format_get_blocksize(pt
->format
);
151 tx
->base
.usage
= usage
;
153 tx
->level_pitch
= lvl
->pitch
;
154 tx
->level_width
= u_minify(mt
->base
.base
.width0
, level
);
155 tx
->level_height
= u_minify(mt
->base
.base
.height0
, level
);
156 tx
->level_depth
= u_minify(mt
->base
.base
.depth0
, level
);
157 tx
->level_offset
= lvl
->image_offset
[image
];
158 tx
->level_tiling
= lvl
->tile_mode
;
159 tx
->level_z
= zslice
;
160 tx
->level_x
= util_format_get_nblocksx(pt
->format
, x
);
161 tx
->level_y
= util_format_get_nblocksy(pt
->format
, y
);
162 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0,
163 tx
->nblocksy
* tx
->base
.stride
, &tx
->bo
);
169 if (usage
& PIPE_TRANSFER_READ
) {
170 nx
= util_format_get_nblocksx(pt
->format
, tx
->base
.width
);
171 ny
= util_format_get_nblocksy(pt
->format
, tx
->base
.height
);
173 nv50_transfer_rect_m2mf(pscreen
, mt
->base
.bo
, tx
->level_offset
,
174 tx
->level_pitch
, tx
->level_tiling
,
176 tx
->nblocksx
, tx
->nblocksy
,
179 tx
->base
.stride
, tx
->bo
->tile_mode
,
181 tx
->nblocksx
, tx
->nblocksy
, 1,
182 util_format_get_blocksize(pt
->format
), nx
, ny
,
183 NOUVEAU_BO_VRAM
| NOUVEAU_BO_GART
,
191 nv50_transfer_del(struct pipe_context
*pcontext
, struct pipe_transfer
*ptx
)
193 struct nv50_transfer
*tx
= (struct nv50_transfer
*)ptx
;
194 struct nv50_miptree
*mt
= nv50_miptree(ptx
->texture
);
195 struct pipe_texture
*pt
= ptx
->texture
;
197 unsigned nx
= util_format_get_nblocksx(pt
->format
, tx
->base
.width
);
198 unsigned ny
= util_format_get_nblocksy(pt
->format
, tx
->base
.height
);
200 if (ptx
->usage
& PIPE_TRANSFER_WRITE
) {
201 struct pipe_screen
*pscreen
= pcontext
->screen
;
203 nv50_transfer_rect_m2mf(pscreen
, tx
->bo
, 0,
204 tx
->base
.stride
, tx
->bo
->tile_mode
,
206 tx
->nblocksx
, tx
->nblocksy
, 1,
207 mt
->base
.bo
, tx
->level_offset
,
208 tx
->level_pitch
, tx
->level_tiling
,
209 tx
->level_x
, tx
->level_y
, tx
->level_z
,
210 tx
->nblocksx
, tx
->nblocksy
,
212 util_format_get_blocksize(pt
->format
), nx
, ny
,
213 NOUVEAU_BO_GART
, NOUVEAU_BO_VRAM
|
217 nouveau_bo_ref(NULL
, &tx
->bo
);
218 pipe_texture_reference(&ptx
->texture
, NULL
);
223 nv50_transfer_map(struct pipe_context
*pcontext
, struct pipe_transfer
*ptx
)
225 struct nv50_transfer
*tx
= (struct nv50_transfer
*)ptx
;
229 if (tx
->map_refcnt
++)
232 if (ptx
->usage
& PIPE_TRANSFER_WRITE
)
233 flags
|= NOUVEAU_BO_WR
;
234 if (ptx
->usage
& PIPE_TRANSFER_READ
)
235 flags
|= NOUVEAU_BO_RD
;
237 ret
= nouveau_bo_map(tx
->bo
, flags
);
246 nv50_transfer_unmap(struct pipe_context
*pcontext
, struct pipe_transfer
*ptx
)
248 struct nv50_transfer
*tx
= (struct nv50_transfer
*)ptx
;
250 if (--tx
->map_refcnt
)
252 nouveau_bo_unmap(tx
->bo
);
256 nv50_init_transfer_functions(struct nv50_context
*nv50
)
258 nv50
->pipe
.get_tex_transfer
= nv50_transfer_new
;
259 nv50
->pipe
.tex_transfer_destroy
= nv50_transfer_del
;
260 nv50
->pipe
.transfer_map
= nv50_transfer_map
;
261 nv50
->pipe
.transfer_unmap
= nv50_transfer_unmap
;
265 nv50_upload_sifc(struct nv50_context
*nv50
,
266 struct nouveau_bo
*bo
, unsigned dst_offset
, unsigned reloc
,
267 unsigned dst_format
, int dst_w
, int dst_h
, int dst_pitch
,
268 void *src
, unsigned src_format
, int src_pitch
,
269 int x
, int y
, int w
, int h
, int cpp
)
271 struct nouveau_channel
*chan
= nv50
->screen
->base
.channel
;
272 struct nouveau_grobj
*eng2d
= nv50
->screen
->eng2d
;
273 struct nouveau_grobj
*tesla
= nv50
->screen
->tesla
;
274 unsigned line_dwords
= (w
* cpp
+ 3) / 4;
276 reloc
|= NOUVEAU_BO_WR
;
278 MARK_RING (chan
, 32, 2); /* flush on lack of space or relocs */
280 if (bo
->tile_flags
) {
281 BEGIN_RING(chan
, eng2d
, NV50_2D_DST_FORMAT
, 5);
282 OUT_RING (chan
, dst_format
);
284 OUT_RING (chan
, bo
->tile_mode
<< 4);
288 BEGIN_RING(chan
, eng2d
, NV50_2D_DST_FORMAT
, 2);
289 OUT_RING (chan
, dst_format
);
291 BEGIN_RING(chan
, eng2d
, NV50_2D_DST_PITCH
, 1);
292 OUT_RING (chan
, dst_pitch
);
295 BEGIN_RING(chan
, eng2d
, NV50_2D_DST_WIDTH
, 4);
296 OUT_RING (chan
, dst_w
);
297 OUT_RING (chan
, dst_h
);
298 OUT_RELOCh(chan
, bo
, dst_offset
, reloc
);
299 OUT_RELOCl(chan
, bo
, dst_offset
, reloc
);
301 /* NV50_2D_OPERATION_SRCCOPY assumed already set */
303 BEGIN_RING(chan
, eng2d
, NV50_2D_SIFC_BITMAP_ENABLE
, 2);
305 OUT_RING (chan
, src_format
);
306 BEGIN_RING(chan
, eng2d
, NV50_2D_SIFC_WIDTH
, 10);
319 const uint32_t *p
= src
;
320 unsigned count
= line_dwords
;
323 unsigned nr
= MIN2(count
, 1792);
325 if (AVAIL_RING(chan
) <= nr
) {
328 BEGIN_RING(chan
, eng2d
,
329 NV50_2D_DST_ADDRESS_HIGH
, 2);
330 OUT_RELOCh(chan
, bo
, dst_offset
, reloc
);
331 OUT_RELOCl(chan
, bo
, dst_offset
, reloc
);
333 assert(AVAIL_RING(chan
) > nr
);
335 BEGIN_RING(chan
, eng2d
,
336 NV50_2D_SIFC_DATA
| (2 << 29), nr
);
337 OUT_RINGp (chan
, p
, nr
);
346 BEGIN_RING(chan
, tesla
, NV50TCL_CODE_CB_FLUSH
, 1);