nv04_surface.c revision 56dcd011b5ec33190f268cf546a4c68f81f5ebd0
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 "nouveau_class.h"
29#include "nouveau_context.h"
30#include "nouveau_util.h"
31#include "nv04_driver.h"
32
33static inline int
34swzsurf_format(gl_format format)
35{
36	switch (format) {
37	case MESA_FORMAT_A8:
38	case MESA_FORMAT_L8:
39	case MESA_FORMAT_I8:
40	case MESA_FORMAT_RGB332:
41	case MESA_FORMAT_CI8:
42		return NV04_SWIZZLED_SURFACE_FORMAT_COLOR_Y8;
43
44	case MESA_FORMAT_RGB565:
45	case MESA_FORMAT_RGB565_REV:
46	case MESA_FORMAT_ARGB4444:
47	case MESA_FORMAT_ARGB4444_REV:
48	case MESA_FORMAT_ARGB1555:
49	case MESA_FORMAT_RGBA5551:
50	case MESA_FORMAT_ARGB1555_REV:
51	case MESA_FORMAT_AL88:
52	case MESA_FORMAT_AL88_REV:
53	case MESA_FORMAT_YCBCR:
54	case MESA_FORMAT_YCBCR_REV:
55	case MESA_FORMAT_Z16:
56		return NV04_SWIZZLED_SURFACE_FORMAT_COLOR_R5G6B5;
57
58	case MESA_FORMAT_RGBA8888:
59	case MESA_FORMAT_RGBA8888_REV:
60	case MESA_FORMAT_XRGB8888:
61	case MESA_FORMAT_ARGB8888:
62	case MESA_FORMAT_ARGB8888_REV:
63	case MESA_FORMAT_S8_Z24:
64	case MESA_FORMAT_Z24_S8:
65	case MESA_FORMAT_Z32:
66		return NV04_SWIZZLED_SURFACE_FORMAT_COLOR_A8R8G8B8;
67
68	default:
69		assert(0);
70	}
71}
72
73static inline int
74surf2d_format(gl_format format)
75{
76	switch (format) {
77	case MESA_FORMAT_A8:
78	case MESA_FORMAT_L8:
79	case MESA_FORMAT_I8:
80	case MESA_FORMAT_RGB332:
81	case MESA_FORMAT_CI8:
82		return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8;
83
84	case MESA_FORMAT_RGB565:
85	case MESA_FORMAT_RGB565_REV:
86	case MESA_FORMAT_ARGB4444:
87	case MESA_FORMAT_ARGB4444_REV:
88	case MESA_FORMAT_ARGB1555:
89	case MESA_FORMAT_RGBA5551:
90	case MESA_FORMAT_ARGB1555_REV:
91	case MESA_FORMAT_AL88:
92	case MESA_FORMAT_AL88_REV:
93	case MESA_FORMAT_YCBCR:
94	case MESA_FORMAT_YCBCR_REV:
95	case MESA_FORMAT_Z16:
96		return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5;
97
98	case MESA_FORMAT_RGBA8888:
99	case MESA_FORMAT_RGBA8888_REV:
100	case MESA_FORMAT_XRGB8888:
101	case MESA_FORMAT_ARGB8888:
102	case MESA_FORMAT_ARGB8888_REV:
103	case MESA_FORMAT_S8_Z24:
104	case MESA_FORMAT_Z24_S8:
105	case MESA_FORMAT_Z32:
106		return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
107
108	default:
109		assert(0);
110	}
111}
112
113static inline int
114rect_format(gl_format format)
115{
116	switch (format) {
117	case MESA_FORMAT_A8:
118	case MESA_FORMAT_L8:
119	case MESA_FORMAT_I8:
120	case MESA_FORMAT_RGB332:
121	case MESA_FORMAT_CI8:
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	case MESA_FORMAT_CI8:
162		return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_AY8;
163
164	case MESA_FORMAT_RGB565:
165	case MESA_FORMAT_RGB565_REV:
166	case MESA_FORMAT_ARGB4444:
167	case MESA_FORMAT_ARGB4444_REV:
168	case MESA_FORMAT_ARGB1555:
169	case MESA_FORMAT_RGBA5551:
170	case MESA_FORMAT_ARGB1555_REV:
171	case MESA_FORMAT_AL88:
172	case MESA_FORMAT_AL88_REV:
173	case MESA_FORMAT_YCBCR:
174	case MESA_FORMAT_YCBCR_REV:
175	case MESA_FORMAT_Z16:
176		return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_R5G6B5;
177
178	case MESA_FORMAT_RGBA8888:
179	case MESA_FORMAT_RGBA8888_REV:
180	case MESA_FORMAT_XRGB8888:
181	case MESA_FORMAT_ARGB8888:
182	case MESA_FORMAT_ARGB8888_REV:
183	case MESA_FORMAT_S8_Z24:
184	case MESA_FORMAT_Z24_S8:
185	case MESA_FORMAT_Z32:
186		return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A8R8G8B8;
187
188	default:
189		assert(0);
190	}
191}
192
193static void
194nv04_surface_copy_swizzle(GLcontext *ctx,
195			  struct nouveau_surface *dst,
196			  struct nouveau_surface *src,
197			  int dx, int dy, int sx, int sy,
198			  int w, int h)
199{
200	struct nouveau_channel *chan = context_chan(ctx);
201	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
202	struct nouveau_grobj *swzsurf = hw->swzsurf;
203	struct nouveau_grobj *sifm = hw->sifm;
204	struct nouveau_bo_context *bctx = context_bctx(ctx, SURFACE);
205	const unsigned bo_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART;
206	/* Max width & height may not be the same on all HW, but must be POT */
207	const unsigned max_w = 1024;
208	const unsigned max_h = 1024;
209	unsigned sub_w = w > max_w ? max_w : w;
210	unsigned sub_h = h > max_h ? max_h : h;
211	unsigned x, y;
212
213        /* Swizzled surfaces must be POT  */
214	assert(_mesa_is_pow_two(dst->width) &&
215	       _mesa_is_pow_two(dst->height));
216
217        /* If area is too large to copy in one shot we must copy it in
218	 * POT chunks to meet alignment requirements */
219	assert(sub_w == w || _mesa_is_pow_two(sub_w));
220	assert(sub_h == h || _mesa_is_pow_two(sub_h));
221
222	nouveau_bo_marko(bctx, sifm, NV03_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE,
223			 src->bo, bo_flags | NOUVEAU_BO_RD);
224	nouveau_bo_marko(bctx, swzsurf, NV04_SWIZZLED_SURFACE_DMA_IMAGE,
225			 dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
226	nouveau_bo_markl(bctx, swzsurf, NV04_SWIZZLED_SURFACE_OFFSET,
227			 dst->bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
228
229	BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_FORMAT, 1);
230	OUT_RING  (chan, swzsurf_format(dst->format) |
231		   log2i(dst->width) << 16 |
232		   log2i(dst->height) << 24);
233
234	BEGIN_RING(chan, sifm, NV04_SCALED_IMAGE_FROM_MEMORY_SURFACE, 1);
235	OUT_RING  (chan, swzsurf->handle);
236
237	for (y = 0; y < h; y += sub_h) {
238		sub_h = MIN2(sub_h, h - y);
239
240		for (x = 0; x < w; x += sub_w) {
241			sub_w = MIN2(sub_w, w - x);
242			/* Must be 64-byte aligned */
243			assert(!(dst->offset & 63));
244
245			MARK_RING(chan, 15, 1);
246
247			BEGIN_RING(chan, sifm,
248				   NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT, 8);
249			OUT_RING(chan, sifm_format(src->format));
250			OUT_RING(chan, NV03_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY);
251			OUT_RING(chan, (y + dy) << 16 | (x + dx));
252			OUT_RING(chan, sub_h << 16 | sub_w);
253			OUT_RING(chan, (y + dy) << 16 | (x + dx));
254			OUT_RING(chan, sub_h << 16 | sub_w);
255			OUT_RING(chan, 1 << 20);
256			OUT_RING(chan, 1 << 20);
257
258			BEGIN_RING(chan, sifm,
259				   NV03_SCALED_IMAGE_FROM_MEMORY_SIZE, 4);
260			OUT_RING(chan, sub_h << 16 | sub_w);
261			OUT_RING(chan, src->pitch  |
262				 NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER |
263				 NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE);
264			OUT_RELOCl(chan, src->bo, src->offset +
265				   (y + sy) * src->pitch +
266				   (x + sx) * src->cpp,
267				   bo_flags | NOUVEAU_BO_RD);
268			OUT_RING(chan, 0);
269		}
270	}
271
272	nouveau_bo_context_reset(bctx);
273
274	if (context_chipset(ctx) < 0x10)
275		FIRE_RING(chan);
276}
277
278static void
279nv04_surface_copy_m2mf(GLcontext *ctx,
280			  struct nouveau_surface *dst,
281			  struct nouveau_surface *src,
282			  int dx, int dy, int sx, int sy,
283			  int w, int h)
284{
285	struct nouveau_channel *chan = context_chan(ctx);
286	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
287	struct nouveau_grobj *m2mf = hw->m2mf;
288	struct nouveau_bo_context *bctx = context_bctx(ctx, SURFACE);
289	const unsigned bo_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART;
290	unsigned dst_offset = dst->offset + dy * dst->pitch + dx * dst->cpp;
291	unsigned src_offset = src->offset + sy * src->pitch + sx * src->cpp;
292
293	nouveau_bo_marko(bctx, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN,
294			 src->bo, bo_flags | NOUVEAU_BO_RD);
295	nouveau_bo_marko(bctx, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_OUT,
296			 dst->bo, bo_flags | NOUVEAU_BO_WR);
297
298	while (h) {
299		int count = (h > 2047) ? 2047 : h;
300
301		MARK_RING(chan, 9, 2);
302
303		BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
304		OUT_RELOCl(chan, src->bo, src_offset,
305			   bo_flags | NOUVEAU_BO_RD);
306		OUT_RELOCl(chan, dst->bo, dst_offset,
307			   bo_flags | NOUVEAU_BO_WR);
308		OUT_RING  (chan, src->pitch);
309		OUT_RING  (chan, dst->pitch);
310		OUT_RING  (chan, w * src->cpp);
311		OUT_RING  (chan, count);
312		OUT_RING  (chan, 0x0101);
313		OUT_RING  (chan, 0);
314
315		h -= count;
316		src_offset += src->pitch * count;
317		dst_offset += dst->pitch * count;
318	}
319
320	nouveau_bo_context_reset(bctx);
321
322	if (context_chipset(ctx) < 0x10)
323		FIRE_RING(chan);
324}
325
326void
327nv04_surface_copy(GLcontext *ctx,
328		  struct nouveau_surface *dst,
329		  struct nouveau_surface *src,
330		  int dx, int dy, int sx, int sy,
331		  int w, int h)
332{
333	/* Setup transfer to swizzle the texture to vram if needed */
334        if (src->layout != SWIZZLED &&
335	    dst->layout == SWIZZLED &&
336	    dst->width > 2 && dst->height > 1) {
337		nv04_surface_copy_swizzle(ctx, dst, src,
338					  dx, dy, sx, sy, w, h);
339		return;
340	}
341
342	nv04_surface_copy_m2mf(ctx, dst, src, dx, dy, sx, sy, w, h);
343}
344
345void
346nv04_surface_fill(GLcontext *ctx,
347		  struct nouveau_surface *dst,
348		  unsigned mask, unsigned value,
349		  int dx, int dy, int w, int h)
350{
351	struct nouveau_channel *chan = context_chan(ctx);
352	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
353	struct nouveau_grobj *surf2d = hw->surf2d;
354	struct nouveau_grobj *patt = hw->patt;
355	struct nouveau_grobj *rect = hw->rect;
356	unsigned bo_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART;
357
358	MARK_RING (chan, 19, 4);
359
360	BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
361	OUT_RELOCo(chan, dst->bo, bo_flags | NOUVEAU_BO_WR);
362	OUT_RELOCo(chan, dst->bo, bo_flags | NOUVEAU_BO_WR);
363	BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
364	OUT_RING  (chan, surf2d_format(dst->format));
365	OUT_RING  (chan, (dst->pitch << 16) | dst->pitch);
366	OUT_RELOCl(chan, dst->bo, dst->offset, bo_flags | NOUVEAU_BO_WR);
367	OUT_RELOCl(chan, dst->bo, dst->offset, bo_flags | NOUVEAU_BO_WR);
368
369	BEGIN_RING(chan, patt, NV04_IMAGE_PATTERN_COLOR_FORMAT, 1);
370	OUT_RING  (chan, rect_format(dst->format));
371	BEGIN_RING(chan, patt, NV04_IMAGE_PATTERN_MONOCHROME_COLOR1, 1);
372	OUT_RING  (chan, mask | ~0 << (8 * dst->cpp));
373
374	BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
375	OUT_RING  (chan, rect_format(dst->format));
376	BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
377	OUT_RING  (chan, value);
378	BEGIN_RING(chan, rect,
379		   NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
380	OUT_RING  (chan, (dx << 16) | dy);
381	OUT_RING  (chan, ( w << 16) |  h);
382
383	if (context_chipset(ctx) < 0x10)
384		FIRE_RING(chan);
385}
386
387void
388nv04_surface_takedown(GLcontext *ctx)
389{
390	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
391
392	nouveau_grobj_free(&hw->swzsurf);
393	nouveau_grobj_free(&hw->sifm);
394	nouveau_grobj_free(&hw->rect);
395	nouveau_grobj_free(&hw->rop);
396	nouveau_grobj_free(&hw->patt);
397	nouveau_grobj_free(&hw->surf2d);
398	nouveau_grobj_free(&hw->m2mf);
399	nouveau_notifier_free(&hw->ntfy);
400}
401
402GLboolean
403nv04_surface_init(GLcontext *ctx)
404{
405	struct nouveau_channel *chan = context_chan(ctx);
406	struct nouveau_hw_state *hw = &to_nouveau_context(ctx)->hw;
407	unsigned handle = 0x88000000, class;
408	int ret;
409
410	/* Notifier object. */
411	ret = nouveau_notifier_alloc(chan, handle++, 1, &hw->ntfy);
412	if (ret)
413		goto fail;
414
415	/* Memory to memory format. */
416	ret = nouveau_grobj_alloc(chan, handle++, NV04_MEMORY_TO_MEMORY_FORMAT,
417				  &hw->m2mf);
418	if (ret)
419		goto fail;
420
421	BEGIN_RING(chan, hw->m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
422	OUT_RING  (chan, hw->ntfy->handle);
423
424	/* Context surfaces 2D. */
425	if (context_chipset(ctx) < 0x10)
426		class = NV04_CONTEXT_SURFACES_2D;
427	else
428		class = NV10_CONTEXT_SURFACES_2D;
429
430	ret = nouveau_grobj_alloc(chan, handle++, class, &hw->surf2d);
431	if (ret)
432		goto fail;
433
434	/* Raster op. */
435	ret = nouveau_grobj_alloc(chan, handle++, NV03_CONTEXT_ROP, &hw->rop);
436	if (ret)
437		goto fail;
438
439	BEGIN_RING(chan, hw->rop, NV03_CONTEXT_ROP_DMA_NOTIFY, 1);
440	OUT_RING  (chan, hw->ntfy->handle);
441
442	BEGIN_RING(chan, hw->rop, NV03_CONTEXT_ROP_ROP, 1);
443	OUT_RING  (chan, 0xca); /* DPSDxax in the GDI speech. */
444
445	/* Image pattern. */
446	ret = nouveau_grobj_alloc(chan, handle++, NV04_IMAGE_PATTERN,
447				  &hw->patt);
448	if (ret)
449		goto fail;
450
451	BEGIN_RING(chan, hw->patt, NV04_IMAGE_PATTERN_DMA_NOTIFY, 1);
452	OUT_RING  (chan, hw->ntfy->handle);
453
454	BEGIN_RING(chan, hw->patt, NV04_IMAGE_PATTERN_MONOCHROME_FORMAT, 3);
455	OUT_RING  (chan, NV04_IMAGE_PATTERN_MONOCHROME_FORMAT_LE);
456	OUT_RING  (chan, NV04_IMAGE_PATTERN_MONOCHROME_SHAPE_8X8);
457	OUT_RING  (chan, NV04_IMAGE_PATTERN_PATTERN_SELECT_MONO);
458
459	BEGIN_RING(chan, hw->patt, NV04_IMAGE_PATTERN_MONOCHROME_COLOR0, 4);
460	OUT_RING  (chan, 0);
461	OUT_RING  (chan, 0);
462	OUT_RING  (chan, ~0);
463	OUT_RING  (chan, ~0);
464
465	/* GDI rectangle text. */
466	ret = nouveau_grobj_alloc(chan, handle++, NV04_GDI_RECTANGLE_TEXT,
467				  &hw->rect);
468	if (ret)
469		goto fail;
470
471	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_DMA_NOTIFY, 1);
472	OUT_RING  (chan, hw->ntfy->handle);
473	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_SURFACE, 1);
474	OUT_RING  (chan, hw->surf2d->handle);
475	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_ROP, 1);
476	OUT_RING  (chan, hw->rop->handle);
477	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_PATTERN, 1);
478	OUT_RING  (chan, hw->patt->handle);
479
480	BEGIN_RING(chan, hw->rect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
481	OUT_RING  (chan, NV04_GDI_RECTANGLE_TEXT_OPERATION_ROP_AND);
482	BEGIN_RING(chan, hw->rect,
483		   NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT, 1);
484	OUT_RING  (chan, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE);
485
486	/* Swizzled surface. */
487	switch (context_chipset(ctx) & 0xf0) {
488	case 0x00:
489	case 0x10:
490		class = NV04_SWIZZLED_SURFACE;
491		break;
492	case 0x20:
493		class = NV20_SWIZZLED_SURFACE;
494		break;
495	default:
496		/* Famous last words: this really can't happen.. */
497		assert(0);
498		break;
499	}
500
501	ret = nouveau_grobj_alloc(chan, handle++, class, &hw->swzsurf);
502	if (ret)
503		goto fail;
504
505	/* Scaled image from memory. */
506	switch (context_chipset(ctx) & 0xf0) {
507	case 0x00:
508		class = NV04_SCALED_IMAGE_FROM_MEMORY;
509		break;
510	case 0x10:
511	case 0x20:
512		class = NV10_SCALED_IMAGE_FROM_MEMORY;
513		break;
514	}
515
516	ret = nouveau_grobj_alloc(chan, handle++, class, &hw->sifm);
517	if (ret)
518		goto fail;
519
520	if (context_chipset(ctx) >= 0x10) {
521		BEGIN_RING(chan, hw->sifm,
522			   NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION, 1);
523		OUT_RING(chan, NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE);
524	}
525
526	return GL_TRUE;
527
528fail:
529	nv04_surface_takedown(ctx);
530	return GL_FALSE;
531}
532