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