gpu_neon: add a test
[pcsx_rearmed.git] / plugins / dfxvideo / gpu.c
CommitLineData
ef79bbde
P
1/***************************************************************************
2 gpu.c - description
3 -------------------
4 begin : Sun Oct 28 2001
5 copyright : (C) 2001 by Pete Bernert
6 email : BlackDove@addcom.de
7 ***************************************************************************/
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. See also the license.txt file for *
14 * additional informations. *
15 * *
16 ***************************************************************************/
17
ef79bbde 18#include "gpu.h"
ef79bbde
P
19#include "stdint.h"
20#include "psemu_plugin_defs.h"
ef79bbde
P
21
22////////////////////////////////////////////////////////////////////////
23// memory image of the PSX vram
24////////////////////////////////////////////////////////////////////////
25
ef79bbde
P
26unsigned char *psxVub;
27signed char *psxVsb;
28unsigned short *psxVuw;
29unsigned short *psxVuw_eom;
30signed short *psxVsw;
a96a5eb2 31uint32_t *psxVul;
ef79bbde
P
32int32_t *psxVsl;
33
34////////////////////////////////////////////////////////////////////////
35// GPU globals
36////////////////////////////////////////////////////////////////////////
37
38static long lGPUdataRet;
39long lGPUstatusRet;
a96a5eb2 40uint32_t ulStatusControl[256];
ef79bbde
P
41
42static uint32_t gpuDataM[256];
43static unsigned char gpuCommand = 0;
44static long gpuDataC = 0;
45static long gpuDataP = 0;
46
47VRAMLoad_t VRAMWrite;
48VRAMLoad_t VRAMRead;
49DATAREGISTERMODES DataWriteMode;
50DATAREGISTERMODES DataReadMode;
51
52BOOL bSkipNextFrame = FALSE;
79f58413 53BOOL fskip_frameReady;
54DWORD lace_count_since_flip;
ef79bbde 55DWORD dwLaceCnt=0;
ef79bbde
P
56short sDispWidths[8] = {256,320,512,640,368,384,512,640};
57PSXDisplay_t PSXDisplay;
58PSXDisplay_t PreviousPSXDisplay;
59long lSelectedSlot=0;
ef79bbde
P
60BOOL bDoLazyUpdate=FALSE;
61uint32_t lGPUInfoVals[16];
62static int iFakePrimBusy=0;
2588a938 63static uint32_t vBlank=0;
e64dc4c5 64static const int *skip_advice;
ef79bbde
P
65
66////////////////////////////////////////////////////////////////////////
67// some misc external display funcs
68////////////////////////////////////////////////////////////////////////
69
70#include <time.h>
ef79bbde 71
a96a5eb2 72// FPS library
73#include "fps.c"
ef79bbde 74
ef79bbde
P
75
76////////////////////////////////////////////////////////////////////////
a96a5eb2 77// sets all kind of act fixes
ef79bbde
P
78////////////////////////////////////////////////////////////////////////
79
a96a5eb2 80static void SetFixes(void)
81 {
82 if(dwActFixes&0x02) sDispWidths[4]=384;
83 else sDispWidths[4]=368;
84 }
ef79bbde
P
85
86////////////////////////////////////////////////////////////////////////
87// INIT, will be called after lib load... well, just do some var init...
88////////////////////////////////////////////////////////////////////////
89
55b0eeea 90// one extra MB for soft drawing funcs security
91static unsigned char vram[1024*512*2 + 1024*1024] __attribute__((aligned(2048)));
92
a96a5eb2 93long CALLBACK GPUinit(void) // GPU INIT
ef79bbde
P
94{
95 memset(ulStatusControl,0,256*sizeof(uint32_t)); // init save state scontrol field
96
ef79bbde 97 //!!! ATTENTION !!!
55b0eeea 98 psxVub=vram + 512 * 1024; // security offset into double sized psx vram!
ef79bbde
P
99
100 psxVsb=(signed char *)psxVub; // different ways of accessing PSX VRAM
101 psxVsw=(signed short *)psxVub;
102 psxVsl=(int32_t *)psxVub;
103 psxVuw=(unsigned short *)psxVub;
104 psxVul=(uint32_t *)psxVub;
105
a96a5eb2 106 psxVuw_eom=psxVuw+1024*512; // pre-calc of end of vram
ef79bbde 107
55b0eeea 108 memset(vram,0x00,(512*2)*1024 + (1024*1024));
ef79bbde
P
109 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
110
ef79bbde
P
111 PSXDisplay.RGB24 = FALSE; // init some stuff
112 PSXDisplay.Interlaced = FALSE;
113 PSXDisplay.DrawOffset.x = 0;
114 PSXDisplay.DrawOffset.y = 0;
115 PSXDisplay.DisplayMode.x= 320;
116 PSXDisplay.DisplayMode.y= 240;
117 PreviousPSXDisplay.DisplayMode.x= 320;
118 PreviousPSXDisplay.DisplayMode.y= 240;
119 PSXDisplay.Disabled = FALSE;
120 PreviousPSXDisplay.Range.x0 =0;
121 PreviousPSXDisplay.Range.y0 =0;
122 PSXDisplay.Range.x0=0;
123 PSXDisplay.Range.x1=0;
124 PreviousPSXDisplay.DisplayModeNew.y=0;
125 PSXDisplay.Double = 1;
126 lGPUdataRet = 0x400;
127
128 DataWriteMode = DR_NORMAL;
129
130 // Reset transfer values, to prevent mis-transfer of data
131 memset(&VRAMWrite, 0, sizeof(VRAMLoad_t));
132 memset(&VRAMRead, 0, sizeof(VRAMLoad_t));
133
134 // device initialised already !
135 lGPUstatusRet = 0x14802000;
136 GPUIsIdle;
137 GPUIsReadyForCommands;
138 bDoVSyncUpdate = TRUE;
139
140 return 0;
141}
142
143////////////////////////////////////////////////////////////////////////
144// Here starts all...
145////////////////////////////////////////////////////////////////////////
146
147
148long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
149{
150 unsigned long d;
a96a5eb2 151
152 SetFixes();
ef79bbde
P
153
154 InitFPS();
155
ef79bbde
P
156 bDoVSyncUpdate = TRUE;
157
158 d=ulInitDisplay(); // setup x
159
160 if(disp)
161 *disp=d; // wanna x pointer? ok
162
163 if(d) return 0;
164 return -1;
165}
166
167
168////////////////////////////////////////////////////////////////////////
169// time to leave...
170////////////////////////////////////////////////////////////////////////
171
172long CALLBACK GPUclose() // GPU CLOSE
173{
ef79bbde
P
174 CloseDisplay(); // shutdown direct draw
175
176 return 0;
177}
178
179////////////////////////////////////////////////////////////////////////
180// I shot the sheriff
181////////////////////////////////////////////////////////////////////////
182
a96a5eb2 183long CALLBACK GPUshutdown(void) // GPU SHUTDOWN
ef79bbde 184{
a96a5eb2 185 CloseDisplay(); // shutdown direct draw
ef79bbde
P
186 return 0; // nothinh to do
187}
188
189////////////////////////////////////////////////////////////////////////
190// Update display (swap buffers)
191////////////////////////////////////////////////////////////////////////
192
a96a5eb2 193static void updateDisplay(void) // UPDATE DISPLAY
ef79bbde
P
194{
195 if(PSXDisplay.Disabled) // disable?
196 {
ef79bbde
P
197 return; // -> and bye
198 }
199
200 if(dwActFixes&32) // pc fps calculation fix
201 {
202 if(UseFrameLimit) PCFrameCap(); // -> brake
a96a5eb2 203 if(UseFrameSkip) PCcalcfps();
ef79bbde
P
204 }
205
206 if(UseFrameSkip) // skip ?
207 {
79f58413 208 if(fskip_frameReady)
ef79bbde 209 {
79f58413 210 DoBufferSwap(); // -> to skip or not to skip
211 fskip_frameReady=FALSE;
212 bDoVSyncUpdate=FALSE; // vsync done
ef79bbde 213 }
ef79bbde
P
214 }
215 else // no skip ?
216 {
0d8f5b89 217 bSkipNextFrame = FALSE;
ef79bbde 218 DoBufferSwap(); // -> swap
79f58413 219 bDoVSyncUpdate=FALSE; // vsync done
ef79bbde 220 }
79f58413 221}
222
223static void decideSkip(void)
224{
225 if(!bDoVSyncUpdate)
226 return;
227
228 lace_count_since_flip=0;
229 fskip_frameReady=!bSkipNextFrame;
f1bad6e1 230
79f58413 231 if(dwActFixes&0xa0) // -> pc fps calculation fix/old skipping fix
232 {
ea4a16e7 233 int skip = (skip_advice && *skip_advice) || UseFrameSkip == 1 || fps_skip < fFrameRateHz;
e64dc4c5 234 if(skip && !bSkipNextFrame) // -> skip max one in a row
79f58413 235 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
236 else bSkipNextFrame = FALSE;
237 }
238 else FrameSkip();
ef79bbde
P
239}
240
241////////////////////////////////////////////////////////////////////////
242// roughly emulated screen centering bits... not complete !!!
243////////////////////////////////////////////////////////////////////////
244
245void ChangeDispOffsetsX(void) // X CENTER
246{
247 long lx,l;
248
249 if(!PSXDisplay.Range.x1) return;
250
251 l=PreviousPSXDisplay.DisplayMode.x;
252
253 l*=(long)PSXDisplay.Range.x1;
254 l/=2560;lx=l;l&=0xfffffff8;
255
256 if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for
257 PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test
258
259 if(lx>=PreviousPSXDisplay.DisplayMode.x)
260 {
261 PreviousPSXDisplay.Range.x1=
262 (short)PreviousPSXDisplay.DisplayMode.x;
263 PreviousPSXDisplay.Range.x0=0;
264 }
265 else
266 {
267 PreviousPSXDisplay.Range.x1=(short)l;
268
269 PreviousPSXDisplay.Range.x0=
270 (PSXDisplay.Range.x0-500)/8;
271
272 if(PreviousPSXDisplay.Range.x0<0)
273 PreviousPSXDisplay.Range.x0=0;
274
275 if((PreviousPSXDisplay.Range.x0+lx)>
276 PreviousPSXDisplay.DisplayMode.x)
277 {
278 PreviousPSXDisplay.Range.x0=
279 (short)(PreviousPSXDisplay.DisplayMode.x-lx);
280 PreviousPSXDisplay.Range.x0+=2; //???
281
282 PreviousPSXDisplay.Range.x1+=(short)(lx-l);
283
284 PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
285
286 }
287
ef79bbde
P
288 // some linux alignment security
289 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
290 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
291 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
292 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
293
ef79bbde
P
294 DoClearScreenBuffer();
295 }
296
297 bDoVSyncUpdate=TRUE;
298}
299
300////////////////////////////////////////////////////////////////////////
301
302void ChangeDispOffsetsY(void) // Y CENTER
303{
304 int iT,iO=PreviousPSXDisplay.Range.y0;
305 int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
306
307// new
308
a96a5eb2 309 if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>512)
ef79bbde 310 {
a96a5eb2 311 int dy1=512-PreviousPSXDisplay.DisplayModeNew.x;
312 int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-512;
ef79bbde
P
313
314 if(dy1>=dy2)
315 {
316 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
317 }
318 else
319 {
320 PSXDisplay.DisplayPosition.y=0;
321 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
322 }
323 }
324 else PreviousPSXDisplay.DisplayModeNew.y=0;
325
326// eon
327
328 if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
329 {
330 PSXDisplay.Height = PSXDisplay.Range.y1 -
331 PSXDisplay.Range.y0 +
332 PreviousPSXDisplay.DisplayModeNew.y;
333 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
334 }
335
336//
337
338 if(PSXDisplay.PAL) iT=48; else iT=28;
339
340 if(PSXDisplay.Range.y0>=iT)
341 {
342 PreviousPSXDisplay.Range.y0=
343 (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
344 if(PreviousPSXDisplay.Range.y0<0)
345 PreviousPSXDisplay.Range.y0=0;
346 PSXDisplay.DisplayModeNew.y+=
347 PreviousPSXDisplay.Range.y0;
348 }
349 else
350 PreviousPSXDisplay.Range.y0=0;
351
352 if(iO!=PreviousPSXDisplay.Range.y0)
353 {
354 DoClearScreenBuffer();
355 }
356}
357
358////////////////////////////////////////////////////////////////////////
359// check if update needed
360////////////////////////////////////////////////////////////////////////
361
a96a5eb2 362static void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED
ef79bbde
P
363{
364 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
365 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
366 {
367 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
368 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
369 }
370
371 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
372
373 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
374 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
375 PreviousPSXDisplay.DisplayMode.x= // previous will hold
376 min(640,PSXDisplay.DisplayMode.x); // max 640x512... that's
377 PreviousPSXDisplay.DisplayMode.y= // the size of my
378 min(512,PSXDisplay.DisplayMode.y); // back buffer surface
379 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
380
381 PSXDisplay.DisplayEnd.x= // calc end of display
382 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
383 PSXDisplay.DisplayEnd.y=
384 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
385 PreviousPSXDisplay.DisplayEnd.x=
386 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
387 PreviousPSXDisplay.DisplayEnd.y=
388 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
389
390 ChangeDispOffsetsX();
391
392 if(iFrameLimit==2) SetAutoFrameCap(); // -> set it
393
79f58413 394 if(UseFrameSkip) decideSkip(); // stupid stuff when frame skipping enabled
ef79bbde
P
395}
396
ef79bbde
P
397////////////////////////////////////////////////////////////////////////
398// update lace is called evry VSync
399////////////////////////////////////////////////////////////////////////
400
401void CALLBACK GPUupdateLace(void) // VSYNC
402{
2588a938 403 //if(!(dwActFixes&1))
404 // lGPUstatusRet^=0x80000000; // odd/even bit
ef79bbde 405
dc40e780 406 //pcsx-rearmed: removed, this is handled by core
72228559 407 //if(!(dwActFixes&32)) // std fps limitation?
408 // CheckFrameRate();
ef79bbde
P
409
410 if(PSXDisplay.Interlaced) // interlaced mode?
411 {
2588a938 412 lGPUstatusRet^=0x80000000; // odd/even bit?
413
ef79bbde
P
414 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
415 {
416 updateDisplay();
417 }
418 }
419 else // non-interlaced?
420 {
421 if(dwActFixes&64) // lazy screen update fix
422 {
79f58413 423 if(bDoLazyUpdate)
ef79bbde
P
424 updateDisplay();
425 bDoLazyUpdate=FALSE;
426 }
427 else
428 {
79f58413 429 if(bDoVSyncUpdate) // some primitives drawn?
f1bad6e1 430 updateDisplay(); // -> update display
ef79bbde
P
431 }
432 }
f1bad6e1 433
79f58413 434 if(UseFrameSkip) { // frame over-skip guard
435 lace_count_since_flip++;
436 if(lace_count_since_flip > 8) {
437 bSkipNextFrame=FALSE;
438 fskip_frameReady=TRUE;
439 }
440 }
ef79bbde
P
441}
442
443////////////////////////////////////////////////////////////////////////
444// process read request from GPU status register
445////////////////////////////////////////////////////////////////////////
446
447
448uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
449{
450 if(dwActFixes&1)
451 {
452 static int iNumRead=0; // odd/even hack
453 if((iNumRead++)==2)
454 {
455 iNumRead=0;
456 lGPUstatusRet^=0x80000000; // interlaced bit toggle... we do it on every 3 read status... needed by some games (like ChronoCross) with old epsxe versions (1.5.2 and older)
457 }
458 }
459
460 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
461 {
462 iFakePrimBusy--;
463
464 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
465 {
466 GPUIsBusy;
467 GPUIsNotReadyForCommands;
468 }
469 else
470 {
471 GPUIsIdle;
472 GPUIsReadyForCommands;
473 }
474 }
2588a938 475 return lGPUstatusRet | vBlank;
ef79bbde
P
476}
477
478////////////////////////////////////////////////////////////////////////
479// processes data send to GPU status register
480// these are always single packet commands.
481////////////////////////////////////////////////////////////////////////
482
483void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
484{
485 uint32_t lCommand=(gdata>>24)&0xff;
486
487 ulStatusControl[lCommand]=gdata; // store command for freezing
488
489 switch(lCommand)
490 {
491 //--------------------------------------------------//
492 // reset gpu
493 case 0x00:
494 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
495 lGPUstatusRet=0x14802000;
496 PSXDisplay.Disabled=1;
497 DataWriteMode=DataReadMode=DR_NORMAL;
498 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
499 drawX=drawY=0;drawW=drawH=0;
500 sSetMask=0;lSetMask=0;bCheckMask=FALSE;
501 usMirror=0;
502 GlobalTextAddrX=0;GlobalTextAddrY=0;
503 GlobalTextTP=0;GlobalTextABR=0;
504 PSXDisplay.RGB24=FALSE;
505 PSXDisplay.Interlaced=FALSE;
506 bUsingTWin = FALSE;
507 return;
508 //--------------------------------------------------//
509 // dis/enable display
510 case 0x03:
511
512 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
513 PSXDisplay.Disabled = (gdata & 1);
514
515 if(PSXDisplay.Disabled)
516 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
517 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
518 return;
519
520 //--------------------------------------------------//
521 // setting transfer mode
522 case 0x04:
523 gdata &= 0x03; // Only want the lower two bits
524
525 DataWriteMode=DataReadMode=DR_NORMAL;
526 if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
527 if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
528 lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits
529 lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data
530
531 return;
532 //--------------------------------------------------//
533 // setting display position
534 case 0x05:
535 {
536 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
537 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
538
ef79bbde 539// new
a96a5eb2 540 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
ef79bbde
P
541
542 // store the same val in some helper var, we need it on later compares
543 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
544
a96a5eb2 545 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>512)
ef79bbde 546 {
a96a5eb2 547 int dy1=512-PSXDisplay.DisplayPosition.y;
548 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-512;
ef79bbde
P
549
550 if(dy1>=dy2)
551 {
552 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
553 }
554 else
555 {
556 PSXDisplay.DisplayPosition.y=0;
557 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
558 }
559 }
560 else PreviousPSXDisplay.DisplayModeNew.y=0;
561// eon
562
563 PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
564 PSXDisplay.DisplayEnd.x=
565 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
566 PSXDisplay.DisplayEnd.y=
567 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
568 PreviousPSXDisplay.DisplayEnd.x=
569 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
570 PreviousPSXDisplay.DisplayEnd.y=
571 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
572
573 bDoVSyncUpdate=TRUE;
574
575 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
576 {
ef79bbde
P
577 if(dwActFixes&64) bDoLazyUpdate=TRUE;
578 }
4215cb1f 579 if(UseFrameSkip) decideSkip();
ef79bbde
P
580 }return;
581 //--------------------------------------------------//
582 // setting width
583 case 0x06:
584
585 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
586 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
587
588 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
589
590 ChangeDispOffsetsX();
591
592 return;
593 //--------------------------------------------------//
594 // setting height
595 case 0x07:
596 {
597
598 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
599 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
600
601 PreviousPSXDisplay.Height = PSXDisplay.Height;
602
603 PSXDisplay.Height = PSXDisplay.Range.y1 -
604 PSXDisplay.Range.y0 +
605 PreviousPSXDisplay.DisplayModeNew.y;
606
607 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
608 {
609 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
610
611 ChangeDispOffsetsY();
612
613 updateDisplayIfChanged();
614 }
615 return;
616 }
617 //--------------------------------------------------//
618 // setting display infos
619 case 0x08:
620
621 PSXDisplay.DisplayModeNew.x =
622 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
623
624 if (gdata&0x04) PSXDisplay.Double=2;
625 else PSXDisplay.Double=1;
626
627 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
628
629 ChangeDispOffsetsY();
630
631 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
632 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
633 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
634
635 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
636 lGPUstatusRet|=
637 (((gdata & 0x03) << 17) |
638 ((gdata & 0x40) << 10)); // Set the width bits
639
640 if(PSXDisplay.InterlacedNew)
641 {
642 if(!PSXDisplay.Interlaced)
643 {
644 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
645 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
646 }
647 lGPUstatusRet|=GPUSTATUS_INTERLACED;
648 }
9f21ebfe 649 else lGPUstatusRet&=~(GPUSTATUS_INTERLACED|0x80000000);
ef79bbde
P
650
651 if (PSXDisplay.PAL)
652 lGPUstatusRet|=GPUSTATUS_PAL;
653 else lGPUstatusRet&=~GPUSTATUS_PAL;
654
655 if (PSXDisplay.Double==2)
656 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
657 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
658
659 if (PSXDisplay.RGB24New)
660 lGPUstatusRet|=GPUSTATUS_RGB24;
661 else lGPUstatusRet&=~GPUSTATUS_RGB24;
662
663 updateDisplayIfChanged();
664
665 return;
666 //--------------------------------------------------//
667 // ask about GPU version and other stuff
668 case 0x10:
669
670 gdata&=0xff;
671
672 switch(gdata)
673 {
674 case 0x02:
675 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
676 return;
677 case 0x03:
678 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
679 return;
680 case 0x04:
681 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
682 return;
683 case 0x05:
684 case 0x06:
685 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
686 return;
687 case 0x07:
a96a5eb2 688 lGPUdataRet=0x02; // gpu type
ef79bbde
P
689 return;
690 case 0x08:
691 case 0x0F: // some bios addr?
692 lGPUdataRet=0xBFC03720;
693 return;
694 }
695 return;
696 //--------------------------------------------------//
697 }
698}
699
700////////////////////////////////////////////////////////////////////////
701// vram read/write helpers, needed by LEWPY's optimized vram read/write :)
702////////////////////////////////////////////////////////////////////////
703
a96a5eb2 704static inline void FinishedVRAMWrite(void)
ef79bbde 705{
ef79bbde
P
706 // Set register to NORMAL operation
707 DataWriteMode = DR_NORMAL;
708 // Reset transfer values, to prevent mis-transfer of data
709 VRAMWrite.x = 0;
710 VRAMWrite.y = 0;
711 VRAMWrite.Width = 0;
712 VRAMWrite.Height = 0;
713 VRAMWrite.ColsRemaining = 0;
714 VRAMWrite.RowsRemaining = 0;
715}
716
a96a5eb2 717static inline void FinishedVRAMRead(void)
ef79bbde
P
718{
719 // Set register to NORMAL operation
720 DataReadMode = DR_NORMAL;
721 // Reset transfer values, to prevent mis-transfer of data
722 VRAMRead.x = 0;
723 VRAMRead.y = 0;
724 VRAMRead.Width = 0;
725 VRAMRead.Height = 0;
726 VRAMRead.ColsRemaining = 0;
727 VRAMRead.RowsRemaining = 0;
728
729 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
730 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
731}
732
733////////////////////////////////////////////////////////////////////////
734// core read from vram
735////////////////////////////////////////////////////////////////////////
736
737void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
738{
739 int i;
740
741 if(DataReadMode!=DR_VRAMTRANSFER) return;
742
743 GPUIsBusy;
744
745 // adjust read ptr, if necessary
746 while(VRAMRead.ImagePtr>=psxVuw_eom)
a96a5eb2 747 VRAMRead.ImagePtr-=512*1024;
ef79bbde 748 while(VRAMRead.ImagePtr<psxVuw)
a96a5eb2 749 VRAMRead.ImagePtr+=512*1024;
ef79bbde
P
750
751 for(i=0;i<iSize;i++)
752 {
753 // do 2 seperate 16bit reads for compatibility (wrap issues)
754 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
755 {
756 // lower 16 bit
757 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
758
759 VRAMRead.ImagePtr++;
a96a5eb2 760 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
761 VRAMRead.RowsRemaining --;
762
763 if(VRAMRead.RowsRemaining<=0)
764 {
765 VRAMRead.RowsRemaining = VRAMRead.Width;
766 VRAMRead.ColsRemaining--;
767 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
a96a5eb2 768 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
769 }
770
771 // higher 16 bit (always, even if it's an odd width)
772 lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
773 PUTLE32(pMem, lGPUdataRet); pMem++;
774
775 if(VRAMRead.ColsRemaining <= 0)
776 {FinishedVRAMRead();goto ENDREAD;}
777
778 VRAMRead.ImagePtr++;
a96a5eb2 779 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
780 VRAMRead.RowsRemaining--;
781 if(VRAMRead.RowsRemaining<=0)
782 {
783 VRAMRead.RowsRemaining = VRAMRead.Width;
784 VRAMRead.ColsRemaining--;
785 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
a96a5eb2 786 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
787 }
788 if(VRAMRead.ColsRemaining <= 0)
789 {FinishedVRAMRead();goto ENDREAD;}
790 }
791 else {FinishedVRAMRead();goto ENDREAD;}
792 }
793
794ENDREAD:
795 GPUIsIdle;
796}
797
798
799////////////////////////////////////////////////////////////////////////
800
801uint32_t CALLBACK GPUreadData(void)
802{
803 uint32_t l;
804 GPUreadDataMem(&l,1);
805 return lGPUdataRet;
806}
807
a96a5eb2 808// Software drawing function
809#include "soft.c"
810
811// PSX drawing primitives
812#include "prim.c"
813
ef79bbde
P
814////////////////////////////////////////////////////////////////////////
815// processes data send to GPU data register
816// extra table entries for fixing polyline troubles
817////////////////////////////////////////////////////////////////////////
818
a96a5eb2 819static const unsigned char primTableCX[256] =
ef79bbde
P
820{
821 // 00
822 0,0,3,0,0,0,0,0,
823 // 08
824 0,0,0,0,0,0,0,0,
825 // 10
826 0,0,0,0,0,0,0,0,
827 // 18
828 0,0,0,0,0,0,0,0,
829 // 20
830 4,4,4,4,7,7,7,7,
831 // 28
832 5,5,5,5,9,9,9,9,
833 // 30
834 6,6,6,6,9,9,9,9,
835 // 38
836 8,8,8,8,12,12,12,12,
837 // 40
838 3,3,3,3,0,0,0,0,
839 // 48
840// 5,5,5,5,6,6,6,6, // FLINE
841 254,254,254,254,254,254,254,254,
842 // 50
843 4,4,4,4,0,0,0,0,
844 // 58
845// 7,7,7,7,9,9,9,9, // GLINE
846 255,255,255,255,255,255,255,255,
847 // 60
848 3,3,3,3,4,4,4,4,
849 // 68
850 2,2,2,2,3,3,3,3, // 3=SPRITE1???
851 // 70
852 2,2,2,2,3,3,3,3,
853 // 78
854 2,2,2,2,3,3,3,3,
855 // 80
856 4,0,0,0,0,0,0,0,
857 // 88
858 0,0,0,0,0,0,0,0,
859 // 90
860 0,0,0,0,0,0,0,0,
861 // 98
862 0,0,0,0,0,0,0,0,
863 // a0
864 3,0,0,0,0,0,0,0,
865 // a8
866 0,0,0,0,0,0,0,0,
867 // b0
868 0,0,0,0,0,0,0,0,
869 // b8
870 0,0,0,0,0,0,0,0,
871 // c0
872 3,0,0,0,0,0,0,0,
873 // c8
874 0,0,0,0,0,0,0,0,
875 // d0
876 0,0,0,0,0,0,0,0,
877 // d8
878 0,0,0,0,0,0,0,0,
879 // e0
880 0,1,1,1,1,1,1,0,
881 // e8
882 0,0,0,0,0,0,0,0,
883 // f0
884 0,0,0,0,0,0,0,0,
885 // f8
886 0,0,0,0,0,0,0,0
887};
888
889void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
890{
891 unsigned char command;
892 uint32_t gdata=0;
893 int i=0;
894 GPUIsBusy;
895 GPUIsNotReadyForCommands;
896
897STARTVRAM:
898
899 if(DataWriteMode==DR_VRAMTRANSFER)
900 {
901 BOOL bFinished=FALSE;
902
903 // make sure we are in vram
904 while(VRAMWrite.ImagePtr>=psxVuw_eom)
a96a5eb2 905 VRAMWrite.ImagePtr-=512*1024;
ef79bbde 906 while(VRAMWrite.ImagePtr<psxVuw)
a96a5eb2 907 VRAMWrite.ImagePtr+=512*1024;
ef79bbde
P
908
909 // now do the loop
910 while(VRAMWrite.ColsRemaining>0)
911 {
912 while(VRAMWrite.RowsRemaining>0)
913 {
914 if(i>=iSize) {goto ENDVRAM;}
915 i++;
916
917 gdata=GETLE32(pMem); pMem++;
918
919 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
a96a5eb2 920 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
ef79bbde
P
921 VRAMWrite.RowsRemaining --;
922
923 if(VRAMWrite.RowsRemaining <= 0)
924 {
925 VRAMWrite.ColsRemaining--;
926 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
927 {
928 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
929 FinishedVRAMWrite();
930 bDoVSyncUpdate=TRUE;
931 goto ENDVRAM;
932 }
933 VRAMWrite.RowsRemaining = VRAMWrite.Width;
934 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
935 }
936
937 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
a96a5eb2 938 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
ef79bbde
P
939 VRAMWrite.RowsRemaining --;
940 }
941
942 VRAMWrite.RowsRemaining = VRAMWrite.Width;
943 VRAMWrite.ColsRemaining--;
944 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
945 bFinished=TRUE;
946 }
947
948 FinishedVRAMWrite();
949 if(bFinished) bDoVSyncUpdate=TRUE;
950 }
951
952ENDVRAM:
953
954 if(DataWriteMode==DR_NORMAL)
955 {
956 void (* *primFunc)(unsigned char *);
957 if(bSkipNextFrame) primFunc=primTableSkip;
958 else primFunc=primTableJ;
959
960 for(;i<iSize;)
961 {
962 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
963
964 gdata=GETLE32(pMem); pMem++; i++;
965
966 if(gpuDataC == 0)
967 {
968 command = (unsigned char)((gdata>>24) & 0xff);
969
970//if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
971
972 if(primTableCX[command])
973 {
974 gpuDataC = primTableCX[command];
975 gpuCommand = command;
0d16cda2 976 PUTLE32_(&gpuDataM[0], gdata);
ef79bbde
P
977 gpuDataP = 1;
978 }
979 else continue;
980 }
981 else
982 {
0d16cda2 983 PUTLE32_(&gpuDataM[gpuDataP], gdata);
ef79bbde
P
984 if(gpuDataC>128)
985 {
986 if((gpuDataC==254 && gpuDataP>=3) ||
987 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
988 {
989 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
990 gpuDataP=gpuDataC-1;
991 }
992 }
993 gpuDataP++;
994 }
995
996 if(gpuDataP == gpuDataC)
997 {
998 gpuDataC=gpuDataP=0;
999 primFunc[gpuCommand]((unsigned char *)gpuDataM);
a96a5eb2 1000 if(dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
1001 iFakePrimBusy=4;
1002 }
ef79bbde
P
1003 }
1004 }
1005
1006 lGPUdataRet=gdata;
1007
1008 GPUIsReadyForCommands;
1009 GPUIsIdle;
1010}
1011
1012////////////////////////////////////////////////////////////////////////
1013
1014void CALLBACK GPUwriteData(uint32_t gdata)
1015{
0d16cda2 1016 PUTLE32_(&gdata, gdata);
ef79bbde
P
1017 GPUwriteDataMem(&gdata,1);
1018}
1019
ef79bbde
P
1020////////////////////////////////////////////////////////////////////////
1021// process gpu commands
1022////////////////////////////////////////////////////////////////////////
1023
1024unsigned long lUsedAddr[3];
1025
a96a5eb2 1026static inline BOOL CheckForEndlessLoop(unsigned long laddr)
ef79bbde
P
1027{
1028 if(laddr==lUsedAddr[1]) return TRUE;
1029 if(laddr==lUsedAddr[2]) return TRUE;
1030
1031 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1032 else lUsedAddr[2]=laddr;
1033 lUsedAddr[0]=laddr;
1034 return FALSE;
1035}
1036
1037long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1038{
1039 uint32_t dmaMem;
1040 unsigned char * baseAddrB;
1041 short count;unsigned int DMACommandCounter = 0;
b03e0caf 1042 long dmaWords = 0;
ef79bbde
P
1043
1044 GPUIsBusy;
1045
1046 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1047
1048 baseAddrB = (unsigned char*) baseAddrL;
1049
1050 do
1051 {
a96a5eb2 1052 addr&=0x1FFFFC;
ef79bbde
P
1053 if(DMACommandCounter++ > 2000000) break;
1054 if(CheckForEndlessLoop(addr)) break;
1055
1056 count = baseAddrB[addr+3];
b03e0caf 1057 dmaWords += 1 + count;
ef79bbde
P
1058
1059 dmaMem=addr+4;
1060
1061 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1062
1063 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1064 }
1065 while (addr != 0xffffff);
1066
1067 GPUIsIdle;
1068
b03e0caf 1069 return dmaWords;
ef79bbde
P
1070}
1071
ef79bbde
P
1072////////////////////////////////////////////////////////////////////////
1073// Freeze
1074////////////////////////////////////////////////////////////////////////
1075
1076typedef struct GPUFREEZETAG
1077{
1078 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
1079 uint32_t ulStatus; // current gpu status
1080 uint32_t ulControl[256]; // latest control register values
1081 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1082} GPUFreeze_t;
1083
1084////////////////////////////////////////////////////////////////////////
1085
1086long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1087{
1088 //----------------------------------------------------//
1089 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1090 {
1091 long lSlotNum=*((long *)pF);
1092 if(lSlotNum<0) return 0;
1093 if(lSlotNum>8) return 0;
1094 lSelectedSlot=lSlotNum+1;
ef79bbde
P
1095 return 1;
1096 }
1097 //----------------------------------------------------//
1098 if(!pF) return 0; // some checks
1099 if(pF->ulFreezeVersion!=1) return 0;
1100
1101 if(ulGetFreezeData==1) // 1: get data
1102 {
1103 pF->ulStatus=lGPUstatusRet;
1104 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
a96a5eb2 1105 memcpy(pF->psxVRam, psxVub, 1024*512*2);
ef79bbde
P
1106
1107 return 1;
1108 }
1109
1110 if(ulGetFreezeData!=0) return 0; // 0: set data
1111
1112 lGPUstatusRet=pF->ulStatus;
1113 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
a96a5eb2 1114 memcpy(psxVub, pF->psxVRam, 1024*512*2);
ef79bbde
P
1115
1116// RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1117
321ca84d 1118 PreviousPSXDisplay.Height = 0;
ef79bbde
P
1119 GPUwriteStatus(ulStatusControl[0]);
1120 GPUwriteStatus(ulStatusControl[1]);
1121 GPUwriteStatus(ulStatusControl[2]);
1122 GPUwriteStatus(ulStatusControl[3]);
1123 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1124 GPUwriteStatus(ulStatusControl[6]);
1125 GPUwriteStatus(ulStatusControl[7]);
1126 GPUwriteStatus(ulStatusControl[5]);
1127 GPUwriteStatus(ulStatusControl[4]);
1128
1129 return 1;
1130}
2588a938 1131
1132void CALLBACK GPUvBlank(int val)
1133{
1134 vBlank=val?0x80000000:0;
1135}
1136
e64dc4c5 1137// rearmed thing
1138#include "../../frontend/plugin_lib.h"
1139
76f7048e 1140const struct rearmed_cbs *rcbs;
1141
e64dc4c5 1142void GPUrearmedCallbacks(const struct rearmed_cbs *cbs)
1143{
1144 // sync config
1145 UseFrameSkip = cbs->frameskip;
1146 iUseDither = cbs->gpu_peops.iUseDither;
1147 dwActFixes = cbs->gpu_peops.dwActFixes;
1148 fFrameRateHz = cbs->gpu_peops.fFrameRateHz;
1149 dwFrameRateTicks = cbs->gpu_peops.dwFrameRateTicks;
55b0eeea 1150 if (cbs->pl_vout_set_raw_vram)
1151 cbs->pl_vout_set_raw_vram(psxVub);
e64dc4c5 1152
1153 skip_advice = &cbs->fskip_advice;
1154 fps_skip = 100.0f;
76f7048e 1155 rcbs = cbs;
e64dc4c5 1156}