1 /*
2  * UAE - The U*nix Amiga Emulator
3  *
4  * Picasso96 Support Module
5  *
6  * Copyright 1997 Brian King <Brian_King@Mitel.com, Brian_King@Cloanto.com>
7  *
8  * Theory of operation:
9  * On the Amiga side, a Picasso card consists mainly of a memory area that
10  * contains the frame buffer.  On the UAE side, we allocate a block of memory
11  * that will hold the frame buffer.  This block is in normal memory, it is
12  * never directly on the graphics card.  All graphics operations, which are
13  * mainly reads and writes into this block and a few basic operations like
14  * filling a rectangle, operate on this block of memory.
15  * Since the memory is not on the graphics card, some work must be done to
16  * synchronize the display with the data in the Picasso frame buffer.  There
17  * are various ways to do this.  One possibility is to allocate a second
18  * buffer of the same size, and perform all write operations twice.  Since
19  * we never read from the second buffer, it can actually be placed in video
20  * memory.  The X11 driver could be made to use the Picasso frame buffer as
21  * the data buffer of an XImage, which could then be XPutImage()d from time
22  * to time.  Another possibility is to translate all Picasso accesses into
23  * Xlib (or GDI, or whatever your graphics system is) calls.  This possibility
24  * is a bit tricky, since there is a risk of generating very many single pixel
25  * accesses which may be rather slow.
26  *
27  * TODO:
28  * - add panning capability
29  * - we want to add a manual switch to override SetSwitch for hardware banging
30  *   programs started from a Picasso workbench.
31  */
32 
33 #include "sysconfig.h"
34 #include "sysdeps.h"
35 
36 #include "options.h"
37 #include "threaddep/thread.h"
38 #include "uae.h"
39 #include "memory.h"
40 #include "custom.h"
41 #include "newcpu.h"
42 #include "xwin.h"
43 #include "picasso96.h"
44 
45 #ifdef PICASSO96
46 
47 #define P96TRACING_ENABLED 0
48 #if P96TRACING_ENABLED
49 #define P96TRACE(x)	do { write_log x; } while(0)
50 #else
51 #define P96TRACE(x)
52 #endif
53 
54 static uae_u32 gfxmem_lget (uaecptr) REGPARAM;
55 static uae_u32 gfxmem_wget (uaecptr) REGPARAM;
56 static uae_u32 gfxmem_bget (uaecptr) REGPARAM;
57 static void gfxmem_lput (uaecptr, uae_u32) REGPARAM;
58 static void gfxmem_wput (uaecptr, uae_u32) REGPARAM;
59 static void gfxmem_bput (uaecptr, uae_u32) REGPARAM;
60 static int gfxmem_check (uaecptr addr, uae_u32 size) REGPARAM;
61 static uae_u8 *gfxmem_xlate (uaecptr addr) REGPARAM;
62 
63 static void write_gfx_long (uaecptr addr, uae_u32 value);
64 static void write_gfx_word (uaecptr addr, uae_u16 value);
65 static void write_gfx_byte (uaecptr addr, uae_u8 value);
66 
67 static uae_u8 all_ones_bitmap, all_zeros_bitmap;
68 
69 struct picasso96_state_struct picasso96_state;
70 struct picasso_vidbuf_description picasso_vidinfo;
71 
72 /* These are the maximum resolutions... They are filled in by GetSupportedResolutions() */
73 /* have to fill this in, otherwise problems occur
74  * @@@ ??? what problems?
75  */
76 struct ScreenResolution planar = { 320, 240 };
77 struct ScreenResolution chunky = { 640, 480 };
78 struct ScreenResolution hicolour = { 640, 480 };
79 struct ScreenResolution truecolour = { 640, 480 };
80 struct ScreenResolution alphacolour = { 640, 480 };
81 
82 uae_u16 picasso96_pixel_format = RGBFF_CHUNKY;
83 
84 struct PicassoResolution DisplayModes[MAX_PICASSO_MODES];
85 
86 static int mode_count = 0;
87 
88 static int set_gc_called = 0;
89 static int set_panning_called = 0;
90 /* Address of the screen in the Amiga frame buffer at the time of the last
91    SetPanning call.  */
92 static uaecptr oldscr;
93 
94 int screen_is_picasso;
95 
96 static uae_u32 p2ctab[256][2];
97 
98 /*
99  * Screen handling.
100  */
101 
set_window_for_picasso(void)102 static void set_window_for_picasso (void)
103 {
104     P96TRACE (("Function: set_window_for_picasso\n"));
105 #if 0
106     if (current_width == picasso_vidinfo.width && current_height == picasso_vidinfo.height)
107 	return;
108 #endif
109 
110     graphics_subshutdown (0);
111     graphics_subinit ();
112 
113     DX_SetPalette (0, 256);
114 }
115 
gfx_set_picasso_modeinfo(int w,int h,int depth,int rgbfmt)116 void gfx_set_picasso_modeinfo (int w, int h, int depth, int rgbfmt)
117 {
118     P96TRACE (("Function: gfx_set_picasso_modeinfo w: %i h: %i depth: %i rgbfmt: %i\n", w, h, depth, rgbfmt));
119 
120     if (screen_is_picasso
121 	&& picasso_vidinfo.width == w
122 	&& picasso_vidinfo.height == h)
123 	return;
124 
125     picasso_vidinfo.width = w;
126     picasso_vidinfo.height = h;
127     picasso_vidinfo.depth = depth;
128     if (screen_is_picasso)
129 	set_window_for_picasso ();
130 }
131 
gfx_set_picasso_baseaddr(uaecptr a)132 void gfx_set_picasso_baseaddr (uaecptr a)
133 {
134 }
135 
gfx_set_picasso_state(int on)136 void gfx_set_picasso_state (int on)
137 {
138     P96TRACE (("Function: gfx_set_picasso_state: %d\n", on));
139 
140     if (on == screen_is_picasso)
141 	return;
142 
143     graphics_subshutdown (0);
144     screen_is_picasso = on;
145     graphics_subinit ();
146 
147     if (on)
148 	DX_SetPalette (0, 256);
149     else
150 	reset_drawing ();
151 }
152 
153 /*
154  * Debugging dumps
155  */
156 
DumpModeInfoStructure(uaecptr amigamodeinfoptr)157 static void DumpModeInfoStructure (uaecptr amigamodeinfoptr)
158 {
159     write_log ("ModeInfo Structure Dump:\n");
160     write_log ("  Node.ln_Succ  = 0x%x\n", get_long (amigamodeinfoptr));
161     write_log ("  Node.ln_Pred  = 0x%x\n", get_long (amigamodeinfoptr + 4));
162     write_log ("  Node.ln_Type  = 0x%x\n", get_byte (amigamodeinfoptr + 8));
163     write_log ("  Node.ln_Pri   = %d\n", get_byte (amigamodeinfoptr + 9));
164     /*write_log ("  Node.ln_Name  = %s\n", uaememptr->Node.ln_Name); */
165     write_log ("  OpenCount     = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_OpenCount));
166     write_log ("  Active        = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Active));
167     write_log ("  Width         = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Width));
168     write_log ("  Height        = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Height));
169     write_log ("  Depth         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Depth));
170     write_log ("  Flags         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Flags));
171     write_log ("  HorTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorTotal));
172     write_log ("  HorBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorBlankSize));
173     write_log ("  HorSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncStart));
174     write_log ("  HorSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSize));
175     write_log ("  HorSyncSkew   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSkew));
176     write_log ("  HorEnableSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorEnableSkew));
177     write_log ("  VerTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerTotal));
178     write_log ("  VerBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerBlankSize));
179     write_log ("  VerSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncStart));
180     write_log ("  VerSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncSize));
181     write_log ("  Clock         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_first_union));
182     write_log ("  ClockDivide   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_second_union));
183     write_log ("  PixelClock    = %d\n", get_long (amigamodeinfoptr + PSSO_ModeInfo_PixelClock));
184 }
185 
DumpLibResolutionStructure(uaecptr amigalibresptr)186 static void DumpLibResolutionStructure (uaecptr amigalibresptr)
187 {
188     int i;
189     uaecptr amigamodeinfoptr;
190     struct LibResolution *uaememptr = (struct LibResolution *) get_mem_bank (amigalibresptr).xlateaddr (amigalibresptr);
191 
192     return;
193 
194     write_log ("LibResolution Structure Dump:\n");
195 
196     if (get_long (amigalibresptr + PSSO_LibResolution_DisplayID) == 0xFFFFFFFF) {
197 	write_log ("  Finished With LibResolutions...\n");
198     } else {
199 	write_log ("  Name      = %s\n", uaememptr->P96ID);
200 	write_log ("  DisplayID = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_DisplayID));
201 	write_log ("  Width     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Width));
202 	write_log ("  Height    = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Height));
203 	write_log ("  Flags     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Flags));
204 	for (i = 0; i < MAXMODES; i++) {
205 	    amigamodeinfoptr = get_long (amigalibresptr + PSSO_LibResolution_Modes + i * 4);
206 	    write_log ("  ModeInfo[%d] = 0x%x\n", i, amigamodeinfoptr);
207 	    if (amigamodeinfoptr)
208 		DumpModeInfoStructure (amigamodeinfoptr);
209 	}
210 	write_log ("  BoardInfo = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_BoardInfo));
211     }
212 }
213 
214 static char binary_byte[9];
215 
BuildBinaryString(uae_u8 value)216 static char *BuildBinaryString (uae_u8 value)
217 {
218     int i;
219     for (i = 0; i < 8; i++) {
220 	binary_byte[i] = (value & (1 << (7 - i))) ? '#' : '.';
221     }
222     binary_byte[8] = '\0';
223     return binary_byte;
224 }
225 
DumpPattern(struct Pattern * patt)226 static void DumpPattern (struct Pattern *patt)
227 {
228     uae_u8 *mem;
229     int row, col;
230     for (row = 0; row < (1 << patt->Size); row++) {
231 	mem = patt->Memory + row * 2;
232 	for (col = 0; col < 2; col++) {
233 	    write_log ("%s", BuildBinaryString (*mem++));
234 	}
235 	write_log ("\n");
236     }
237 }
238 
DumpTemplate(struct Template * tmp,uae_u16 w,uae_u16 h)239 static void DumpTemplate (struct Template *tmp, uae_u16 w, uae_u16 h)
240 {
241     uae_u8 *mem = tmp->Memory;
242     int row, col, width;
243     width = (w + 7) >> 3;
244     write_log ("xoffset = %d, bpr = %d\n", tmp->XOffset, tmp->BytesPerRow);
245     for (row = 0; row < h; row++) {
246 	mem = tmp->Memory + row * tmp->BytesPerRow;
247 	for (col = 0; col < width; col++) {
248 	    write_log ("%s", BuildBinaryString (*mem++));
249 	}
250 	write_log ("\n");
251     }
252 }
253 
picasso_nr_resolutions(void)254 int picasso_nr_resolutions (void)
255 {
256     return mode_count;
257 }
258 
ShowSupportedResolutions(void)259 static void ShowSupportedResolutions (void)
260 {
261     int i;
262 
263     return;
264 
265     for (i = 0; i < mode_count; i++)
266 	write_log ("%s\n", DisplayModes[i].name);
267 }
268 
GetBytesPerPixel(uae_u32 RGBfmt)269 static uae_u8 GetBytesPerPixel (uae_u32 RGBfmt)
270 {
271     switch (RGBfmt) {
272     case RGBFB_CLUT:
273 	return 1;
274 
275     case RGBFB_A8R8G8B8:
276     case RGBFB_A8B8G8R8:
277     case RGBFB_R8G8B8A8:
278     case RGBFB_B8G8R8A8:
279 	return 4;
280 
281     case RGBFB_B8G8R8:
282     case RGBFB_R8G8B8:
283 	return 3;
284 
285     case RGBFB_R5G5B5:
286     case RGBFB_R5G6B5:
287     case RGBFB_R5G6B5PC:
288     case RGBFB_R5G5B5PC:
289     case RGBFB_B5G6R5PC:
290     case RGBFB_B5G5R5PC:
291 	return 2;
292     default:
293 	write_log ("ERROR - GetBytesPerPixel() was unsuccessful with 0x%x?!\n", RGBfmt);
294 	return 0;
295     }
296 }
297 
298 /*
299  * Amiga <-> native structure conversion functions
300  */
301 
CopyRenderInfoStructureA2U(uaecptr amigamemptr,struct RenderInfo * ri)302 static int CopyRenderInfoStructureA2U (uaecptr amigamemptr, struct RenderInfo *ri)
303 {
304     uaecptr memp = get_long (amigamemptr + PSSO_RenderInfo_Memory);
305 
306     if (valid_address (memp, PSSO_RenderInfo_sizeof)) {
307 	ri->Memory = get_real_address (memp);
308 	ri->BytesPerRow = get_word (amigamemptr + PSSO_RenderInfo_BytesPerRow);
309 	ri->RGBFormat = get_long (amigamemptr + PSSO_RenderInfo_RGBFormat);
310 	return 1;
311     }
312     write_log ("ERROR - Invalid RenderInfo memory area...\n");
313     return 0;
314 }
315 
CopyPatternStructureA2U(uaecptr amigamemptr,struct Pattern * pattern)316 static int CopyPatternStructureA2U (uaecptr amigamemptr, struct Pattern *pattern)
317 {
318     uaecptr memp = get_long (amigamemptr + PSSO_Pattern_Memory);
319     if (valid_address (memp, PSSO_Pattern_sizeof)) {
320 	pattern->Memory = get_real_address (memp);
321 	pattern->XOffset = get_word (amigamemptr + PSSO_Pattern_XOffset);
322 	pattern->YOffset = get_word (amigamemptr + PSSO_Pattern_YOffset);
323 	pattern->FgPen = get_long (amigamemptr + PSSO_Pattern_FgPen);
324 	pattern->BgPen = get_long (amigamemptr + PSSO_Pattern_BgPen);
325 	pattern->Size = get_byte (amigamemptr + PSSO_Pattern_Size);
326 	pattern->DrawMode = get_byte (amigamemptr + PSSO_Pattern_DrawMode);
327 	return 1;
328     }
329     write_log ("ERROR - Invalid Pattern memory area...\n");
330     return 0;
331 }
332 
CopyColorIndexMappingA2U(uaecptr amigamemptr,struct ColorIndexMapping * cim)333 static void CopyColorIndexMappingA2U (uaecptr amigamemptr, struct ColorIndexMapping *cim)
334 {
335     int i;
336     cim->ColorMask = get_long (amigamemptr);
337     for (i = 0; i < 256; i++, amigamemptr += 4)
338 	cim->Colors[i] = get_long (amigamemptr + 4);
339 }
340 
CopyBitMapStructureA2U(uaecptr amigamemptr,struct BitMap * bm)341 static int CopyBitMapStructureA2U (uaecptr amigamemptr, struct BitMap *bm)
342 {
343     int i;
344 
345     bm->BytesPerRow = get_word (amigamemptr + PSSO_BitMap_BytesPerRow);
346     bm->Rows = get_word (amigamemptr + PSSO_BitMap_Rows);
347     bm->Flags = get_byte (amigamemptr + PSSO_BitMap_Flags);
348     bm->Depth = get_byte (amigamemptr + PSSO_BitMap_Depth);
349 
350     for (i = 0; i < bm->Depth; i++) {
351 	uaecptr plane = get_long (amigamemptr + PSSO_BitMap_Planes + i * 4);
352 	switch (plane) {
353 	case 0:
354 	    bm->Planes[i] = &all_zeros_bitmap;
355 	    break;
356 	case 0xFFFFFFFF:
357 	    bm->Planes[i] = &all_ones_bitmap;
358 	    break;
359 	default:
360 	    if (valid_address (plane, bm->BytesPerRow * bm->Rows))
361 		bm->Planes[i] = get_real_address (plane);
362 	    else
363 		return 0;
364 	    break;
365 	}
366     }
367     return 1;
368 }
369 
CopyTemplateStructureA2U(uaecptr amigamemptr,struct Template * tmpl)370 static int CopyTemplateStructureA2U (uaecptr amigamemptr, struct Template *tmpl)
371 {
372     uaecptr memp = get_long (amigamemptr + PSSO_Template_Memory);
373 
374     if (valid_address (memp, 1 /* FIXME */ )) {
375 	tmpl->Memory = get_real_address (memp);
376 	tmpl->BytesPerRow = get_word (amigamemptr + PSSO_Template_BytesPerRow);
377 	tmpl->XOffset = get_byte (amigamemptr + PSSO_Template_XOffset);
378 	tmpl->DrawMode = get_byte (amigamemptr + PSSO_Template_DrawMode);
379 	tmpl->FgPen = get_long (amigamemptr + PSSO_Template_FgPen);
380 	tmpl->BgPen = get_long (amigamemptr + PSSO_Template_BgPen);
381 	return 1;
382     }
383     write_log ("ERROR - Invalid Template memory area...\n");
384     return 0;
385 }
386 
CopyLibResolutionStructureU2A(struct LibResolution * libres,uaecptr amigamemptr)387 static void CopyLibResolutionStructureU2A (struct LibResolution *libres, uaecptr amigamemptr)
388 {
389     char *uaememptr = 0;
390     int i;
391 
392     /* I know that amigamemptr is inside my gfxmem chunk, so I can just
393      * do the xlate() */
394     uaememptr = gfxmem_xlate (amigamemptr);
395 
396     /* zero out our LibResolution structure */
397     memset (uaememptr, 0, PSSO_LibResolution_sizeof);
398 
399     strcpy (uaememptr + PSSO_LibResolution_P96ID, libres->P96ID);
400     put_long (amigamemptr + PSSO_LibResolution_DisplayID, libres->DisplayID);
401     put_word (amigamemptr + PSSO_LibResolution_Width, libres->Width);
402     put_word (amigamemptr + PSSO_LibResolution_Height, libres->Height);
403     put_word (amigamemptr + PSSO_LibResolution_Flags, libres->Flags);
404     for (i = 0; i < MAXMODES; i++)
405 	put_long (amigamemptr + PSSO_LibResolution_Modes + i * 4, libres->Modes[i]);
406 #if 0
407     put_long (amigamemptr, libres->Node.ln_Succ);
408     put_long (amigamemptr + 4, libres->Node.ln_Pred);
409     put_byte (amigamemptr + 8, libres->Node.ln_Type);
410     put_byte (amigamemptr + 9, libres->Node.ln_Pri);
411 #endif
412     put_long (amigamemptr + 10, amigamemptr + PSSO_LibResolution_P96ID);
413     put_long (amigamemptr + PSSO_LibResolution_BoardInfo, libres->BoardInfo);
414 }
415 
416 /* list is Amiga address of list, in correct endian format for UAE
417  * node is Amiga address of node, in correct endian format for UAE */
AmigaListAddTail(uaecptr list,uaecptr node)418 static void AmigaListAddTail (uaecptr list, uaecptr node)
419 {
420     uaecptr amigamemptr = 0;
421 
422     if (get_long (list + 8) == list) {
423 	/* Empty list - set it up */
424 	put_long (list, node);	/* point the lh_Head to our new node */
425 	put_long (list + 4, 0);	/* set the lh_Tail to NULL */
426 	put_long (list + 8, node);	/* point the lh_TailPred to our new node */
427 
428 	/* Adjust the new node - don't rely on it being zeroed out */
429 	put_long (node, 0);	/* ln_Succ */
430 	put_long (node + 4, 0);	/* ln_Pred */
431     } else {
432 	amigamemptr = get_long (list + 8);	/* get the lh_TailPred contents */
433 
434 	put_long (list + 8, node);	/* point the lh_TailPred to our new node */
435 
436 	/* Adjust the previous lh_TailPred node */
437 	put_long (amigamemptr, node);	/* point the ln_Succ to our new node */
438 
439 	/* Adjust the new node - don't rely on it being zeroed out */
440 	put_long (node, 0);	/* ln_Succ */
441 	put_long (node + 4, amigamemptr);	/* ln_Pred */
442     }
443 }
444 
445 /*
446  * Functions to perform an action on the real screen
447  */
448 
449 /*
450  * Fill a rectangle on the screen.  src points to the start of a line of the
451  * filled rectangle in the frame buffer; it can be used as a memcpy source if
452  * there is no OS specific function to fill the rectangle.
453  */
do_fillrect(uae_u8 * src,int x,int y,int width,int height,uae_u32 pen,int Bpp,RGBFTYPE rgbtype)454 static void do_fillrect (uae_u8 * src, int x, int y, int width, int height,
455 			 uae_u32 pen, int Bpp, RGBFTYPE rgbtype)
456 {
457     uae_u8 *dst;
458 
459     /* Clipping.  */
460     x -= picasso96_state.XOffset;
461     y -= picasso96_state.YOffset;
462     if (x < 0) {
463 	width += x;
464 	x = 0;
465     }
466     if (y < 0) {
467 	height += y;
468 	y = 0;
469     }
470     if (x + width > picasso96_state.Width)
471 	width = picasso96_state.Width - x;
472     if (y + height > picasso96_state.Height)
473 	height = picasso96_state.Height - y;
474 
475     if (width <= 0 || height <= 0)
476 	return;
477 
478     /* Try OS specific fillrect function here; and return if successful.  */
479 
480     DX_Invalidate (y, y + height - 1);
481     if (!picasso_vidinfo.extra_mem)
482 	return;
483 
484     width *= picasso96_state.BytesPerPixel;
485     dst = gfx_lock_picasso ();
486     if (!dst)
487 	goto out;
488 
489     dst += y * picasso_vidinfo.rowbytes + x * picasso_vidinfo.pixbytes;
490     if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
491 	if (Bpp == 1) {
492 	    while (height-- > 0) {
493 		memset (dst, pen, width);
494 		dst += picasso_vidinfo.rowbytes;
495 	    }
496 	} else {
497 	    while (height-- > 0) {
498 		memcpy (dst, src, width);
499 		dst += picasso_vidinfo.rowbytes;
500 	    }
501 	}
502     } else {
503 	int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
504 	if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
505 	    abort ();
506 
507 	while (height-- > 0) {
508 	    int i;
509 	    switch (psiz) {
510 	    case 2:
511 		for (i = 0; i < width; i++)
512 		    *((uae_u16 *) dst + i) = picasso_vidinfo.clut[src[i]];
513 		break;
514 	    case 4:
515 		for (i = 0; i < width; i++)
516 		    *((uae_u32 *) dst + i) = picasso_vidinfo.clut[src[i]];
517 		break;
518 	    default:
519 		abort ();
520 	    }
521 	    dst += picasso_vidinfo.rowbytes;
522 	}
523     }
524   out:
525     gfx_unlock_picasso ();
526 }
527 
528 /*
529  * This routine modifies the real screen buffer after a blit has been
530  * performed in the save area. If can_do_blit is nonzero, the blit can
531  * be performed within the real screen buffer; otherwise, this routine
532  * must do it by hand using the data in the save area, pointed to by
533  * srcp.
534  */
535 
do_blit(struct RenderInfo * ri,int Bpp,int srcx,int srcy,int dstx,int dsty,int width,int height,BLIT_OPCODE opcode,int can_do_blit)536 static void do_blit (struct RenderInfo *ri, int Bpp, int srcx, int srcy,
537 		     int dstx, int dsty, int width, int height,
538 		     BLIT_OPCODE opcode, int can_do_blit)
539 {
540     int xoff = picasso96_state.XOffset;
541     int yoff = picasso96_state.YOffset;
542     uae_u8 *srcp, *dstp;
543 
544     /* Clipping.  */
545     dstx -= xoff;
546     dsty -= yoff;
547     if (srcy < yoff || srcx < xoff
548 	|| srcx - xoff + width > picasso96_state.Width
549 	|| srcy - yoff + height > picasso96_state.Height)
550     {
551 	can_do_blit = 0;
552     }
553     if (dstx < 0) {
554 	srcx -= dstx;
555 	width += dstx;
556 	dstx = 0;
557     }
558     if (dsty < 0) {
559 	srcy -= dsty;
560 	height += dsty;
561 	dsty = 0;
562     }
563     if (dstx + width > picasso96_state.Width)
564 	width = picasso96_state.Width - dstx;
565     if (dsty + height > picasso96_state.Height)
566 	height = picasso96_state.Height - dsty;
567     if (width <= 0 || height <= 0)
568 	return;
569 
570     /* If this RenderInfo points at something else than the currently visible
571      * screen, we must ignore the blit.  */
572     if (can_do_blit) {
573 	/*
574 	 * Call OS blitting function that can do it in video memory.
575 	 * Should return if it was successful
576 	 */
577     }
578 
579     /* If no OS blit available, we do a copy from the P96 framebuffer in Amiga
580        memory to the host's frame buffer.  */
581     DX_Invalidate (dsty, dsty + height - 1);
582     if (!picasso_vidinfo.extra_mem)
583 	return;
584 
585     dstp = gfx_lock_picasso ();
586     if (dstp == 0)
587 	goto out;
588     dstp += dsty * picasso_vidinfo.rowbytes + dstx * picasso_vidinfo.pixbytes;
589     P96TRACE(("do_blit with srcp 0x%x, dstp 0x%x, dst_rowbytes %d, srcx %d, srcy %d, dstx %d, dsty %d, w %d, h %d, dst_pixbytes %d\n",
590 	srcp, dstp, picasso_vidinfo.rowbytes, srcx, srcy, dstx, dsty, width, height, picasso_vidinfo.pixbytes));
591     P96TRACE(("gfxmem is at 0x%x\n",gfxmemory));
592 
593     srcp = ri->Memory + srcx * Bpp + srcy * ri->BytesPerRow;
594     if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
595 	width *= Bpp;
596 	while (height-- > 0) {
597 	    memcpy (dstp, srcp, width);
598 	    srcp += ri->BytesPerRow;
599 	    dstp += picasso_vidinfo.rowbytes;
600 	}
601     } else {
602 	int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
603 	if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
604 	    abort ();
605 
606 	while (height-- > 0) {
607 	    int i;
608 	    switch (psiz) {
609 	    case 2:
610 		for (i = 0; i < width; i++)
611 		    *((uae_u16 *) dstp + i) = picasso_vidinfo.clut[srcp[i]];
612 		break;
613 	    case 4:
614 		for (i = 0; i < width; i++)
615 		    *((uae_u32 *) dstp + i) = picasso_vidinfo.clut[srcp[i]];
616 		break;
617 	    default:
618 		abort ();
619 	    }
620 	    srcp += ri->BytesPerRow;
621 	    dstp += picasso_vidinfo.rowbytes;
622 	}
623     }
624   out:
625     gfx_unlock_picasso ();
626 }
627 
628 /*
629  * Invert a rectangle on the screen.
630  */
631 
do_invertrect(struct RenderInfo * ri,int Bpp,int x,int y,int width,int height)632 static void do_invertrect (struct RenderInfo *ri, int Bpp, int x, int y, int width, int height)
633 {
634 #if 0
635     /* Clipping.  */
636     x -= picasso96_state.XOffset;
637     y -= picasso96_state.YOffset;
638     if (x < 0) {
639 	width += x;
640 	x = 0;
641     }
642     if (y < 0) {
643 	height += y;
644 	y = 0;
645     }
646     if (x + width > picasso96_state.Width)
647 	width = picasso96_state.Width - x;
648     if (y + height > picasso96_state.Height)
649 	height = picasso96_state.Height - y;
650 
651     if (width <= 0 || height <= 0)
652 	return;
653 
654 #endif
655     /* TODO: Try OS specific invertrect function here; and return if successful.  */
656 
657     do_blit (ri, Bpp, x, y, x, y, width, height, BLIT_SRC, 0);
658 }
659 
660 static uaecptr wgfx_linestart;
661 static uaecptr wgfx_lineend;
662 static uaecptr wgfx_min, wgfx_max;
663 static long wgfx_y;
664 
wgfx_do_flushline(void)665 static void wgfx_do_flushline (void)
666 {
667     int src_y = wgfx_y;
668     long x0, x1, width;
669     uae_u8 *src, *dstp;
670     int Bpp = GetBytesPerPixel (picasso_vidinfo.rgbformat);
671     int fb_bpp = picasso96_state.BytesPerPixel;
672 
673     wgfx_y -= picasso96_state.YOffset;
674     if (wgfx_y < 0 || wgfx_y >= picasso96_state.Height)
675 	goto out1;
676 
677     DX_Invalidate (wgfx_y, wgfx_y);
678     if (!picasso_vidinfo.extra_mem)
679 	goto out1;
680 
681     x0 = wgfx_min - wgfx_linestart;
682     width = wgfx_max - wgfx_min;
683     x0 -= picasso96_state.XOffset * fb_bpp;
684     if (x0 < 0) {
685 	width += x0;
686 	wgfx_min += x0;
687 	x0 = 0;
688     }
689     if (x0 + width > picasso96_state.Width * fb_bpp)
690 	width = picasso96_state.Width * fb_bpp - x0;
691 
692     dstp = gfx_lock_picasso ();
693     if (dstp == 0)
694 	goto out;
695 
696     //    P96TRACE(("flushing %d\n", wgfx_y));
697     src = gfxmemory + wgfx_min;
698 
699     if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
700 	dstp += wgfx_y * picasso_vidinfo.rowbytes + x0;
701 	memcpy (dstp, src, width);
702     } else {
703 	int i;
704 
705 	if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
706 	    abort ();
707 
708 	dstp += wgfx_y * picasso_vidinfo.rowbytes + x0 * Bpp;
709 	switch (Bpp) {
710 	case 2:
711 	    for (i = 0; i < width; i++)
712 		*((uae_u16 *) dstp + i) = picasso_vidinfo.clut[src[i]];
713 	    break;
714 	case 4:
715 	    for (i = 0; i < width; i++)
716 		*((uae_u32 *) dstp + i) = picasso_vidinfo.clut[src[i]];
717 	    break;
718 	default:
719 	    abort ();
720 	}
721     }
722 
723   out:
724     gfx_unlock_picasso ();
725   out1:
726     wgfx_linestart = 0xFFFFFFFF;
727 }
728 
wgfx_flushline(void)729 STATIC_INLINE void wgfx_flushline (void)
730 {
731     if (wgfx_linestart == 0xFFFFFFFF || !picasso_on)
732 	return;
733     wgfx_do_flushline ();
734 }
735 
renderinfo_is_current_screen(struct RenderInfo * ri)736 static int renderinfo_is_current_screen (struct RenderInfo *ri)
737 {
738     if (!picasso_on)
739 	return 0;
740     if (ri->Memory != gfxmemory + (picasso96_state.Address - gfxmem_start))
741 	return 0;
742 
743     return 1;
744 }
745 
746 /* Clear our screen, since we've got a new Picasso screen-mode, and refresh with the proper contents
747  * This is called on several occasions:
748  * 1. Amiga-->Picasso transition, via SetSwitch()
749  * 2. Picasso-->Picasso transition, via SetPanning().
750  * 3. whenever the graphics code notifies us that the screen contents have been lost.
751  */
picasso_refresh(void)752 void picasso_refresh (void)
753 {
754     struct RenderInfo ri;
755 
756     if (!picasso_on)
757 	return;
758 
759     /* Make sure that the first time we show a Picasso video mode, we don't blit any crap.
760      * We can do this by checking if we have an Address yet.  */
761     if (picasso96_state.Address) {
762 	unsigned int width, height;
763 	/* blit the stuff from our static frame-buffer to the gfx-card */
764 	ri.Memory = gfxmemory + (picasso96_state.Address - gfxmem_start);
765 	ri.BytesPerRow = picasso96_state.BytesPerRow;
766 	ri.RGBFormat = picasso96_state.RGBFormat;
767 
768 	if (set_panning_called) {
769 	    width = picasso96_state.VirtualWidth;
770 	    height = picasso96_state.VirtualHeight;
771 	} else {
772 	    width = picasso96_state.Width;
773 	    height = picasso96_state.Height;
774 	}
775 
776 	do_blit (&ri, picasso96_state.BytesPerPixel, 0, 0, 0, 0, width, height, BLIT_SRC, 0);
777     } else
778 	write_log ("ERROR - picasso_refresh() can't refresh!\n");
779 }
780 
781 /*
782  * BOOL FindCard(struct BoardInfo *bi);       and
783  *
784  * FindCard is called in the first stage of the board initialisation and
785  * configuration and is used to look if there is a free and unconfigured
786  * board of the type the driver is capable of managing. If it finds one,
787  * it immediately reserves it for use by Picasso96, usually by clearing
788  * the CDB_CONFIGME bit in the flags field of the ConfigDev struct of
789  * this expansion card. But this is only a common example, a driver can
790  * do whatever it wants to mark this card as used by the driver. This
791  * mechanism is intended to ensure that a board is only configured and
792  * used by one driver. FindBoard also usually fills some fields of the
793  * BoardInfo struct supplied by the caller, the rtg.library, for example
794  * the MemoryBase, MemorySize and RegisterBase fields.
795  */
picasso_FindCard(void)796 uae_u32 picasso_FindCard (void)
797 {
798     uaecptr AmigaBoardInfo = m68k_areg (regs, 0);
799     /* NOTES: See BoardInfo struct definition in Picasso96 dev info */
800 
801     if (allocated_gfxmem && !picasso96_state.CardFound) {
802 	/* Fill in MemoryBase, MemorySize */
803 	put_long (AmigaBoardInfo + PSSO_BoardInfo_MemoryBase, gfxmem_start);
804 	/* size of memory, minus a 32K chunk: 16K for pattern bitmaps, 16K for resolution list */
805 	put_long (AmigaBoardInfo + PSSO_BoardInfo_MemorySize, allocated_gfxmem - 32768);
806 
807 	picasso96_state.CardFound = 1;	/* mark our "card" as being found */
808 	return -1;
809     } else
810 	return 0;
811 }
812 
FillBoardInfo(uaecptr amigamemptr,struct LibResolution * res,struct PicassoResolution * dm)813 static void FillBoardInfo (uaecptr amigamemptr, struct LibResolution *res, struct PicassoResolution *dm)
814 {
815     char *uaememptr;
816     switch (dm->depth) {
817     case 1:
818 	res->Modes[CHUNKY] = amigamemptr;
819 	break;
820     case 2:
821 	res->Modes[HICOLOR] = amigamemptr;
822 	break;
823     case 3:
824 	res->Modes[TRUECOLOR] = amigamemptr;
825 	break;
826     default:
827 	res->Modes[TRUEALPHA] = amigamemptr;
828 	break;
829     }
830     uaememptr = gfxmem_xlate (amigamemptr);	/* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
831     memset (uaememptr, 0, PSSO_ModeInfo_sizeof);	/* zero out our ModeInfo struct */
832 
833     put_word (amigamemptr + PSSO_ModeInfo_Width, dm->res.width);
834     put_word (amigamemptr + PSSO_ModeInfo_Height, dm->res.height);
835     put_byte (amigamemptr + PSSO_ModeInfo_Depth, dm->depth * 8);
836     put_byte (amigamemptr + PSSO_ModeInfo_Flags, 0);
837     put_word (amigamemptr + PSSO_ModeInfo_HorTotal, dm->res.width);
838     put_word (amigamemptr + PSSO_ModeInfo_HorBlankSize, 0);
839     put_word (amigamemptr + PSSO_ModeInfo_HorSyncStart, 0);
840     put_word (amigamemptr + PSSO_ModeInfo_HorSyncSize, 0);
841     put_byte (amigamemptr + PSSO_ModeInfo_HorSyncSkew, 0);
842     put_byte (amigamemptr + PSSO_ModeInfo_HorEnableSkew, 0);
843 
844     put_word (amigamemptr + PSSO_ModeInfo_VerTotal, dm->res.height);
845     put_word (amigamemptr + PSSO_ModeInfo_VerBlankSize, 0);
846     put_word (amigamemptr + PSSO_ModeInfo_VerSyncStart, 0);
847     put_word (amigamemptr + PSSO_ModeInfo_VerSyncSize, 0);
848 
849     put_byte (amigamemptr + PSSO_ModeInfo_first_union, 98);
850     put_byte (amigamemptr + PSSO_ModeInfo_second_union, 14);
851 
852     put_long (amigamemptr + PSSO_ModeInfo_PixelClock, dm->res.width * dm->res.height * dm->refresh);
853 }
854 
AssignModeID(int i,int count)855 static uae_u32 AssignModeID (int i, int count)
856 {
857     if (DisplayModes[i].res.width == 320 && DisplayModes[i].res.height == 200)
858 	return 0x50001000;
859     else if (DisplayModes[i].res.width == 320 && DisplayModes[i].res.height == 240)
860 	return 0x50011000;
861     else if (DisplayModes[i].res.width == 640 && DisplayModes[i].res.height == 400)
862 	return 0x50021000;
863     else if (DisplayModes[i].res.width == 640 && DisplayModes[i].res.height == 480)
864 	return 0x50031000;
865     else if (DisplayModes[i].res.width == 800 && DisplayModes[i].res.height == 600)
866 	return 0x50041000;
867     else if (DisplayModes[i].res.width == 1024 && DisplayModes[i].res.height == 768)
868 	return 0x50051000;
869     else if (DisplayModes[i].res.width == 1152 && DisplayModes[i].res.height == 864)
870 	return 0x50061000;
871     else if (DisplayModes[i].res.width == 1280 && DisplayModes[i].res.height == 1024)
872 	return 0x50071000;
873     else if (DisplayModes[i].res.width == 1600 && DisplayModes[i].res.height == 1280)
874 	return 0x50081000;
875 
876     return 0x50091000 + count * 0x10000;
877 }
878 
879 /****************************************
880 * InitCard()
881 *
882 * a2: BoardInfo structure ptr - Amiga-based address in Intel endian-format
883 *
884 * Job - fill in the following structure members:
885 * gbi_RGBFormats: the pixel formats that the host-OS of UAE supports
886 *     If UAE is running in a window, it should ONLY report the pixel format of the host-OS desktop
887 *     If UAE is running full-screen, it should report ALL pixel formats that the host-OS can handle in full-screen
888 *     NOTE: If full-screen, and the user toggles to windowed-mode, all hell will break loose visually.  Must inform
889 *           user that they're doing something stupid (unless their desktop and full-screen colour modes match).
890 * gbi_SoftSpriteFlags: should be the same as above for now, until actual cursor support is added
891 * gbi_BitsPerCannon: could be 6 or 8 or ???, depending on the host-OS gfx-card
892 * gbi_MaxHorResolution: fill this in for all modes (even if you don't support them)
893 * gbi_MaxVerResolution: fill this in for all modes (even if you don't support them)
894 */
picasso_InitCard(void)895 uae_u32 picasso_InitCard (void)
896 {
897     struct LibResolution res;
898     int i;
899     int ModeInfoStructureCount = 1, LibResolutionStructureCount = 0;
900     uaecptr amigamemptr = 0;
901     uaecptr AmigaBoardInfo = m68k_areg (regs, 2);
902     put_word (AmigaBoardInfo + PSSO_BoardInfo_BitsPerCannon, DX_BitsPerCannon ());
903     put_word (AmigaBoardInfo + PSSO_BoardInfo_RGBFormats, picasso96_pixel_format);
904     put_word (AmigaBoardInfo + PSSO_BoardInfo_SoftSpriteFlags, picasso96_pixel_format);
905     put_long (AmigaBoardInfo + PSSO_BoardInfo_BoardType, BT_uaegfx);
906     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 0, planar.width);
907     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 2, chunky.width);
908     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 4, hicolour.width);
909     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 6, truecolour.width);
910     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 8, alphacolour.width);
911     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 0, planar.height);
912     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 2, chunky.height);
913     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 4, hicolour.height);
914     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 6, truecolour.height);
915     put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 8, alphacolour.height);
916 
917     for (i = 0; i < mode_count;) {
918 	int j = i;
919 	/* Add a LibResolution structure to the ResolutionsList MinList in our BoardInfo */
920 	res.DisplayID = AssignModeID (i, LibResolutionStructureCount);
921 	res.BoardInfo = AmigaBoardInfo;
922 	res.Width = DisplayModes[i].res.width;
923 	res.Height = DisplayModes[i].res.height;
924 	res.Flags = P96F_PUBLIC;
925 	res.P96ID[0] = 'P';
926 	res.P96ID[1] = '9';
927 	res.P96ID[2] = '6';
928 	res.P96ID[3] = '-';
929 	res.P96ID[4] = '0';
930 	res.P96ID[5] = ':';
931 	strcpy (res.Name, "uaegfx:");
932 	strncat (res.Name, DisplayModes[i].name, strchr (DisplayModes[i].name, ',') - DisplayModes[i].name);
933 	res.Modes[PLANAR] = 0;
934 	res.Modes[CHUNKY] = 0;
935 	res.Modes[HICOLOR] = 0;
936 	res.Modes[TRUECOLOR] = 0;
937 	res.Modes[TRUEALPHA] = 0;
938 
939 	do {
940 	    /* Handle this display mode's depth */
941 	    /* Only add the modes when there is enough P96 RTG memory to hold the bitmap */
942 	    long required = DisplayModes[i].res.width * DisplayModes[i].res.height * DisplayModes[i].depth;
943 	    if (allocated_gfxmem - 32768 > required) {
944 		amigamemptr = gfxmem_start + allocated_gfxmem - (PSSO_ModeInfo_sizeof * ModeInfoStructureCount++);
945 		FillBoardInfo (amigamemptr, &res, &DisplayModes[i]);
946 	    }
947 	    i++;
948 	} while (i < mode_count
949 		 && DisplayModes[i].res.width == DisplayModes[j].res.width
950 		 && DisplayModes[i].res.height == DisplayModes[j].res.height);
951 
952 	amigamemptr = gfxmem_start + allocated_gfxmem - 16384 + (PSSO_LibResolution_sizeof * LibResolutionStructureCount++);
953 	CopyLibResolutionStructureU2A (&res, amigamemptr);
954 	DumpLibResolutionStructure (amigamemptr);
955 	AmigaListAddTail (AmigaBoardInfo + PSSO_BoardInfo_ResolutionsList, amigamemptr);
956     }
957 
958     return 0;
959 }
960 
961 extern int x_size, y_size;
962 
963 /*
964  * SetSwitch:
965  * a0:	struct BoardInfo
966  * d0.w:	BOOL state
967  * this function should set a board switch to let the Amiga signal pass
968  * through when supplied with a 0 in d0 and to show the board signal if
969  * a 1 is passed in d0. You should remember the current state of the
970  * switch to avoid unneeded switching. If your board has no switch, then
971  * simply supply a function that does nothing except a RTS.
972  *
973  * NOTE: Return the opposite of the switch-state. BDK
974 */
picasso_SetSwitch(void)975 uae_u32 picasso_SetSwitch (void)
976 {
977     uae_u16 flag = m68k_dreg (regs, 0) & 0xFFFF;
978 
979     /* Do not switch immediately.  Tell the custom chip emulation about the
980      * desired state, and wait for custom.c to call picasso_enablescreen
981      * whenever it is ready to change the screen state.  */
982     picasso_requested_on = !!flag;
983 #if 1
984     write_log ("SetSwitch() - trying to show %s screen\n", flag ? "picasso96" : "amiga");
985 #endif
986     /* Put old switch-state in D0 */
987     return !flag;
988 }
989 
picasso_enablescreen(int on)990 void picasso_enablescreen (int on)
991 {
992     wgfx_linestart = 0xFFFFFFFF;
993     picasso_refresh ();
994 #if 1
995     write_log ("SetSwitch() - showing %s screen\n", on ? "picasso96" : "amiga");
996 #endif
997 }
998 
999 static int first_color_changed = 256;
1000 static int last_color_changed = -1;
1001 
picasso_handle_vsync(void)1002 void picasso_handle_vsync (void)
1003 {
1004     if (first_color_changed < last_color_changed) {
1005 	DX_SetPalette (first_color_changed, last_color_changed - first_color_changed);
1006 	/* If we're emulating a CLUT mode, we need to redraw the entire screen.  */
1007 	if (picasso_vidinfo.rgbformat != picasso96_state.RGBFormat)
1008 	    picasso_refresh ();
1009     }
1010 
1011     first_color_changed = 256;
1012     last_color_changed = -1;
1013 }
1014 
picasso_clip_mouse(int * px,int * py)1015 void picasso_clip_mouse (int *px, int *py)
1016 {
1017     int xoff = picasso96_state.XOffset;
1018     int yoff = picasso96_state.YOffset;
1019     if (*px < -xoff)
1020 	*px = -xoff;
1021     if (*px + xoff > picasso_vidinfo.width)
1022 	*px = picasso_vidinfo.width - xoff;
1023     if (*py < -yoff)
1024 	*py = -yoff;
1025     if (*py + yoff > picasso_vidinfo.height)
1026 	*py = picasso_vidinfo.height - yoff;
1027 }
1028 
1029 /*
1030  * SetColorArray:
1031  * a0: struct BoardInfo
1032  * d0.w: startindex
1033  * d1.w: count
1034  * when this function is called, your driver has to fetch "count" color
1035  * values starting at "startindex" from the CLUT field of the BoardInfo
1036  * structure and write them to the hardware. The color values are always
1037  * between 0 and 255 for each component regardless of the number of bits
1038  * per cannon your board has. So you might have to shift the colors
1039  * before writing them to the hardware.
1040  */
picasso_SetColorArray(void)1041 uae_u32 picasso_SetColorArray (void)
1042 {
1043     /* Fill in some static UAE related structure about this new CLUT setting
1044      * We need this for CLUT-based displays, and for mapping CLUT to hi/true colour */
1045     uae_u16 start = m68k_dreg (regs, 0);
1046     uae_u16 count = m68k_dreg (regs, 1);
1047     int i;
1048     uaecptr boardinfo = m68k_areg (regs, 0);
1049     uaecptr clut = boardinfo + PSSO_BoardInfo_CLUT + start * 3;
1050     int changed = 0;
1051 
1052     for (i = start; i < start + count; i++) {
1053 	int r = get_byte (clut);
1054 	int g = get_byte (clut + 1);
1055 	int b = get_byte (clut + 2);
1056 
1057 	changed |= (picasso96_state.CLUT[i].Red != r || picasso96_state.CLUT[i].Green != g || picasso96_state.CLUT[i].Blue != b);
1058 
1059 	picasso96_state.CLUT[i].Red = r;
1060 	picasso96_state.CLUT[i].Green = g;
1061 	picasso96_state.CLUT[i].Blue = b;
1062 	clut += 3;
1063     }
1064     if (changed) {
1065 	if (start < first_color_changed)
1066 	    first_color_changed = start;
1067 	if (start + count > last_color_changed)
1068 	    last_color_changed = start + count;
1069     }
1070     /*write_log ("SetColorArray(%d,%d)\n", start, count); */
1071     return 1;
1072 }
1073 
1074 /*
1075  * SetDAC:
1076  * a0: struct BoardInfo
1077  * d7: RGBFTYPE RGBFormat
1078  * This function is called whenever the RGB format of the display changes,
1079  * e.g. from chunky to TrueColor. Usually, all you have to do is to set
1080  * the RAMDAC of your board accordingly.
1081  */
picasso_SetDAC(void)1082 uae_u32 picasso_SetDAC (void)
1083 {
1084     /* Fill in some static UAE related structure about this new DAC setting
1085      * Lets us keep track of what pixel format the Amiga is thinking about in our frame-buffer */
1086 
1087     write_log ("SetDAC()\n");
1088     return 1;
1089 }
1090 
init_picasso_screen(void)1091 static void init_picasso_screen (void)
1092 {
1093     int width = picasso96_state.Width;
1094     int height = picasso96_state.Height;
1095     int vwidth = picasso96_state.VirtualWidth;
1096     int vheight = picasso96_state.VirtualHeight;
1097     int xoff = 0;
1098     int yoff = 0;
1099 
1100     if (!set_gc_called)
1101 	return;
1102 
1103     if (set_panning_called) {
1104 	picasso96_state.Extent = picasso96_state.Address + (picasso96_state.BytesPerRow * vheight);
1105 	xoff = picasso96_state.XOffset;
1106 	yoff = picasso96_state.YOffset;
1107     }
1108 
1109     gfx_set_picasso_modeinfo (width, height, picasso96_state.GC_Depth, picasso96_state.RGBFormat);
1110     DX_SetPalette (0, 256);
1111 
1112     wgfx_linestart = 0xFFFFFFFF;
1113     picasso_refresh ();
1114 }
1115 
1116 /*
1117  * SetGC:
1118  * a0: struct BoardInfo
1119  * a1: struct ModeInfo
1120  * d0: BOOL Border
1121  * This function is called whenever another ModeInfo has to be set. This
1122  * function simply sets up the CRTC and TS registers to generate the
1123  * timing used for that screen mode. You should not set the DAC, clocks
1124  * or linear start adress. They will be set when appropriate by their
1125  * own functions.
1126  */
picasso_SetGC(void)1127 uae_u32 picasso_SetGC (void)
1128 {
1129     /* Fill in some static UAE related structure about this new ModeInfo setting */
1130     uaecptr modeinfo = m68k_areg (regs, 1);
1131 
1132     picasso96_state.Width = get_word (modeinfo + PSSO_ModeInfo_Width);
1133     picasso96_state.VirtualWidth = picasso96_state.Width;	/* in case SetPanning doesn't get called */
1134 
1135     picasso96_state.Height = get_word (modeinfo + PSSO_ModeInfo_Height);
1136     picasso96_state.VirtualHeight = picasso96_state.Height;
1137 
1138     picasso96_state.GC_Depth = get_byte (modeinfo + PSSO_ModeInfo_Depth);
1139     picasso96_state.GC_Flags = get_byte (modeinfo + PSSO_ModeInfo_Flags);
1140 
1141     P96TRACE (("SetGC(%d,%d,%d)\n", picasso96_state.Width, picasso96_state.Height, picasso96_state.GC_Depth));
1142 
1143     set_gc_called = 1;		/* @@@ when do we need to reset this? */
1144     init_picasso_screen ();
1145     return 1;
1146 }
1147 
1148 /*
1149  * SetPanning:
1150  * a0: struct BoardInfo
1151  * a1: UBYTE *Memory
1152  * d0: uae_u16 Width
1153  * d1: WORD XOffset
1154  * d2: WORD YOffset
1155  * d7: RGBFTYPE RGBFormat
1156  * This function sets the view origin of a display which might also be
1157  * overscanned. In register a1 you get the start address of the screen
1158  * bitmap on the Amiga side. You will have to subtract the starting
1159  * address of the board memory from that value to get the memory start
1160  * offset within the board. Then you get the offset in pixels of the
1161  * left upper edge of the visible part of an overscanned display. From
1162  * these values you will have to calculate the LinearStartingAddress
1163  * fields of the CRTC registers.
1164 
1165  * NOTE: SetPanning() can be used to know when a Picasso96 screen is
1166  * being opened.  Better to do the appropriate clearing of the
1167  * background here than in SetSwitch() derived functions,
1168  * because SetSwitch() is not called for subsequent Picasso screens.
1169  */
picasso_SetPanning(void)1170 uae_u32 picasso_SetPanning (void)
1171 {
1172     uae_u16 Width = m68k_dreg (regs, 0);
1173     uaecptr start_of_screen = m68k_areg (regs, 1);
1174     uaecptr bi = m68k_areg (regs, 0);
1175     uaecptr bmeptr = get_long (bi + PSSO_BoardInfo_BitMapExtra);        /* Get our BoardInfo ptr's BitMapExtra ptr */
1176     int oldxoff = picasso96_state.XOffset;
1177     int oldyoff = picasso96_state.YOffset;
1178 #if 0
1179     /* @@@ This is in WinUAE, but it breaks things.  */
1180     if (oldscr == 0) {
1181 	oldscr = start_of_screen;
1182     }
1183     if ((oldscr != start_of_screen)) {
1184 	set_gc_called = 0;
1185 	oldscr = start_of_screen;
1186     }
1187 #endif
1188 
1189     picasso96_state.Address = start_of_screen;	/* Amiga-side address */
1190     picasso96_state.XOffset = (uae_s16) m68k_dreg (regs, 1);
1191     picasso96_state.YOffset = (uae_s16) m68k_dreg (regs, 2);
1192     picasso96_state.VirtualWidth = get_word (bmeptr + PSSO_BitMapExtra_Width);
1193     picasso96_state.VirtualHeight = get_word (bmeptr + PSSO_BitMapExtra_Height);
1194     picasso96_state.RGBFormat = m68k_dreg (regs, 7);
1195     picasso96_state.BytesPerPixel = GetBytesPerPixel (picasso96_state.RGBFormat);
1196     picasso96_state.BytesPerRow = Width * picasso96_state.BytesPerPixel;
1197 
1198     set_panning_called = 1;
1199     P96TRACE (("SetPanning(%d, %d, %d) Start 0x%x, BPR %d\n",
1200 	       Width, picasso96_state.XOffset, picasso96_state.YOffset, start_of_screen, picasso96_state.BytesPerRow));
1201 
1202     init_picasso_screen ();
1203 
1204     return 1;
1205 }
1206 
do_xor8(uae_u8 * ptr,long len,uae_u32 val)1207 static void do_xor8 (uae_u8 * ptr, long len, uae_u32 val)
1208 {
1209     int i;
1210 #if 0 && defined ALIGN_POINTER_TO32
1211     int align_adjust = ALIGN_POINTER_TO32 (ptr);
1212     int len2;
1213 
1214     len -= align_adjust;
1215     while (align_adjust) {
1216 	*ptr ^= val;
1217 	ptr++;
1218 	align_adjust--;
1219     }
1220     len2 = len >> 2;
1221     len -= len2 << 2;
1222     for (i = 0; i < len2; i++, ptr += 4) {
1223 	*(uae_u32 *) ptr ^= val;
1224     }
1225     while (len) {
1226 	*ptr ^= val;
1227 	ptr++;
1228 	len--;
1229     }
1230     return;
1231 #endif
1232     for (i = 0; i < len; i++, ptr++) {
1233 	do_put_mem_byte (ptr, do_get_mem_byte (ptr) ^ val);
1234     }
1235 }
1236 
1237 /*
1238  * InvertRect:
1239  *
1240  * Inputs:
1241  * a0:struct BoardInfo *bi
1242  * a1:struct RenderInfo *ri
1243  * d0.w:X
1244  * d1.w:Y
1245  * d2.w:Width
1246  * d3.w:Height
1247  * d4.l:Mask
1248  * d7.l:RGBFormat
1249  *
1250  * This function is used to invert a rectangular area on the board. It is called by BltBitMap,
1251  * BltPattern and BltTemplate.
1252  */
picasso_InvertRect(void)1253 uae_u32 picasso_InvertRect (void)
1254 {
1255     uaecptr renderinfo = m68k_areg (regs, 1);
1256     unsigned long X = (uae_u16) m68k_dreg (regs, 0);
1257     unsigned long Y = (uae_u16) m68k_dreg (regs, 1);
1258     unsigned long Width = (uae_u16) m68k_dreg (regs, 2);
1259     unsigned long Height = (uae_u16) m68k_dreg (regs, 3);
1260     uae_u32 mask = m68k_dreg (regs, 4);
1261     int Bpp = GetBytesPerPixel (m68k_dreg (regs, 7));
1262     uae_u32 xorval;
1263     unsigned int lines;
1264     struct RenderInfo ri;
1265     uae_u8 *uae_mem;
1266     unsigned long width_in_bytes;
1267 
1268     wgfx_flushline ();
1269 
1270     if (!CopyRenderInfoStructureA2U (renderinfo, &ri))
1271 	return 0;
1272 
1273     P96TRACE (("InvertRect: X %d Y %d Width %d Height %d\n", X, Y, Width, Height));
1274     /*write_log ("InvertRect %d %lx\n", Bpp, (long)mask); */
1275 
1276     /* ??? Brian? mask used to be 32 bit, but it appears that only 8 bit
1277      * values are passed to this function.  This code here seems to work
1278      * much better... */
1279     if (mask != 0xFF && Bpp > 1) {
1280 	write_log ("InvertRect: not obeying mask 0x%x properly with Bpp %d.\n", mask, Bpp);
1281 	mask = 0xFF;
1282     }
1283     if ((mask & ~0xFF) != 0) {
1284 	write_log ("InvertRect: mask has high bits set!\n");
1285     }
1286     xorval = 0x01010101 * (mask & 0xFF);
1287     width_in_bytes = Bpp * Width;
1288     uae_mem = ri.Memory + Y * ri.BytesPerRow + X * Bpp;
1289 
1290     for (lines = 0; lines < Height; lines++, uae_mem += ri.BytesPerRow)
1291 	do_xor8 (uae_mem, width_in_bytes, xorval);
1292 
1293     if (renderinfo_is_current_screen (&ri)) {
1294 	if (mask == 0xFF)
1295 	    do_invertrect (&ri, Bpp, X, Y, Width, Height);
1296 	else
1297 	    do_blit (&ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0);
1298     }
1299 
1300     return 1;			/* 1 if supported, 0 otherwise */
1301 }
1302 
1303 /* Fill a rectangle in the Amiga-memory frame buffer.  */
1304 
do_fillrect_frame_buffer(struct RenderInfo * ri,int X,int Y,int Width,int Height,uae_u32 Pen,int Bpp,RGBFTYPE RGBFormat)1305 STATIC_INLINE void do_fillrect_frame_buffer (struct RenderInfo *ri, int X, int Y,
1306 					     int Width, int Height, uae_u32 Pen, int Bpp,
1307 					     RGBFTYPE RGBFormat)
1308 {
1309     uae_u8 *start, *oldstart, *dst;
1310     long lines, cols;
1311 
1312     /* Do our virtual frame-buffer memory.  First, we do a single line fill by hand */
1313     oldstart = start = ri->Memory + Y * ri->BytesPerRow + X * Bpp;
1314     switch (Bpp) {
1315     case 1:
1316 	memset (start, Pen, Width);
1317 	break;
1318     case 2:
1319 	for (cols = 0; cols < Width; cols++) {
1320 	    do_put_mem_word ((uae_u16 *) start, Pen);
1321 	    start += 2;
1322 	}
1323 	break;
1324     case 3:
1325 	for (cols = 0; cols < Width; cols++) {
1326 	    do_put_mem_byte (start, Pen & 0x000000FF);
1327 	    start++;
1328 	    *(uae_u16 *) (start) = (Pen & 0x00FFFF00) >> 8;
1329 	    start += 2;
1330 	}
1331 	break;
1332     case 4:
1333 	for (cols = 0; cols < Width; cols++) {
1334 	    /**start = Pen; */
1335 	    do_put_mem_long ((uae_u32 *) start, Pen);
1336 	    start += 4;
1337 	}
1338 	break;
1339     }
1340 
1341     dst = oldstart + ri->BytesPerRow;
1342     /* next, we do the remaining line fills via memcpy() for > 1 BPP, otherwise some more memset() calls */
1343     if (Bpp > 1) {
1344 	for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow)
1345 	    memcpy (dst, oldstart, Width * Bpp);
1346     } else {
1347 	for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow)
1348 	    memset (dst, Pen, Width);
1349     }
1350 }
1351 
1352 
1353 /***********************************************************
1354 FillRect:
1355 ***********************************************************
1356 * a0: 	struct BoardInfo *
1357 * a1:	struct RenderInfo *
1358 * d0: 	WORD X
1359 * d1: 	WORD Y
1360 * d2: 	WORD Width
1361 * d3: 	WORD Height
1362 * d4:	uae_u32 Pen
1363 * d5:	UBYTE Mask
1364 * d7:	uae_u32 RGBFormat
1365 ***********************************************************/
picasso_FillRect(void)1366 uae_u32 picasso_FillRect (void)
1367 {
1368     uaecptr renderinfo = m68k_areg (regs, 1);
1369     unsigned long X = (uae_u16) m68k_dreg (regs, 0);
1370     unsigned long Y = (uae_u16) m68k_dreg (regs, 1);
1371     unsigned long Width = (uae_u16) m68k_dreg (regs, 2);
1372     unsigned long Height = (uae_u16) m68k_dreg (regs, 3);
1373     uae_u32 Pen = m68k_dreg (regs, 4);
1374     uae_u8 Mask = (uae_u8) m68k_dreg (regs, 5);
1375     uae_u32 RGBFormat = m68k_dreg (regs, 7);
1376 
1377     int Bpp;
1378     struct RenderInfo ri;
1379 
1380     wgfx_flushline ();
1381 
1382     if (!CopyRenderInfoStructureA2U (renderinfo, &ri) || Y == 0xFFFF)
1383 	return 0;
1384 
1385     P96TRACE(("FillRect(%d, %d, %d, %d) Pen 0x%x BPP %d BPR %d Mask 0x%x\n",
1386 	      X, Y, Width, Height, Pen, Bpp, ri.BytesPerRow, Mask));
1387 
1388     if (ri.RGBFormat != RGBFormat)
1389 	write_log ("Weird Stuff!\n");
1390 
1391     Bpp = GetBytesPerPixel (RGBFormat);
1392 
1393     /* write_log ("FillRect(%d, %d, %d, %d) Pen 0x%x BPP %d BPR %d Mask 0x%x\n",
1394        X, Y, Width, Height, Pen, Bpp, ri.BytesPerRow, Mask); */
1395 
1396     if (Mask == 0xFF) {
1397 	do_fillrect_frame_buffer (&ri, X, Y, Width, Height, Pen, Bpp, RGBFormat);
1398 
1399 	if (renderinfo_is_current_screen (&ri))
1400 	    do_fillrect (ri.Memory + Y * ri.BytesPerRow + X * Bpp, X, Y,
1401 			 Width, Height, Pen, Bpp, RGBFormat);
1402 
1403 	return 1;
1404     }
1405 
1406     /* We get here only if Mask != 0xFF */
1407     if (Bpp != 1) {
1408 	write_log ("Picasso: mask != 0xFF in truecolor mode!\n");
1409 	return 0;
1410     }
1411     Pen &= Mask;
1412     Mask = ~Mask;
1413 
1414     {
1415 	uae_u8 *start = ri.Memory + Y * ri.BytesPerRow + X * Bpp;
1416 	uae_u8 *end = start + Height * ri.BytesPerRow;
1417 	for (; start != end; start += ri.BytesPerRow) {
1418 	    uae_u8 *p = start;
1419 	    unsigned long cols;
1420 	    for (cols = 0; cols < Width; cols++) {
1421 		uae_u32 tmpval = do_get_mem_byte (p + cols) & Mask;
1422 		do_put_mem_byte (p + cols, Pen | tmpval);
1423 	    }
1424 	}
1425     }
1426 
1427     if (renderinfo_is_current_screen (&ri))
1428 	do_blit (&ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0);
1429 
1430     return 1;
1431 }
1432 
1433 /*
1434  * BlitRect() is a generic (any chunky pixel format) rectangle copier
1435  * NOTE: If dstri is NULL, then we're only dealing with one RenderInfo area, and called from picasso_BlitRect()
1436  */
BlitRect(struct RenderInfo * ri,struct RenderInfo * dstri,unsigned long srcx,unsigned long srcy,unsigned long dstx,unsigned long dsty,unsigned long width,unsigned long height,uae_u8 mask,BLIT_OPCODE opcode)1437 static void BlitRect (struct RenderInfo *ri, struct RenderInfo *dstri,
1438 		      unsigned long srcx, unsigned long srcy, unsigned long dstx, unsigned long dsty,
1439 		      unsigned long width, unsigned long height, uae_u8 mask, BLIT_OPCODE opcode)
1440 {
1441     uae_u8 *src, *dst, *tmp, *tmp2, *tmp3;
1442     unsigned long lines;
1443     uae_u8 Bpp = GetBytesPerPixel (ri->RGBFormat);
1444     uae_u8 *blitsrc;
1445     unsigned long total_width = width * Bpp;
1446     unsigned long linewidth = (total_width + 15) & ~15;
1447     int cant_blit = 1;
1448 
1449     /*
1450      * If we have no destination RenderInfo, then we're dealing with a single-buffer action, called
1451      * from picasso_BlitRect().  The code up to the DX_xxxxx() functions deals with the frame-buffer,
1452      * while the DX_ functions actually deal with the visible screen.
1453      *
1454      * If we have a destination RenderInfo, then we've been called from picasso_BlitRectNoMaskComplete()
1455      * and we need to put the results on the screen from the frame-buffer.
1456      */
1457     if (dstri == NULL) {
1458 	dstri = ri;
1459 	cant_blit = 0;
1460     }
1461 
1462     /* Do our virtual frame-buffer memory first */
1463     src = ri->Memory + srcx * Bpp + srcy * ri->BytesPerRow;
1464     dst = dstri->Memory + dstx * Bpp + dsty * dstri->BytesPerRow;
1465     blitsrc = dst;
1466     if (mask != 0xFF && Bpp > 1)
1467 	write_log ("ERROR - not obeying BlitRect() mask 0x%x properly with Bpp %d.\n", mask, Bpp);
1468 
1469     if (mask == 0xFF || Bpp > 1) {
1470 	/* handle normal case efficiently */
1471 	if (ri->Memory == dstri->Memory && dsty == srcy) {
1472 	    unsigned long i;
1473 	    for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
1474 		memmove (dst, src, total_width);
1475 	} else if (dsty < srcy) {
1476 	    unsigned long i;
1477 	    for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
1478 		memcpy (dst, src, total_width);
1479 	} else {
1480 	    unsigned long i;
1481 	    src += (height - 1) * ri->BytesPerRow;
1482 	    dst += (height - 1) * dstri->BytesPerRow;
1483 	    for (i = 0; i < height; i++, src -= ri->BytesPerRow, dst -= dstri->BytesPerRow)
1484 		memcpy (dst, src, total_width);
1485 	}
1486 	if (cant_blit)
1487 	    srcx = dstx, srcy = dsty;
1488 	if (renderinfo_is_current_screen (dstri))
1489 	    do_blit (dstri, Bpp, srcx, srcy, dstx, dsty, width, height, opcode, !cant_blit);
1490 	return;
1491     }
1492 
1493     tmp3 = tmp2 = tmp = xmalloc (linewidth * height);	/* allocate enough memory for the src-rect */
1494     if (!tmp)
1495 	return;
1496 
1497     /* copy the src-rect into our temporary buffer space */
1498     for (lines = 0; lines < height; lines++, src += ri->BytesPerRow, tmp2 += linewidth) {
1499 	memcpy (tmp2, src, total_width);
1500     }
1501 
1502     /* copy the temporary buffer to the destination */
1503     for (lines = 0; lines < height; lines++, dst += dstri->BytesPerRow, tmp += linewidth) {
1504 	unsigned long cols;
1505 	for (cols = 0; cols < width; cols++) {
1506 	    dst[cols] &= ~mask;
1507 	    dst[cols] |= tmp[cols] & mask;
1508 	}
1509     }
1510     if (renderinfo_is_current_screen (dstri))
1511 	do_blit (dstri, Bpp, dstx, dsty, dstx, dsty, width, height, opcode, 0);
1512 
1513     /* free the temp-buf */
1514     free (tmp3);
1515 
1516 }
1517 
1518 /***********************************************************
1519 BlitRect:
1520 ***********************************************************
1521 * a0: 	struct BoardInfo
1522 * a1:	struct RenderInfo
1523 * d0: 	WORD SrcX
1524 * d1: 	WORD SrcY
1525 * d2: 	WORD DstX
1526 * d3: 	WORD DstY
1527 * d4:   WORD Width
1528 * d5:   WORD Height
1529 * d6:	UBYTE Mask
1530 * d7:	uae_u32 RGBFormat
1531 ***********************************************************/
picasso_BlitRect(void)1532 uae_u32 picasso_BlitRect (void)
1533 {
1534     uaecptr renderinfo = m68k_areg (regs, 1);
1535     unsigned long srcx = (uae_u16) m68k_dreg (regs, 0);
1536     unsigned long srcy = (uae_u16) m68k_dreg (regs, 1);
1537     unsigned long dstx = (uae_u16) m68k_dreg (regs, 2);
1538     unsigned long dsty = (uae_u16) m68k_dreg (regs, 3);
1539     unsigned long width = (uae_u16) m68k_dreg (regs, 4);
1540     unsigned long height = (uae_u16) m68k_dreg (regs, 5);
1541     uae_u8 Mask = (uae_u8) m68k_dreg (regs, 6);
1542 
1543     struct RenderInfo ri;
1544 
1545     wgfx_flushline ();
1546 
1547     if (!CopyRenderInfoStructureA2U (renderinfo, &ri))
1548 	return 0;
1549 
1550     P96TRACE(("BlitRect(%d, %d, %d, %d, %d, %d, 0x%x)\n", srcx, srcy, dstx, dsty, width, height, Mask));
1551     BlitRect (&ri, NULL, srcx, srcy, dstx, dsty, width, height, Mask, BLIT_SRC);
1552     /*write_log ("BlitRect(%d, %d, %d, %d, %d, %d, 0x%x)\n", srcx, srcy, dstx, dsty, width, height, Mask); */
1553 
1554     return 1;
1555 }
1556 
1557 /***********************************************************
1558 BlitRectNoMaskComplete:
1559 ***********************************************************
1560 * a0: 	struct BoardInfo
1561 * a1:	struct RenderInfo (src)
1562 * a2:   struct RenderInfo (dst)
1563 * d0: 	WORD SrcX
1564 * d1: 	WORD SrcY
1565 * d2: 	WORD DstX
1566 * d3: 	WORD DstY
1567 * d4:   WORD Width
1568 * d5:   WORD Height
1569 * d6:	UBYTE OpCode
1570 * d7:	uae_u32 RGBFormat
1571 * NOTE: MUST return 0 in D0 if we're not handling this operation
1572 *       because the RGBFormat or opcode aren't supported.
1573 *       OTHERWISE return 1
1574 ***********************************************************/
picasso_BlitRectNoMaskComplete(void)1575 uae_u32 picasso_BlitRectNoMaskComplete (void)
1576 {
1577     uaecptr srcri = m68k_areg (regs, 1);
1578     uaecptr dstri = m68k_areg (regs, 2);
1579     unsigned long srcx = (uae_u16) m68k_dreg (regs, 0);
1580     unsigned long srcy = (uae_u16) m68k_dreg (regs, 1);
1581     unsigned long dstx = (uae_u16) m68k_dreg (regs, 2);
1582     unsigned long dsty = (uae_u16) m68k_dreg (regs, 3);
1583     unsigned long width = (uae_u16) m68k_dreg (regs, 4);
1584     unsigned long height = (uae_u16) m68k_dreg (regs, 5);
1585     uae_u8 OpCode = m68k_dreg (regs, 6);
1586     uae_u32 RGBFmt = m68k_dreg (regs, 7);
1587     struct RenderInfo src_ri, dst_ri;
1588 
1589     wgfx_flushline ();
1590 
1591     if (!CopyRenderInfoStructureA2U (srcri, &src_ri)
1592 	|| !CopyRenderInfoStructureA2U (dstri, &dst_ri))
1593 	return 0;
1594 
1595     P96TRACE(("BlitRectNoMaskComplete() op 0x%2x, xy(%4d,%4d) --> xy(%4d,%4d), wh(%4d,%4d)\n",
1596 	OpCode, srcx, srcy, dstx, dsty, width, height));
1597 
1598     switch (OpCode) {
1599     case 0x0C:
1600 	BlitRect (&src_ri, &dst_ri, srcx, srcy, dstx, dsty, width, height, 0xFF, OpCode);
1601 	return 1;
1602 
1603     default:
1604 	/* FOR NOW! */
1605 	return 0;
1606     }
1607 }
1608 
1609 /* This utility function is used both by BlitTemplate() and BlitPattern() */
PixelWrite1(uae_u8 * mem,int bits,uae_u32 fgpen,uae_u32 mask)1610 STATIC_INLINE void PixelWrite1 (uae_u8 * mem, int bits, uae_u32 fgpen, uae_u32 mask)
1611 {
1612     if (mask != 0xFF)
1613 	fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
1614     do_put_mem_byte (mem + bits, fgpen);
1615 }
1616 
PixelWrite2(uae_u8 * mem,int bits,uae_u32 fgpen)1617 STATIC_INLINE void PixelWrite2 (uae_u8 * mem, int bits, uae_u32 fgpen)
1618 {
1619     do_put_mem_word (((uae_u16 *) mem) + bits, fgpen);
1620 }
1621 
PixelWrite3(uae_u8 * mem,int bits,uae_u32 fgpen)1622 STATIC_INLINE void PixelWrite3 (uae_u8 * mem, int bits, uae_u32 fgpen)
1623 {
1624     do_put_mem_byte (mem + bits * 3, fgpen & 0x000000FF);
1625     *(uae_u16 *) (mem + bits * 3 + 1) = (fgpen & 0x00FFFF00) >> 8;
1626 }
1627 
PixelWrite4(uae_u8 * mem,int bits,uae_u32 fgpen)1628 STATIC_INLINE void PixelWrite4 (uae_u8 * mem, int bits, uae_u32 fgpen)
1629 {
1630     do_put_mem_long (((uae_u32 *) mem) + bits, fgpen);
1631 }
1632 
PixelWrite(uae_u8 * mem,int bits,uae_u32 fgpen,uae_u8 Bpp,uae_u32 mask)1633 STATIC_INLINE void PixelWrite (uae_u8 * mem, int bits, uae_u32 fgpen, uae_u8 Bpp, uae_u32 mask)
1634 {
1635     switch (Bpp) {
1636     case 1:
1637 	if (mask != 0xFF)
1638 	    fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
1639 	do_put_mem_byte (mem + bits, fgpen);
1640 	break;
1641     case 2:
1642 	do_put_mem_word (((uae_u16 *) mem) + bits, fgpen);
1643 	break;
1644     case 3:
1645 	do_put_mem_byte (mem + bits * 3, fgpen & 0x000000FF);
1646 	*(uae_u16 *) (mem + bits * 3 + 1) = (fgpen & 0x00FFFF00) >> 8;
1647 	break;
1648     case 4:
1649 	do_put_mem_long (((uae_u32 *) mem) + bits, fgpen);
1650 	break;
1651     }
1652 }
1653 
1654 /*
1655  * BlitPattern:
1656  *
1657  * Synopsis:BlitPattern(bi, ri, pattern, X, Y, Width, Height, Mask, RGBFormat);
1658  * Inputs:
1659  * a0:struct BoardInfo *bi
1660  * a1:struct RenderInfo *ri
1661  * a2:struct Pattern *pattern
1662  * d0.w:X
1663  * d1.w:Y
1664  * d2.w:Width
1665  * d3.w:Height
1666  * d4.w:Mask
1667  * d7.l:RGBFormat
1668  *
1669  * This function is used to paint a pattern on the board memory using the blitter. It is called by
1670  * BltPattern, if a AreaPtrn is used with positive AreaPtSz. The pattern consists of a b/w image
1671  * using a single plane of image data which will be expanded repeatedly to the destination RGBFormat
1672  * using ForeGround and BackGround pens as well as draw modes. The width of the pattern data is
1673  * always 16 pixels (one word) and the height is calculated as 2^Size. The data must be shifted up
1674  * and to the left by XOffset and YOffset pixels at the beginning.
1675  */
picasso_BlitPattern(void)1676 uae_u32 picasso_BlitPattern (void)
1677 {
1678     uaecptr rinf = m68k_areg (regs, 1);
1679     uaecptr pinf = m68k_areg (regs, 2);
1680     unsigned long X = (uae_u16) m68k_dreg (regs, 0);
1681     unsigned long Y = (uae_u16) m68k_dreg (regs, 1);
1682     unsigned long W = (uae_u16) m68k_dreg (regs, 2);
1683     unsigned long H = (uae_u16) m68k_dreg (regs, 3);
1684     uae_u8 Mask = (uae_u8) m68k_dreg (regs, 4);
1685     uae_u32 RGBFmt = m68k_dreg (regs, 7);
1686 
1687     uae_u8 Bpp = GetBytesPerPixel (RGBFmt);
1688     int inversion = 0;
1689     struct RenderInfo ri;
1690     struct Pattern pattern;
1691     unsigned long rows;
1692     uae_u32 fgpen;
1693     uae_u8 *uae_mem;
1694     int xshift;
1695     unsigned long ysize_mask;
1696 
1697     wgfx_flushline ();
1698 
1699     if (! CopyRenderInfoStructureA2U (rinf, &ri)
1700 	|| !CopyPatternStructureA2U (pinf, &pattern))
1701 	return 0;
1702 
1703     Bpp = GetBytesPerPixel (ri.RGBFormat);
1704     uae_mem = ri.Memory + Y * ri.BytesPerRow + X * Bpp;	/* offset with address */
1705 
1706     if (pattern.DrawMode & INVERS)
1707 	inversion = 1;
1708 
1709     pattern.DrawMode &= 0x03;
1710     if (Mask != 0xFF) {
1711 	if (Bpp > 1)
1712 	    write_log ("ERROR - not obeying BlitPattern() mask 0x%x properly with Bpp %d.\n", Mask, Bpp);
1713 	else if (pattern.DrawMode == COMP) {
1714 	    write_log ("ERROR - Unsupported Mask value 0x%x with COMP Draw in BlitPattern(), using fallback method.\n", Mask);
1715 	    return 0;
1716 	}
1717     }
1718 
1719     P96TRACE (("BlitPattern() xy(%d,%d), wh(%d,%d) draw 0x%x, off(%d,%d), ph %d\n",
1720 	       X, Y, W, H, pattern.DrawMode, pattern.XOffset, pattern.YOffset, 1 << pattern.Size));
1721 #ifdef _DEBUG
1722     DumpPattern (&pattern);
1723 #endif
1724     ysize_mask = (1 << pattern.Size) - 1;
1725     xshift = pattern.XOffset & 15;
1726 
1727     for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow) {
1728 	unsigned long prow = (rows + pattern.YOffset) & ysize_mask;
1729 	unsigned int d = do_get_mem_word (((uae_u16 *) pattern.Memory) + prow);
1730 	uae_u8 *uae_mem2 = uae_mem;
1731 	unsigned long cols;
1732 
1733 	if (xshift != 0)
1734 	    d = (d << xshift) | (d >> (16 - xshift));
1735 
1736 	for (cols = 0; cols < W; cols += 16, uae_mem2 += Bpp << 4) {
1737 	    long bits;
1738 	    long max = W - cols;
1739 	    unsigned int data = d;
1740 
1741 	    if (max > 16)
1742 		max = 16;
1743 
1744 	    for (bits = 0; bits < max; bits++) {
1745 		int bit_set = data & 0x8000;
1746 		data <<= 1;
1747 		switch (pattern.DrawMode) {
1748 		case JAM1:
1749 		    if (inversion)
1750 			bit_set = !bit_set;
1751 		    if (bit_set)
1752 			PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
1753 		    break;
1754 		case JAM2:
1755 		    if (inversion)
1756 			bit_set = !bit_set;
1757 		    if (bit_set)
1758 			PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
1759 		    else
1760 			PixelWrite (uae_mem2, bits, pattern.BgPen, Bpp, Mask);
1761 		    break;
1762 		case COMP:
1763 		    if (bit_set) {
1764 			fgpen = pattern.FgPen;
1765 
1766 			switch (Bpp) {
1767 			case 1:
1768 			    {
1769 				uae_u8 *addr = uae_mem2 + bits;
1770 				do_put_mem_byte (addr, do_get_mem_byte (addr) ^ fgpen);
1771 			    }
1772 			    break;
1773 			case 2:
1774 			    {
1775 				uae_u16 *addr = ((uae_u16 *) uae_mem2) + bits;
1776 				do_put_mem_word (addr, do_get_mem_word (addr) ^ fgpen);
1777 			    }
1778 			    break;
1779 			case 3:
1780 			    {
1781 				uae_u32 *addr = (uae_u32 *) (uae_mem2 + bits * 3);
1782 				do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
1783 			    }
1784 			    break;
1785 			case 4:
1786 			    {
1787 				uae_u32 *addr = ((uae_u32 *) uae_mem2) + bits;
1788 				do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
1789 			    }
1790 			    break;
1791 			}
1792 		    }
1793 		    break;
1794 		}
1795 	    }
1796 	}
1797     }
1798 
1799     if (renderinfo_is_current_screen (&ri))
1800 	do_blit (&ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0);
1801 
1802     return 1;
1803 }
1804 
1805 /*************************************************
1806 BlitTemplate:
1807 **************************************************
1808 * Synopsis: BlitTemplate(bi, ri, template, X, Y, Width, Height, Mask, RGBFormat);
1809 * a0: struct BoardInfo *bi
1810 * a1: struct RenderInfo *ri
1811 * a2: struct Template *template
1812 * d0.w: X
1813 * d1.w: Y
1814 * d2.w: Width
1815 * d3.w: Height
1816 * d4.w: Mask
1817 * d7.l: RGBFormat
1818 *
1819 * This function is used to paint a template on the board memory using the blitter.
1820 * It is called by BltPattern and BltTemplate. The template consists of a b/w image
1821 * using a single plane of image data which will be expanded to the destination RGBFormat
1822 * using ForeGround and BackGround pens as well as draw modes.
1823 ***********************************************************************************/
picasso_BlitTemplate(void)1824 uae_u32 picasso_BlitTemplate (void)
1825 {
1826     uae_u8 inversion = 0;
1827     uaecptr rinf = m68k_areg (regs, 1);
1828     uaecptr tmpl = m68k_areg (regs, 2);
1829     unsigned long X = (uae_u16) m68k_dreg (regs, 0);
1830     unsigned long Y = (uae_u16) m68k_dreg (regs, 1);
1831     unsigned long W = (uae_u16) m68k_dreg (regs, 2);
1832     unsigned long H = (uae_u16) m68k_dreg (regs, 3);
1833     uae_u16 Mask = (uae_u16) m68k_dreg (regs, 4);
1834     struct Template tmp;
1835     struct RenderInfo ri;
1836     unsigned long rows;
1837     int bitoffset;
1838     uae_u32 fgpen;
1839     uae_u8 *uae_mem, Bpp;
1840     uae_u8 *tmpl_base;
1841 
1842     wgfx_flushline ();
1843 
1844     if (!CopyRenderInfoStructureA2U (rinf, &ri)
1845 	|| !CopyTemplateStructureA2U (tmpl, &tmp))
1846 	return 0;
1847 
1848     Bpp = GetBytesPerPixel (ri.RGBFormat);
1849     uae_mem = ri.Memory + Y * ri.BytesPerRow + X * Bpp;	/* offset into address */
1850 
1851     if (tmp.DrawMode & INVERS)
1852 	inversion = 1;
1853 
1854     tmp.DrawMode &= 0x03;
1855     if (Mask != 0xFF) {
1856 	if (Bpp > 1)
1857 	    write_log ("ERROR - not obeying BlitTemplate() mask 0x%x properly with Bpp %d.\n", Mask, Bpp);
1858 	else if (tmp.DrawMode == COMP) {
1859 	    write_log ("ERROR - Unsupported Mask value 0x%x with COMP Draw in BlitTemplate(), using fallback method.\n", Mask);
1860 	    return 0;
1861 	}
1862     }
1863 
1864     P96TRACE (("BlitTemplate() xy(%d,%d), wh(%d,%d) draw 0x%x fg 0x%x bg 0x%x \n",
1865 	       X, Y, W, H, tmp.DrawMode, tmp.FgPen, tmp.BgPen));
1866 
1867     bitoffset = tmp.XOffset % 8;
1868 
1869 #ifdef _DEBUG
1870     DumpTemplate (&tmp, W, H);
1871 #endif
1872 
1873     tmpl_base = tmp.Memory + tmp.XOffset / 8;
1874 
1875     for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow, tmpl_base += tmp.BytesPerRow) {
1876 	unsigned long cols;
1877 	uae_u8 *tmpl_mem = tmpl_base;
1878 	uae_u8 *uae_mem2 = uae_mem;
1879 	unsigned int data = *tmpl_mem;
1880 
1881 	for (cols = 0; cols < W; cols += 8, uae_mem2 += Bpp << 3) {
1882 	    unsigned int byte;
1883 	    long bits;
1884 	    long max = W - cols;
1885 
1886 	    if (max > 8)
1887 		max = 8;
1888 
1889 	    data <<= 8;
1890 	    data |= *++tmpl_mem;
1891 
1892 	    byte = data >> (8 - bitoffset);
1893 
1894 	    for (bits = 0; bits < max; bits++) {
1895 		int bit_set = (byte & 0x80);
1896 		byte <<= 1;
1897 		switch (tmp.DrawMode) {
1898 		case JAM1:
1899 		    if (inversion)
1900 			bit_set = !bit_set;
1901 		    if (bit_set) {
1902 			fgpen = tmp.FgPen;
1903 			PixelWrite (uae_mem2, bits, fgpen, Bpp, Mask);
1904 		    }
1905 		    break;
1906 		case JAM2:
1907 		    if (inversion)
1908 			bit_set = !bit_set;
1909 		    fgpen = tmp.BgPen;
1910 		    if (bit_set)
1911 			fgpen = tmp.FgPen;
1912 
1913 		    PixelWrite (uae_mem2, bits, fgpen, Bpp, Mask);
1914 		    break;
1915 		case COMP:
1916 		    if (bit_set) {
1917 			fgpen = tmp.FgPen;
1918 
1919 			switch (Bpp) {
1920 			case 1:
1921 			    {
1922 				uae_u8 *addr = uae_mem2 + bits;
1923 				do_put_mem_byte (addr, do_get_mem_byte (addr) ^ fgpen);
1924 			    }
1925 			    break;
1926 			case 2:
1927 			    {
1928 				uae_u16 *addr = ((uae_u16 *) uae_mem2) + bits;
1929 				do_put_mem_word (addr, do_get_mem_word (addr) ^ fgpen);
1930 			    }
1931 			    break;
1932 			case 3:
1933 			    {
1934 				uae_u32 *addr = (uae_u32 *) (uae_mem2 + bits * 3);
1935 				do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
1936 			    }
1937 			    break;
1938 			case 4:
1939 			    {
1940 				uae_u32 *addr = ((uae_u32 *) uae_mem2) + bits;
1941 				do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
1942 			    }
1943 			    break;
1944 			}
1945 		    }
1946 		    break;
1947 		}
1948 	    }
1949 	}
1950     }
1951 
1952     if (renderinfo_is_current_screen (&ri))
1953 	do_blit (&ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0);
1954 
1955     return 1;
1956 }
1957 
1958 /*
1959  * CalculateBytesPerRow:
1960  * a0: 	struct BoardInfo
1961  * d0: 	uae_u16 Width
1962  * d7:	RGBFTYPE RGBFormat
1963  * This function calculates the amount of bytes needed for a line of
1964  * "Width" pixels in the given RGBFormat.
1965  */
picasso_CalculateBytesPerRow(void)1966 uae_u32 picasso_CalculateBytesPerRow (void)
1967 {
1968     uae_u16 width = m68k_dreg (regs, 0);
1969     uae_u32 type = m68k_dreg (regs, 7);
1970 
1971     width = GetBytesPerPixel (type) * width;
1972     P96TRACE  (("CalculateBytesPerRow() = %d\n", width));
1973 
1974     return width;
1975 }
1976 
1977 /*
1978  * SetDisplay:
1979  * a0:	struct BoardInfo
1980  * d0:	BOOL state
1981  * This function enables and disables the video display.
1982  *
1983  * NOTE: return the opposite of the state
1984  */
picasso_SetDisplay(void)1985 uae_u32 picasso_SetDisplay (void)
1986 {
1987     uae_u32 state = m68k_dreg (regs, 0);
1988     P96TRACE (("SetDisplay(%d)\n", state));
1989     return !state;
1990 }
1991 
1992 /*
1993  * WaitVerticalSync:
1994  * a0:	struct BoardInfo
1995  * This function waits for the next horizontal retrace.
1996  */
picasso_WaitVerticalSync(void)1997 uae_u32 picasso_WaitVerticalSync (void)
1998 {
1999     /*write_log ("WaitVerticalSync()\n"); */
2000     return 1;
2001 }
2002 
2003 /* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
PlanarToChunky(struct RenderInfo * ri,struct BitMap * bm,unsigned long srcx,unsigned long srcy,unsigned long dstx,unsigned long dsty,unsigned long width,unsigned long height,uae_u8 mask)2004 static void PlanarToChunky (struct RenderInfo *ri, struct BitMap *bm,
2005 			    unsigned long srcx, unsigned long srcy,
2006 			    unsigned long dstx, unsigned long dsty, unsigned long width, unsigned long height, uae_u8 mask)
2007 {
2008     int j;
2009 
2010     uae_u8 *PLANAR[8], *image = ri->Memory + dstx * GetBytesPerPixel (ri->RGBFormat) + dsty * ri->BytesPerRow;
2011     int Depth = bm->Depth;
2012     unsigned long rows, bitoffset = srcx & 7;
2013     long eol_offset;
2014 
2015     /* if (mask != 0xFF)
2016        write_log ("P2C - pixel-width = %d, bit-offset = %d\n", width, bitoffset); */
2017 
2018     /* Set up our bm->Planes[] pointers to the right horizontal offset */
2019     for (j = 0; j < Depth; j++) {
2020 	uae_u8 *p = bm->Planes[j];
2021 	if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
2022 	    p += srcx / 8 + srcy * bm->BytesPerRow;
2023 	PLANAR[j] = p;
2024 	if ((mask & (1 << j)) == 0)
2025 	    PLANAR[j] = &all_zeros_bitmap;
2026     }
2027     eol_offset = (long) bm->BytesPerRow - (long) ((width + 7) >> 3);
2028     for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
2029 	unsigned long cols;
2030 
2031 	for (cols = 0; cols < width; cols += 8) {
2032 	    int k;
2033 	    uae_u32 a = 0, b = 0;
2034 	    unsigned int msk = 0xFF;
2035 	    long tmp = cols + 8 - width;
2036 	    if (tmp > 0) {
2037 		msk <<= tmp;
2038 		b = do_get_mem_long ((uae_u32 *) (image + cols + 4));
2039 		if (tmp < 4)
2040 		    b &= 0xFFFFFFFF >> (32 - tmp * 8);
2041 		else if (tmp > 4) {
2042 		    a = do_get_mem_long ((uae_u32 *) (image + cols));
2043 		    a &= 0xFFFFFFFF >> (64 - tmp * 8);
2044 		}
2045 	    }
2046 	    for (k = 0; k < Depth; k++) {
2047 		unsigned int data;
2048 		if (PLANAR[k] == &all_zeros_bitmap)
2049 		    data = 0;
2050 		else if (PLANAR[k] == &all_ones_bitmap)
2051 		    data = 0xFF;
2052 		else {
2053 		    data = (uae_u8) (do_get_mem_word ((uae_u16 *) PLANAR[k]) >> (8 - bitoffset));
2054 		    PLANAR[k]++;
2055 		}
2056 		data &= msk;
2057 		a |= p2ctab[data][0] << k;
2058 		b |= p2ctab[data][1] << k;
2059 	    }
2060 	    do_put_mem_long ((uae_u32 *) (image + cols), a);
2061 	    do_put_mem_long ((uae_u32 *) (image + cols + 4), b);
2062 	}
2063 	for (j = 0; j < Depth; j++) {
2064 	    if (PLANAR[j] != &all_zeros_bitmap && PLANAR[j] != &all_ones_bitmap) {
2065 		PLANAR[j] += eol_offset;
2066 	    }
2067 	}
2068     }
2069 }
2070 
2071 /*
2072  * BlitPlanar2Chunky:
2073  * a0: struct BoardInfo *bi
2074  * a1: struct BitMap *bm - source containing planar information and assorted details
2075  * a2: struct RenderInfo *ri - dest area and its details
2076  * d0.w: SrcX
2077  * d1.w: SrcY
2078  * d2.w: DstX
2079  * d3.w: DstY
2080  * d4.w: SizeX
2081  * d5.w: SizeY
2082  * d6.b: MinTerm - uh oh!
2083  * d7.b: Mask - uh oh!
2084  *
2085  * This function is currently used to blit from planar bitmaps within system memory to chunky bitmaps
2086  * on the board. Watch out for plane pointers that are 0x00000000 (represents a plane with all bits "0")
2087  * or 0xffffffff (represents a plane with all bits "1").
2088  */
picasso_BlitPlanar2Chunky(void)2089 uae_u32 picasso_BlitPlanar2Chunky (void)
2090 {
2091     uaecptr bm = m68k_areg (regs, 1);
2092     uaecptr ri = m68k_areg (regs, 2);
2093     unsigned long srcx = (uae_u16) m68k_dreg (regs, 0);
2094     unsigned long srcy = (uae_u16) m68k_dreg (regs, 1);
2095     unsigned long dstx = (uae_u16) m68k_dreg (regs, 2);
2096     unsigned long dsty = (uae_u16) m68k_dreg (regs, 3);
2097     unsigned long width = (uae_u16) m68k_dreg (regs, 4);
2098     unsigned long height = (uae_u16) m68k_dreg (regs, 5);
2099     uae_u8 minterm = m68k_dreg (regs, 6) & 0xFF;
2100     uae_u8 mask = m68k_dreg (regs, 7) & 0xFF;
2101     struct RenderInfo local_ri;
2102     struct BitMap local_bm;
2103 
2104     wgfx_flushline ();
2105 
2106     if (minterm != 0x0C) {
2107 	write_log ("ERROR - BlitPlanar2Chunky() has minterm 0x%x, which I don't handle. Using fall-back routine.\n", minterm);
2108 	return 0;
2109     }
2110     if (!CopyRenderInfoStructureA2U (ri, &local_ri)
2111 	|| !CopyBitMapStructureA2U (bm, &local_bm))
2112 	return 0;
2113 
2114     P96TRACE (("BlitPlanar2Chunky(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
2115 	       srcx, srcy, dstx, dsty, width, height, minterm, mask, local_bm.Depth));
2116     P96TRACE (("P2C - BitMap has %d BPR, %d rows\n", local_bm.BytesPerRow, local_bm.Rows));
2117     PlanarToChunky (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, mask);
2118     if (renderinfo_is_current_screen (&local_ri))
2119 	do_blit (&local_ri, GetBytesPerPixel (local_ri.RGBFormat), dstx, dsty, dstx, dsty, width, height, BLIT_SRC, 0);
2120 
2121     return 1;
2122 }
2123 
PlanarToDirect(struct RenderInfo * ri,struct BitMap * bm,unsigned long srcx,unsigned long srcy,unsigned long dstx,unsigned long dsty,unsigned long width,unsigned long height,uae_u8 mask,struct ColorIndexMapping * cim)2124 static void PlanarToDirect (struct RenderInfo *ri, struct BitMap *bm,
2125 			    unsigned long srcx, unsigned long srcy,
2126 			    unsigned long dstx, unsigned long dsty,
2127 			    unsigned long width, unsigned long height, uae_u8 mask, struct ColorIndexMapping *cim)
2128 {
2129     int j;
2130     int bpp = GetBytesPerPixel (ri->RGBFormat);
2131     uae_u8 *PLANAR[8];
2132     uae_u8 *image = ri->Memory + dstx * bpp + dsty * ri->BytesPerRow;
2133     int Depth = bm->Depth;
2134     unsigned long rows;
2135     long eol_offset;
2136 
2137     /* Set up our bm->Planes[] pointers to the right horizontal offset */
2138     for (j = 0; j < Depth; j++) {
2139 	uae_u8 *p = bm->Planes[j];
2140 	if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
2141 	    p += srcx / 8 + srcy * bm->BytesPerRow;
2142 	PLANAR[j] = p;
2143 	if ((mask & (1 << j)) == 0)
2144 	    PLANAR[j] = &all_zeros_bitmap;
2145     }
2146 
2147     eol_offset = (long) bm->BytesPerRow - (long) ((width + (srcx & 7)) >> 3);
2148     for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
2149 	unsigned long cols;
2150 	uae_u8 *image2 = image;
2151 	unsigned int bitoffs = 7 - (srcx & 7);
2152 	int i;
2153 
2154 	for (cols = 0; cols < width; cols++) {
2155 	    int v = 0, k;
2156 	    for (k = 0; k < Depth; k++) {
2157 		if (PLANAR[k] == &all_ones_bitmap)
2158 		    v |= 1 << k;
2159 		else if (PLANAR[k] != &all_zeros_bitmap) {
2160 		    v |= ((*PLANAR[k] >> bitoffs) & 1) << k;
2161 		}
2162 	    }
2163 
2164 	    switch (bpp) {
2165 	    case 2:
2166 		do_put_mem_word ((uae_u16 *) image2, cim->Colors[v]);
2167 		image2 += 2;
2168 		break;
2169 	    case 3:
2170 		do_put_mem_byte (image2++, cim->Colors[v] & 0x000000FF);
2171 		do_put_mem_word ((uae_u16 *) image2, (cim->Colors[v] & 0x00FFFF00) >> 8);
2172 		image2 += 2;
2173 		break;
2174 	    case 4:
2175 		do_put_mem_long ((uae_u32 *) image2, cim->Colors[v]);
2176 		image2 += 4;
2177 		break;
2178 	    }
2179 	    bitoffs--;
2180 	    bitoffs &= 7;
2181 	    if (bitoffs == 7) {
2182 		int k;
2183 		for (k = 0; k < Depth; k++) {
2184 		    if (PLANAR[k] != &all_zeros_bitmap && PLANAR[k] != &all_ones_bitmap) {
2185 			PLANAR[k]++;
2186 		    }
2187 		}
2188 	    }
2189 	}
2190 
2191 	for (i = 0; i < Depth; i++) {
2192 	    if (PLANAR[i] != &all_zeros_bitmap && PLANAR[i] != &all_ones_bitmap) {
2193 		PLANAR[i] += eol_offset;
2194 	    }
2195 	}
2196     }
2197 }
2198 
2199 /*
2200  * BlitPlanar2Direct:
2201  *
2202  * Synopsis:
2203  * BlitPlanar2Direct(bi, bm, ri, cim, SrcX, SrcY, DstX, DstY, SizeX, SizeY, MinTerm, Mask);
2204  * Inputs:
2205  * a0:struct BoardInfo *bi
2206  * a1:struct BitMap *bm
2207  * a2:struct RenderInfo *ri
2208  * a3:struct ColorIndexMapping *cmi
2209  * d0.w:SrcX
2210  * d1.w:SrcY
2211  * d2.w:DstX
2212  * d3.w:DstY
2213  * d4.w:SizeX
2214  * d5.w:SizeY
2215  * d6.b:MinTerm
2216  * d7.b:Mask
2217  *
2218  * This function is currently used to blit from planar bitmaps within system memory to direct color
2219  * bitmaps (15, 16, 24 or 32 bit) on the board. Watch out for plane pointers that are 0x00000000 (represents
2220  * a plane with all bits "0") or 0xffffffff (represents a plane with all bits "1"). The ColorIndexMapping is
2221  * used to map the color index of each pixel formed by the bits in the bitmap's planes to a direct color value
2222  * which is written to the destination RenderInfo. The color mask and all colors within the mapping are words,
2223  * triple bytes or longwords respectively similar to the color values used in FillRect(), BlitPattern() or
2224  * BlitTemplate().
2225  */
picasso_BlitPlanar2Direct(void)2226 uae_u32 picasso_BlitPlanar2Direct (void)
2227 {
2228     uaecptr bm = m68k_areg (regs, 1);
2229     uaecptr ri = m68k_areg (regs, 2);
2230     uaecptr cim = m68k_areg (regs, 3);
2231     unsigned long srcx = (uae_u16) m68k_dreg (regs, 0);
2232     unsigned long srcy = (uae_u16) m68k_dreg (regs, 1);
2233     unsigned long dstx = (uae_u16) m68k_dreg (regs, 2);
2234     unsigned long dsty = (uae_u16) m68k_dreg (regs, 3);
2235     unsigned long width = (uae_u16) m68k_dreg (regs, 4);
2236     unsigned long height = (uae_u16) m68k_dreg (regs, 5);
2237     uae_u8 minterm = m68k_dreg (regs, 6);
2238     uae_u8 Mask = m68k_dreg (regs, 7);
2239     struct RenderInfo local_ri;
2240     struct BitMap local_bm;
2241     struct ColorIndexMapping local_cim;
2242 
2243     wgfx_flushline ();
2244 
2245     if (minterm != 0x0C) {
2246 	write_log ("ERROR - BlitPlanar2Direct() has op-code 0x%x, which I don't handle. Using fall-back routine.\n", minterm);
2247 	return 0;
2248     }
2249     if (Mask != 0xFF) {
2250 	write_log ("ERROR - Unsupported Mask value 0x%x in BlitPlanar2Direct(), using fallback method.\n", Mask);
2251 	return 0;
2252     }
2253     if (!CopyRenderInfoStructureA2U (ri, &local_ri)
2254 	|| !CopyBitMapStructureA2U (bm, &local_bm))
2255 	return 0;
2256 
2257     CopyColorIndexMappingA2U (cim, &local_cim);
2258     P96TRACE (("BlitPlanar2Direct(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
2259        srcx, srcy, dstx, dsty, width, height, minterm, Mask, local_bm.Depth));
2260     PlanarToDirect (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, Mask, &local_cim);
2261     if (renderinfo_is_current_screen (&local_ri))
2262 	do_blit (&local_ri, GetBytesPerPixel (local_ri.RGBFormat), dstx, dsty, dstx, dsty, width, height, BLIT_SRC, 0);
2263     return 1;
2264 }
2265 
2266 /* @@@ - Work to be done here!
2267  *
2268  * The address is the offset into our Picasso96 frame-buffer (pointed to by gfxmem_start)
2269  * where the value was put.
2270  *
2271  * Porting work: on some machines you may not need these functions, ie. if the memory for the
2272  * Picasso96 frame-buffer is directly viewable or directly blittable.  On Win32 with DirectX,
2273  * this is not the case.  So I provide some write-through functions (as per Mathias' orders!)
2274  */
write_gfx_long(uaecptr addr,uae_u32 value)2275 static void write_gfx_long (uaecptr addr, uae_u32 value)
2276 {
2277     uaecptr oldaddr = addr;
2278     int x, xbytes, y;
2279     uae_u8 *dst;
2280 
2281     if (!picasso_on)
2282 	return;
2283 
2284     /*
2285      * Several writes to successive memory locations are a common access pattern.
2286      * Try to optimize it.
2287      */
2288     if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
2289 	if (addr < wgfx_min)
2290 	    wgfx_min = addr;
2291 	if (addr + 4 > wgfx_max)
2292 	    wgfx_max = addr + 4;
2293 	return;
2294     } else
2295 	wgfx_flushline ();
2296 
2297     addr += gfxmem_start;
2298     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
2299     if (addr < picasso96_state.Address || addr + 4 > picasso96_state.Extent)
2300 	return;
2301 
2302     addr -= picasso96_state.Address;
2303     y = addr / picasso96_state.BytesPerRow;
2304 
2305     if (y >= picasso96_state.VirtualHeight)
2306 	return;
2307     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
2308     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
2309     wgfx_y = y;
2310     wgfx_min = oldaddr;
2311     wgfx_max = oldaddr + 4;
2312 }
2313 
write_gfx_word(uaecptr addr,uae_u16 value)2314 static void write_gfx_word (uaecptr addr, uae_u16 value)
2315 {
2316     uaecptr oldaddr = addr;
2317     int x, xbytes, y;
2318     uae_u8 *dst;
2319 
2320     if (!picasso_on)
2321 	return;
2322 
2323     /*
2324      * Several writes to successive memory locations are a common access pattern.
2325      * Try to optimize it.
2326      */
2327     if (addr >= wgfx_linestart && addr + 2 <= wgfx_lineend) {
2328 	if (addr < wgfx_min)
2329 	    wgfx_min = addr;
2330 	if (addr + 2 > wgfx_max)
2331 	    wgfx_max = addr + 2;
2332 	return;
2333     } else
2334 	wgfx_flushline ();
2335 
2336     addr += gfxmem_start;
2337     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
2338     if (addr < picasso96_state.Address || addr + 2 > picasso96_state.Extent)
2339 	return;
2340 
2341     addr -= picasso96_state.Address;
2342     y = addr / picasso96_state.BytesPerRow;
2343 
2344     if (y >= picasso96_state.VirtualHeight)
2345 	return;
2346     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
2347     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
2348     wgfx_y = y;
2349     wgfx_min = oldaddr;
2350     wgfx_max = oldaddr + 2;
2351 }
2352 
write_gfx_byte(uaecptr addr,uae_u8 value)2353 static void write_gfx_byte (uaecptr addr, uae_u8 value)
2354 {
2355     uaecptr oldaddr = addr;
2356     int x, xbytes, y;
2357     uae_u8 *dst;
2358 
2359     if (!picasso_on)
2360 	return;
2361 
2362     /*
2363      * Several writes to successive memory locations are a common access pattern.
2364      * Try to optimize it.
2365      */
2366     if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
2367 	if (addr < wgfx_min)
2368 	    wgfx_min = addr;
2369 	if (addr + 1 > wgfx_max)
2370 	    wgfx_max = addr + 1;
2371 	return;
2372     } else
2373 	wgfx_flushline ();
2374 
2375     addr += gfxmem_start;
2376     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
2377     if (addr < picasso96_state.Address || addr + 1 > picasso96_state.Extent)
2378 	return;
2379 
2380     addr -= picasso96_state.Address;
2381     y = addr / picasso96_state.BytesPerRow;
2382 
2383     if (y >= picasso96_state.VirtualHeight)
2384 	return;
2385     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
2386     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
2387     wgfx_y = y;
2388     wgfx_min = oldaddr;
2389     wgfx_max = oldaddr + 1;
2390 }
2391 
gfxmem_lget(uaecptr addr)2392 static uae_u32 REGPARAM2 gfxmem_lget (uaecptr addr)
2393 {
2394     uae_u32 *m;
2395     addr -= gfxmem_start;
2396     addr &= gfxmem_mask;
2397     m = (uae_u32 *) (gfxmemory + addr);
2398     return do_get_mem_long (m);
2399 }
2400 
gfxmem_wget(uaecptr addr)2401 static uae_u32 REGPARAM2 gfxmem_wget (uaecptr addr)
2402 {
2403     uae_u16 *m;
2404     addr -= gfxmem_start;
2405     addr &= gfxmem_mask;
2406     m = (uae_u16 *) (gfxmemory + addr);
2407     return do_get_mem_word (m);
2408 }
2409 
gfxmem_bget(uaecptr addr)2410 static uae_u32 REGPARAM2 gfxmem_bget (uaecptr addr)
2411 {
2412     addr -= gfxmem_start;
2413     addr &= gfxmem_mask;
2414     return gfxmemory[addr];
2415 }
2416 
gfxmem_lput(uaecptr addr,uae_u32 l)2417 static void REGPARAM2 gfxmem_lput (uaecptr addr, uae_u32 l)
2418 {
2419     uae_u32 *m;
2420     addr -= gfxmem_start;
2421     addr &= gfxmem_mask;
2422     m = (uae_u32 *) (gfxmemory + addr);
2423     do_put_mem_long (m, l);
2424 
2425     /* write the long-word to our displayable memory */
2426     write_gfx_long (addr, l);
2427 }
2428 
gfxmem_wput(uaecptr addr,uae_u32 w)2429 static void REGPARAM2 gfxmem_wput (uaecptr addr, uae_u32 w)
2430 {
2431     uae_u16 *m;
2432     addr -= gfxmem_start;
2433     addr &= gfxmem_mask;
2434     m = (uae_u16 *) (gfxmemory + addr);
2435     do_put_mem_word (m, (uae_u16) w);
2436 
2437     /* write the word to our displayable memory */
2438     write_gfx_word (addr, (uae_u16) w);
2439 }
2440 
gfxmem_bput(uaecptr addr,uae_u32 b)2441 static void REGPARAM2 gfxmem_bput (uaecptr addr, uae_u32 b)
2442 {
2443     addr -= gfxmem_start;
2444     addr &= gfxmem_mask;
2445     gfxmemory[addr] = b;
2446 
2447     /* write the byte to our displayable memory */
2448     write_gfx_byte (addr, (uae_u8) b);
2449 }
2450 
gfxmem_check(uaecptr addr,uae_u32 size)2451 static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size)
2452 {
2453     addr -= gfxmem_start;
2454     addr &= gfxmem_mask;
2455     return (addr + size) < allocated_gfxmem;
2456 }
2457 
gfxmem_xlate(uaecptr addr)2458 static uae_u8 REGPARAM2 *gfxmem_xlate (uaecptr addr)
2459 {
2460     addr -= gfxmem_start;
2461     addr &= gfxmem_mask;
2462     return gfxmemory + addr;
2463 }
2464 
2465 addrbank gfxmem_bank = {
2466     gfxmem_lget, gfxmem_wget, gfxmem_bget,
2467     gfxmem_lput, gfxmem_wput, gfxmem_bput,
2468     gfxmem_xlate, gfxmem_check, NULL
2469 };
2470 
picasso_display_mode_index(uae_u32 x,uae_u32 y,uae_u32 d)2471 int picasso_display_mode_index (uae_u32 x, uae_u32 y, uae_u32 d)
2472 {
2473     int i;
2474     for (i = 0; i < mode_count; i++) {
2475 	if (DisplayModes[i].res.width == x
2476 	    && DisplayModes[i].res.height == y
2477 	    && DisplayModes[i].depth == d)
2478 	    break;
2479     }
2480     if (i == mode_count)
2481 	i = -1;
2482     return i;
2483 }
2484 
resolution_compare(const void * a,const void * b)2485 static int resolution_compare (const void *a, const void *b)
2486 {
2487     struct PicassoResolution *ma = (struct PicassoResolution *) a;
2488     struct PicassoResolution *mb = (struct PicassoResolution *) b;
2489     if (ma->res.width > mb->res.width)
2490 	return -1;
2491     if (ma->res.width < mb->res.width)
2492 	return 1;
2493     if (ma->res.height > mb->res.height)
2494 	return -1;
2495     if (ma->res.height < mb->res.height)
2496 	return 1;
2497     return ma->depth - mb->depth;
2498 }
2499 
2500 /* Call this function first, near the beginning of code flow
2501  * NOTE: Don't stuff it in InitGraphics() which seems reasonable...
2502  * Instead, put it in customreset() for safe-keeping.  */
InitPicasso96(void)2503 void InitPicasso96 (void)
2504 {
2505     static int first_time = 1;
2506 
2507     memset (&picasso96_state, 0, sizeof (struct picasso96_state_struct));
2508 
2509     if (first_time) {
2510 	int i;
2511 
2512 	for (i = 0; i < 256; i++) {
2513 	    p2ctab[i][0] = (((i & 128) ? 0x01000000 : 0)
2514 			    | ((i & 64) ? 0x010000 : 0)
2515 			    | ((i & 32) ? 0x0100 : 0)
2516 			    | ((i & 16) ? 0x01 : 0));
2517 	    p2ctab[i][1] = (((i & 8) ? 0x01000000 : 0)
2518 			    | ((i & 4) ? 0x010000 : 0)
2519 			    | ((i & 2) ? 0x0100 : 0)
2520 			    | ((i & 1) ? 0x01 : 0));
2521 	}
2522 	mode_count = DX_FillResolutions (&picasso96_pixel_format);
2523 	qsort (DisplayModes, mode_count, sizeof (struct PicassoResolution), resolution_compare);
2524 
2525 	for (i = 0; i < mode_count; i++) {
2526 	    sprintf (DisplayModes[i].name, "%dx%d, %d-bit, %d Hz",
2527 		     DisplayModes[i].res.width, DisplayModes[i].res.height, DisplayModes[i].depth * 8, DisplayModes[i].refresh);
2528 	    switch (DisplayModes[i].depth) {
2529 	    case 1:
2530 		if (DisplayModes[i].res.width > chunky.width)
2531 		    chunky.width = DisplayModes[i].res.width;
2532 		if (DisplayModes[i].res.height > chunky.height)
2533 		    chunky.height = DisplayModes[i].res.height;
2534 		break;
2535 	    case 2:
2536 		if (DisplayModes[i].res.width > hicolour.width)
2537 		    hicolour.width = DisplayModes[i].res.width;
2538 		if (DisplayModes[i].res.height > hicolour.height)
2539 		    hicolour.height = DisplayModes[i].res.height;
2540 		break;
2541 	    case 3:
2542 		if (DisplayModes[i].res.width > truecolour.width)
2543 		    truecolour.width = DisplayModes[i].res.width;
2544 		if (DisplayModes[i].res.height > truecolour.height)
2545 		    truecolour.height = DisplayModes[i].res.height;
2546 		break;
2547 	    case 4:
2548 		if (DisplayModes[i].res.width > alphacolour.width)
2549 		    alphacolour.width = DisplayModes[i].res.width;
2550 		if (DisplayModes[i].res.height > alphacolour.height)
2551 		    alphacolour.height = DisplayModes[i].res.height;
2552 		break;
2553 	    }
2554 	}
2555 	ShowSupportedResolutions ();
2556 
2557 	first_time = 0;
2558     }
2559 }
2560 
2561 #endif
2562