2 #include "pipe/p_context.h"
3 #include "pipe/p_inlines.h"
5 #include "nv50_context.h"
8 struct pipe_transfer base
;
10 unsigned level_offset
;
11 unsigned level_tiling
;
21 nv50_transfer_rect_m2mf(struct pipe_screen
*pscreen
,
22 struct nouveau_bo
*src_bo
, unsigned src_offset
,
23 int src_pitch
, unsigned src_tile_mode
,
24 int sx
, int sy
, int sw
, int sh
, int sd
,
25 struct nouveau_bo
*dst_bo
, unsigned dst_offset
,
26 int dst_pitch
, unsigned dst_tile_mode
,
27 int dx
, int dy
, int dw
, int dh
, int dd
,
28 int cpp
, int width
, int height
,
29 unsigned src_reloc
, unsigned dst_reloc
)
31 struct nv50_screen
*screen
= nv50_screen(pscreen
);
32 struct nouveau_channel
*chan
= screen
->m2mf
->channel
;
33 struct nouveau_grobj
*m2mf
= screen
->m2mf
;
35 src_reloc
|= NOUVEAU_BO_RD
;
36 dst_reloc
|= NOUVEAU_BO_WR
;
40 if (!src_bo
->tile_flags
) {
41 BEGIN_RING(chan
, m2mf
,
42 NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN
, 1);
44 BEGIN_RING(chan
, m2mf
,
45 NV50_MEMORY_TO_MEMORY_FORMAT_PITCH_IN
, 1);
46 OUT_RING (chan
, src_pitch
);
47 src_offset
+= (sy
* src_pitch
) + (sx
* cpp
);
49 BEGIN_RING(chan
, m2mf
,
50 NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN
, 6);
52 OUT_RING (chan
, src_tile_mode
<< 4);
53 OUT_RING (chan
, sw
* cpp
);
59 if (!dst_bo
->tile_flags
) {
60 BEGIN_RING(chan
, m2mf
,
61 NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT
, 1);
63 BEGIN_RING(chan
, m2mf
,
64 NV50_MEMORY_TO_MEMORY_FORMAT_PITCH_OUT
, 1);
65 OUT_RING (chan
, dst_pitch
);
66 dst_offset
+= (dy
* dst_pitch
) + (dx
* cpp
);
68 BEGIN_RING(chan
, m2mf
,
69 NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT
, 6);
71 OUT_RING (chan
, dst_tile_mode
<< 4);
72 OUT_RING (chan
, dw
* cpp
);
79 int line_count
= height
> 2047 ? 2047 : height
;
82 BEGIN_RING(chan
, m2mf
,
83 NV50_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN_HIGH
, 2);
84 OUT_RELOCh(chan
, src_bo
, src_offset
, src_reloc
);
85 OUT_RELOCh(chan
, dst_bo
, dst_offset
, dst_reloc
);
86 BEGIN_RING(chan
, m2mf
,
87 NV50_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN
, 2);
88 OUT_RELOCl(chan
, src_bo
, src_offset
, src_reloc
);
89 OUT_RELOCl(chan
, dst_bo
, dst_offset
, dst_reloc
);
90 if (src_bo
->tile_flags
) {
91 BEGIN_RING(chan
, m2mf
,
92 NV50_MEMORY_TO_MEMORY_FORMAT_TILING_POSITION_IN
, 1);
93 OUT_RING (chan
, (sy
<< 16) | (sx
* cpp
));
95 src_offset
+= (line_count
* src_pitch
);
97 if (dst_bo
->tile_flags
) {
98 BEGIN_RING(chan
, m2mf
,
99 NV50_MEMORY_TO_MEMORY_FORMAT_TILING_POSITION_OUT
, 1);
100 OUT_RING (chan
, (dy
<< 16) | (dx
* cpp
));
102 dst_offset
+= (line_count
* dst_pitch
);
104 BEGIN_RING(chan
, m2mf
,
105 NV50_MEMORY_TO_MEMORY_FORMAT_LINE_LENGTH_IN
, 4);
106 OUT_RING (chan
, width
* cpp
);
107 OUT_RING (chan
, line_count
);
108 OUT_RING (chan
, 0x00000101);
112 height
-= line_count
;
118 static INLINE
unsigned
119 get_zslice_offset(unsigned tile_mode
, unsigned z
, unsigned pitch
, unsigned ny
)
121 unsigned tile_h
= get_tile_height(tile_mode
);
122 unsigned tile_d
= get_tile_depth(tile_mode
);
124 /* pitch_2d == to next slice within this volume-tile */
125 /* pitch_3d == to next slice in next 2D array of blocks */
126 unsigned pitch_2d
= tile_h
* 64;
127 unsigned pitch_3d
= tile_d
* align(ny
, tile_h
) * pitch
;
129 return (z
% tile_d
) * pitch_2d
+ (z
/ tile_d
) * pitch_3d
;
132 static struct pipe_transfer
*
133 nv50_transfer_new(struct pipe_screen
*pscreen
, struct pipe_texture
*pt
,
134 unsigned face
, unsigned level
, unsigned zslice
,
135 enum pipe_transfer_usage usage
,
136 unsigned x
, unsigned y
, unsigned w
, unsigned h
)
138 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
139 struct nv50_miptree
*mt
= nv50_miptree(pt
);
140 struct nv50_miptree_level
*lvl
= &mt
->level
[level
];
141 struct nv50_transfer
*tx
;
142 unsigned nx
, ny
, image
= 0;
145 if (pt
->target
== PIPE_TEXTURE_CUBE
)
148 tx
= CALLOC_STRUCT(nv50_transfer
);
152 pipe_texture_reference(&tx
->base
.texture
, pt
);
153 tx
->base
.format
= pt
->format
;
156 tx
->base
.block
= pt
->block
;
157 if (!pt
->nblocksx
[level
]) {
158 tx
->base
.nblocksx
= pf_get_nblocksx(&pt
->block
,
160 tx
->base
.nblocksy
= pf_get_nblocksy(&pt
->block
,
163 tx
->base
.nblocksx
= pt
->nblocksx
[level
];
164 tx
->base
.nblocksy
= pt
->nblocksy
[level
];
166 tx
->base
.stride
= tx
->base
.nblocksx
* pt
->block
.size
;
167 tx
->base
.usage
= usage
;
169 tx
->level_pitch
= lvl
->pitch
;
170 tx
->level_width
= mt
->base
.base
.width
[level
];
171 tx
->level_height
= mt
->base
.base
.height
[level
];
172 tx
->level_depth
= mt
->base
.base
.depth
[level
];
173 tx
->level_offset
= lvl
->image_offset
[image
];
174 tx
->level_tiling
= lvl
->tile_mode
;
175 tx
->level_x
= pf_get_nblocksx(&tx
->base
.block
, x
);
176 tx
->level_y
= pf_get_nblocksy(&tx
->base
.block
, y
);
177 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0,
178 tx
->base
.nblocksy
* tx
->base
.stride
, &tx
->bo
);
184 if (pt
->target
== PIPE_TEXTURE_3D
)
185 tx
->level_offset
+= get_zslice_offset(lvl
->tile_mode
, zslice
,
189 if (usage
& PIPE_TRANSFER_READ
) {
190 nx
= pf_get_nblocksx(&tx
->base
.block
, tx
->base
.width
);
191 ny
= pf_get_nblocksy(&tx
->base
.block
, tx
->base
.height
);
193 nv50_transfer_rect_m2mf(pscreen
, mt
->base
.bo
, tx
->level_offset
,
194 tx
->level_pitch
, tx
->level_tiling
,
196 tx
->base
.nblocksx
, tx
->base
.nblocksy
,
199 tx
->base
.stride
, tx
->bo
->tile_mode
,
201 tx
->base
.nblocksx
, tx
->base
.nblocksy
, 1,
202 tx
->base
.block
.size
, nx
, ny
,
203 NOUVEAU_BO_VRAM
| NOUVEAU_BO_GART
,
211 nv50_transfer_del(struct pipe_transfer
*ptx
)
213 struct nv50_transfer
*tx
= (struct nv50_transfer
*)ptx
;
214 struct nv50_miptree
*mt
= nv50_miptree(ptx
->texture
);
216 unsigned nx
= pf_get_nblocksx(&tx
->base
.block
, tx
->base
.width
);
217 unsigned ny
= pf_get_nblocksy(&tx
->base
.block
, tx
->base
.height
);
219 if (ptx
->usage
& PIPE_TRANSFER_WRITE
) {
220 struct pipe_screen
*pscreen
= ptx
->texture
->screen
;
222 nv50_transfer_rect_m2mf(pscreen
, tx
->bo
, 0,
223 tx
->base
.stride
, tx
->bo
->tile_mode
,
225 tx
->base
.nblocksx
, tx
->base
.nblocksy
, 1,
226 mt
->base
.bo
, tx
->level_offset
,
227 tx
->level_pitch
, tx
->level_tiling
,
228 tx
->level_x
, tx
->level_y
,
229 tx
->base
.nblocksx
, tx
->base
.nblocksy
,
231 tx
->base
.block
.size
, nx
, ny
,
232 NOUVEAU_BO_GART
, NOUVEAU_BO_VRAM
|
236 nouveau_bo_ref(NULL
, &tx
->bo
);
237 pipe_texture_reference(&ptx
->texture
, NULL
);
242 nv50_transfer_map(struct pipe_screen
*pscreen
, struct pipe_transfer
*ptx
)
244 struct nv50_transfer
*tx
= (struct nv50_transfer
*)ptx
;
248 if (ptx
->usage
& PIPE_TRANSFER_WRITE
)
249 flags
|= NOUVEAU_BO_WR
;
250 if (ptx
->usage
& PIPE_TRANSFER_READ
)
251 flags
|= NOUVEAU_BO_RD
;
253 ret
= nouveau_bo_map(tx
->bo
, flags
);
260 nv50_transfer_unmap(struct pipe_screen
*pscreen
, struct pipe_transfer
*ptx
)
262 struct nv50_transfer
*tx
= (struct nv50_transfer
*)ptx
;
264 nouveau_bo_unmap(tx
->bo
);
268 nv50_transfer_init_screen_functions(struct pipe_screen
*pscreen
)
270 pscreen
->get_tex_transfer
= nv50_transfer_new
;
271 pscreen
->tex_transfer_destroy
= nv50_transfer_del
;
272 pscreen
->transfer_map
= nv50_transfer_map
;
273 pscreen
->transfer_unmap
= nv50_transfer_unmap
;
277 nv50_upload_sifc(struct nv50_context
*nv50
,
278 struct nouveau_bo
*bo
, unsigned dst_offset
, unsigned reloc
,
279 unsigned dst_format
, int dst_w
, int dst_h
, int dst_pitch
,
280 void *src
, unsigned src_format
, int src_pitch
,
281 int x
, int y
, int w
, int h
, int cpp
)
283 struct nouveau_channel
*chan
= nv50
->screen
->base
.channel
;
284 struct nouveau_grobj
*eng2d
= nv50
->screen
->eng2d
;
285 struct nouveau_grobj
*tesla
= nv50
->screen
->tesla
;
286 unsigned line_dwords
= (w
* cpp
+ 3) / 4;
288 reloc
|= NOUVEAU_BO_WR
;
290 WAIT_RING (chan
, 32);
292 if (bo
->tile_flags
) {
293 BEGIN_RING(chan
, eng2d
, NV50_2D_DST_FORMAT
, 5);
294 OUT_RING (chan
, dst_format
);
296 OUT_RING (chan
, bo
->tile_mode
<< 4);
300 BEGIN_RING(chan
, eng2d
, NV50_2D_DST_FORMAT
, 2);
301 OUT_RING (chan
, dst_format
);
303 BEGIN_RING(chan
, eng2d
, NV50_2D_DST_PITCH
, 1);
304 OUT_RING (chan
, dst_pitch
);
307 BEGIN_RING(chan
, eng2d
, NV50_2D_DST_WIDTH
, 4);
308 OUT_RING (chan
, dst_w
);
309 OUT_RING (chan
, dst_h
);
310 OUT_RELOCh(chan
, bo
, dst_offset
, reloc
);
311 OUT_RELOCl(chan
, bo
, dst_offset
, reloc
);
313 /* NV50_2D_OPERATION_SRCCOPY assumed already set */
315 BEGIN_RING(chan
, eng2d
, NV50_2D_SIFC_UNK0800
, 2);
317 OUT_RING (chan
, src_format
);
318 BEGIN_RING(chan
, eng2d
, NV50_2D_SIFC_WIDTH
, 10);
331 const uint32_t *p
= src
;
332 unsigned count
= line_dwords
;
335 unsigned nr
= MIN2(count
, 1792);
337 if (chan
->pushbuf
->remaining
<= nr
) {
340 BEGIN_RING(chan
, eng2d
,
341 NV50_2D_DST_ADDRESS_HIGH
, 2);
342 OUT_RELOCh(chan
, bo
, dst_offset
, reloc
);
343 OUT_RELOCl(chan
, bo
, dst_offset
, reloc
);
345 assert(chan
->pushbuf
->remaining
> nr
);
347 BEGIN_RING(chan
, eng2d
,
348 NV50_2D_SIFC_DATA
| (2 << 29), nr
);
349 OUT_RINGp (chan
, p
, nr
);
358 BEGIN_RING(chan
, tesla
, 0x1440, 1);