2 #include "util/u_format.h"
4 #include "nv50_context.h"
5 #include "nv50_transfer.h"
7 #include "nv50_defs.xml.h"
10 struct pipe_transfer base
;
11 struct nv50_m2mf_rect rect
[2];
17 nv50_m2mf_transfer_rect(struct pipe_screen
*pscreen
,
18 const struct nv50_m2mf_rect
*dst
,
19 const struct nv50_m2mf_rect
*src
,
20 uint32_t nblocksx
, uint32_t nblocksy
)
22 struct nouveau_channel
*chan
= nouveau_screen(pscreen
)->channel
;
23 const int cpp
= dst
->cpp
;
24 uint32_t src_ofst
= src
->base
;
25 uint32_t dst_ofst
= dst
->base
;
26 uint32_t height
= nblocksy
;
30 assert(dst
->cpp
== src
->cpp
);
32 if (nouveau_bo_tile_layout(src
->bo
)) {
33 BEGIN_RING(chan
, RING_MF(LINEAR_IN
), 6);
35 OUT_RING (chan
, src
->tile_mode
<< 4);
36 OUT_RING (chan
, src
->width
* cpp
);
37 OUT_RING (chan
, src
->height
);
38 OUT_RING (chan
, src
->depth
);
39 OUT_RING (chan
, src
->z
);
41 src_ofst
+= src
->y
* src
->pitch
+ src
->x
* cpp
;
43 BEGIN_RING(chan
, RING_MF(LINEAR_IN
), 1);
45 BEGIN_RING(chan
, RING_MF_(NV04_M2MF_PITCH_IN
), 1);
46 OUT_RING (chan
, src
->pitch
);
49 if (nouveau_bo_tile_layout(dst
->bo
)) {
50 BEGIN_RING(chan
, RING_MF(LINEAR_OUT
), 6);
52 OUT_RING (chan
, dst
->tile_mode
<< 4);
53 OUT_RING (chan
, dst
->width
* cpp
);
54 OUT_RING (chan
, dst
->height
);
55 OUT_RING (chan
, dst
->depth
);
56 OUT_RING (chan
, dst
->z
);
58 dst_ofst
+= dst
->y
* dst
->pitch
+ dst
->x
* cpp
;
60 BEGIN_RING(chan
, RING_MF(LINEAR_OUT
), 1);
62 BEGIN_RING(chan
, RING_MF_(NV04_M2MF_PITCH_OUT
), 1);
63 OUT_RING (chan
, dst
->pitch
);
67 int line_count
= height
> 2047 ? 2047 : height
;
69 MARK_RING (chan
, 17, 4);
71 BEGIN_RING(chan
, RING_MF(OFFSET_IN_HIGH
), 2);
72 OUT_RELOCh(chan
, src
->bo
, src_ofst
, src
->domain
| NOUVEAU_BO_RD
);
73 OUT_RELOCh(chan
, dst
->bo
, dst_ofst
, dst
->domain
| NOUVEAU_BO_WR
);
75 BEGIN_RING(chan
, RING_MF_(NV04_M2MF_OFFSET_IN
), 2);
76 OUT_RELOCl(chan
, src
->bo
, src_ofst
, src
->domain
| NOUVEAU_BO_RD
);
77 OUT_RELOCl(chan
, dst
->bo
, dst_ofst
, dst
->domain
| NOUVEAU_BO_WR
);
79 if (nouveau_bo_tile_layout(src
->bo
)) {
80 BEGIN_RING(chan
, RING_MF(TILING_POSITION_IN
), 1);
81 OUT_RING (chan
, (sy
<< 16) | (src
->x
* cpp
));
83 src_ofst
+= line_count
* src
->pitch
;
85 if (nouveau_bo_tile_layout(dst
->bo
)) {
86 BEGIN_RING(chan
, RING_MF(TILING_POSITION_OUT
), 1);
87 OUT_RING (chan
, (dy
<< 16) | (dst
->x
* cpp
));
89 dst_ofst
+= line_count
* dst
->pitch
;
92 BEGIN_RING(chan
, RING_MF_(NV04_M2MF_LINE_LENGTH_IN
), 4);
93 OUT_RING (chan
, nblocksx
* cpp
);
94 OUT_RING (chan
, line_count
);
95 OUT_RING (chan
, (1 << 8) | (1 << 0));
105 nv50_sifc_linear_u8(struct nouveau_context
*nv
,
106 struct nouveau_bo
*dst
, unsigned offset
, unsigned domain
,
107 unsigned size
, void *data
)
109 struct nouveau_channel
*chan
= nv
->screen
->channel
;
110 uint32_t *src
= (uint32_t *)data
;
111 unsigned count
= (size
+ 3) / 4;
112 unsigned xcoord
= offset
& 0xff;
116 MARK_RING (chan
, 23, 4);
117 BEGIN_RING(chan
, RING_2D(DST_FORMAT
), 2);
118 OUT_RING (chan
, NV50_SURFACE_FORMAT_R8_UNORM
);
120 BEGIN_RING(chan
, RING_2D(DST_PITCH
), 5);
121 OUT_RING (chan
, 262144);
122 OUT_RING (chan
, 65536);
124 OUT_RELOCh(chan
, dst
, offset
, domain
| NOUVEAU_BO_WR
);
125 OUT_RELOCl(chan
, dst
, offset
, domain
| NOUVEAU_BO_WR
);
126 BEGIN_RING(chan
, RING_2D(SIFC_BITMAP_ENABLE
), 2);
128 OUT_RING (chan
, NV50_SURFACE_FORMAT_R8_UNORM
);
129 BEGIN_RING(chan
, RING_2D(SIFC_WIDTH
), 10);
130 OUT_RING (chan
, size
);
137 OUT_RING (chan
, xcoord
);
142 unsigned nr
= AVAIL_RING(chan
);
146 nouveau_bo_validate(chan
, dst
, NOUVEAU_BO_WR
);
149 nr
= MIN2(count
, nr
- 1);
150 nr
= MIN2(nr
, NV04_PFIFO_MAX_PACKET_LEN
);
152 BEGIN_RING_NI(chan
, RING_2D(SIFC_DATA
), nr
);
153 OUT_RINGp (chan
, src
, nr
);
161 nv50_m2mf_copy_linear(struct nouveau_context
*nv
,
162 struct nouveau_bo
*dst
, unsigned dstoff
, unsigned dstdom
,
163 struct nouveau_bo
*src
, unsigned srcoff
, unsigned srcdom
,
166 struct nouveau_channel
*chan
= nv
->screen
->channel
;
168 BEGIN_RING(chan
, RING_MF(LINEAR_IN
), 1);
170 BEGIN_RING(chan
, RING_MF(LINEAR_OUT
), 1);
174 unsigned bytes
= MIN2(size
, 1 << 17);
176 MARK_RING (chan
, 11, 4);
177 BEGIN_RING(chan
, RING_MF(OFFSET_IN_HIGH
), 2);
178 OUT_RELOCh(chan
, src
, srcoff
, srcdom
| NOUVEAU_BO_RD
);
179 OUT_RELOCh(chan
, dst
, dstoff
, dstdom
| NOUVEAU_BO_WR
);
180 BEGIN_RING(chan
, RING_MF_(NV04_M2MF_OFFSET_IN
), 2);
181 OUT_RELOCl(chan
, src
, srcoff
, srcdom
| NOUVEAU_BO_RD
);
182 OUT_RELOCl(chan
, dst
, dstoff
, dstdom
| NOUVEAU_BO_WR
);
183 BEGIN_RING(chan
, RING_MF_(NV04_M2MF_LINE_LENGTH_IN
), 4);
184 OUT_RING (chan
, bytes
);
186 OUT_RING (chan
, (1 << 8) | (1 << 0));
195 struct pipe_transfer
*
196 nv50_miptree_transfer_new(struct pipe_context
*pctx
,
197 struct pipe_resource
*res
,
200 const struct pipe_box
*box
)
202 struct nv50_context
*nv50
= nv50_context(pctx
);
203 struct pipe_screen
*pscreen
= pctx
->screen
;
204 struct nouveau_device
*dev
= nv50
->screen
->base
.device
;
205 struct nv50_miptree
*mt
= nv50_miptree(res
);
206 struct nv50_miptree_level
*lvl
= &mt
->level
[level
];
207 struct nv50_transfer
*tx
;
209 uint32_t w
, h
, d
, z
, layer
;
212 if (usage
& PIPE_TRANSFER_MAP_DIRECTLY
)
217 d
= u_minify(res
->depth0
, level
);
225 tx
= CALLOC_STRUCT(nv50_transfer
);
229 pipe_resource_reference(&tx
->base
.resource
, res
);
231 tx
->base
.level
= level
;
232 tx
->base
.usage
= usage
;
235 tx
->nblocksx
= util_format_get_nblocksx(res
->format
, box
->width
);
236 tx
->nblocksy
= util_format_get_nblocksy(res
->format
, box
->height
);
238 tx
->base
.stride
= tx
->nblocksx
* util_format_get_blocksize(res
->format
);
239 tx
->base
.layer_stride
= tx
->nblocksy
* tx
->base
.stride
;
241 w
= u_minify(res
->width0
, level
);
242 h
= u_minify(res
->height0
, level
);
244 tx
->rect
[0].cpp
= tx
->rect
[1].cpp
= util_format_get_blocksize(res
->format
);
246 tx
->rect
[0].bo
= mt
->base
.bo
;
247 tx
->rect
[0].base
= lvl
->offset
+ layer
* mt
->layer_stride
;
248 tx
->rect
[0].tile_mode
= lvl
->tile_mode
;
249 tx
->rect
[0].x
= util_format_get_nblocksx(res
->format
, box
->x
);
250 tx
->rect
[0].y
= util_format_get_nblocksy(res
->format
, box
->y
);
252 tx
->rect
[0].width
= util_format_get_nblocksx(res
->format
, w
);
253 tx
->rect
[0].height
= util_format_get_nblocksy(res
->format
, h
);
254 tx
->rect
[0].depth
= d
;
255 tx
->rect
[0].pitch
= lvl
->pitch
;
256 tx
->rect
[0].domain
= NOUVEAU_BO_VRAM
;
258 size
= tx
->base
.layer_stride
;
260 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0,
261 size
* tx
->base
.box
.depth
, &tx
->rect
[1].bo
);
267 tx
->rect
[1].width
= tx
->nblocksx
;
268 tx
->rect
[1].height
= tx
->nblocksy
;
269 tx
->rect
[1].depth
= 1;
270 tx
->rect
[1].pitch
= tx
->base
.stride
;
271 tx
->rect
[1].domain
= NOUVEAU_BO_GART
;
273 if (usage
& PIPE_TRANSFER_READ
) {
274 unsigned base
= tx
->rect
[0].base
;
276 for (i
= 0; i
< box
->depth
; ++i
) {
277 nv50_m2mf_transfer_rect(pscreen
, &tx
->rect
[1], &tx
->rect
[0],
278 tx
->nblocksx
, tx
->nblocksy
);
282 tx
->rect
[0].base
+= mt
->layer_stride
;
283 tx
->rect
[1].base
+= size
;
286 tx
->rect
[0].base
= base
;
287 tx
->rect
[1].base
= 0;
294 nv50_miptree_transfer_del(struct pipe_context
*pctx
,
295 struct pipe_transfer
*transfer
)
297 struct pipe_screen
*pscreen
= pctx
->screen
;
298 struct nv50_transfer
*tx
= (struct nv50_transfer
*)transfer
;
299 struct nv50_miptree
*mt
= nv50_miptree(tx
->base
.resource
);
302 if (tx
->base
.usage
& PIPE_TRANSFER_WRITE
) {
303 for (i
= 0; i
< tx
->base
.box
.depth
; ++i
) {
304 nv50_m2mf_transfer_rect(pscreen
, &tx
->rect
[0], &tx
->rect
[1],
305 tx
->nblocksx
, tx
->nblocksy
);
309 tx
->rect
[0].base
+= mt
->layer_stride
;
310 tx
->rect
[1].base
+= tx
->nblocksy
* tx
->base
.stride
;
314 nouveau_bo_ref(NULL
, &tx
->rect
[1].bo
);
315 pipe_resource_reference(&transfer
->resource
, NULL
);
321 nv50_miptree_transfer_map(struct pipe_context
*pctx
,
322 struct pipe_transfer
*transfer
)
324 struct nv50_transfer
*tx
= (struct nv50_transfer
*)transfer
;
328 if (tx
->rect
[1].bo
->map
)
329 return tx
->rect
[1].bo
->map
;
331 if (transfer
->usage
& PIPE_TRANSFER_READ
)
332 flags
= NOUVEAU_BO_RD
;
333 if (transfer
->usage
& PIPE_TRANSFER_WRITE
)
334 flags
|= NOUVEAU_BO_WR
;
336 ret
= nouveau_bo_map(tx
->rect
[1].bo
, flags
);
339 return tx
->rect
[1].bo
->map
;
343 nv50_miptree_transfer_unmap(struct pipe_context
*pctx
,
344 struct pipe_transfer
*transfer
)
346 struct nv50_transfer
*tx
= (struct nv50_transfer
*)transfer
;
348 nouveau_bo_unmap(tx
->rect
[1].bo
);