1 #include "pipe/p_context.h"
2 #include "pipe/p_format.h"
3 #include "util/u_math.h"
4 #include "util/u_memory.h"
6 #include "nouveau/nouveau_winsys.h"
7 #include "nouveau/nouveau_util.h"
8 #include "nouveau/nouveau_screen.h"
9 #include "nv04_surface_2d.h"
12 nv04_surface_format(enum pipe_format format
)
15 case PIPE_FORMAT_A8_UNORM
:
16 case PIPE_FORMAT_L8_UNORM
:
17 case PIPE_FORMAT_I8_UNORM
:
18 return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8
;
19 case PIPE_FORMAT_R16_SNORM
:
20 case PIPE_FORMAT_R5G6B5_UNORM
:
21 case PIPE_FORMAT_Z16_UNORM
:
22 case PIPE_FORMAT_A8L8_UNORM
:
23 return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5
;
24 case PIPE_FORMAT_X8R8G8B8_UNORM
:
25 case PIPE_FORMAT_A8R8G8B8_UNORM
:
26 return NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8
;
27 case PIPE_FORMAT_Z24S8_UNORM
:
28 case PIPE_FORMAT_Z24X8_UNORM
:
29 return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32
;
36 nv04_rect_format(enum pipe_format format
)
39 case PIPE_FORMAT_A8_UNORM
:
40 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8
;
41 case PIPE_FORMAT_R5G6B5_UNORM
:
42 case PIPE_FORMAT_A8L8_UNORM
:
43 case PIPE_FORMAT_Z16_UNORM
:
44 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5
;
45 case PIPE_FORMAT_X8R8G8B8_UNORM
:
46 case PIPE_FORMAT_A8R8G8B8_UNORM
:
47 case PIPE_FORMAT_Z24S8_UNORM
:
48 case PIPE_FORMAT_Z24X8_UNORM
:
49 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8
;
56 nv04_scaled_image_format(enum pipe_format format
)
59 case PIPE_FORMAT_A8_UNORM
:
60 case PIPE_FORMAT_L8_UNORM
:
61 case PIPE_FORMAT_I8_UNORM
:
62 return NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_Y8
;
63 case PIPE_FORMAT_A1R5G5B5_UNORM
:
64 return NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A1R5G5B5
;
65 case PIPE_FORMAT_A8R8G8B8_UNORM
:
66 return NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A8R8G8B8
;
67 case PIPE_FORMAT_X8R8G8B8_UNORM
:
68 return NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_X8R8G8B8
;
69 case PIPE_FORMAT_R5G6B5_UNORM
:
70 case PIPE_FORMAT_R16_SNORM
:
71 case PIPE_FORMAT_A8L8_UNORM
:
72 return NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_R5G6B5
;
78 static INLINE
unsigned
79 nv04_swizzle_bits(unsigned x
, unsigned y
)
81 unsigned u
= (x
& 0x001) << 0 |
94 unsigned v
= (y
& 0x001) << 1 |
110 nv04_surface_copy_swizzle(struct nv04_surface_2d
*ctx
,
111 struct pipe_surface
*dst
, int dx
, int dy
,
112 struct pipe_surface
*src
, int sx
, int sy
,
115 struct nouveau_channel
*chan
= ctx
->swzsurf
->channel
;
116 struct nouveau_grobj
*swzsurf
= ctx
->swzsurf
;
117 struct nouveau_grobj
*sifm
= ctx
->sifm
;
118 struct nouveau_bo
*src_bo
= nouveau_bo(ctx
->buf(src
));
119 struct nouveau_bo
*dst_bo
= nouveau_bo(ctx
->buf(dst
));
120 const unsigned src_pitch
= ((struct nv04_surface
*)src
)->pitch
;
121 /* Max width & height may not be the same on all HW, but must be POT */
122 const unsigned max_w
= 1024;
123 const unsigned max_h
= 1024;
124 unsigned sub_w
= w
> max_w
? max_w
: w
;
125 unsigned sub_h
= h
> max_h
? max_h
: h
;
129 /* Swizzled surfaces must be POT */
130 assert(util_is_pot(dst
->width
) && util_is_pot(dst
->height
));
132 /* If area is too large to copy in one shot we must copy it in POT chunks to meet alignment requirements */
133 assert(sub_w
== w
|| util_is_pot(sub_w
));
134 assert(sub_h
== h
|| util_is_pot(sub_h
));
136 MARK_RING (chan
, 8 + ((w
+sub_w
)/sub_w
)*((h
+sub_h
)/sub_h
)*17, 2 +
137 ((w
+sub_w
)/sub_w
)*((h
+sub_h
)/sub_h
)*2);
139 BEGIN_RING(chan
, swzsurf
, NV04_SWIZZLED_SURFACE_DMA_IMAGE
, 1);
140 OUT_RELOCo(chan
, dst_bo
,
141 NOUVEAU_BO_GART
| NOUVEAU_BO_VRAM
| NOUVEAU_BO_WR
);
143 BEGIN_RING(chan
, swzsurf
, NV04_SWIZZLED_SURFACE_FORMAT
, 1);
144 OUT_RING (chan
, nv04_surface_format(dst
->format
) |
145 log2i(dst
->width
) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_U_SHIFT
|
146 log2i(dst
->height
) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_V_SHIFT
);
148 BEGIN_RING(chan
, sifm
, NV04_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE
, 1);
149 OUT_RELOCo(chan
, src_bo
,
150 NOUVEAU_BO_GART
| NOUVEAU_BO_VRAM
| NOUVEAU_BO_RD
);
151 BEGIN_RING(chan
, sifm
, NV04_SCALED_IMAGE_FROM_MEMORY_SURFACE
, 1);
152 OUT_RING (chan
, swzsurf
->handle
);
154 for (y
= 0; y
< h
; y
+= sub_h
) {
155 sub_h
= MIN2(sub_h
, h
- y
);
157 for (x
= 0; x
< w
; x
+= sub_w
) {
158 sub_w
= MIN2(sub_w
, w
- x
);
160 /* Must be 64-byte aligned */
161 assert(!((dst
->offset
+ nv04_swizzle_bits(dx
+x
, dy
+y
) * pf_get_blocksize(dst
->texture
->format
)) & 63));
163 BEGIN_RING(chan
, swzsurf
, NV04_SWIZZLED_SURFACE_OFFSET
, 1);
164 OUT_RELOCl(chan
, dst_bo
, dst
->offset
+ nv04_swizzle_bits(dx
+x
, dy
+y
) * pf_get_blocksize(dst
->texture
->format
),
165 NOUVEAU_BO_GART
| NOUVEAU_BO_VRAM
| NOUVEAU_BO_WR
);
167 BEGIN_RING(chan
, sifm
, NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION
, 9);
168 OUT_RING (chan
, NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE
);
169 OUT_RING (chan
, nv04_scaled_image_format(src
->format
));
170 OUT_RING (chan
, NV04_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY
);
172 OUT_RING (chan
, sub_h
<< NV04_SCALED_IMAGE_FROM_MEMORY_CLIP_SIZE_H_SHIFT
| sub_w
);
174 OUT_RING (chan
, sub_h
<< NV04_SCALED_IMAGE_FROM_MEMORY_OUT_SIZE_H_SHIFT
| sub_w
);
175 OUT_RING (chan
, 1 << 20);
176 OUT_RING (chan
, 1 << 20);
178 BEGIN_RING(chan
, sifm
, NV04_SCALED_IMAGE_FROM_MEMORY_SIZE
, 4);
179 OUT_RING (chan
, sub_h
<< NV04_SCALED_IMAGE_FROM_MEMORY_SIZE_H_SHIFT
| sub_w
);
180 OUT_RING (chan
, src_pitch
|
181 NV04_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER
|
182 NV04_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE
);
183 OUT_RELOCl(chan
, src_bo
, src
->offset
+ (sy
+y
) * src_pitch
+ (sx
+x
) * pf_get_blocksize(src
->texture
->format
),
184 NOUVEAU_BO_GART
| NOUVEAU_BO_VRAM
| NOUVEAU_BO_RD
);
193 nv04_surface_copy_m2mf(struct nv04_surface_2d
*ctx
,
194 struct pipe_surface
*dst
, int dx
, int dy
,
195 struct pipe_surface
*src
, int sx
, int sy
, int w
, int h
)
197 struct nouveau_channel
*chan
= ctx
->m2mf
->channel
;
198 struct nouveau_grobj
*m2mf
= ctx
->m2mf
;
199 struct nouveau_bo
*src_bo
= nouveau_bo(ctx
->buf(src
));
200 struct nouveau_bo
*dst_bo
= nouveau_bo(ctx
->buf(dst
));
201 unsigned src_pitch
= ((struct nv04_surface
*)src
)->pitch
;
202 unsigned dst_pitch
= ((struct nv04_surface
*)dst
)->pitch
;
203 unsigned dst_offset
= dst
->offset
+ dy
* dst_pitch
+
204 dx
* pf_get_blocksize(dst
->texture
->format
);
205 unsigned src_offset
= src
->offset
+ sy
* src_pitch
+
206 sx
* pf_get_blocksize(src
->texture
->format
);
208 MARK_RING (chan
, 3 + ((h
/ 2047) + 1) * 9, 2 + ((h
/ 2047) + 1) * 2);
209 BEGIN_RING(chan
, m2mf
, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN
, 2);
210 OUT_RELOCo(chan
, src_bo
,
211 NOUVEAU_BO_GART
| NOUVEAU_BO_VRAM
| NOUVEAU_BO_RD
);
212 OUT_RELOCo(chan
, dst_bo
,
213 NOUVEAU_BO_GART
| NOUVEAU_BO_VRAM
| NOUVEAU_BO_WR
);
216 int count
= (h
> 2047) ? 2047 : h
;
218 BEGIN_RING(chan
, m2mf
, NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN
, 8);
219 OUT_RELOCl(chan
, src_bo
, src_offset
,
220 NOUVEAU_BO_VRAM
| NOUVEAU_BO_GART
| NOUVEAU_BO_RD
);
221 OUT_RELOCl(chan
, dst_bo
, dst_offset
,
222 NOUVEAU_BO_VRAM
| NOUVEAU_BO_GART
| NOUVEAU_BO_WR
);
223 OUT_RING (chan
, src_pitch
);
224 OUT_RING (chan
, dst_pitch
);
225 OUT_RING (chan
, w
* pf_get_blocksize(src
->texture
->format
));
226 OUT_RING (chan
, count
);
227 OUT_RING (chan
, 0x0101);
231 src_offset
+= src_pitch
* count
;
232 dst_offset
+= dst_pitch
* count
;
239 nv04_surface_copy_blit(struct nv04_surface_2d
*ctx
, struct pipe_surface
*dst
,
240 int dx
, int dy
, struct pipe_surface
*src
, int sx
, int sy
,
243 struct nouveau_channel
*chan
= ctx
->surf2d
->channel
;
244 struct nouveau_grobj
*surf2d
= ctx
->surf2d
;
245 struct nouveau_grobj
*blit
= ctx
->blit
;
246 struct nouveau_bo
*src_bo
= nouveau_bo(ctx
->buf(src
));
247 struct nouveau_bo
*dst_bo
= nouveau_bo(ctx
->buf(dst
));
248 unsigned src_pitch
= ((struct nv04_surface
*)src
)->pitch
;
249 unsigned dst_pitch
= ((struct nv04_surface
*)dst
)->pitch
;
252 format
= nv04_surface_format(dst
->format
);
256 MARK_RING (chan
, 12, 4);
257 BEGIN_RING(chan
, surf2d
, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE
, 2);
258 OUT_RELOCo(chan
, src_bo
, NOUVEAU_BO_VRAM
| NOUVEAU_BO_RD
);
259 OUT_RELOCo(chan
, dst_bo
, NOUVEAU_BO_VRAM
| NOUVEAU_BO_WR
);
260 BEGIN_RING(chan
, surf2d
, NV04_CONTEXT_SURFACES_2D_FORMAT
, 4);
261 OUT_RING (chan
, format
);
262 OUT_RING (chan
, (dst_pitch
<< 16) | src_pitch
);
263 OUT_RELOCl(chan
, src_bo
, src
->offset
, NOUVEAU_BO_VRAM
| NOUVEAU_BO_RD
);
264 OUT_RELOCl(chan
, dst_bo
, dst
->offset
, NOUVEAU_BO_VRAM
| NOUVEAU_BO_WR
);
266 BEGIN_RING(chan
, blit
, 0x0300, 3);
267 OUT_RING (chan
, (sy
<< 16) | sx
);
268 OUT_RING (chan
, (dy
<< 16) | dx
);
269 OUT_RING (chan
, ( h
<< 16) | w
);
275 nv04_surface_copy(struct nv04_surface_2d
*ctx
, struct pipe_surface
*dst
,
276 int dx
, int dy
, struct pipe_surface
*src
, int sx
, int sy
,
279 unsigned src_pitch
= ((struct nv04_surface
*)src
)->pitch
;
280 unsigned dst_pitch
= ((struct nv04_surface
*)dst
)->pitch
;
281 int src_linear
= src
->texture
->tex_usage
& NOUVEAU_TEXTURE_USAGE_LINEAR
;
282 int dst_linear
= dst
->texture
->tex_usage
& NOUVEAU_TEXTURE_USAGE_LINEAR
;
284 assert(src
->format
== dst
->format
);
286 /* Setup transfer to swizzle the texture to vram if needed */
287 if (src_linear
&& !dst_linear
&& w
> 1 && h
> 1) {
288 nv04_surface_copy_swizzle(ctx
, dst
, dx
, dy
, src
, sx
, sy
, w
, h
);
292 /* NV_CONTEXT_SURFACES_2D has buffer alignment restrictions, fallback
293 * to NV_MEMORY_TO_MEMORY_FORMAT in this case.
295 if ((src
->offset
& 63) || (dst
->offset
& 63) ||
296 (src_pitch
& 63) || (dst_pitch
& 63)) {
297 nv04_surface_copy_m2mf(ctx
, dst
, dx
, dy
, src
, sx
, sy
, w
, h
);
301 nv04_surface_copy_blit(ctx
, dst
, dx
, dy
, src
, sx
, sy
, w
, h
);
305 nv04_surface_fill(struct nv04_surface_2d
*ctx
, struct pipe_surface
*dst
,
306 int dx
, int dy
, int w
, int h
, unsigned value
)
308 struct nouveau_channel
*chan
= ctx
->surf2d
->channel
;
309 struct nouveau_grobj
*surf2d
= ctx
->surf2d
;
310 struct nouveau_grobj
*rect
= ctx
->rect
;
311 struct nouveau_bo
*dst_bo
= nouveau_bo(ctx
->buf(dst
));
312 unsigned dst_pitch
= ((struct nv04_surface
*)dst
)->pitch
;
313 int cs2d_format
, gdirect_format
;
315 cs2d_format
= nv04_surface_format(dst
->format
);
316 assert(cs2d_format
>= 0);
318 gdirect_format
= nv04_rect_format(dst
->format
);
319 assert(gdirect_format
>= 0);
321 MARK_RING (chan
, 16, 4);
322 BEGIN_RING(chan
, surf2d
, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE
, 2);
323 OUT_RELOCo(chan
, dst_bo
, NOUVEAU_BO_VRAM
| NOUVEAU_BO_WR
);
324 OUT_RELOCo(chan
, dst_bo
, NOUVEAU_BO_VRAM
| NOUVEAU_BO_WR
);
325 BEGIN_RING(chan
, surf2d
, NV04_CONTEXT_SURFACES_2D_FORMAT
, 4);
326 OUT_RING (chan
, cs2d_format
);
327 OUT_RING (chan
, (dst_pitch
<< 16) | dst_pitch
);
328 OUT_RELOCl(chan
, dst_bo
, dst
->offset
, NOUVEAU_BO_VRAM
| NOUVEAU_BO_WR
);
329 OUT_RELOCl(chan
, dst_bo
, dst
->offset
, NOUVEAU_BO_VRAM
| NOUVEAU_BO_WR
);
331 BEGIN_RING(chan
, rect
, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT
, 1);
332 OUT_RING (chan
, gdirect_format
);
333 BEGIN_RING(chan
, rect
, NV04_GDI_RECTANGLE_TEXT_COLOR1_A
, 1);
334 OUT_RING (chan
, value
);
335 BEGIN_RING(chan
, rect
,
336 NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
337 OUT_RING (chan
, (dx
<< 16) | dy
);
338 OUT_RING (chan
, ( w
<< 16) | h
);
342 nv04_surface_2d_takedown(struct nv04_surface_2d
**pctx
)
344 struct nv04_surface_2d
*ctx
;
351 nouveau_notifier_free(&ctx
->ntfy
);
352 nouveau_grobj_free(&ctx
->m2mf
);
353 nouveau_grobj_free(&ctx
->surf2d
);
354 nouveau_grobj_free(&ctx
->swzsurf
);
355 nouveau_grobj_free(&ctx
->rect
);
356 nouveau_grobj_free(&ctx
->blit
);
357 nouveau_grobj_free(&ctx
->sifm
);
362 struct nv04_surface_2d
*
363 nv04_surface_2d_init(struct nouveau_screen
*screen
)
365 struct nv04_surface_2d
*ctx
= CALLOC_STRUCT(nv04_surface_2d
);
366 struct nouveau_channel
*chan
= screen
->channel
;
367 unsigned handle
= 0x88000000, class;
373 ret
= nouveau_notifier_alloc(chan
, handle
++, 1, &ctx
->ntfy
);
375 nv04_surface_2d_takedown(&ctx
);
379 ret
= nouveau_grobj_alloc(chan
, handle
++, 0x0039, &ctx
->m2mf
);
381 nv04_surface_2d_takedown(&ctx
);
385 BEGIN_RING(chan
, ctx
->m2mf
, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY
, 1);
386 OUT_RING (chan
, ctx
->ntfy
->handle
);
388 if (chan
->device
->chipset
< 0x10)
389 class = NV04_CONTEXT_SURFACES_2D
;
391 class = NV10_CONTEXT_SURFACES_2D
;
393 ret
= nouveau_grobj_alloc(chan
, handle
++, class, &ctx
->surf2d
);
395 nv04_surface_2d_takedown(&ctx
);
399 BEGIN_RING(chan
, ctx
->surf2d
,
400 NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE
, 2);
401 OUT_RING (chan
, chan
->vram
->handle
);
402 OUT_RING (chan
, chan
->vram
->handle
);
404 if (chan
->device
->chipset
< 0x10)
405 class = NV04_IMAGE_BLIT
;
407 class = NV12_IMAGE_BLIT
;
409 ret
= nouveau_grobj_alloc(chan
, handle
++, class, &ctx
->blit
);
411 nv04_surface_2d_takedown(&ctx
);
415 BEGIN_RING(chan
, ctx
->blit
, NV04_IMAGE_BLIT_DMA_NOTIFY
, 1);
416 OUT_RING (chan
, ctx
->ntfy
->handle
);
417 BEGIN_RING(chan
, ctx
->blit
, NV04_IMAGE_BLIT_SURFACE
, 1);
418 OUT_RING (chan
, ctx
->surf2d
->handle
);
419 BEGIN_RING(chan
, ctx
->blit
, NV04_IMAGE_BLIT_OPERATION
, 1);
420 OUT_RING (chan
, NV04_IMAGE_BLIT_OPERATION_SRCCOPY
);
422 ret
= nouveau_grobj_alloc(chan
, handle
++, NV04_GDI_RECTANGLE_TEXT
,
425 nv04_surface_2d_takedown(&ctx
);
429 BEGIN_RING(chan
, ctx
->rect
, NV04_GDI_RECTANGLE_TEXT_DMA_NOTIFY
, 1);
430 OUT_RING (chan
, ctx
->ntfy
->handle
);
431 BEGIN_RING(chan
, ctx
->rect
, NV04_GDI_RECTANGLE_TEXT_SURFACE
, 1);
432 OUT_RING (chan
, ctx
->surf2d
->handle
);
433 BEGIN_RING(chan
, ctx
->rect
, NV04_GDI_RECTANGLE_TEXT_OPERATION
, 1);
434 OUT_RING (chan
, NV04_GDI_RECTANGLE_TEXT_OPERATION_SRCCOPY
);
435 BEGIN_RING(chan
, ctx
->rect
,
436 NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT
, 1);
437 OUT_RING (chan
, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE
);
439 switch (chan
->device
->chipset
& 0xf0) {
442 class = NV04_SWIZZLED_SURFACE
;
445 class = NV20_SWIZZLED_SURFACE
;
448 class = NV30_SWIZZLED_SURFACE
;
452 class = NV40_SWIZZLED_SURFACE
;
455 /* Famous last words: this really can't happen.. */
460 ret
= nouveau_grobj_alloc(chan
, handle
++, class, &ctx
->swzsurf
);
462 nv04_surface_2d_takedown(&ctx
);
466 switch (chan
->device
->chipset
& 0xf0) {
469 class = NV10_SCALED_IMAGE_FROM_MEMORY
;
472 class = NV30_SCALED_IMAGE_FROM_MEMORY
;
476 class = NV40_SCALED_IMAGE_FROM_MEMORY
;
479 class = NV04_SCALED_IMAGE_FROM_MEMORY
;
483 ret
= nouveau_grobj_alloc(chan
, handle
++, class, &ctx
->sifm
);
485 nv04_surface_2d_takedown(&ctx
);
489 ctx
->copy
= nv04_surface_copy
;
490 ctx
->fill
= nv04_surface_fill
;