mirror of https://github.com/PCSX2/pcsx2.git
676 lines
12 KiB
C++
676 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2007-2009 Gabest
|
|
* http://www.gabest.org
|
|
*
|
|
* This Program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This Program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GNU Make; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "GSUtil.h"
|
|
#include "GSRendererDX9.h"
|
|
#include "GSRendererDX10.h"
|
|
#include "GSRendererDX11.h"
|
|
#include "GSRendererOGL.h"
|
|
#include "GSRendererSW.h"
|
|
#include "GSRendererNull.h"
|
|
#include "GSSettingsDlg.h"
|
|
|
|
#define PS2E_LT_GS 0x01
|
|
#define PS2E_GS_VERSION 0x0006
|
|
#define PS2E_X86 0x01 // 32 bit
|
|
#define PS2E_X86_64 0x02 // 64 bit
|
|
|
|
static HRESULT s_hr = E_FAIL;
|
|
static GSRenderer* s_gs = NULL;
|
|
static void (*s_irq)() = NULL;
|
|
static uint8* s_basemem = NULL;
|
|
|
|
EXPORT_C_(uint32) PS2EgetLibType()
|
|
{
|
|
return PS2E_LT_GS;
|
|
}
|
|
|
|
EXPORT_C_(char*) PS2EgetLibName()
|
|
{
|
|
return GSUtil::GetLibName();
|
|
}
|
|
|
|
EXPORT_C_(uint32) PS2EgetLibVersion2(uint32 type)
|
|
{
|
|
const uint32 revision = 0;
|
|
const uint32 build = 1;
|
|
|
|
return (build << 0) | (revision << 8) | (PS2E_GS_VERSION << 16) | (PLUGIN_VERSION << 24);
|
|
}
|
|
|
|
EXPORT_C_(uint32) PS2EgetCpuPlatform()
|
|
{
|
|
#if _M_AMD64
|
|
return PS2E_X86_64;
|
|
#else
|
|
return PS2E_X86;
|
|
#endif
|
|
}
|
|
|
|
EXPORT_C GSsetBaseMem(uint8* mem)
|
|
{
|
|
s_basemem = mem - 0x12000000;
|
|
}
|
|
|
|
EXPORT_C_(INT32) GSinit()
|
|
{
|
|
if(!GSUtil::CheckSSE())
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
|
|
if(!GSUtil::CheckDirectX())
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
EXPORT_C GSshutdown()
|
|
{
|
|
delete s_gs;
|
|
|
|
s_gs = NULL;
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
if(SUCCEEDED(s_hr))
|
|
{
|
|
::CoUninitialize();
|
|
|
|
s_hr = E_FAIL;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
EXPORT_C GSclose()
|
|
{
|
|
if( !s_gs ) return;
|
|
|
|
s_gs->ResetDevice();
|
|
|
|
if( s_gs->m_dev )
|
|
s_gs->m_dev->Reset(1, 1, GSDevice::Windowed);
|
|
|
|
delete s_gs->m_dev;
|
|
s_gs->m_dev = NULL;
|
|
|
|
s_gs->m_wnd.Detach();
|
|
}
|
|
|
|
static INT32 GSopen(void* dsp, char* title, int mt, int renderer)
|
|
{
|
|
GSclose();
|
|
|
|
GSDevice* dev = NULL;
|
|
|
|
switch(renderer)
|
|
{
|
|
default:
|
|
case 0: case 1: case 2: dev = new GSDevice9(); break;
|
|
case 3: case 4: case 5: dev = new GSDevice10(); break;
|
|
case 6: case 7: case 8: dev = new GSDevice11(); break;
|
|
#if 0
|
|
case 9: case 10: case 11: dev = new GSDeviceOGL(); break;
|
|
#endif
|
|
case 12: case 13: new GSDeviceNull(); break;
|
|
}
|
|
|
|
if( !dev ) return -1;
|
|
|
|
if( !s_gs )
|
|
{
|
|
switch(renderer)
|
|
{
|
|
default:
|
|
case 0: s_gs = new GSRendererDX9(s_basemem, !!mt, s_irq); break;
|
|
case 3: s_gs = new GSRendererDX10(s_basemem, !!mt, s_irq); break;
|
|
case 6: s_gs = new GSRendererDX11(s_basemem, !!mt, s_irq); break;
|
|
#if 0
|
|
case 9: s_gs = new GSRendererOGL(s_basemem, !!mt, s_irq); break;
|
|
#endif
|
|
case 2: case 5: case 8: case 11: case 13:
|
|
s_gs = new GSRendererNull(s_basemem, !!mt, s_irq); break;
|
|
|
|
case 1: case 4: case 7: case 10: case 12:
|
|
s_gs = new GSRendererSW(s_basemem, !!mt, s_irq); break;
|
|
}
|
|
}
|
|
|
|
if( *(HWND*)dsp == NULL )
|
|
{
|
|
// old-style API expects us to create and manage our own window:
|
|
|
|
int w = theApp.GetConfig("ModeWidth", 0);
|
|
int h = theApp.GetConfig("ModeHeight", 0);
|
|
|
|
if(!s_gs->CreateWnd(title, w, h))
|
|
{
|
|
GSclose();
|
|
return -1;
|
|
}
|
|
|
|
s_gs->m_wnd.Show();
|
|
*(HWND*)dsp = (HWND)s_gs->m_wnd.GetHandle();
|
|
}
|
|
else
|
|
{
|
|
s_gs->m_wnd.Attach( *(HWND*)dsp, false );
|
|
}
|
|
|
|
if( !s_gs->CreateDevice(dev) )
|
|
{
|
|
GSclose();
|
|
return -1;
|
|
}
|
|
|
|
// if(mt) _mm_setcsr(MXCSR);
|
|
|
|
return 0;
|
|
}
|
|
|
|
EXPORT_C_(INT32) GSopen2(void* dsp, INT32 forceSoftware )
|
|
{
|
|
int renderer = theApp.GetConfig("renderer", 0);
|
|
if( forceSoftware )
|
|
{
|
|
renderer = 1;
|
|
}
|
|
|
|
return GSopen( dsp, NULL, true, renderer );
|
|
}
|
|
|
|
EXPORT_C_(INT32) GSopen(void* dsp, char* title, int mt)
|
|
{
|
|
int renderer;
|
|
|
|
if(mt == 2)
|
|
{
|
|
// pcsx2 sent a switch renderer request
|
|
renderer = 1; //DX9 sw
|
|
mt = 1;
|
|
}
|
|
else
|
|
{
|
|
// normal init
|
|
renderer = theApp.GetConfig("renderer", 0);
|
|
}
|
|
|
|
*(HWND*)dsp = NULL;
|
|
return GSopen(dsp, title, mt, renderer);
|
|
}
|
|
|
|
EXPORT_C GSreset()
|
|
{
|
|
s_gs->Reset();
|
|
}
|
|
|
|
EXPORT_C GSgifSoftReset(uint32 mask)
|
|
{
|
|
s_gs->SoftReset(mask);
|
|
}
|
|
|
|
EXPORT_C GSwriteCSR(uint32 csr)
|
|
{
|
|
s_gs->WriteCSR(csr);
|
|
}
|
|
|
|
EXPORT_C GSreadFIFO(uint8* mem)
|
|
{
|
|
s_gs->ReadFIFO(mem, 1);
|
|
}
|
|
|
|
EXPORT_C GSreadFIFO2(uint8* mem, uint32 size)
|
|
{
|
|
s_gs->ReadFIFO(mem, size);
|
|
}
|
|
|
|
EXPORT_C GSgifTransfer1(uint8* mem, uint32 addr)
|
|
{
|
|
s_gs->Transfer<0>(mem + addr, (0x4000 - addr) / 16);
|
|
}
|
|
|
|
EXPORT_C GSgifTransfer2(uint8* mem, uint32 size)
|
|
{
|
|
s_gs->Transfer<1>(mem, size);
|
|
}
|
|
|
|
EXPORT_C GSgifTransfer3(uint8* mem, uint32 size)
|
|
{
|
|
s_gs->Transfer<2>(mem, size);
|
|
}
|
|
|
|
EXPORT_C GSvsync(int field)
|
|
{
|
|
#ifdef _WINDOWS
|
|
|
|
MSG msg;
|
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
|
|
while(msg.message != WM_QUIT && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
#endif
|
|
|
|
s_gs->VSync(field);
|
|
}
|
|
|
|
EXPORT_C_(uint32) GSmakeSnapshot(char* path)
|
|
{
|
|
return s_gs->MakeSnapshot(string(path) + "gsdx");
|
|
}
|
|
|
|
EXPORT_C GSkeyEvent(GSKeyEventData* e)
|
|
{
|
|
s_gs->KeyEvent(e);
|
|
}
|
|
|
|
EXPORT_C_(int) GSfreeze(int mode, GSFreezeData* data)
|
|
{
|
|
if(mode == FREEZE_SAVE)
|
|
{
|
|
return s_gs->Freeze(data, false);
|
|
}
|
|
else if(mode == FREEZE_SIZE)
|
|
{
|
|
return s_gs->Freeze(data, true);
|
|
}
|
|
else if(mode == FREEZE_LOAD)
|
|
{
|
|
return s_gs->Defrost(data);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
EXPORT_C GSconfigure()
|
|
{
|
|
GSSettingsDlg().DoModal();
|
|
}
|
|
|
|
EXPORT_C_(INT32) GStest()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
EXPORT_C GSabout()
|
|
{
|
|
}
|
|
|
|
EXPORT_C GSirqCallback(void (*irq)())
|
|
{
|
|
s_irq = irq;
|
|
}
|
|
|
|
EXPORT_C_(int) GSsetupRecording(int start, void* data)
|
|
{
|
|
GSKeyEventData e;
|
|
|
|
e.type = KEYPRESS;
|
|
e.key = VK_F12;
|
|
|
|
s_gs->KeyEvent(&e, start & 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
EXPORT_C GSsetGameCRC(uint32 crc, int options)
|
|
{
|
|
s_gs->SetGameCRC(crc, options);
|
|
}
|
|
|
|
EXPORT_C GSgetLastTag(uint32* tag)
|
|
{
|
|
s_gs->GetLastTag(tag);
|
|
}
|
|
|
|
EXPORT_C GSsetFrameSkip(int frameskip)
|
|
{
|
|
s_gs->SetFrameSkip(frameskip);
|
|
}
|
|
|
|
EXPORT_C GSsetFrameLimit(int limit)
|
|
{
|
|
s_gs->SetFrameLimit(limit != 0);
|
|
}
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
EXPORT_C GSReplay(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
|
|
{
|
|
int renderer = -1;
|
|
|
|
{
|
|
char* start = lpszCmdLine;
|
|
char* end = NULL;
|
|
long n = strtol(lpszCmdLine, &end, 10);
|
|
if(end > start) {renderer = n; lpszCmdLine = end;}
|
|
}
|
|
|
|
while(*lpszCmdLine == ' ') lpszCmdLine++;
|
|
|
|
::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
|
|
|
vector<uint8> buff;
|
|
|
|
if(FILE* fp = fopen(lpszCmdLine, "rb"))
|
|
{
|
|
GSinit();
|
|
|
|
uint8 regs[0x2000];
|
|
GSsetBaseMem(regs);
|
|
|
|
HWND hWnd = NULL;
|
|
GSopen(&hWnd, "", true, renderer);
|
|
|
|
uint32 crc;
|
|
fread(&crc, 4, 1, fp);
|
|
GSsetGameCRC(crc, 0);
|
|
|
|
GSFreezeData fd;
|
|
fread(&fd.size, 4, 1, fp);
|
|
fd.data = new uint8[fd.size];
|
|
fread(fd.data, fd.size, 1, fp);
|
|
GSfreeze(FREEZE_LOAD, &fd);
|
|
delete [] fd.data;
|
|
|
|
fread(regs, 0x2000, 1, fp);
|
|
|
|
long start = ftell(fp);
|
|
|
|
unsigned int index, size, addr;
|
|
|
|
GSvsync(1);
|
|
|
|
while(1)
|
|
{
|
|
switch(fgetc(fp))
|
|
{
|
|
case EOF:
|
|
fseek(fp, start, 0);
|
|
if(!IsWindowVisible(hWnd)) return;
|
|
break;
|
|
case 0:
|
|
index = fgetc(fp);
|
|
fread(&size, 4, 1, fp);
|
|
switch(index)
|
|
{
|
|
case 0:
|
|
if(buff.size() < 0x4000) buff.resize(0x4000);
|
|
addr = 0x4000 - size;
|
|
fread(&buff[0] + addr, size, 1, fp);
|
|
GSgifTransfer1(&buff[0], addr);
|
|
break;
|
|
case 1:
|
|
if(buff.size() < size) buff.resize(size);
|
|
fread(&buff[0], size, 1, fp);
|
|
GSgifTransfer2(&buff[0], size / 16);
|
|
break;
|
|
case 2:
|
|
if(buff.size() < size) buff.resize(size);
|
|
fread(&buff[0], size, 1, fp);
|
|
GSgifTransfer3(&buff[0], size / 16);
|
|
break;
|
|
}
|
|
break;
|
|
case 1:
|
|
GSvsync(fgetc(fp));
|
|
if(!IsWindowVisible(hWnd)) return;
|
|
break;
|
|
case 2:
|
|
fread(&size, 4, 1, fp);
|
|
if(buff.size() < size) buff.resize(size);
|
|
GSreadFIFO2(&buff[0], size / 16);
|
|
break;
|
|
case 3:
|
|
fread(regs, 0x2000, 1, fp);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
GSclose();
|
|
|
|
GSshutdown();
|
|
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
EXPORT_C GSBenchmark(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
|
|
{
|
|
::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
|
|
|
FILE* file = fopen("c:\\log.txt", "a");
|
|
|
|
fprintf(file, "-------------------------\n\n");
|
|
|
|
if(1)
|
|
{
|
|
GSLocalMemory mem;
|
|
|
|
static struct {int psm; const char* name;} s_format[] =
|
|
{
|
|
{PSM_PSMCT32, "32"},
|
|
{PSM_PSMCT24, "24"},
|
|
{PSM_PSMCT16, "16"},
|
|
{PSM_PSMCT16S, "16S"},
|
|
{PSM_PSMT8, "8"},
|
|
{PSM_PSMT4, "4"},
|
|
{PSM_PSMT8H, "8H"},
|
|
{PSM_PSMT4HL, "4HL"},
|
|
{PSM_PSMT4HH, "4HH"},
|
|
{PSM_PSMZ32, "32Z"},
|
|
{PSM_PSMZ24, "24Z"},
|
|
{PSM_PSMZ16, "16Z"},
|
|
{PSM_PSMZ16S, "16ZS"},
|
|
};
|
|
|
|
uint8* ptr = (uint8*)_aligned_malloc(1024 * 1024 * 4, 16);
|
|
|
|
for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (uint8)i;
|
|
|
|
//
|
|
|
|
for(int tbw = 5; tbw <= 10; tbw++)
|
|
{
|
|
int n = 256 << ((10 - tbw) * 2);
|
|
|
|
int w = 1 << tbw;
|
|
int h = 1 << tbw;
|
|
|
|
fprintf(file, "%d x %d\n\n", w, h);
|
|
|
|
for(int i = 0; i < countof(s_format); i++)
|
|
{
|
|
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[s_format[i].psm];
|
|
|
|
GSLocalMemory::writeImage wi = psm.wi;
|
|
GSLocalMemory::readImage ri = psm.ri;
|
|
GSLocalMemory::readTexture rtx = psm.rtx;
|
|
GSLocalMemory::readTexture rtxP = psm.rtxP;
|
|
|
|
GIFRegBITBLTBUF BITBLTBUF;
|
|
|
|
BITBLTBUF.SBP = 0;
|
|
BITBLTBUF.SBW = w / 64;
|
|
BITBLTBUF.SPSM = s_format[i].psm;
|
|
BITBLTBUF.DBP = 0;
|
|
BITBLTBUF.DBW = w / 64;
|
|
BITBLTBUF.DPSM = s_format[i].psm;
|
|
|
|
GIFRegTRXPOS TRXPOS;
|
|
|
|
TRXPOS.SSAX = 0;
|
|
TRXPOS.SSAY = 0;
|
|
TRXPOS.DSAX = 0;
|
|
TRXPOS.DSAY = 0;
|
|
|
|
GIFRegTRXREG TRXREG;
|
|
|
|
TRXREG.RRW = w;
|
|
TRXREG.RRH = h;
|
|
|
|
GSVector4i r(0, 0, w, h);
|
|
|
|
GIFRegTEX0 TEX0;
|
|
|
|
TEX0.TBP0 = 0;
|
|
TEX0.TBW = w / 64;
|
|
|
|
GIFRegTEXA TEXA;
|
|
|
|
TEXA.TA0 = 0;
|
|
TEXA.TA1 = 0x80;
|
|
TEXA.AEM = 0;
|
|
|
|
int trlen = w * h * psm.trbpp / 8;
|
|
int len = w * h * psm.bpp / 8;
|
|
|
|
clock_t start, end;
|
|
|
|
_ftprintf(file, _T("[%4s] "), s_format[i].name);
|
|
|
|
start = clock();
|
|
|
|
for(int j = 0; j < n; j++)
|
|
{
|
|
int x = 0;
|
|
int y = 0;
|
|
|
|
(mem.*wi)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG);
|
|
}
|
|
|
|
end = clock();
|
|
|
|
fprintf(file, "%6d %6d | ", (int)((float)trlen * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000));
|
|
|
|
start = clock();
|
|
|
|
for(int j = 0; j < n; j++)
|
|
{
|
|
int x = 0;
|
|
int y = 0;
|
|
|
|
(mem.*ri)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG);
|
|
}
|
|
|
|
end = clock();
|
|
|
|
fprintf(file, "%6d %6d | ", (int)((float)trlen * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000));
|
|
|
|
const GSOffset* o = mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
|
|
|
start = clock();
|
|
|
|
for(int j = 0; j < n; j++)
|
|
{
|
|
(mem.*rtx)(o, r, ptr, w * 4, TEXA);
|
|
}
|
|
|
|
end = clock();
|
|
|
|
fprintf(file, "%6d %6d ", (int)((float)len * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000));
|
|
|
|
if(psm.pal > 0)
|
|
{
|
|
start = clock();
|
|
|
|
for(int j = 0; j < n; j++)
|
|
{
|
|
(mem.*rtxP)(o, r, ptr, w, TEXA);
|
|
}
|
|
|
|
end = clock();
|
|
|
|
fprintf(file, "| %6d %6d ", (int)((float)len * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000));
|
|
}
|
|
|
|
fprintf(file, "\n");
|
|
|
|
fflush(file);
|
|
}
|
|
|
|
fprintf(file, "\n");
|
|
}
|
|
|
|
_aligned_free(ptr);
|
|
}
|
|
|
|
//
|
|
|
|
if(0)
|
|
{
|
|
GSLocalMemory mem;
|
|
|
|
uint8* ptr = (uint8*)_aligned_malloc(1024 * 1024 * 4, 16);
|
|
|
|
for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (uint8)i;
|
|
|
|
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[PSM_PSMCT32];
|
|
|
|
GSLocalMemory::writeImage wi = psm.wi;
|
|
|
|
GIFRegBITBLTBUF BITBLTBUF;
|
|
|
|
BITBLTBUF.DBP = 0;
|
|
BITBLTBUF.DBW = 32;
|
|
BITBLTBUF.DPSM = PSM_PSMCT32;
|
|
|
|
GIFRegTRXPOS TRXPOS;
|
|
|
|
TRXPOS.DSAX = 0;
|
|
TRXPOS.DSAY = 1;
|
|
|
|
GIFRegTRXREG TRXREG;
|
|
|
|
TRXREG.RRW = 256;
|
|
TRXREG.RRH = 256;
|
|
|
|
int trlen = 256 * 256 * psm.trbpp / 8;
|
|
|
|
int x = 0;
|
|
int y = 0;
|
|
|
|
(mem.*wi)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG);
|
|
}
|
|
|
|
//
|
|
|
|
fclose(file);
|
|
}
|
|
|
|
#endif
|