pnozz_accel.c revision a6b33934
1/*
2 * SBus Weitek P9100 hardware acceleration support
3 *
4 * Copyright (C) 2005 Michael Lorenz
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * MICHAEL LORENZ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23/* $NetBSD: pnozz_accel.c,v 1.1 2009/08/26 22:28:26 macallan Exp $ */
24
25#include <fcntl.h>
26#include <sys/time.h>
27#include <sys/types.h>
28#include <dev/sun/fbio.h>
29#include <dev/wscons/wsconsio.h>
30
31#include "pnozz.h"
32
33static CARD32 PnozzCopyROP[] = {
34	/*GXclear*/		0,
35	/*GXand*/		ROP_SRC & ROP_DST,
36	/*GXandReverse*/	ROP_SRC & (~ROP_DST),
37	/*GXcopy*/		ROP_SRC,
38	/*GXandInverted*/	(~ROP_SRC) & ROP_DST,
39	/*GXnoop*/		ROP_DST,
40	/*GXxor*/		ROP_SRC ^ ROP_DST,
41	/*GXor*/		ROP_SRC | ROP_DST,
42	/*GXnor*/		(~ROP_SRC) & (~ROP_DST),
43	/*GXequiv*/		(~ROP_SRC) ^ ROP_DST,
44	/*GXinvert*/		(~ROP_DST),
45	/*GXorReverse*/		ROP_SRC | (~ROP_DST),
46	/*GXcopyInverted*/	(~ROP_SRC),
47	/*GXorInverted*/	(~ROP_SRC) | ROP_DST,
48	/*GXnand*/		(~ROP_SRC) | (~ROP_DST),
49	/*GXset*/		ROP_SET
50};
51
52static CARD32 PnozzDrawROP[] = {
53	/*GXclear*/		0,
54	/*GXand*/		ROP_PAT & ROP_DST,
55	/*GXandReverse*/	ROP_PAT & (~ROP_DST),
56	/*GXcopy*/		ROP_PAT,
57	/*GXandInverted*/	(~ROP_PAT) & ROP_DST,
58	/*GXnoop*/		ROP_DST,
59	/*GXxor*/		ROP_PAT ^ ROP_DST,
60	/*GXor*/		ROP_PAT | ROP_DST,
61	/*GXnor*/		(~ROP_PAT) & (~ROP_DST),
62	/*GXequiv*/		(~ROP_PAT) ^ ROP_DST,
63	/*GXinvert*/		(~ROP_DST),
64	/*GXorReverse*/		ROP_PAT | (~ROP_DST),
65	/*GXcopyInverted*/	(~ROP_PAT),
66	/*GXorInverted*/	(~ROP_PAT) | ROP_DST,
67	/*GXnand*/		(~ROP_PAT) | (~ROP_DST),
68	/*GXset*/		ROP_PAT
69};
70
71CARD32 MaxClip, junk;
72
73void
74PnozzSync(ScrnInfoPtr pScrn)
75{
76    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
77    while((pnozz_read_4(pPnozz, ENGINE_STATUS) &
78        (ENGINE_BUSY | BLITTER_BUSY)) !=0 );
79}
80
81/*
82 * Both the framebuffer and the colour registers are apparently little endian.
83 * For framebuffer accesses we can just turn on byte swapping, for the colour
84 * registers we need to juggle bytes ourselves.
85 */
86
87static void
88pnozz_write_colour(PnozzPtr pPnozz, int reg, CARD32 colour)
89{
90    CARD32 c2;
91
92    switch(pPnozz->depthshift)
93    {
94    	case 0:
95	    c2 = (colour << 8 | colour);
96	    pnozz_write_4(pPnozz, reg, c2 << 16 | c2);
97	    break;
98    	case 1:
99    	    c2 = ((colour & 0xff) << 8) | ((colour & 0xff00) >> 8);
100	    c2 |= c2 << 16;
101	    pnozz_write_4(pPnozz, reg, c2);
102	    break;
103    	case 2:
104    	    c2 = ((colour & 0x00ff00ff) << 8) | ((colour & 0xff00ff00) >> 8);
105    	    c2 = (( c2 & 0xffff0000) >> 16) | ((c2 & 0x0000ffff) << 16);
106	    pnozz_write_4(pPnozz, reg, c2);
107	    break;
108    }
109}
110
111static void unClip(PnozzPtr pPnozz)
112{
113    pnozz_write_4(pPnozz, WINDOW_OFFSET, 0);
114    pnozz_write_4(pPnozz, WINDOW_MIN, 0);
115    pnozz_write_4(pPnozz, WINDOW_MAX, MaxClip);
116    pnozz_write_4(pPnozz, BYTE_CLIP_MIN, 0);
117    pnozz_write_4(pPnozz, BYTE_CLIP_MAX, MaxClip);
118}
119
120static void
121PnozzInitEngine(PnozzPtr pPnozz)
122{
123    unClip(pPnozz);
124    pnozz_write_4(pPnozz, DRAW_MODE, 0);
125    pnozz_write_4(pPnozz, PLANE_MASK, 0xffffffff);
126    pnozz_write_4(pPnozz, PATTERN0, 0xffffffff);
127    pnozz_write_4(pPnozz, PATTERN1, 0xffffffff);
128    pnozz_write_4(pPnozz, PATTERN2, 0xffffffff);
129    pnozz_write_4(pPnozz, PATTERN3, 0xffffffff);
130}
131
132static void
133PnozzSetupForScreenToScreenCopy(
134    ScrnInfoPtr  pScrn,
135    int          xdir,
136    int          ydir,
137    int          rop,
138    unsigned int planemask,
139    int          TransparencyColour
140)
141{
142    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
143    PnozzSync(pScrn);
144
145    pnozz_write_4(pPnozz, RASTER_OP, (PnozzCopyROP[rop] & 0xff));
146    pnozz_write_4(pPnozz, PLANE_MASK, planemask);
147}
148
149/*
150 * the drawing engine is weird. Even though BLIT and QUAD commands use the
151 * same registers to program coordinates there's an important difference -
152 * horizontal coordinates for QUAD commands are in pixels, for BLIT commands
153 * and the byte clipping registers they're IN BYTES.
154 */
155static void
156PnozzSubsequentScreenToScreenCopy
157(
158    ScrnInfoPtr pScrn,
159    int         xSrc,
160    int         ySrc,
161    int         xDst,
162    int         yDst,
163    int         w,
164    int         h
165)
166{
167    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
168    CARD32 src, dst, srcw, dstw;
169
170    src = (((xSrc << pPnozz->depthshift) & 0x1fff) << 16) | (ySrc & 0x1fff);
171    dst = (((xDst << pPnozz->depthshift) & 0x1fff) << 16) | (yDst & 0x1fff);
172    srcw = ((((xSrc + w) << pPnozz->depthshift) - 1) << 16) |
173        ((ySrc + h - 1) & 0x1fff);
174    dstw = ((((xDst + w) << pPnozz->depthshift) - 1) << 16) |
175        ((yDst + h - 1) & 0x1fff);
176
177    PnozzSync(pScrn);
178
179    pnozz_write_4(pPnozz, ABS_XY0, src);
180    pnozz_write_4(pPnozz, ABS_XY1, srcw);
181    pnozz_write_4(pPnozz, ABS_XY2, dst);
182    pnozz_write_4(pPnozz, ABS_XY3, dstw);
183    junk = pnozz_read_4(pPnozz, COMMAND_BLIT);
184}
185
186static void
187PnozzSetupForSolidFill
188(
189    ScrnInfoPtr  pScrn,
190    int          colour,
191    int          rop,
192    unsigned int planemask
193)
194{
195    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
196    CARD32 c2;
197
198    PnozzSync(pScrn);
199
200    pnozz_write_colour(pPnozz, FOREGROUND_COLOR, colour);
201    pnozz_write_4(pPnozz, RASTER_OP, PnozzDrawROP[rop] & 0xff);
202    pnozz_write_4(pPnozz, PLANE_MASK, planemask);
203    pnozz_write_4(pPnozz, COORD_INDEX, 0);
204}
205
206static void
207PnozzSubsequentSolidFillRect
208(
209    ScrnInfoPtr pScrn,
210    int         x,
211    int         y,
212    int         w,
213    int         h
214)
215{
216    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
217
218    PnozzSync(pScrn);
219    pnozz_write_4(pPnozz, RECT_RTW_XY, ((x & 0x1fff) << 16) |
220        (y & 0x1fff));
221    pnozz_write_4(pPnozz, RECT_RTP_XY, (((w & 0x1fff) << 16) |
222        (h & 0x1fff)));
223    junk = pnozz_read_4(pPnozz, COMMAND_QUAD);
224}
225
226static void
227PnozzSetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn,
228        		int fg, int bg,
229			int rop,
230			unsigned int planemask)
231{
232    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
233
234    PnozzSync(pScrn);
235
236    if (bg == -1) {
237    	/* transparent */
238	pnozz_write_colour(pPnozz, FOREGROUND_COLOR, fg);
239	pnozz_write_4(pPnozz, RASTER_OP, PnozzDrawROP[rop] | ROP_PIX1_TRANS);
240    } else {
241	/*
242	 * this doesn't make any sense to me either, but for some reason the
243	 * chip applies the foreground colour to 0 pixels and background to 1
244	 * when set to this sort of ROP. The old XF 3.3 driver source claimed
245	 * that the chip doesn't support opaque colour expansion at all.
246	 */
247	pnozz_write_colour(pPnozz, FOREGROUND_COLOR, bg);
248	pnozz_write_colour(pPnozz, BACKGROUND_COLOR, fg);
249
250	pnozz_write_4(pPnozz, RASTER_OP, PnozzCopyROP[rop] & 0xff);
251    }
252
253    pnozz_write_4(pPnozz, PLANE_MASK, planemask);
254    pnozz_write_4(pPnozz, COORD_INDEX, 0);
255}
256
257static void
258PnozzSubsequentScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn,
259			int x, int y, int w, int h,
260			int skipleft )
261{
262    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
263    CARD32 rest = w & 0x1f;
264
265    pnozz_write_4(pPnozz, ABS_X0, x);
266    pnozz_write_4(pPnozz, ABS_XY1, (x << 16) | (y & 0xFFFFL));
267    pnozz_write_4(pPnozz, ABS_X2, (x + w));
268    pnozz_write_4(pPnozz, ABS_Y3, 1);
269
270    pPnozz->words = (w >> 5);	/* whole words to write */
271
272    if (rest > 0) {
273    	pPnozz->last_word = (rest - 1) << 2;
274    } else
275    	pPnozz->last_word = -1;
276}
277
278static void
279PnozzSubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno)
280{
281    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
282#define PIXEL_1_FULL (PIXEL_1 + (31 << 2))
283    CARD32 *buf;
284    volatile CARD32 *pix = ((volatile CARD32 *)(pPnozz->fbc + PIXEL_1_FULL));
285    int i = 0;
286
287    PnozzSync(pScrn);
288    buf = (CARD32 *)pPnozz->buffers[bufno];
289    junk = *(volatile CARD32 *)(pPnozz->fb + PIXEL_1_FULL);
290    for (i = 0; i < pPnozz->words; i++)
291	*pix = buf[i];
292    if (pPnozz->last_word >= 0)
293    	*(volatile CARD32 *)(pPnozz->fbc + PIXEL_1 + pPnozz->last_word) =
294    	    buf[i];
295}
296
297static void
298PnozzSetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop,
299    unsigned int planemask)
300{
301    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
302
303    PnozzSync(pScrn);
304
305    pnozz_write_colour(pPnozz, FOREGROUND_COLOR, color);
306    pnozz_write_4(pPnozz, RASTER_OP, (PnozzDrawROP[rop] & 0xff) | ROP_OVERSIZE);
307
308    pnozz_write_4(pPnozz, PLANE_MASK, planemask);
309    pnozz_write_4(pPnozz, COORD_INDEX, 0);
310
311}
312
313static void
314PnozzSubsequentSolidTwoPointLine(ScrnInfoPtr pScrn, int x1, int y1, int x2,
315    int y2, int flags)
316{
317    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
318
319    PnozzSync(pScrn);
320
321    /*
322     * XXX we're blatantly ignoring the flags parameter which could tell us not
323     * to draw the last point. Xsun simply reads it from the framebuffer and
324     * puts it back after drawing the line but that would mean we have to wait
325     * until the line is actually drawn. On the other hand - line drawing is
326     * pretty fast so we won't lose too much speed
327     */
328    pnozz_write_4(pPnozz, LINE_RTW_XY, (x1 << 16) | y1);
329    pnozz_write_4(pPnozz, LINE_RTW_XY, (x2 << 16) | y2);
330    junk = pnozz_read_4(pPnozz, COMMAND_QUAD);
331}
332
333static void
334PnozzSetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int pat0, int pat1,
335        int fg, int bg, int rop, unsigned int planemask)
336{
337    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
338    CARD32 pat;
339
340    PnozzSync(pScrn);
341
342    if (bg == -1) {
343	pnozz_write_4(pPnozz, RASTER_OP,
344	    (PnozzDrawROP[rop] & 0xff) | ROP_NO_SOLID | ROP_TRANS);
345    } else {
346        pnozz_write_colour(pPnozz, COLOR_0, bg);
347        pnozz_write_4(pPnozz, RASTER_OP,
348            (PnozzDrawROP[rop] & 0xff) | ROP_NO_SOLID);
349    }
350    pnozz_write_colour(pPnozz, COLOR_1, fg);
351    pnozz_write_4(pPnozz, PLANE_MASK, planemask);
352    pat = (pat0 & 0xff000000) | ((pat0 >> 8) & 0x00ffff00) |
353        ((pat0 >> 16) & 0x000000ff);
354    pnozz_write_4(pPnozz, PATTERN0, pat);
355    pat = ((pat0 << 8) & 0x00ffff00) | ((pat0 << 16) & 0xff000000) |
356        (pat0 & 0x000000ff);
357    pnozz_write_4(pPnozz, PATTERN1, pat);
358    pat = (pat1 & 0xff000000) | ((pat1 >> 8) & 0x00ffff00) |
359        ((pat1 >> 16) & 0x000000ff);
360    pnozz_write_4(pPnozz, PATTERN2, pat);
361    pat = ((pat1 << 8) & 0x00ffff00) | ((pat1 << 16) & 0xff000000) |
362        (pat1 & 0x000000ff);
363    pnozz_write_4(pPnozz, PATTERN3, pat);
364    pnozz_write_4(pPnozz, COORD_INDEX, 0);
365}
366
367static void
368PnozzSubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn,
369        	int patx, int paty, int x, int y, int w, int h)
370{
371    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
372
373    PnozzSync(pScrn);
374    pnozz_write_4(pPnozz, PATTERN_ORIGIN_X, patx);
375    pnozz_write_4(pPnozz, PATTERN_ORIGIN_Y, paty);
376    pnozz_write_4(pPnozz, RECT_RTW_XY, ((x & 0x1fff) << 16) |
377        (y & 0x1fff));
378    pnozz_write_4(pPnozz, RECT_RTP_XY, (((w & 0x1fff) << 16) |
379        (h & 0x1fff)));
380    junk = pnozz_read_4(pPnozz, COMMAND_QUAD);
381
382}
383
384static void
385PnozzSetClippingRectangle(ScrnInfoPtr pScrn, int left, int top, int right,
386			 int bottom)
387{
388    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
389    CARD32 cmin, cmax;
390
391    cmin = (left << 16) | top;
392    cmax = (right << 16) | bottom;
393
394    pnozz_write_4(pPnozz, WINDOW_MIN, cmin);
395    pnozz_write_4(pPnozz, WINDOW_MAX, cmax);
396
397    cmin = ((left << pPnozz->depthshift) << 16) | top;
398    cmax = ((right << pPnozz->depthshift) << 16) | bottom;
399
400    pnozz_write_4(pPnozz, BYTE_CLIP_MIN, cmin);
401    pnozz_write_4(pPnozz, BYTE_CLIP_MAX, cmax);
402}
403
404static void
405PnozzDisableClipping(ScrnInfoPtr pScrn)
406{
407    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
408
409    pnozz_write_4(pPnozz, WINDOW_MIN, 0);
410    pnozz_write_4(pPnozz, WINDOW_MAX, MaxClip);
411    pnozz_write_4(pPnozz, BYTE_CLIP_MIN, 0);
412    pnozz_write_4(pPnozz, BYTE_CLIP_MAX, MaxClip);
413}
414
415static void
416PnozzSetupForImageWrite(ScrnInfoPtr pScrn, int rop, unsigned int planemask,
417  int trans_color, int depth, int bpp)
418{
419    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
420
421    pnozz_write_4(pPnozz, RASTER_OP, PnozzCopyROP[rop] & 0xff);
422    pnozz_write_4(pPnozz, PLANE_MASK, planemask);
423    pnozz_write_4(pPnozz, COORD_INDEX, 0);
424
425    Xf86Msg(X_ERROR, "setup for image write\n");
426}
427
428static void
429PnozzImageWriteRect(ScrnInfoPtr pScrn, int x, int y, int wi, int he, int skip)
430{
431    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
432    volatile CARD32 junk;
433
434    pnozz_write_4(pPnozz, ABS_X0, x);
435    pnozz_write_4(pPnozz, ABS_XY1, (x << 16) | y);
436    pnozz_write_4(pPnozz, ABS_X2, x + wi);
437    pnozz_write_4(pPnozz, ABS_Y3, 1);
438    junk = *(volatile CARD32 *)(pPnozz->fb + PIXEL_8);
439}
440
441/*
442 * TODO:
443 * - CPU to VRAM colour blits
444 * - DGA support
445 */
446
447int
448PnozzAccelInit(ScrnInfoPtr pScrn)
449{
450    PnozzPtr pPnozz = GET_PNOZZ_FROM_SCRN(pScrn);
451    XAAInfoRecPtr pXAAInfo = pPnozz->pXAA;
452
453    pXAAInfo->Flags = LINEAR_FRAMEBUFFER | PIXMAP_CACHE | OFFSCREEN_PIXMAPS;
454    pXAAInfo->maxOffPixWidth = pPnozz->width;
455    pXAAInfo->maxOffPixHeight = pPnozz->maxheight;
456    MaxClip = ((pPnozz->scanlinesize & 0xffff) << 16) | (pPnozz->maxheight);
457
458    PnozzInitEngine(pPnozz);
459
460#if 1
461    {
462	CARD32 src, srcw, junk;
463	src = 0;
464	srcw = pPnozz->width << 16 | pPnozz->height;
465
466	/* Blit the screen black. For aesthetic reasons. */
467
468	PnozzSync(pScrn);
469	pnozz_write_4(pPnozz, FOREGROUND_COLOR, 0x00000000);
470	pnozz_write_4(pPnozz, BACKGROUND_COLOR, 0xffffffff);
471	pnozz_write_4(pPnozz, RASTER_OP, ROP_PAT);
472	pnozz_write_4(pPnozz, COORD_INDEX, 0);
473	pnozz_write_4(pPnozz, RECT_RTW_XY, src);
474	pnozz_write_4(pPnozz, RECT_RTW_XY, srcw);
475	junk = pnozz_read_4(pPnozz, COMMAND_QUAD);
476	PnozzSync(pScrn);
477    }
478#endif
479
480    /* Sync */
481    pXAAInfo->Sync = PnozzSync;
482
483    /* Screen-to-screen copy */
484    pXAAInfo->ScreenToScreenCopyFlags = NO_TRANSPARENCY;
485    pXAAInfo->SetupForScreenToScreenCopy = PnozzSetupForScreenToScreenCopy;
486    pXAAInfo->SubsequentScreenToScreenCopy =
487        PnozzSubsequentScreenToScreenCopy;
488
489    /* Solid fills */
490    pXAAInfo->SetupForSolidFill = PnozzSetupForSolidFill;
491    pXAAInfo->SubsequentSolidFillRect = PnozzSubsequentSolidFillRect;
492
493    /* colour expansion */
494    pXAAInfo->ScanlineCPUToScreenColorExpandFillFlags =
495	/*LEFT_EDGE_CLIPPING|*/SCANLINE_PAD_DWORD;
496    pXAAInfo->NumScanlineColorExpandBuffers = 2;
497    pPnozz->buffers[0] = (unsigned char *)pPnozz->Buffer;
498    pPnozz->buffers[1] = (unsigned char *)&pPnozz->Buffer[pPnozz->scanlinesize];
499    pXAAInfo->ScanlineColorExpandBuffers = pPnozz->buffers;
500    pXAAInfo->SetupForScanlineCPUToScreenColorExpandFill =
501	PnozzSetupForCPUToScreenColorExpandFill;
502    pXAAInfo->SubsequentScanlineCPUToScreenColorExpandFill =
503	PnozzSubsequentScanlineCPUToScreenColorExpandFill;
504    pXAAInfo->SubsequentColorExpandScanline =
505	PnozzSubsequentColorExpandScanline;
506
507    /* line drawing */
508    pXAAInfo->SetupForSolidLine = PnozzSetupForSolidLine;
509    pXAAInfo->SubsequentSolidTwoPointLine = PnozzSubsequentSolidTwoPointLine;
510    pXAAInfo->SolidLineFlags = BIT_ORDER_IN_BYTE_MSBFIRST;
511
512    /* clipping */
513    pXAAInfo->SetClippingRectangle = PnozzSetClippingRectangle;
514    pXAAInfo->DisableClipping = PnozzDisableClipping;
515    pXAAInfo->ClippingFlags = HARDWARE_CLIP_SCREEN_TO_SCREEN_COPY |
516        HARDWARE_CLIP_SOLID_FILL |
517        HARDWARE_CLIP_MONO_8x8_FILL |
518        /*HARDWARE_CLIP_COLOR_8x8_FILL |*/
519        HARDWARE_CLIP_SOLID_LINE;
520
521    /* 8x8 mono pattern fills */
522    pXAAInfo->Mono8x8PatternFillFlags = HARDWARE_PATTERN_PROGRAMMED_BITS |
523        HARDWARE_PATTERN_SCREEN_ORIGIN | HARDWARE_PATTERN_PROGRAMMED_ORIGIN;
524    pXAAInfo->SetupForMono8x8PatternFill = PnozzSetupForMono8x8PatternFill;
525    pXAAInfo->SubsequentMono8x8PatternFillRect =
526        PnozzSubsequentMono8x8PatternFillRect;
527
528    /* image uploads */
529    pXAAInfo->ImageWriteBase = pPnozz->fbc + PIXEL_8;
530    pXAAInfo->ImageWriteRange = 4;
531    pXAAInfo->ImageWriteFlags = /*CPU_TRANSFER_BASE_FIXED |*/ CPU_TRANSFER_PAD_DWORD |
532        NO_TRANSPARENCY;
533    pXAAInfo->SetupForImageWrite = PnozzSetupForImageWrite;
534    pXAAInfo->SubsequentImageWriteRect = PnozzImageWriteRect;
535
536    return 0;
537}
538