Home | History | Annotate | Download | only in nouveau
      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 
     36 static inline int
     37 swzsurf_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 
     75 static inline int
     76 surf2d_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 
    114 static inline int
    115 rect_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 
    153 static inline int
    154 sifm_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 
    192 static void
    193 nv04_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 
    273 static void
    274 nv04_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 
    316 typedef unsigned (*get_offset_t)(struct nouveau_surface *s,
    317 				 unsigned x, unsigned y);
    318 
    319 static unsigned
    320 get_linear_offset(struct nouveau_surface *s, unsigned x, unsigned y)
    321 {
    322 	return x * s->cpp + y * s->pitch;
    323 }
    324 
    325 static unsigned
    326 get_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 
    361 static void
    362 nv04_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 
    389 void
    390 nv04_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 
    423 void
    424 nv04_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 
    463 void
    464 nv04_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 
    478 GLboolean
    479 nv04_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 
    610 fail:
    611 	nv04_surface_takedown(ctx);
    612 	return GL_FALSE;
    613 }
    614