2 #include "util/u_format.h"
4 #include "nvc0_context.h"
6 #include "nv50/nv50_defs.xml.h"
9 struct pipe_transfer base
;
10 struct nv50_m2mf_rect rect
[2];
17 nvc0_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
;
29 uint32_t exec
= (1 << 20);
31 assert(dst
->cpp
== src
->cpp
);
33 if (nouveau_bo_tile_layout(src
->bo
)) {
34 BEGIN_RING(chan
, RING_MF(TILING_MODE_IN
), 5);
35 OUT_RING (chan
, src
->tile_mode
);
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(PITCH_IN
), 1);
44 OUT_RING (chan
, src
->width
* cpp
);
46 exec
|= NVC0_M2MF_EXEC_LINEAR_IN
;
49 if (nouveau_bo_tile_layout(dst
->bo
)) {
50 BEGIN_RING(chan
, RING_MF(TILING_MODE_OUT
), 5);
51 OUT_RING (chan
, dst
->tile_mode
);
52 OUT_RING (chan
, dst
->width
* cpp
);
53 OUT_RING (chan
, dst
->height
);
54 OUT_RING (chan
, dst
->depth
);
55 OUT_RING (chan
, dst
->z
);
57 dst_ofst
+= dst
->y
* dst
->pitch
+ dst
->x
* cpp
;
59 BEGIN_RING(chan
, RING_MF(PITCH_OUT
), 1);
60 OUT_RING (chan
, dst
->width
* cpp
);
62 exec
|= NVC0_M2MF_EXEC_LINEAR_OUT
;
66 int line_count
= height
> 2047 ? 2047 : height
;
68 MARK_RING (chan
, 17, 4);
70 BEGIN_RING(chan
, RING_MF(OFFSET_IN_HIGH
), 2);
71 OUT_RELOCh(chan
, src
->bo
, src_ofst
, src
->domain
| NOUVEAU_BO_RD
);
72 OUT_RELOCl(chan
, src
->bo
, src_ofst
, src
->domain
| NOUVEAU_BO_RD
);
74 BEGIN_RING(chan
, RING_MF(OFFSET_OUT_HIGH
), 2);
75 OUT_RELOCh(chan
, dst
->bo
, dst_ofst
, dst
->domain
| NOUVEAU_BO_WR
);
76 OUT_RELOCl(chan
, dst
->bo
, dst_ofst
, dst
->domain
| NOUVEAU_BO_WR
);
78 if (!(exec
& NVC0_M2MF_EXEC_LINEAR_IN
)) {
79 BEGIN_RING(chan
, RING_MF(TILING_POSITION_IN_X
), 2);
80 OUT_RING (chan
, src
->x
* cpp
);
83 src_ofst
+= line_count
* src
->pitch
;
85 if (!(exec
& NVC0_M2MF_EXEC_LINEAR_OUT
)) {
86 BEGIN_RING(chan
, RING_MF(TILING_POSITION_OUT_X
), 2);
87 OUT_RING (chan
, dst
->x
* cpp
);
90 dst_ofst
+= line_count
* dst
->pitch
;
93 BEGIN_RING(chan
, RING_MF(LINE_LENGTH_IN
), 2);
94 OUT_RING (chan
, nblocksx
* cpp
);
95 OUT_RING (chan
, line_count
);
96 BEGIN_RING(chan
, RING_MF(EXEC
), 1);
97 OUT_RING (chan
, exec
);
106 nvc0_m2mf_push_linear(struct nouveau_context
*nv
,
107 struct nouveau_bo
*dst
, unsigned offset
, unsigned domain
,
108 unsigned size
, const void *data
)
110 struct nouveau_channel
*chan
= nv
->screen
->channel
;
111 uint32_t *src
= (uint32_t *)data
;
112 unsigned count
= (size
+ 3) / 4;
117 MARK_RING (chan
, 16, 2);
119 nr
= AVAIL_RING(chan
) - 9;
120 nr
= MIN2(count
, nr
);
121 nr
= MIN2(nr
, NV04_PFIFO_MAX_PACKET_LEN
);
123 BEGIN_RING(chan
, RING_MF(OFFSET_OUT_HIGH
), 2);
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_MF(LINE_LENGTH_IN
), 2);
127 OUT_RING (chan
, nr
* 4);
129 BEGIN_RING(chan
, RING_MF(EXEC
), 1);
130 OUT_RING (chan
, 0x100111);
132 /* must not be interrupted (trap on QUERY fence, 0x50 works however) */
133 BEGIN_RING_NI(chan
, RING_MF(DATA
), nr
);
134 OUT_RINGp (chan
, src
, nr
);
143 nvc0_m2mf_copy_linear(struct nouveau_context
*nv
,
144 struct nouveau_bo
*dst
, unsigned dstoff
, unsigned dstdom
,
145 struct nouveau_bo
*src
, unsigned srcoff
, unsigned srcdom
,
148 struct nouveau_channel
*chan
= nv
->screen
->channel
;
151 unsigned bytes
= MIN2(size
, 1 << 17);
153 MARK_RING (chan
, 11, 4);
155 BEGIN_RING(chan
, RING_MF(OFFSET_OUT_HIGH
), 2);
156 OUT_RELOCh(chan
, dst
, dstoff
, dstdom
| NOUVEAU_BO_WR
);
157 OUT_RELOCl(chan
, dst
, dstoff
, dstdom
| NOUVEAU_BO_WR
);
158 BEGIN_RING(chan
, RING_MF(OFFSET_IN_HIGH
), 2);
159 OUT_RELOCh(chan
, src
, srcoff
, srcdom
| NOUVEAU_BO_RD
);
160 OUT_RELOCl(chan
, src
, srcoff
, srcdom
| NOUVEAU_BO_RD
);
161 BEGIN_RING(chan
, RING_MF(LINE_LENGTH_IN
), 2);
162 OUT_RING (chan
, bytes
);
164 BEGIN_RING(chan
, RING_MF(EXEC
), 1);
165 OUT_RING (chan
, (1 << NVC0_M2MF_EXEC_INC__SHIFT
) |
166 NVC0_M2MF_EXEC_LINEAR_IN
| NVC0_M2MF_EXEC_LINEAR_OUT
);
176 nvc0_m2mf_push_rect(struct pipe_screen
*pscreen
,
177 const struct nv50_m2mf_rect
*dst
,
179 unsigned nblocksx
, unsigned nblocksy
)
181 struct nouveau_channel
*chan
;
182 const uint8_t *src
= (const uint8_t *)data
;
183 const int cpp
= dst
->cpp
;
184 const int line_len
= nblocksx
* cpp
;
187 assert(nouveau_bo_tile_layout(dst
->bo
));
189 BEGIN_RING(chan
, RING_MF(TILING_MODE_OUT
), 5);
190 OUT_RING (chan
, dst
->tile_mode
);
191 OUT_RING (chan
, dst
->width
* cpp
);
192 OUT_RING (chan
, dst
->height
);
193 OUT_RING (chan
, dst
->depth
);
194 OUT_RING (chan
, dst
->z
);
197 int line_count
, words
;
198 int size
= MIN2(AVAIL_RING(chan
), NV04_PFIFO_MAX_PACKET_LEN
);
200 if (size
< (12 + words
)) {
204 line_count
= (size
* 4) / line_len
;
205 words
= (line_count
* line_len
+ 3) / 4;
207 BEGIN_RING(chan
, RING_MF(OFFSET_OUT_HIGH
), 2);
208 OUT_RELOCh(chan
, dst
->bo
, dst
->base
, dst
->domain
| NOUVEAU_BO_WR
);
209 OUT_RELOCl(chan
, dst
->bo
, dst
->base
, dst
->domain
| NOUVEAU_BO_WR
);
211 BEGIN_RING(chan
, RING_MF(TILING_POSITION_OUT_X
), 2);
212 OUT_RING (chan
, dst
->x
* cpp
);
214 BEGIN_RING(chan
, RING_MF(LINE_LENGTH_IN
), 2);
215 OUT_RING (chan
, line_len
);
216 OUT_RING (chan
, line_count
);
217 BEGIN_RING(chan
, RING_MF(EXEC
), 1);
218 OUT_RING (chan
, (1 << NVC0_M2MF_EXEC_INC__SHIFT
) |
219 NVC0_M2MF_EXEC_PUSH
| NVC0_M2MF_EXEC_LINEAR_IN
);
221 BEGIN_RING_NI(chan
, RING_MF(DATA
), words
);
222 OUT_RINGp (chan
, src
, words
);
225 src
+= line_len
* line_count
;
226 nblocksy
-= line_count
;
231 struct pipe_transfer
*
232 nvc0_miptree_transfer_new(struct pipe_context
*pctx
,
233 struct pipe_resource
*res
,
236 const struct pipe_box
*box
)
238 struct nvc0_context
*nvc0
= nvc0_context(pctx
);
239 struct pipe_screen
*pscreen
= pctx
->screen
;
240 struct nouveau_device
*dev
= nvc0
->screen
->base
.device
;
241 struct nv50_miptree
*mt
= nv50_miptree(res
);
242 struct nvc0_transfer
*tx
;
246 if (usage
& PIPE_TRANSFER_MAP_DIRECTLY
)
249 tx
= CALLOC_STRUCT(nvc0_transfer
);
253 pipe_resource_reference(&tx
->base
.resource
, res
);
255 tx
->base
.level
= level
;
256 tx
->base
.usage
= usage
;
259 if (util_format_is_plain(res
->format
)) {
260 tx
->nblocksx
= box
->width
<< mt
->ms_x
;
261 tx
->nblocksy
= box
->height
<< mt
->ms_y
;
263 tx
->nblocksx
= util_format_get_nblocksx(res
->format
, box
->width
);
264 tx
->nblocksy
= util_format_get_nblocksy(res
->format
, box
->height
);
266 tx
->nlayers
= box
->depth
;
268 tx
->base
.stride
= tx
->nblocksx
* util_format_get_blocksize(res
->format
);
269 tx
->base
.layer_stride
= tx
->nblocksy
* tx
->base
.stride
;
271 nv50_m2mf_rect_setup(&tx
->rect
[0], res
, level
, box
->x
, box
->y
, box
->z
);
273 size
= tx
->base
.layer_stride
;
275 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0,
276 size
* tx
->nlayers
, &tx
->rect
[1].bo
);
282 tx
->rect
[1].cpp
= tx
->rect
[0].cpp
;
283 tx
->rect
[1].width
= tx
->nblocksx
;
284 tx
->rect
[1].height
= tx
->nblocksy
;
285 tx
->rect
[1].depth
= 1;
286 tx
->rect
[1].pitch
= tx
->base
.stride
;
287 tx
->rect
[1].domain
= NOUVEAU_BO_GART
;
289 if (usage
& PIPE_TRANSFER_READ
) {
290 unsigned base
= tx
->rect
[0].base
;
291 unsigned z
= tx
->rect
[0].z
;
293 for (i
= 0; i
< tx
->nlayers
; ++i
) {
294 nvc0_m2mf_transfer_rect(pscreen
, &tx
->rect
[1], &tx
->rect
[0],
295 tx
->nblocksx
, tx
->nblocksy
);
299 tx
->rect
[0].base
+= mt
->layer_stride
;
300 tx
->rect
[1].base
+= size
;
303 tx
->rect
[0].base
= base
;
304 tx
->rect
[1].base
= 0;
311 nvc0_miptree_transfer_del(struct pipe_context
*pctx
,
312 struct pipe_transfer
*transfer
)
314 struct pipe_screen
*pscreen
= pctx
->screen
;
315 struct nvc0_transfer
*tx
= (struct nvc0_transfer
*)transfer
;
316 struct nv50_miptree
*mt
= nv50_miptree(tx
->base
.resource
);
319 if (tx
->base
.usage
& PIPE_TRANSFER_WRITE
) {
320 for (i
= 0; i
< tx
->nlayers
; ++i
) {
321 nvc0_m2mf_transfer_rect(pscreen
, &tx
->rect
[0], &tx
->rect
[1],
322 tx
->nblocksx
, tx
->nblocksy
);
326 tx
->rect
[0].base
+= mt
->layer_stride
;
327 tx
->rect
[1].base
+= tx
->nblocksy
* tx
->base
.stride
;
331 nouveau_bo_ref(NULL
, &tx
->rect
[1].bo
);
332 pipe_resource_reference(&transfer
->resource
, NULL
);
338 nvc0_miptree_transfer_map(struct pipe_context
*pctx
,
339 struct pipe_transfer
*transfer
)
341 struct nvc0_transfer
*tx
= (struct nvc0_transfer
*)transfer
;
345 if (tx
->rect
[1].bo
->map
)
346 return tx
->rect
[1].bo
->map
;
348 if (transfer
->usage
& PIPE_TRANSFER_READ
)
349 flags
= NOUVEAU_BO_RD
;
350 if (transfer
->usage
& PIPE_TRANSFER_WRITE
)
351 flags
|= NOUVEAU_BO_WR
;
353 ret
= nouveau_bo_map(tx
->rect
[1].bo
, flags
);
356 return tx
->rect
[1].bo
->map
;
360 nvc0_miptree_transfer_unmap(struct pipe_context
*pctx
,
361 struct pipe_transfer
*transfer
)
363 struct nvc0_transfer
*tx
= (struct nvc0_transfer
*)transfer
;
365 nouveau_bo_unmap(tx
->rect
[1].bo
);