nv04_surface.c revision 0c1b71665487fcaeffa8f4d7b5ad0ba425a2c169
1/*
2 * Copyright (C) 2007-2010 The Nouveau Project.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27#include "nouveau_driver.h"
28#include "nv_object.xml.h"
29#include "nv_m2mf.xml.h"
30#include "nv01_2d.xml.h"
31#include "nv04_3d.xml.h"
32#include "nouveau_context.h"
33#include "nouveau_util.h"
34#include "nv04_driver.h"
35
36static inline int
37swzsurf_format(gl_format format)
38{
39	switch (format) {
40	case MESA_FORMAT_A8:
41	case MESA_FORMAT_L8:
42	case MESA_FORMAT_I8:
43	case MESA_FORMAT_RGB332:
44		return NV04_SWIZZLED_SURFACE_FORMAT_COLOR_Y8;
45
46	case MESA_FORMAT_RGB565:
47	case MESA_FORMAT_RGB565_REV:
48	case MESA_FORMAT_ARGB4444:
49	case MESA_FORMAT_ARGB4444_REV:
50	case MESA_FORMAT_ARGB1555:
51	case MESA_FORMAT_RGBA5551:
52	case MESA_FORMAT_ARGB1555_REV:
53	case MESA_FORMAT_AL88:
54	case MESA_FORMAT_AL88_REV:
55	case MESA_FORMAT_YCBCR:
56	case MESA_FORMAT_YCBCR_REV:
57	case MESA_FORMAT_Z16:
58		return NV04_SWIZZLED_SURFACE_FORMAT_COLOR_R5G6B5;
59
60	case MESA_FORMAT_RGBA8888:
61	case MESA_FORMAT_RGBA8888_REV:
62	case MESA_FORMAT_XRGB8888:
63	case MESA_FORMAT_ARGB8888:
64	case MESA_FORMAT_ARGB8888_REV:
65	case MESA_FORMAT_S8_Z24:
66	case MESA_FORMAT_Z24_S8:
67	case MESA_FORMAT_Z32:
68		return NV04_SWIZZLED_SURFACE_FORMAT_COLOR_A8R8G8B8;
69
70	default:
71		assert(0);
72	}
73}
74
75static inline int
76surf2d_format(gl_format format)
77{
78	switch (format) {
79	case MESA_FORMAT_A8:
80	case MESA_FORMAT_L8:
81	case MESA_FORMAT_I8:
82	case MESA_FORMAT_RGB332:
83		return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8;
84
85	case MESA_FORMAT_RGB565:
86	case MESA_FORMAT_RGB565_REV:
87	case MESA_FORMAT_ARGB4444:
88	case MESA_FORMAT_ARGB4444_REV:
89	case MESA_FORMAT_ARGB1555:
90	case MESA_FORMAT_RGBA5551:
91	case MESA_FORMAT_ARGB1555_REV:
92	case MESA_FORMAT_AL88:
93	case MESA_FORMAT_AL88_REV:
94	case MESA_FORMAT_YCBCR:
95	case MESA_FORMAT_YCBCR_REV:
96	case MESA_FORMAT_Z16:
97		return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5;
98
99	case MESA_FORMAT_RGBA8888:
100	case MESA_FORMAT_RGBA8888_REV:
101	case MESA_FORMAT_XRGB8888:
102	case MESA_FORMAT_ARGB8888:
103	case MESA_FORMAT_ARGB8888_REV:
104	case MESA_FORMAT_S8_Z24:
105	case MESA_FORMAT_Z24_S8:
106	case MESA_FORMAT_Z32:
107		return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
108
109	default:
110		assert(0);
111	}
112}
113
114static inline int
115rect_format(gl_format format)
116{
117	switch (format) {
118	case MESA_FORMAT_A8:
119	case MESA_FORMAT_L8:
120	case MESA_FORMAT_I8:
121	case MESA_FORMAT_RGB332:
122		return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
123
124	case MESA_FORMAT_RGB565:
125	case MESA_FORMAT_RGB565_REV:
126	case MESA_FORMAT_ARGB4444:
127	case MESA_FORMAT_ARGB4444_REV:
128	case MESA_FORMAT_ARGB1555:
129	case MESA_FORMAT_RGBA5551:
130	case MESA_FORMAT_ARGB1555_REV:
131	case MESA_FORMAT_AL88:
132	case MESA_FORMAT_AL88_REV:
133	case MESA_FORMAT_YCBCR:
134	case MESA_FORMAT_YCBCR_REV:
135	case MESA_FORMAT_Z16:
136		return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
137
138	case MESA_FORMAT_RGBA8888:
139	case MESA_FORMAT_RGBA8888_REV:
140	case MESA_FORMAT_XRGB8888:
141	case MESA_FORMAT_ARGB8888:
142	case MESA_FORMAT_ARGB8888_REV:
143	case MESA_FORMAT_S8_Z24:
144	case MESA_FORMAT_Z24_S8:
145	case MESA_FORMAT_Z32:
146		return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
147
148	default:
149		assert(0);
150	}
151}
152
153static inline int
154sifm_format(gl_format format)
155{
156	switch (format) {
157	case MESA_FORMAT_A8:
158	case MESA_FORMAT_L8:
159	case MESA_FORMAT_I8:
160	case MESA_FORMAT_RGB332:
161		return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_AY8;
162
163	case MESA_FORMAT_RGB565:
164	case MESA_FORMAT_RGB565_REV:
165	case MESA_FORMAT_ARGB4444:
166	case MESA_FORMAT_ARGB4444_REV:
167	case MESA_FORMAT_ARGB1555:
168	case MESA_FORMAT_RGBA5551:
169	case MESA_FORMAT_ARGB1555_REV:
170	case MESA_FORMAT_AL88:
171	case MESA_FORMAT_AL88_REV:
172	case MESA_FORMAT_YCBCR:
173	case MESA_FORMAT_YCBCR_REV:
174	case MESA_FORMAT_Z16:
175		return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_R5G6B5;
176
177	case MESA_FORMAT_RGBA8888:
178	case MESA_FORMAT_RGBA8888_REV:
179	case MESA_FORMAT_XRGB8888:
180	case MESA_FORMAT_ARGB8888:
181	case MESA_FORMAT_ARGB8888_REV:
182	case MESA_FORMAT_S8_Z24:
183	case MESA_FORMAT_Z24_S8:
184	case MESA_FORMAT_Z32:
185		return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A8R8G8B8;
186
187	default:
188		assert(0);
189	}
190}
191
192static void
193nv04_surface_copy_swizzle(struct gl_context *ctx,
194			  struct nouveau_surface *dst,
195			  struct nouveau_surface *src,
196			  int dx, int dy, int sx, int sy,
197			  int w, int h)
198{
199	struct nouveau_channel *chan = context_chan(ctx);
200	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
201	struct nouveau_grobj *swzsurf = hw->swzsurf;
202	struct nouveau_grobj *sifm = hw->sifm;
203	struct nouveau_bo_context *bctx = context_bctx(ctx, SURFACE);
204	const unsigned bo_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART;
205	/* Max width & height may not be the same on all HW, but must be POT */
206	const unsigned max_w = 1024;
207	const unsigned max_h = 1024;
208	unsigned sub_w = w > max_w ? max_w : w;
209	unsigned sub_h = h > max_h ? max_h : h;
210	unsigned x, y;
211
212        /* Swizzled surfaces must be POT  */
213	assert(_mesa_is_pow_two(dst->width) &&
214	       _mesa_is_pow_two(dst->height));
215
216	nouveau_bo_marko(bctx, sifm, NV03_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE,
217			 src->bo, bo_flags | NOUVEAU_BO_RD);
218	nouveau_bo_marko(bctx, swzsurf, NV04_SWIZZLED_SURFACE_DMA_IMAGE,
219			 dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
220	nouveau_bo_markl(bctx, swzsurf, NV04_SWIZZLED_SURFACE_OFFSET,
221			 dst->bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
222
223	BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_FORMAT, 1);
224	OUT_RING  (chan, swzsurf_format(dst->format) |
225		   log2i(dst->width) << 16 |
226		   log2i(dst->height) << 24);
227
228	BEGIN_RING(chan, sifm, NV04_SCALED_IMAGE_FROM_MEMORY_SURFACE, 1);
229	OUT_RING  (chan, swzsurf->handle);
230
231	for (y = 0; y < h; y += sub_h) {
232		sub_h = MIN2(sub_h, h - y);
233
234		for (x = 0; x < w; x += sub_w) {
235			sub_w = MIN2(sub_w, w - x);
236
237			MARK_RING(chan, 15, 1);
238
239			BEGIN_RING(chan, sifm,
240				   NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT, 8);
241			OUT_RING(chan, sifm_format(src->format));
242			OUT_RING(chan, NV03_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY);
243			OUT_RING(chan, (y + dy) << 16 | (x + dx));
244			OUT_RING(chan, sub_h << 16 | sub_w);
245			OUT_RING(chan, (y + dy) << 16 | (x + dx));
246			OUT_RING(chan, sub_h << 16 | sub_w);
247			OUT_RING(chan, 1 << 20);
248			OUT_RING(chan, 1 << 20);
249
250			BEGIN_RING(chan, sifm,
251				   NV03_SCALED_IMAGE_FROM_MEMORY_SIZE, 4);
252			OUT_RING(chan, align(sub_h, 2) << 16 | align(sub_w, 2));
253			OUT_RING(chan, src->pitch  |
254				 NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER |
255				 NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE);
256			OUT_RELOCl(chan, src->bo, src->offset +
257				   (y + sy) * src->pitch +
258				   (x + sx) * src->cpp,
259				   bo_flags | NOUVEAU_BO_RD);
260			OUT_RING(chan, 0);
261		}
262	}
263
264	nouveau_bo_context_reset(bctx);
265
266	if (context_chipset(ctx) < 0x10)
267		FIRE_RING(chan);
268}
269
270static void
271nv04_surface_copy_m2mf(struct gl_context *ctx,
272		       struct nouveau_surface *dst,
273		       struct nouveau_surface *src,
274		       int dx, int dy, int sx, int sy,
275		       int w, int h)
276{
277	struct nouveau_channel *chan = context_chan(ctx);
278	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
279	struct nouveau_grobj *m2mf = hw->m2mf;
280	struct nouveau_bo_context *bctx = context_bctx(ctx, SURFACE);
281	const unsigned bo_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART;
282	unsigned dst_offset = dst->offset + dy * dst->pitch + dx * dst->cpp;
283	unsigned src_offset = src->offset + sy * src->pitch + sx * src->cpp;
284
285	nouveau_bo_marko(bctx, m2mf, NV04_M2MF_DMA_BUFFER_IN,
286			 src->bo, bo_flags | NOUVEAU_BO_RD);
287	nouveau_bo_marko(bctx, m2mf, NV04_M2MF_DMA_BUFFER_OUT,
288			 dst->bo, bo_flags | NOUVEAU_BO_WR);
289
290	while (h) {
291		int count = (h > 2047) ? 2047 : h;
292
293		MARK_RING(chan, 9, 2);
294
295		BEGIN_RING(chan, m2mf, NV04_M2MF_OFFSET_IN, 8);
296		OUT_RELOCl(chan, src->bo, src_offset,
297			   bo_flags | NOUVEAU_BO_RD);
298		OUT_RELOCl(chan, dst->bo, dst_offset,
299			   bo_flags | NOUVEAU_BO_WR);
300		OUT_RING  (chan, src->pitch);
301		OUT_RING  (chan, dst->pitch);
302		OUT_RING  (chan, w * src->cpp);
303		OUT_RING  (chan, count);
304		OUT_RING  (chan, 0x0101);
305		OUT_RING  (chan, 0);
306
307		h -= count;
308		src_offset += src->pitch * count;
309		dst_offset += dst->pitch * count;
310	}
311
312	nouveau_bo_context_reset(bctx);
313
314	if (context_chipset(ctx) < 0x10)
315		FIRE_RING(chan);
316}
317
318typedef unsigned (*get_offset_t)(struct nouveau_surface *s,
319				 unsigned x, unsigned y);
320
321static unsigned
322get_linear_offset(struct nouveau_surface *s, unsigned x, unsigned y)
323{
324	return x * s->cpp + y * s->pitch;
325}
326
327static unsigned
328get_swizzled_offset(struct nouveau_surface *s, unsigned x, unsigned y)
329{
330	unsigned k = log2i(MIN2(s->width, s->height));
331
332	unsigned u = (x & 0x001) << 0 |
333		(x & 0x002) << 1 |
334		(x & 0x004) << 2 |
335		(x & 0x008) << 3 |
336		(x & 0x010) << 4 |
337		(x & 0x020) << 5 |
338		(x & 0x040) << 6 |
339		(x & 0x080) << 7 |
340		(x & 0x100) << 8 |
341		(x & 0x200) << 9 |
342		(x & 0x400) << 10 |
343		(x & 0x800) << 11;
344
345	unsigned v = (y & 0x001) << 1 |
346		(y & 0x002) << 2 |
347		(y & 0x004) << 3 |
348		(y & 0x008) << 4 |
349		(y & 0x010) << 5 |
350		(y & 0x020) << 6 |
351		(y & 0x040) << 7 |
352		(y & 0x080) << 8 |
353		(y & 0x100) << 9 |
354		(y & 0x200) << 10 |
355		(y & 0x400) << 11 |
356		(y & 0x800) << 12;
357
358	return s->cpp * (((u | v) & ~(~0 << 2*k)) |
359			 (x & (~0 << k)) << k |
360			 (y & (~0 << k)) << k);
361}
362
363static void
364nv04_surface_copy_cpu(struct gl_context *ctx,
365		      struct nouveau_surface *dst,
366		      struct nouveau_surface *src,
367		      int dx, int dy, int sx, int sy,
368		      int w, int h)
369{
370	int x, y;
371	get_offset_t get_dst = (dst->layout == SWIZZLED ?
372				get_swizzled_offset : get_linear_offset);
373	get_offset_t get_src = (src->layout == SWIZZLED ?
374				get_swizzled_offset : get_linear_offset);
375	void *dp, *sp;
376
377	nouveau_bo_map(dst->bo, NOUVEAU_BO_WR);
378	nouveau_bo_map(src->bo, NOUVEAU_BO_RD);
379
380	dp = dst->bo->map + dst->offset;
381	sp = src->bo->map + src->offset;
382
383	for (y = 0; y < h; y++) {
384		for (x = 0; x < w; x++) {
385			memcpy(dp + get_dst(dst, dx + x, dy + y),
386			       sp + get_src(src, sx + x, sy + y), dst->cpp);
387		}
388	}
389
390	nouveau_bo_unmap(src->bo);
391	nouveau_bo_unmap(dst->bo);
392}
393
394void
395nv04_surface_copy(struct gl_context *ctx,
396		  struct nouveau_surface *dst,
397		  struct nouveau_surface *src,
398		  int dx, int dy, int sx, int sy,
399		  int w, int h)
400{
401	/* Linear texture copy. */
402	if ((src->layout == LINEAR && dst->layout == LINEAR) ||
403	    dst->width <= 2 || dst->height <= 1) {
404		nv04_surface_copy_m2mf(ctx, dst, src, dx, dy, sx, sy, w, h);
405		return;
406	}
407
408	/* Swizzle using sifm+swzsurf. */
409        if (src->layout == LINEAR && dst->layout == SWIZZLED &&
410	    dst->cpp != 1 && !(dst->offset & 63)) {
411		nv04_surface_copy_swizzle(ctx, dst, src, dx, dy, sx, sy, w, h);
412		return;
413	}
414
415	/* Fallback to CPU copy. */
416	nv04_surface_copy_cpu(ctx, dst, src, dx, dy, sx, sy, w, h);
417}
418
419void
420nv04_surface_fill(struct gl_context *ctx,
421		  struct nouveau_surface *dst,
422		  unsigned mask, unsigned value,
423		  int dx, int dy, int w, int h)
424{
425	struct nouveau_channel *chan = context_chan(ctx);
426	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
427	struct nouveau_grobj *surf2d = hw->surf2d;
428	struct nouveau_grobj *patt = hw->patt;
429	struct nouveau_grobj *rect = hw->rect;
430	unsigned bo_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART;
431
432	MARK_RING (chan, 19, 4);
433
434	BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
435	OUT_RELOCo(chan, dst->bo, bo_flags | NOUVEAU_BO_WR);
436	OUT_RELOCo(chan, dst->bo, bo_flags | NOUVEAU_BO_WR);
437	BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
438	OUT_RING  (chan, surf2d_format(dst->format));
439	OUT_RING  (chan, (dst->pitch << 16) | dst->pitch);
440	OUT_RELOCl(chan, dst->bo, dst->offset, bo_flags | NOUVEAU_BO_WR);
441	OUT_RELOCl(chan, dst->bo, dst->offset, bo_flags | NOUVEAU_BO_WR);
442
443	BEGIN_RING(chan, patt, NV04_IMAGE_PATTERN_COLOR_FORMAT, 1);
444	OUT_RING  (chan, rect_format(dst->format));
445	BEGIN_RING(chan, patt, NV04_IMAGE_PATTERN_MONOCHROME_COLOR1, 1);
446	OUT_RING  (chan, mask | ~0ll << (8 * dst->cpp));
447
448	BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
449	OUT_RING  (chan, rect_format(dst->format));
450	BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
451	OUT_RING  (chan, value);
452	BEGIN_RING(chan, rect,
453		   NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
454	OUT_RING  (chan, (dx << 16) | dy);
455	OUT_RING  (chan, ( w << 16) |  h);
456
457	if (context_chipset(ctx) < 0x10)
458		FIRE_RING(chan);
459}
460
461void
462nv04_surface_takedown(struct gl_context *ctx)
463{
464	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
465
466	nouveau_grobj_free(&hw->swzsurf);
467	nouveau_grobj_free(&hw->sifm);
468	nouveau_grobj_free(&hw->rect);
469	nouveau_grobj_free(&hw->rop);
470	nouveau_grobj_free(&hw->patt);
471	nouveau_grobj_free(&hw->surf2d);
472	nouveau_grobj_free(&hw->m2mf);
473	nouveau_notifier_free(&hw->ntfy);
474}
475
476GLboolean
477nv04_surface_init(struct gl_context *ctx)
478{
479	struct nouveau_channel *chan = context_chan(ctx);
480	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
481	unsigned handle = 0x88000000, class;
482	int ret;
483
484	/* Notifier object. */
485	ret = nouveau_notifier_alloc(chan, handle++, 1, &hw->ntfy);
486	if (ret)
487		goto fail;
488
489	/* Memory to memory format. */
490	ret = nouveau_grobj_alloc(chan, handle++, NV04_M2MF, &hw->m2mf);
491	if (ret)
492		goto fail;
493
494	BEGIN_RING(chan, hw->m2mf, NV04_M2MF_DMA_NOTIFY, 1);
495	OUT_RING  (chan, hw->ntfy->handle);
496
497	/* Context surfaces 2D. */
498	if (context_chipset(ctx) < 0x10)
499		class = NV04_CONTEXT_SURFACES_2D;
500	else
501		class = NV10_CONTEXT_SURFACES_2D;
502
503	ret = nouveau_grobj_alloc(chan, handle++, class, &hw->surf2d);
504	if (ret)
505		goto fail;
506
507	/* Raster op. */
508	ret = nouveau_grobj_alloc(chan, handle++, NV03_CONTEXT_ROP, &hw->rop);
509	if (ret)
510		goto fail;
511
512	BEGIN_RING(chan, hw->rop, NV03_CONTEXT_ROP_DMA_NOTIFY, 1);
513	OUT_RING  (chan, hw->ntfy->handle);
514
515	BEGIN_RING(chan, hw->rop, NV03_CONTEXT_ROP_ROP, 1);
516	OUT_RING  (chan, 0xca); /* DPSDxax in the GDI speech. */
517
518	/* Image pattern. */
519	ret = nouveau_grobj_alloc(chan, handle++, NV04_IMAGE_PATTERN,
520				  &hw->patt);
521	if (ret)
522		goto fail;
523
524	BEGIN_RING(chan, hw->patt, NV04_IMAGE_PATTERN_DMA_NOTIFY, 1);
525	OUT_RING  (chan, hw->ntfy->handle);
526
527	BEGIN_RING(chan, hw->patt, NV04_IMAGE_PATTERN_MONOCHROME_FORMAT, 3);
528	OUT_RING  (chan, NV04_IMAGE_PATTERN_MONOCHROME_FORMAT_LE);
529	OUT_RING  (chan, NV04_IMAGE_PATTERN_MONOCHROME_SHAPE_8X8);
530	OUT_RING  (chan, NV04_IMAGE_PATTERN_PATTERN_SELECT_MONO);
531
532	BEGIN_RING(chan, hw->patt, NV04_IMAGE_PATTERN_MONOCHROME_COLOR0, 4);
533	OUT_RING  (chan, 0);
534	OUT_RING  (chan, 0);
535	OUT_RING  (chan, ~0);
536	OUT_RING  (chan, ~0);
537
538	/* GDI rectangle text. */
539	ret = nouveau_grobj_alloc(chan, handle++, NV04_GDI_RECTANGLE_TEXT,
540				  &hw->rect);
541	if (ret)
542		goto fail;
543
544	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_DMA_NOTIFY, 1);
545	OUT_RING  (chan, hw->ntfy->handle);
546	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_SURFACE, 1);
547	OUT_RING  (chan, hw->surf2d->handle);
548	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_ROP, 1);
549	OUT_RING  (chan, hw->rop->handle);
550	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_PATTERN, 1);
551	OUT_RING  (chan, hw->patt->handle);
552
553	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
554	OUT_RING  (chan, NV04_GDI_RECTANGLE_TEXT_OPERATION_ROP_AND);
555	BEGIN_RING(chan, hw->rect,
556		   NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT, 1);
557	OUT_RING  (chan, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE);
558
559	/* Swizzled surface. */
560	if (context_chipset(ctx) < 0x20)
561		class = NV04_SWIZZLED_SURFACE;
562	else
563		class = NV20_SWIZZLED_SURFACE;
564
565	ret = nouveau_grobj_alloc(chan, handle++, class, &hw->swzsurf);
566	if (ret)
567		goto fail;
568
569	/* Scaled image from memory. */
570	if  (context_chipset(ctx) < 0x10)
571		class = NV04_SCALED_IMAGE_FROM_MEMORY;
572	else
573		class = NV10_SCALED_IMAGE_FROM_MEMORY;
574
575	ret = nouveau_grobj_alloc(chan, handle++, class, &hw->sifm);
576	if (ret)
577		goto fail;
578
579	if (context_chipset(ctx) >= 0x10) {
580		BEGIN_RING(chan, hw->sifm,
581			   NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION, 1);
582		OUT_RING(chan, NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE);
583	}
584
585	return GL_TRUE;
586
587fail:
588	nv04_surface_takedown(ctx);
589	return GL_FALSE;
590}
591