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
swzsurf_format(mesa_format format)37 swzsurf_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 
74 static inline int
surf2d_format(mesa_format format)75 surf2d_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 
112 static inline int
rect_format(mesa_format format)113 rect_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 
150 static inline int
sifm_format(mesa_format format)151 sifm_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 
188 static void
nv04_surface_copy_swizzle(struct gl_context * ctx,struct nouveau_surface * dst,struct nouveau_surface * src,int dx,int dy,int sx,int sy,int w,int h)189 nv04_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 
269 static void
nv04_surface_copy_m2mf(struct gl_context * ctx,struct nouveau_surface * dst,struct nouveau_surface * src,int dx,int dy,int sx,int sy,int w,int h)270 nv04_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 
312 typedef unsigned (*get_offset_t)(struct nouveau_surface *s,
313 				 unsigned x, unsigned y);
314 
315 static unsigned
get_linear_offset(struct nouveau_surface * s,unsigned x,unsigned y)316 get_linear_offset(struct nouveau_surface *s, unsigned x, unsigned y)
317 {
318 	return x * s->cpp + y * s->pitch;
319 }
320 
321 static unsigned
get_swizzled_offset(struct nouveau_surface * s,unsigned x,unsigned y)322 get_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 
357 static void
nv04_surface_copy_cpu(struct gl_context * ctx,struct nouveau_surface * dst,struct nouveau_surface * src,int dx,int dy,int sx,int sy,int w,int h)358 nv04_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 
385 void
nv04_surface_copy(struct gl_context * ctx,struct nouveau_surface * dst,struct nouveau_surface * src,int dx,int dy,int sx,int sy,int w,int h)386 nv04_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 
419 void
nv04_surface_fill(struct gl_context * ctx,struct nouveau_surface * dst,unsigned mask,unsigned value,int dx,int dy,int w,int h)420 nv04_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 
459 void
nv04_surface_takedown(struct gl_context * ctx)460 nv04_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 
474 GLboolean
nv04_surface_init(struct gl_context * ctx)475 nv04_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 
608 fail:
609 	nv04_surface_takedown(ctx);
610 	return GL_FALSE;
611 }
612