2 #include "util/u_format.h"
4 #include "nvc0_context.h"
5 #include "nvc0_transfer.h"
7 #include "nv50_defs.xml.h"
10 struct pipe_transfer base
;
11 struct nvc0_m2mf_rect rect
[2];
18 nvc0_m2mf_transfer_rect(struct pipe_screen
*pscreen
,
19 const struct nvc0_m2mf_rect
*dst
,
20 const struct nvc0_m2mf_rect
*src
,
21 uint32_t nblocksx
, uint32_t nblocksy
)
23 struct nouveau_channel
*chan
= nouveau_screen(pscreen
)->channel
;
24 const int cpp
= dst
->cpp
;
25 uint32_t src_ofst
= src
->base
;
26 uint32_t dst_ofst
= dst
->base
;
27 uint32_t height
= nblocksy
;
30 uint32_t exec
= (1 << 20);
32 assert(dst
->cpp
== src
->cpp
);
34 if (nouveau_bo_tile_layout(src
->bo
)) {
35 BEGIN_RING(chan
, RING_MF(TILING_MODE_IN
), 5);
36 OUT_RING (chan
, src
->tile_mode
);
37 OUT_RING (chan
, src
->width
* cpp
);
38 OUT_RING (chan
, src
->height
);
39 OUT_RING (chan
, src
->depth
);
40 OUT_RING (chan
, src
->z
);
42 src_ofst
+= src
->y
* src
->pitch
+ src
->x
* cpp
;
44 BEGIN_RING(chan
, RING_MF(PITCH_IN
), 1);
45 OUT_RING (chan
, src
->width
* cpp
);
47 exec
|= NVC0_M2MF_EXEC_LINEAR_IN
;
50 if (nouveau_bo_tile_layout(dst
->bo
)) {
51 BEGIN_RING(chan
, RING_MF(TILING_MODE_OUT
), 5);
52 OUT_RING (chan
, dst
->tile_mode
);
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(PITCH_OUT
), 1);
61 OUT_RING (chan
, dst
->width
* cpp
);
63 exec
|= NVC0_M2MF_EXEC_LINEAR_OUT
;
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_RELOCl(chan
, src
->bo
, src_ofst
, src
->domain
| NOUVEAU_BO_RD
);
75 BEGIN_RING(chan
, RING_MF(OFFSET_OUT_HIGH
), 2);
76 OUT_RELOCh(chan
, dst
->bo
, dst_ofst
, dst
->domain
| NOUVEAU_BO_WR
);
77 OUT_RELOCl(chan
, dst
->bo
, dst_ofst
, dst
->domain
| NOUVEAU_BO_WR
);
79 if (!(exec
& NVC0_M2MF_EXEC_LINEAR_IN
)) {
80 BEGIN_RING(chan
, RING_MF(TILING_POSITION_IN_X
), 2);
81 OUT_RING (chan
, src
->x
* cpp
);
84 src_ofst
+= line_count
* src
->pitch
;
86 if (!(exec
& NVC0_M2MF_EXEC_LINEAR_OUT
)) {
87 BEGIN_RING(chan
, RING_MF(TILING_POSITION_OUT_X
), 2);
88 OUT_RING (chan
, dst
->x
* cpp
);
91 dst_ofst
+= line_count
* dst
->pitch
;
94 BEGIN_RING(chan
, RING_MF(LINE_LENGTH_IN
), 2);
95 OUT_RING (chan
, nblocksx
* cpp
);
96 OUT_RING (chan
, line_count
);
97 BEGIN_RING(chan
, RING_MF(EXEC
), 1);
98 OUT_RING (chan
, exec
);
100 height
-= line_count
;
107 nvc0_m2mf_push_linear(struct nouveau_context
*nv
,
108 struct nouveau_bo
*dst
, unsigned offset
, unsigned domain
,
109 unsigned size
, void *data
)
111 struct nouveau_channel
*chan
= nv
->screen
->channel
;
112 uint32_t *src
= (uint32_t *)data
;
113 unsigned count
= (size
+ 3) / 4;
115 MARK_RING (chan
, 8, 2);
117 BEGIN_RING(chan
, RING_MF(OFFSET_OUT_HIGH
), 2);
118 OUT_RELOCh(chan
, dst
, offset
, domain
| NOUVEAU_BO_WR
);
119 OUT_RELOCl(chan
, dst
, offset
, domain
| NOUVEAU_BO_WR
);
120 BEGIN_RING(chan
, RING_MF(LINE_LENGTH_IN
), 2);
121 OUT_RING (chan
, size
);
123 BEGIN_RING(chan
, RING_MF(EXEC
), 1);
124 OUT_RING (chan
, 0x100111);
127 unsigned nr
= AVAIL_RING(chan
);
131 nouveau_bo_validate(chan
, dst
, NOUVEAU_BO_WR
);
134 nr
= MIN2(count
, nr
- 1);
135 nr
= MIN2(nr
, NV04_PFIFO_MAX_PACKET_LEN
);
137 BEGIN_RING_NI(chan
, RING_MF(DATA
), nr
);
138 OUT_RINGp (chan
, src
, nr
);
146 nvc0_m2mf_copy_linear(struct nouveau_context
*nv
,
147 struct nouveau_bo
*dst
, unsigned dstoff
, unsigned dstdom
,
148 struct nouveau_bo
*src
, unsigned srcoff
, unsigned srcdom
,
151 struct nouveau_channel
*chan
= nv
->screen
->channel
;
154 unsigned bytes
= MIN2(size
, 1 << 17);
156 MARK_RING (chan
, 11, 4);
158 BEGIN_RING(chan
, RING_MF(OFFSET_OUT_HIGH
), 2);
159 OUT_RELOCh(chan
, dst
, dstoff
, dstdom
| NOUVEAU_BO_WR
);
160 OUT_RELOCl(chan
, dst
, dstoff
, dstdom
| NOUVEAU_BO_WR
);
161 BEGIN_RING(chan
, RING_MF(OFFSET_IN_HIGH
), 2);
162 OUT_RELOCh(chan
, src
, srcoff
, srcdom
| NOUVEAU_BO_RD
);
163 OUT_RELOCl(chan
, src
, srcoff
, srcdom
| NOUVEAU_BO_RD
);
164 BEGIN_RING(chan
, RING_MF(LINE_LENGTH_IN
), 2);
165 OUT_RING (chan
, bytes
);
167 BEGIN_RING(chan
, RING_MF(EXEC
), 1);
168 OUT_RING (chan
, (1 << NVC0_M2MF_EXEC_INC__SHIFT
) |
169 NVC0_M2MF_EXEC_LINEAR_IN
| NVC0_M2MF_EXEC_LINEAR_OUT
);
178 nvc0_m2mf_push_rect(struct pipe_screen
*pscreen
,
179 const struct nvc0_m2mf_rect
*dst
,
181 unsigned nblocksx
, unsigned nblocksy
)
183 struct nouveau_channel
*chan
;
184 const uint8_t *src
= (const uint8_t *)data
;
185 const int cpp
= dst
->cpp
;
186 const int line_len
= nblocksx
* cpp
;
189 assert(nouveau_bo_tile_layout(dst
->bo
));
191 BEGIN_RING(chan
, RING_MF(TILING_MODE_OUT
), 5);
192 OUT_RING (chan
, dst
->tile_mode
);
193 OUT_RING (chan
, dst
->width
* cpp
);
194 OUT_RING (chan
, dst
->height
);
195 OUT_RING (chan
, dst
->depth
);
196 OUT_RING (chan
, dst
->z
);
199 int line_count
, words
;
200 int size
= MIN2(AVAIL_RING(chan
), NV04_PFIFO_MAX_PACKET_LEN
);
202 if (size
< (12 + words
)) {
206 line_count
= (size
* 4) / line_len
;
207 words
= (line_count
* line_len
+ 3) / 4;
209 BEGIN_RING(chan
, RING_MF(OFFSET_OUT_HIGH
), 2);
210 OUT_RELOCh(chan
, dst
->bo
, dst
->base
, dst
->domain
| NOUVEAU_BO_WR
);
211 OUT_RELOCl(chan
, dst
->bo
, dst
->base
, dst
->domain
| NOUVEAU_BO_WR
);
213 BEGIN_RING(chan
, RING_MF(TILING_POSITION_OUT_X
), 2);
214 OUT_RING (chan
, dst
->x
* cpp
);
216 BEGIN_RING(chan
, RING_MF(LINE_LENGTH_IN
), 2);
217 OUT_RING (chan
, line_len
);
218 OUT_RING (chan
, line_count
);
219 BEGIN_RING(chan
, RING_MF(EXEC
), 1);
220 OUT_RING (chan
, (1 << NVC0_M2MF_EXEC_INC__SHIFT
) |
221 NVC0_M2MF_EXEC_PUSH
| NVC0_M2MF_EXEC_LINEAR_IN
);
223 BEGIN_RING_NI(chan
, RING_MF(DATA
), words
);
224 OUT_RINGp (chan
, src
, words
);
227 src
+= line_len
* line_count
;
228 nblocksy
-= line_count
;
232 struct pipe_transfer
*
233 nvc0_miptree_transfer_new(struct pipe_context
*pctx
,
234 struct pipe_resource
*res
,
237 const struct pipe_box
*box
)
239 struct nvc0_context
*nvc0
= nvc0_context(pctx
);
240 struct pipe_screen
*pscreen
= pctx
->screen
;
241 struct nouveau_device
*dev
= nvc0
->screen
->base
.device
;
242 struct nvc0_miptree
*mt
= nvc0_miptree(res
);
243 struct nvc0_miptree_level
*lvl
= &mt
->level
[level
];
244 struct nvc0_transfer
*tx
;
246 uint32_t w
, h
, d
, z
, layer
, box_h
, box_y
;
249 tx
= CALLOC_STRUCT(nvc0_transfer
);
258 d
= u_minify(res
->depth0
, level
);
260 tx
->nlayers
= box
->depth
;
264 if (res
->target
== PIPE_TEXTURE_1D
||
265 res
->target
== PIPE_TEXTURE_1D_ARRAY
) {
269 tx
->nlayers
= box
->height
;
272 tx
->nlayers
= box
->depth
;
276 pipe_resource_reference(&tx
->base
.resource
, res
);
278 tx
->base
.level
= level
;
279 tx
->base
.usage
= usage
;
282 tx
->nblocksx
= util_format_get_nblocksx(res
->format
, box
->width
);
283 tx
->nblocksy
= util_format_get_nblocksy(res
->format
, box_h
);
285 tx
->base
.stride
= tx
->nblocksx
* util_format_get_blocksize(res
->format
);
286 tx
->base
.layer_stride
= tx
->nblocksy
* tx
->base
.stride
;
288 w
= u_minify(res
->width0
, level
);
289 h
= u_minify(res
->height0
, level
);
291 tx
->rect
[0].cpp
= tx
->rect
[1].cpp
= util_format_get_blocksize(res
->format
);
293 tx
->rect
[0].bo
= mt
->base
.bo
;
294 tx
->rect
[0].base
= lvl
->offset
+ layer
* mt
->layer_stride
;
295 tx
->rect
[0].tile_mode
= lvl
->tile_mode
;
296 tx
->rect
[0].x
= util_format_get_nblocksx(res
->format
, box
->x
);
297 tx
->rect
[0].y
= util_format_get_nblocksy(res
->format
, box_y
);
299 tx
->rect
[0].width
= util_format_get_nblocksx(res
->format
, w
);
300 tx
->rect
[0].height
= util_format_get_nblocksy(res
->format
, h
);
301 tx
->rect
[0].depth
= d
;
302 tx
->rect
[0].pitch
= lvl
->pitch
;
303 tx
->rect
[0].domain
= NOUVEAU_BO_VRAM
;
305 size
= tx
->base
.layer_stride
;
307 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0,
308 size
* tx
->nlayers
, &tx
->rect
[1].bo
);
314 tx
->rect
[1].width
= tx
->nblocksx
;
315 tx
->rect
[1].height
= tx
->nblocksy
;
316 tx
->rect
[1].depth
= 1;
317 tx
->rect
[1].pitch
= tx
->base
.stride
;
318 tx
->rect
[1].domain
= NOUVEAU_BO_GART
;
320 if (usage
& PIPE_TRANSFER_READ
) {
321 unsigned base
= tx
->rect
[0].base
;
323 for (i
= 0; i
< tx
->nlayers
; ++i
) {
324 nvc0_m2mf_transfer_rect(pscreen
, &tx
->rect
[1], &tx
->rect
[0],
325 tx
->nblocksx
, tx
->nblocksy
);
329 tx
->rect
[0].base
+= mt
->layer_stride
;
330 tx
->rect
[1].base
+= size
;
333 tx
->rect
[0].base
= base
;
334 tx
->rect
[1].base
= 0;
341 nvc0_miptree_transfer_del(struct pipe_context
*pctx
,
342 struct pipe_transfer
*transfer
)
344 struct pipe_screen
*pscreen
= pctx
->screen
;
345 struct nvc0_transfer
*tx
= (struct nvc0_transfer
*)transfer
;
346 struct nvc0_miptree
*mt
= nvc0_miptree(tx
->base
.resource
);
349 if (tx
->base
.usage
& PIPE_TRANSFER_WRITE
) {
350 for (i
= 0; i
< tx
->nlayers
; ++i
) {
351 nvc0_m2mf_transfer_rect(pscreen
, &tx
->rect
[0], &tx
->rect
[1],
352 tx
->nblocksx
, tx
->nblocksy
);
356 tx
->rect
[0].base
+= mt
->layer_stride
;
357 tx
->rect
[1].base
+= tx
->nblocksy
* tx
->base
.stride
;
361 nouveau_bo_ref(NULL
, &tx
->rect
[1].bo
);
362 pipe_resource_reference(&transfer
->resource
, NULL
);
368 nvc0_miptree_transfer_map(struct pipe_context
*pctx
,
369 struct pipe_transfer
*transfer
)
371 struct nvc0_transfer
*tx
= (struct nvc0_transfer
*)transfer
;
375 if (tx
->rect
[1].bo
->map
)
376 return tx
->rect
[1].bo
->map
;
378 if (transfer
->usage
& PIPE_TRANSFER_READ
)
379 flags
= NOUVEAU_BO_RD
;
380 if (transfer
->usage
& PIPE_TRANSFER_WRITE
)
381 flags
|= NOUVEAU_BO_WR
;
383 ret
= nouveau_bo_map(tx
->rect
[1].bo
, flags
);
386 return tx
->rect
[1].bo
->map
;
390 nvc0_miptree_transfer_unmap(struct pipe_context
*pctx
,
391 struct pipe_transfer
*transfer
)
393 struct nvc0_transfer
*tx
= (struct nvc0_transfer
*)transfer
;
395 nouveau_bo_unmap(tx
->rect
[1].bo
);