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_pushbuf_refn refs[] = {
200		{ src->bo, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART },
201		{ dst->bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM },
202	};
203	struct nouveau_pushbuf *push = context_push(ctx);
204	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
205	struct nouveau_object *swzsurf = hw->swzsurf;
206	struct nv04_fifo *fifo = hw->chan->data;
207	/* Max width & height may not be the same on all HW, but must be POT */
208	const unsigned max_w = 1024;
209	const unsigned max_h = 1024;
210	unsigned sub_w = w > max_w ? max_w : w;
211	unsigned sub_h = h > max_h ? max_h : h;
212	unsigned x, y;
213
214        /* Swizzled surfaces must be POT  */
215	assert(_mesa_is_pow_two(dst->width) &&
216	       _mesa_is_pow_two(dst->height));
217
218	if (context_chipset(ctx) < 0x10) {
219		BEGIN_NV04(push, NV01_SUBC(SURF, OBJECT), 1);
220		PUSH_DATA (push, swzsurf->handle);
221	}
222
223	for (y = 0; y < h; y += sub_h) {
224		sub_h = MIN2(sub_h, h - y);
225
226		for (x = 0; x < w; x += sub_w) {
227			sub_w = MIN2(sub_w, w - x);
228
229			if (nouveau_pushbuf_space(push, 64, 4, 0) ||
230			    nouveau_pushbuf_refn (push, refs, 2))
231				return;
232
233			BEGIN_NV04(push, NV04_SSWZ(DMA_IMAGE), 1);
234			PUSH_DATA (push, fifo->vram);
235			BEGIN_NV04(push, NV04_SSWZ(FORMAT), 2);
236			PUSH_DATA (push, swzsurf_format(dst->format) |
237					 log2i(dst->width) << 16 |
238					 log2i(dst->height) << 24);
239			PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
240
241			BEGIN_NV04(push, NV03_SIFM(DMA_IMAGE), 1);
242			PUSH_RELOC(push, src->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
243			BEGIN_NV04(push, NV05_SIFM(SURFACE), 1);
244			PUSH_DATA (push, swzsurf->handle);
245
246			BEGIN_NV04(push, NV03_SIFM(COLOR_FORMAT), 8);
247			PUSH_DATA (push, sifm_format(src->format));
248			PUSH_DATA (push, NV03_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY);
249			PUSH_DATA (push, (y + dy) << 16 | (x + dx));
250			PUSH_DATA (push, sub_h << 16 | sub_w);
251			PUSH_DATA (push, (y + dy) << 16 | (x + dx));
252			PUSH_DATA (push, sub_h << 16 | sub_w);
253			PUSH_DATA (push, 1 << 20);
254			PUSH_DATA (push, 1 << 20);
255
256			BEGIN_NV04(push, NV03_SIFM(SIZE), 4);
257			PUSH_DATA (push, align(sub_h, 2) << 16 | align(sub_w, 2));
258			PUSH_DATA (push, src->pitch  |
259					 NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER |
260					 NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE);
261			PUSH_RELOC(push, src->bo, src->offset + (y + sy) * src->pitch +
262					 (x + sx) * src->cpp, NOUVEAU_BO_LOW, 0, 0);
263			PUSH_DATA (push, 0);
264		}
265	}
266
267	if (context_chipset(ctx) < 0x10) {
268		BEGIN_NV04(push, NV01_SUBC(SURF, OBJECT), 1);
269		PUSH_DATA (push, hw->surf3d->handle);
270	}
271}
272
273static void
274nv04_surface_copy_m2mf(struct gl_context *ctx,
275		       struct nouveau_surface *dst,
276		       struct nouveau_surface *src,
277		       int dx, int dy, int sx, int sy,
278		       int w, int h)
279{
280	struct nouveau_pushbuf_refn refs[] = {
281		{ src->bo, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART },
282		{ dst->bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART },
283	};
284	struct nouveau_pushbuf *push = context_push(ctx);
285	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
286	struct nv04_fifo *fifo = hw->chan->data;
287	unsigned dst_offset = dst->offset + dy * dst->pitch + dx * dst->cpp;
288	unsigned src_offset = src->offset + sy * src->pitch + sx * src->cpp;
289
290	while (h) {
291		int count = (h > 2047) ? 2047 : h;
292
293		if (nouveau_pushbuf_space(push, 16, 4, 0) ||
294		    nouveau_pushbuf_refn (push, refs, 2))
295			return;
296
297		BEGIN_NV04(push, NV03_M2MF(DMA_BUFFER_IN), 2);
298		PUSH_RELOC(push, src->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
299		PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
300		BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8);
301		PUSH_RELOC(push, src->bo, src->offset, NOUVEAU_BO_LOW, 0, 0);
302		PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
303		PUSH_DATA (push, src->pitch);
304		PUSH_DATA (push, dst->pitch);
305		PUSH_DATA (push, w * src->cpp);
306		PUSH_DATA (push, count);
307		PUSH_DATA (push, 0x0101);
308		PUSH_DATA (push, 0);
309
310		src_offset += src->pitch * count;
311		dst_offset += dst->pitch * count;
312		h -= count;
313	}
314}
315
316typedef unsigned (*get_offset_t)(struct nouveau_surface *s,
317				 unsigned x, unsigned y);
318
319static unsigned
320get_linear_offset(struct nouveau_surface *s, unsigned x, unsigned y)
321{
322	return x * s->cpp + y * s->pitch;
323}
324
325static unsigned
326get_swizzled_offset(struct nouveau_surface *s, unsigned x, unsigned y)
327{
328	unsigned k = log2i(MIN2(s->width, s->height));
329
330	unsigned u = (x & 0x001) << 0 |
331		(x & 0x002) << 1 |
332		(x & 0x004) << 2 |
333		(x & 0x008) << 3 |
334		(x & 0x010) << 4 |
335		(x & 0x020) << 5 |
336		(x & 0x040) << 6 |
337		(x & 0x080) << 7 |
338		(x & 0x100) << 8 |
339		(x & 0x200) << 9 |
340		(x & 0x400) << 10 |
341		(x & 0x800) << 11;
342
343	unsigned v = (y & 0x001) << 1 |
344		(y & 0x002) << 2 |
345		(y & 0x004) << 3 |
346		(y & 0x008) << 4 |
347		(y & 0x010) << 5 |
348		(y & 0x020) << 6 |
349		(y & 0x040) << 7 |
350		(y & 0x080) << 8 |
351		(y & 0x100) << 9 |
352		(y & 0x200) << 10 |
353		(y & 0x400) << 11 |
354		(y & 0x800) << 12;
355
356	return s->cpp * (((u | v) & ~(~0 << 2*k)) |
357			 (x & (~0 << k)) << k |
358			 (y & (~0 << k)) << k);
359}
360
361static void
362nv04_surface_copy_cpu(struct gl_context *ctx,
363		      struct nouveau_surface *dst,
364		      struct nouveau_surface *src,
365		      int dx, int dy, int sx, int sy,
366		      int w, int h)
367{
368	int x, y;
369	get_offset_t get_dst = (dst->layout == SWIZZLED ?
370				get_swizzled_offset : get_linear_offset);
371	get_offset_t get_src = (src->layout == SWIZZLED ?
372				get_swizzled_offset : get_linear_offset);
373	void *dp, *sp;
374
375	nouveau_bo_map(dst->bo, NOUVEAU_BO_WR, context_client(ctx));
376	nouveau_bo_map(src->bo, NOUVEAU_BO_RD, context_client(ctx));
377
378	dp = dst->bo->map + dst->offset;
379	sp = src->bo->map + src->offset;
380
381	for (y = 0; y < h; y++) {
382		for (x = 0; x < w; x++) {
383			memcpy(dp + get_dst(dst, dx + x, dy + y),
384			       sp + get_src(src, sx + x, sy + y), dst->cpp);
385		}
386	}
387}
388
389void
390nv04_surface_copy(struct gl_context *ctx,
391		  struct nouveau_surface *dst,
392		  struct nouveau_surface *src,
393		  int dx, int dy, int sx, int sy,
394		  int w, int h)
395{
396	if (_mesa_is_format_compressed(src->format)) {
397		sx = get_format_blocksx(src->format, sx);
398		sy = get_format_blocksy(src->format, sy);
399		dx = get_format_blocksx(dst->format, dx);
400		dy = get_format_blocksy(dst->format, dy);
401		w = get_format_blocksx(src->format, w);
402		h = get_format_blocksy(src->format, h);
403	}
404
405	/* Linear texture copy. */
406	if ((src->layout == LINEAR && dst->layout == LINEAR) ||
407	    dst->width <= 2 || dst->height <= 1) {
408		nv04_surface_copy_m2mf(ctx, dst, src, dx, dy, sx, sy, w, h);
409		return;
410	}
411
412	/* Swizzle using sifm+swzsurf. */
413        if (src->layout == LINEAR && dst->layout == SWIZZLED &&
414	    dst->cpp != 1 && !(dst->offset & 63)) {
415		nv04_surface_copy_swizzle(ctx, dst, src, dx, dy, sx, sy, w, h);
416		return;
417	}
418
419	/* Fallback to CPU copy. */
420	nv04_surface_copy_cpu(ctx, dst, src, dx, dy, sx, sy, w, h);
421}
422
423void
424nv04_surface_fill(struct gl_context *ctx,
425		  struct nouveau_surface *dst,
426		  unsigned mask, unsigned value,
427		  int dx, int dy, int w, int h)
428{
429	struct nouveau_pushbuf_refn refs[] = {
430		{ dst->bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART },
431	};
432	struct nouveau_pushbuf *push = context_push(ctx);
433	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
434	struct nv04_fifo *fifo = hw->chan->data;
435
436	if (nouveau_pushbuf_space(push, 64, 4, 0) ||
437	    nouveau_pushbuf_refn (push, refs, 1))
438		return;
439
440	BEGIN_NV04(push, NV04_SF2D(DMA_IMAGE_SOURCE), 2);
441	PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
442	PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
443	BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
444	PUSH_DATA (push, surf2d_format(dst->format));
445	PUSH_DATA (push, (dst->pitch << 16) | dst->pitch);
446	PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
447	PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
448
449	BEGIN_NV04(push, NV01_PATT(COLOR_FORMAT), 1);
450	PUSH_DATA (push, rect_format(dst->format));
451	BEGIN_NV04(push, NV01_PATT(MONOCHROME_COLOR1), 1);
452	PUSH_DATA (push, mask | ~0ll << (8 * dst->cpp));
453
454	BEGIN_NV04(push, NV04_GDI(COLOR_FORMAT), 1);
455	PUSH_DATA (push, rect_format(dst->format));
456	BEGIN_NV04(push, NV04_GDI(COLOR1_A), 1);
457	PUSH_DATA (push, value);
458	BEGIN_NV04(push, NV04_GDI(UNCLIPPED_RECTANGLE_POINT(0)), 2);
459	PUSH_DATA (push, (dx << 16) | dy);
460	PUSH_DATA (push, ( w << 16) |  h);
461}
462
463void
464nv04_surface_takedown(struct gl_context *ctx)
465{
466	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
467
468	nouveau_object_del(&hw->swzsurf);
469	nouveau_object_del(&hw->sifm);
470	nouveau_object_del(&hw->rect);
471	nouveau_object_del(&hw->rop);
472	nouveau_object_del(&hw->patt);
473	nouveau_object_del(&hw->surf2d);
474	nouveau_object_del(&hw->m2mf);
475	nouveau_object_del(&hw->ntfy);
476}
477
478GLboolean
479nv04_surface_init(struct gl_context *ctx)
480{
481	struct nouveau_pushbuf *push = context_push(ctx);
482	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
483	struct nouveau_object *chan = hw->chan;
484	unsigned handle = 0x88000000, class;
485	int ret;
486
487	/* Notifier object. */
488	ret = nouveau_object_new(chan, handle++, NOUVEAU_NOTIFIER_CLASS,
489				 &(struct nv04_notify) {
490					.length = 32,
491				 }, sizeof(struct nv04_notify), &hw->ntfy);
492	if (ret)
493		goto fail;
494
495	/* Memory to memory format. */
496	ret = nouveau_object_new(chan, handle++, NV03_M2MF_CLASS,
497				 NULL, 0, &hw->m2mf);
498	if (ret)
499		goto fail;
500
501	BEGIN_NV04(push, NV01_SUBC(M2MF, OBJECT), 1);
502	PUSH_DATA (push, hw->m2mf->handle);
503	BEGIN_NV04(push, NV03_M2MF(DMA_NOTIFY), 1);
504	PUSH_DATA (push, hw->ntfy->handle);
505
506	/* Context surfaces 2D. */
507	if (context_chipset(ctx) < 0x10)
508		class = NV04_SURFACE_2D_CLASS;
509	else
510		class = NV10_SURFACE_2D_CLASS;
511
512	ret = nouveau_object_new(chan, handle++, class, NULL, 0, &hw->surf2d);
513	if (ret)
514		goto fail;
515
516	BEGIN_NV04(push, NV01_SUBC(SF2D, OBJECT), 1);
517	PUSH_DATA (push, hw->surf2d->handle);
518
519	/* Raster op. */
520	ret = nouveau_object_new(chan, handle++, NV03_ROP_CLASS,
521				 NULL, 0, &hw->rop);
522	if (ret)
523		goto fail;
524
525	BEGIN_NV04(push, NV01_SUBC(PATT, OBJECT), 1);
526	PUSH_DATA (push, hw->rop->handle);
527	BEGIN_NV04(push, NV01_ROP(DMA_NOTIFY), 1);
528	PUSH_DATA (push, hw->ntfy->handle);
529
530	BEGIN_NV04(push, NV01_ROP(ROP), 1);
531	PUSH_DATA (push, 0xca); /* DPSDxax in the GDI speech. */
532
533	/* Image pattern. */
534	ret = nouveau_object_new(chan, handle++, NV04_PATTERN_CLASS,
535				 NULL, 0, &hw->patt);
536	if (ret)
537		goto fail;
538
539	BEGIN_NV04(push, NV01_SUBC(PATT, OBJECT), 1);
540	PUSH_DATA (push, hw->patt->handle);
541	BEGIN_NV04(push, NV01_PATT(DMA_NOTIFY), 1);
542	PUSH_DATA (push, hw->ntfy->handle);
543
544	BEGIN_NV04(push, NV01_PATT(MONOCHROME_FORMAT), 3);
545	PUSH_DATA (push, NV04_IMAGE_PATTERN_MONOCHROME_FORMAT_LE);
546	PUSH_DATA (push, NV04_IMAGE_PATTERN_MONOCHROME_SHAPE_8X8);
547	PUSH_DATA (push, NV04_IMAGE_PATTERN_PATTERN_SELECT_MONO);
548
549	BEGIN_NV04(push, NV01_PATT(MONOCHROME_COLOR0), 4);
550	PUSH_DATA (push, 0);
551	PUSH_DATA (push, 0);
552	PUSH_DATA (push, ~0);
553	PUSH_DATA (push, ~0);
554
555	/* GDI rectangle text. */
556	ret = nouveau_object_new(chan, handle++, NV04_GDI_CLASS,
557				 NULL, 0, &hw->rect);
558	if (ret)
559		goto fail;
560
561	BEGIN_NV04(push, NV01_SUBC(GDI, OBJECT), 1);
562	PUSH_DATA (push, hw->rect->handle);
563	BEGIN_NV04(push, NV04_GDI(DMA_NOTIFY), 1);
564	PUSH_DATA (push, hw->ntfy->handle);
565	BEGIN_NV04(push, NV04_GDI(SURFACE), 1);
566	PUSH_DATA (push, hw->surf2d->handle);
567	BEGIN_NV04(push, NV04_GDI(ROP), 1);
568	PUSH_DATA (push, hw->rop->handle);
569	BEGIN_NV04(push, NV04_GDI(PATTERN), 1);
570	PUSH_DATA (push, hw->patt->handle);
571
572	BEGIN_NV04(push, NV04_GDI(OPERATION), 1);
573	PUSH_DATA (push, NV04_GDI_RECTANGLE_TEXT_OPERATION_ROP_AND);
574	BEGIN_NV04(push, NV04_GDI(MONOCHROME_FORMAT), 1);
575	PUSH_DATA (push, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE);
576
577	/* Swizzled surface. */
578	if (context_chipset(ctx) < 0x20)
579		class = NV04_SURFACE_SWZ_CLASS;
580	else
581		class = NV20_SURFACE_SWZ_CLASS;
582
583	ret = nouveau_object_new(chan, handle++, class, NULL, 0, &hw->swzsurf);
584	if (ret)
585		goto fail;
586
587	BEGIN_NV04(push, NV01_SUBC(SURF, OBJECT), 1);
588	PUSH_DATA (push, hw->swzsurf->handle);
589
590	/* Scaled image from memory. */
591	if  (context_chipset(ctx) < 0x10)
592		class = NV04_SIFM_CLASS;
593	else
594		class = NV10_SIFM_CLASS;
595
596	ret = nouveau_object_new(chan, handle++, class, NULL, 0, &hw->sifm);
597	if (ret)
598		goto fail;
599
600	BEGIN_NV04(push, NV01_SUBC(SIFM, OBJECT), 1);
601	PUSH_DATA (push, hw->sifm->handle);
602
603	if (context_chipset(ctx) >= 0x10) {
604		BEGIN_NV04(push, NV05_SIFM(COLOR_CONVERSION), 1);
605		PUSH_DATA (push, NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE);
606	}
607
608	return GL_TRUE;
609
610fail:
611	nv04_surface_takedown(ctx);
612	return GL_FALSE;
613}
614