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(mesa_format format)
38{
39	switch (format) {
40	case MESA_FORMAT_A_UNORM8:
41	case MESA_FORMAT_L_UNORM8:
42	case MESA_FORMAT_I_UNORM8:
43	case MESA_FORMAT_B2G3R3_UNORM:
44		return NV04_SWIZZLED_SURFACE_FORMAT_COLOR_Y8;
45
46	case MESA_FORMAT_B5G6R5_UNORM:
47	case MESA_FORMAT_R5G6B5_UNORM:
48	case MESA_FORMAT_B4G4R4A4_UNORM:
49	case MESA_FORMAT_A4R4G4B4_UNORM:
50	case MESA_FORMAT_B5G5R5A1_UNORM:
51	case MESA_FORMAT_A1B5G5R5_UNORM:
52	case MESA_FORMAT_A1R5G5B5_UNORM:
53	case MESA_FORMAT_LA_UNORM8:
54	case MESA_FORMAT_YCBCR:
55	case MESA_FORMAT_YCBCR_REV:
56	case MESA_FORMAT_Z_UNORM16:
57		return NV04_SWIZZLED_SURFACE_FORMAT_COLOR_R5G6B5;
58
59	case MESA_FORMAT_A8B8G8R8_UNORM:
60	case MESA_FORMAT_R8G8B8A8_UNORM:
61	case MESA_FORMAT_B8G8R8X8_UNORM:
62	case MESA_FORMAT_B8G8R8A8_UNORM:
63	case MESA_FORMAT_A8R8G8B8_UNORM:
64	case MESA_FORMAT_Z24_UNORM_S8_UINT:
65	case MESA_FORMAT_S8_UINT_Z24_UNORM:
66	case MESA_FORMAT_Z_UNORM32:
67		return NV04_SWIZZLED_SURFACE_FORMAT_COLOR_A8R8G8B8;
68
69	default:
70		assert(0);
71	}
72}
73
74static inline int
75surf2d_format(mesa_format format)
76{
77	switch (format) {
78	case MESA_FORMAT_A_UNORM8:
79	case MESA_FORMAT_L_UNORM8:
80	case MESA_FORMAT_I_UNORM8:
81	case MESA_FORMAT_B2G3R3_UNORM:
82		return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8;
83
84	case MESA_FORMAT_B5G6R5_UNORM:
85	case MESA_FORMAT_R5G6B5_UNORM:
86	case MESA_FORMAT_B4G4R4A4_UNORM:
87	case MESA_FORMAT_A4R4G4B4_UNORM:
88	case MESA_FORMAT_B5G5R5A1_UNORM:
89	case MESA_FORMAT_A1B5G5R5_UNORM:
90	case MESA_FORMAT_A1R5G5B5_UNORM:
91	case MESA_FORMAT_LA_UNORM8:
92	case MESA_FORMAT_YCBCR:
93	case MESA_FORMAT_YCBCR_REV:
94	case MESA_FORMAT_Z_UNORM16:
95		return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5;
96
97	case MESA_FORMAT_A8B8G8R8_UNORM:
98	case MESA_FORMAT_R8G8B8A8_UNORM:
99	case MESA_FORMAT_B8G8R8X8_UNORM:
100	case MESA_FORMAT_B8G8R8A8_UNORM:
101	case MESA_FORMAT_A8R8G8B8_UNORM:
102	case MESA_FORMAT_Z24_UNORM_S8_UINT:
103	case MESA_FORMAT_S8_UINT_Z24_UNORM:
104	case MESA_FORMAT_Z_UNORM32:
105		return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
106
107	default:
108		assert(0);
109	}
110}
111
112static inline int
113rect_format(mesa_format format)
114{
115	switch (format) {
116	case MESA_FORMAT_A_UNORM8:
117	case MESA_FORMAT_L_UNORM8:
118	case MESA_FORMAT_I_UNORM8:
119	case MESA_FORMAT_B2G3R3_UNORM:
120		return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
121
122	case MESA_FORMAT_B5G6R5_UNORM:
123	case MESA_FORMAT_R5G6B5_UNORM:
124	case MESA_FORMAT_B4G4R4A4_UNORM:
125	case MESA_FORMAT_A4R4G4B4_UNORM:
126	case MESA_FORMAT_B5G5R5A1_UNORM:
127	case MESA_FORMAT_A1B5G5R5_UNORM:
128	case MESA_FORMAT_A1R5G5B5_UNORM:
129	case MESA_FORMAT_LA_UNORM8:
130	case MESA_FORMAT_YCBCR:
131	case MESA_FORMAT_YCBCR_REV:
132	case MESA_FORMAT_Z_UNORM16:
133		return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
134
135	case MESA_FORMAT_A8B8G8R8_UNORM:
136	case MESA_FORMAT_R8G8B8A8_UNORM:
137	case MESA_FORMAT_B8G8R8X8_UNORM:
138	case MESA_FORMAT_B8G8R8A8_UNORM:
139	case MESA_FORMAT_A8R8G8B8_UNORM:
140	case MESA_FORMAT_Z24_UNORM_S8_UINT:
141	case MESA_FORMAT_S8_UINT_Z24_UNORM:
142	case MESA_FORMAT_Z_UNORM32:
143		return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
144
145	default:
146		assert(0);
147	}
148}
149
150static inline int
151sifm_format(mesa_format format)
152{
153	switch (format) {
154	case MESA_FORMAT_A_UNORM8:
155	case MESA_FORMAT_L_UNORM8:
156	case MESA_FORMAT_I_UNORM8:
157	case MESA_FORMAT_B2G3R3_UNORM:
158		return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_AY8;
159
160	case MESA_FORMAT_B5G6R5_UNORM:
161	case MESA_FORMAT_R5G6B5_UNORM:
162	case MESA_FORMAT_B4G4R4A4_UNORM:
163	case MESA_FORMAT_A4R4G4B4_UNORM:
164	case MESA_FORMAT_B5G5R5A1_UNORM:
165	case MESA_FORMAT_A1B5G5R5_UNORM:
166	case MESA_FORMAT_A1R5G5B5_UNORM:
167	case MESA_FORMAT_LA_UNORM8:
168	case MESA_FORMAT_YCBCR:
169	case MESA_FORMAT_YCBCR_REV:
170	case MESA_FORMAT_Z_UNORM16:
171		return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_R5G6B5;
172
173	case MESA_FORMAT_A8B8G8R8_UNORM:
174	case MESA_FORMAT_R8G8B8A8_UNORM:
175	case MESA_FORMAT_B8G8R8X8_UNORM:
176	case MESA_FORMAT_B8G8R8A8_UNORM:
177	case MESA_FORMAT_A8R8G8B8_UNORM:
178	case MESA_FORMAT_Z24_UNORM_S8_UINT:
179	case MESA_FORMAT_S8_UINT_Z24_UNORM:
180	case MESA_FORMAT_Z_UNORM32:
181		return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A8R8G8B8;
182
183	default:
184		assert(0);
185	}
186}
187
188static void
189nv04_surface_copy_swizzle(struct gl_context *ctx,
190			  struct nouveau_surface *dst,
191			  struct nouveau_surface *src,
192			  int dx, int dy, int sx, int sy,
193			  int w, int h)
194{
195	struct nouveau_pushbuf_refn refs[] = {
196		{ src->bo, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART },
197		{ dst->bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM },
198	};
199	struct nouveau_pushbuf *push = context_push(ctx);
200	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
201	struct nouveau_object *swzsurf = hw->swzsurf;
202	struct nv04_fifo *fifo = hw->chan->data;
203	/* Max width & height may not be the same on all HW, but must be POT */
204	const unsigned max_w = 1024;
205	const unsigned max_h = 1024;
206	unsigned sub_w = w > max_w ? max_w : w;
207	unsigned sub_h = h > max_h ? max_h : h;
208	unsigned x, y;
209
210        /* Swizzled surfaces must be POT  */
211	assert(util_is_power_of_two_or_zero(dst->width) &&
212	       util_is_power_of_two_or_zero(dst->height));
213
214	if (context_chipset(ctx) < 0x10) {
215		BEGIN_NV04(push, NV01_SUBC(SURF, OBJECT), 1);
216		PUSH_DATA (push, swzsurf->handle);
217	}
218
219	for (y = 0; y < h; y += sub_h) {
220		sub_h = MIN2(sub_h, h - y);
221
222		for (x = 0; x < w; x += sub_w) {
223			sub_w = MIN2(sub_w, w - x);
224
225			if (nouveau_pushbuf_space(push, 64, 4, 0) ||
226			    nouveau_pushbuf_refn (push, refs, 2))
227				return;
228
229			BEGIN_NV04(push, NV04_SSWZ(DMA_IMAGE), 1);
230			PUSH_DATA (push, fifo->vram);
231			BEGIN_NV04(push, NV04_SSWZ(FORMAT), 2);
232			PUSH_DATA (push, swzsurf_format(dst->format) |
233					 log2i(dst->width) << 16 |
234					 log2i(dst->height) << 24);
235			PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
236
237			BEGIN_NV04(push, NV03_SIFM(DMA_IMAGE), 1);
238			PUSH_RELOC(push, src->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
239			BEGIN_NV04(push, NV05_SIFM(SURFACE), 1);
240			PUSH_DATA (push, swzsurf->handle);
241
242			BEGIN_NV04(push, NV03_SIFM(COLOR_FORMAT), 8);
243			PUSH_DATA (push, sifm_format(src->format));
244			PUSH_DATA (push, NV03_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY);
245			PUSH_DATA (push, (y + dy) << 16 | (x + dx));
246			PUSH_DATA (push, sub_h << 16 | sub_w);
247			PUSH_DATA (push, (y + dy) << 16 | (x + dx));
248			PUSH_DATA (push, sub_h << 16 | sub_w);
249			PUSH_DATA (push, 1 << 20);
250			PUSH_DATA (push, 1 << 20);
251
252			BEGIN_NV04(push, NV03_SIFM(SIZE), 4);
253			PUSH_DATA (push, align(sub_h, 2) << 16 | align(sub_w, 2));
254			PUSH_DATA (push, src->pitch  |
255					 NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER |
256					 NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE);
257			PUSH_RELOC(push, src->bo, src->offset + (y + sy) * src->pitch +
258					 (x + sx) * src->cpp, NOUVEAU_BO_LOW, 0, 0);
259			PUSH_DATA (push, 0);
260		}
261	}
262
263	if (context_chipset(ctx) < 0x10) {
264		BEGIN_NV04(push, NV01_SUBC(SURF, OBJECT), 1);
265		PUSH_DATA (push, hw->surf3d->handle);
266	}
267}
268
269static void
270nv04_surface_copy_m2mf(struct gl_context *ctx,
271		       struct nouveau_surface *dst,
272		       struct nouveau_surface *src,
273		       int dx, int dy, int sx, int sy,
274		       int w, int h)
275{
276	struct nouveau_pushbuf_refn refs[] = {
277		{ src->bo, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART },
278		{ dst->bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART },
279	};
280	struct nouveau_pushbuf *push = context_push(ctx);
281	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
282	struct nv04_fifo *fifo = hw->chan->data;
283	unsigned dst_offset = dst->offset + dy * dst->pitch + dx * dst->cpp;
284	unsigned src_offset = src->offset + sy * src->pitch + sx * src->cpp;
285
286	while (h) {
287		int count = (h > 2047) ? 2047 : h;
288
289		if (nouveau_pushbuf_space(push, 16, 4, 0) ||
290		    nouveau_pushbuf_refn (push, refs, 2))
291			return;
292
293		BEGIN_NV04(push, NV03_M2MF(DMA_BUFFER_IN), 2);
294		PUSH_RELOC(push, src->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
295		PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
296		BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8);
297		PUSH_RELOC(push, src->bo, src->offset, NOUVEAU_BO_LOW, 0, 0);
298		PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
299		PUSH_DATA (push, src->pitch);
300		PUSH_DATA (push, dst->pitch);
301		PUSH_DATA (push, w * src->cpp);
302		PUSH_DATA (push, count);
303		PUSH_DATA (push, 0x0101);
304		PUSH_DATA (push, 0);
305
306		src_offset += src->pitch * count;
307		dst_offset += dst->pitch * count;
308		h -= count;
309	}
310}
311
312typedef unsigned (*get_offset_t)(struct nouveau_surface *s,
313				 unsigned x, unsigned y);
314
315static unsigned
316get_linear_offset(struct nouveau_surface *s, unsigned x, unsigned y)
317{
318	return x * s->cpp + y * s->pitch;
319}
320
321static unsigned
322get_swizzled_offset(struct nouveau_surface *s, unsigned x, unsigned y)
323{
324	unsigned k = log2i(MIN2(s->width, s->height));
325
326	unsigned u = (x & 0x001) << 0 |
327		(x & 0x002) << 1 |
328		(x & 0x004) << 2 |
329		(x & 0x008) << 3 |
330		(x & 0x010) << 4 |
331		(x & 0x020) << 5 |
332		(x & 0x040) << 6 |
333		(x & 0x080) << 7 |
334		(x & 0x100) << 8 |
335		(x & 0x200) << 9 |
336		(x & 0x400) << 10 |
337		(x & 0x800) << 11;
338
339	unsigned v = (y & 0x001) << 1 |
340		(y & 0x002) << 2 |
341		(y & 0x004) << 3 |
342		(y & 0x008) << 4 |
343		(y & 0x010) << 5 |
344		(y & 0x020) << 6 |
345		(y & 0x040) << 7 |
346		(y & 0x080) << 8 |
347		(y & 0x100) << 9 |
348		(y & 0x200) << 10 |
349		(y & 0x400) << 11 |
350		(y & 0x800) << 12;
351
352	return s->cpp * (((u | v) & ~(~0 << 2*k)) |
353			 (x & (~0 << k)) << k |
354			 (y & (~0 << k)) << k);
355}
356
357static void
358nv04_surface_copy_cpu(struct gl_context *ctx,
359		      struct nouveau_surface *dst,
360		      struct nouveau_surface *src,
361		      int dx, int dy, int sx, int sy,
362		      int w, int h)
363{
364	int x, y;
365	get_offset_t get_dst = (dst->layout == SWIZZLED ?
366				get_swizzled_offset : get_linear_offset);
367	get_offset_t get_src = (src->layout == SWIZZLED ?
368				get_swizzled_offset : get_linear_offset);
369	void *dp, *sp;
370
371	nouveau_bo_map(dst->bo, NOUVEAU_BO_WR, context_client(ctx));
372	nouveau_bo_map(src->bo, NOUVEAU_BO_RD, context_client(ctx));
373
374	dp = dst->bo->map + dst->offset;
375	sp = src->bo->map + src->offset;
376
377	for (y = 0; y < h; y++) {
378		for (x = 0; x < w; x++) {
379			memcpy(dp + get_dst(dst, dx + x, dy + y),
380			       sp + get_src(src, sx + x, sy + y), dst->cpp);
381		}
382	}
383}
384
385void
386nv04_surface_copy(struct gl_context *ctx,
387		  struct nouveau_surface *dst,
388		  struct nouveau_surface *src,
389		  int dx, int dy, int sx, int sy,
390		  int w, int h)
391{
392	if (_mesa_is_format_compressed(src->format)) {
393		sx = get_format_blocksx(src->format, sx);
394		sy = get_format_blocksy(src->format, sy);
395		dx = get_format_blocksx(dst->format, dx);
396		dy = get_format_blocksy(dst->format, dy);
397		w = get_format_blocksx(src->format, w);
398		h = get_format_blocksy(src->format, h);
399	}
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_pushbuf_refn refs[] = {
426		{ dst->bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM | NOUVEAU_BO_GART },
427	};
428	struct nouveau_pushbuf *push = context_push(ctx);
429	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
430	struct nv04_fifo *fifo = hw->chan->data;
431
432	if (nouveau_pushbuf_space(push, 64, 4, 0) ||
433	    nouveau_pushbuf_refn (push, refs, 1))
434		return;
435
436	BEGIN_NV04(push, NV04_SF2D(DMA_IMAGE_SOURCE), 2);
437	PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
438	PUSH_RELOC(push, dst->bo, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
439	BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
440	PUSH_DATA (push, surf2d_format(dst->format));
441	PUSH_DATA (push, (dst->pitch << 16) | dst->pitch);
442	PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
443	PUSH_RELOC(push, dst->bo, dst->offset, NOUVEAU_BO_LOW, 0, 0);
444
445	BEGIN_NV04(push, NV01_PATT(COLOR_FORMAT), 1);
446	PUSH_DATA (push, rect_format(dst->format));
447	BEGIN_NV04(push, NV01_PATT(MONOCHROME_COLOR1), 1);
448	PUSH_DATA (push, mask | ~0ll << (8 * dst->cpp));
449
450	BEGIN_NV04(push, NV04_GDI(COLOR_FORMAT), 1);
451	PUSH_DATA (push, rect_format(dst->format));
452	BEGIN_NV04(push, NV04_GDI(COLOR1_A), 1);
453	PUSH_DATA (push, value);
454	BEGIN_NV04(push, NV04_GDI(UNCLIPPED_RECTANGLE_POINT(0)), 2);
455	PUSH_DATA (push, (dx << 16) | dy);
456	PUSH_DATA (push, ( w << 16) |  h);
457}
458
459void
460nv04_surface_takedown(struct gl_context *ctx)
461{
462	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
463
464	nouveau_object_del(&hw->swzsurf);
465	nouveau_object_del(&hw->sifm);
466	nouveau_object_del(&hw->rect);
467	nouveau_object_del(&hw->rop);
468	nouveau_object_del(&hw->patt);
469	nouveau_object_del(&hw->surf2d);
470	nouveau_object_del(&hw->m2mf);
471	nouveau_object_del(&hw->ntfy);
472}
473
474GLboolean
475nv04_surface_init(struct gl_context *ctx)
476{
477	struct nouveau_pushbuf *push = context_push(ctx);
478	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
479	struct nouveau_object *chan = hw->chan;
480	unsigned handle = 0x88000000, class;
481	int ret;
482
483	/* Notifier object. */
484	ret = nouveau_object_new(chan, handle++, NOUVEAU_NOTIFIER_CLASS,
485				 &(struct nv04_notify) {
486					.length = 32,
487				 }, sizeof(struct nv04_notify), &hw->ntfy);
488	if (ret)
489		goto fail;
490
491	/* Memory to memory format. */
492	ret = nouveau_object_new(chan, handle++, NV03_M2MF_CLASS,
493				 NULL, 0, &hw->m2mf);
494	if (ret)
495		goto fail;
496
497	BEGIN_NV04(push, NV01_SUBC(M2MF, OBJECT), 1);
498	PUSH_DATA (push, hw->m2mf->handle);
499	BEGIN_NV04(push, NV03_M2MF(DMA_NOTIFY), 1);
500	PUSH_DATA (push, hw->ntfy->handle);
501
502	/* Context surfaces 2D. */
503	if (context_chipset(ctx) < 0x10)
504		class = NV04_SURFACE_2D_CLASS;
505	else
506		class = NV10_SURFACE_2D_CLASS;
507
508	ret = nouveau_object_new(chan, handle++, class, NULL, 0, &hw->surf2d);
509	if (ret)
510		goto fail;
511
512	BEGIN_NV04(push, NV01_SUBC(SF2D, OBJECT), 1);
513	PUSH_DATA (push, hw->surf2d->handle);
514
515	/* Raster op. */
516	ret = nouveau_object_new(chan, handle++, NV03_ROP_CLASS,
517				 NULL, 0, &hw->rop);
518	if (ret)
519		goto fail;
520
521	BEGIN_NV04(push, NV01_SUBC(PATT, OBJECT), 1);
522	PUSH_DATA (push, hw->rop->handle);
523	BEGIN_NV04(push, NV01_ROP(DMA_NOTIFY), 1);
524	PUSH_DATA (push, hw->ntfy->handle);
525
526	BEGIN_NV04(push, NV01_ROP(ROP), 1);
527	PUSH_DATA (push, 0xca); /* DPSDxax in the GDI speech. */
528
529	/* Image pattern. */
530	ret = nouveau_object_new(chan, handle++, NV04_PATTERN_CLASS,
531				 NULL, 0, &hw->patt);
532	if (ret)
533		goto fail;
534
535	BEGIN_NV04(push, NV01_SUBC(PATT, OBJECT), 1);
536	PUSH_DATA (push, hw->patt->handle);
537	BEGIN_NV04(push, NV01_PATT(DMA_NOTIFY), 1);
538	PUSH_DATA (push, hw->ntfy->handle);
539
540	BEGIN_NV04(push, NV01_PATT(MONOCHROME_FORMAT), 3);
541	PUSH_DATA (push, NV04_IMAGE_PATTERN_MONOCHROME_FORMAT_LE);
542	PUSH_DATA (push, NV04_IMAGE_PATTERN_MONOCHROME_SHAPE_8X8);
543	PUSH_DATA (push, NV04_IMAGE_PATTERN_PATTERN_SELECT_MONO);
544
545	BEGIN_NV04(push, NV01_PATT(MONOCHROME_COLOR0), 4);
546	PUSH_DATA (push, 0);
547	PUSH_DATA (push, 0);
548	PUSH_DATA (push, ~0);
549	PUSH_DATA (push, ~0);
550
551	/* GDI rectangle text. */
552	ret = nouveau_object_new(chan, handle++, NV04_GDI_CLASS,
553				 NULL, 0, &hw->rect);
554	if (ret)
555		goto fail;
556
557	BEGIN_NV04(push, NV01_SUBC(GDI, OBJECT), 1);
558	PUSH_DATA (push, hw->rect->handle);
559	BEGIN_NV04(push, NV04_GDI(DMA_NOTIFY), 1);
560	PUSH_DATA (push, hw->ntfy->handle);
561	BEGIN_NV04(push, NV04_GDI(SURFACE), 1);
562	PUSH_DATA (push, hw->surf2d->handle);
563	BEGIN_NV04(push, NV04_GDI(ROP), 1);
564	PUSH_DATA (push, hw->rop->handle);
565	BEGIN_NV04(push, NV04_GDI(PATTERN), 1);
566	PUSH_DATA (push, hw->patt->handle);
567
568	BEGIN_NV04(push, NV04_GDI(OPERATION), 1);
569	PUSH_DATA (push, NV04_GDI_RECTANGLE_TEXT_OPERATION_ROP_AND);
570	BEGIN_NV04(push, NV04_GDI(MONOCHROME_FORMAT), 1);
571	PUSH_DATA (push, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE);
572
573	/* Swizzled surface. */
574	if (context_chipset(ctx) < 0x20)
575		class = NV04_SURFACE_SWZ_CLASS;
576	else if (context_chipset (ctx) < 0x30)
577		class = NV20_SURFACE_SWZ_CLASS;
578	else
579		class = NV30_SURFACE_SWZ_CLASS;
580
581	ret = nouveau_object_new(chan, handle++, class, NULL, 0, &hw->swzsurf);
582	if (ret)
583		goto fail;
584
585	BEGIN_NV04(push, NV01_SUBC(SURF, OBJECT), 1);
586	PUSH_DATA (push, hw->swzsurf->handle);
587
588	/* Scaled image from memory. */
589	if  (context_chipset(ctx) < 0x10)
590		class = NV04_SIFM_CLASS;
591	else
592		class = NV10_SIFM_CLASS;
593
594	ret = nouveau_object_new(chan, handle++, class, NULL, 0, &hw->sifm);
595	if (ret)
596		goto fail;
597
598	BEGIN_NV04(push, NV01_SUBC(SIFM, OBJECT), 1);
599	PUSH_DATA (push, hw->sifm->handle);
600
601	if (context_chipset(ctx) >= 0x10) {
602		BEGIN_NV04(push, NV05_SIFM(COLOR_CONVERSION), 1);
603		PUSH_DATA (push, NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE);
604	}
605
606	return GL_TRUE;
607
608fail:
609	nv04_surface_takedown(ctx);
610	return GL_FALSE;
611}
612