mirror of https://github.com/PCSX2/pcsx2.git
added gsdx, xpad, cdvdolio
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@405 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
5587ee7640
commit
e4e6d8ad3a
|
@ -0,0 +1,194 @@
|
|||
// SettingsDlg.cpp : implementation file
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "cdvd.h"
|
||||
#include "SettingsDlg.h"
|
||||
#include <dbt.h>
|
||||
#include <afxdlgs.h>
|
||||
|
||||
// CSettingsDlg dialog
|
||||
|
||||
IMPLEMENT_DYNAMIC(CSettingsDlg, CDialog)
|
||||
|
||||
CSettingsDlg::CSettingsDlg(CWnd* pParent /*=NULL*/)
|
||||
: CDialog(CSettingsDlg::IDD, pParent)
|
||||
, m_iso(_T(""))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CSettingsDlg::~CSettingsDlg()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL CSettingsDlg::OnInitDialog()
|
||||
{
|
||||
__super::OnInitDialog();
|
||||
|
||||
InitDrive();
|
||||
InitISO();
|
||||
|
||||
UpdateData(FALSE);
|
||||
|
||||
return TRUE; // return TRUE unless you set the focus to a control
|
||||
// EXCEPTION: OCX Property Pages should return FALSE
|
||||
}
|
||||
|
||||
void CSettingsDlg::InitDrive()
|
||||
{
|
||||
int drive = AfxGetApp()->GetProfileInt(_T("Settings"), _T("drive"), -1);
|
||||
|
||||
int sel = m_drive.GetCurSel();
|
||||
|
||||
if(sel >= 0)
|
||||
{
|
||||
drive = m_drive.GetItemData(sel);
|
||||
}
|
||||
|
||||
while(m_drive.GetCount() > 0)
|
||||
{
|
||||
m_drive.DeleteString(0);
|
||||
}
|
||||
|
||||
for(int i = 'A'; i <= 'Z'; i++)
|
||||
{
|
||||
CString path;
|
||||
|
||||
path.Format(_T("%c:"), i);
|
||||
|
||||
if(GetDriveType(path) == DRIVE_CDROM)
|
||||
{
|
||||
CString label = path;
|
||||
|
||||
path.Format(_T("\\\\.\\%c:"), i);
|
||||
|
||||
CDVD cdvd;
|
||||
|
||||
if(cdvd.Open(path))
|
||||
{
|
||||
CString str = cdvd.GetLabel();
|
||||
|
||||
if(str.IsEmpty())
|
||||
{
|
||||
str = _T("(no label)");
|
||||
}
|
||||
|
||||
label.Format(_T("[%s] %s"), CString(label), str);
|
||||
}
|
||||
else
|
||||
{
|
||||
label.Format(_T("[%s] (not detected)"), CString(label));
|
||||
}
|
||||
|
||||
m_drive.SetItemData(m_drive.AddString(label), (DWORD_PTR)i);
|
||||
}
|
||||
}
|
||||
|
||||
m_drive.SetItemData(m_drive.AddString(_T("Other...")), (DWORD_PTR)-1);
|
||||
|
||||
for(int i = 0, j = m_drive.GetCount(); i < j; i++)
|
||||
{
|
||||
if((int)m_drive.GetItemData(i) == drive)
|
||||
{
|
||||
m_drive.SetCurSel(i);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_drive.SetCurSel(-1);
|
||||
}
|
||||
|
||||
void CSettingsDlg::InitISO()
|
||||
{
|
||||
m_iso = AfxGetApp()->GetProfileString(_T("Settings"), _T("iso"), _T(""));
|
||||
}
|
||||
|
||||
void CSettingsDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
DDX_Control(pDX, IDC_COMBO1, m_drive);
|
||||
DDX_Text(pDX, IDC_EDIT1, m_iso);
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(CSettingsDlg, CDialog)
|
||||
ON_BN_CLICKED(IDC_BUTTON1, &CSettingsDlg::OnBrowse)
|
||||
ON_BN_CLICKED(IDOK, &CSettingsDlg::OnBnClickedOk)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
// CSettingsDlg message handlers
|
||||
|
||||
LRESULT CSettingsDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if(message == WM_DEVICECHANGE)
|
||||
{
|
||||
if(wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE)
|
||||
{
|
||||
InitDrive();
|
||||
|
||||
DEV_BROADCAST_HDR* p = (DEV_BROADCAST_HDR*)lParam;
|
||||
|
||||
if(p->dbch_devicetype == DBT_DEVTYP_VOLUME)
|
||||
{
|
||||
DEV_BROADCAST_VOLUME* v = (DEV_BROADCAST_VOLUME*)p;
|
||||
|
||||
for(int i = 0; i < 32; i++)
|
||||
{
|
||||
if(v->dbcv_unitmask & (1 << i))
|
||||
{
|
||||
TRACE(_T("%c:\n"), 'A' + i);
|
||||
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return __super::WindowProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
void CSettingsDlg::OnBrowse()
|
||||
{
|
||||
UpdateData();
|
||||
|
||||
CFileDialog fd(TRUE, NULL, m_iso,
|
||||
OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY,
|
||||
_T("ISO file|*.iso|All files|*.*|"), this);
|
||||
|
||||
if(fd.DoModal() == IDOK)
|
||||
{
|
||||
m_iso = fd.GetPathName();
|
||||
|
||||
UpdateData(FALSE);
|
||||
|
||||
for(int i = 0, j = m_drive.GetCount(); i < j; i++)
|
||||
{
|
||||
if((int)m_drive.GetItemData(i) < 0)
|
||||
{
|
||||
m_drive.SetCurSel(i);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSettingsDlg::OnBnClickedOk()
|
||||
{
|
||||
UpdateData();
|
||||
|
||||
int i = m_drive.GetCurSel();
|
||||
|
||||
if(i >= 0)
|
||||
{
|
||||
i = (int)m_drive.GetItemData(i);
|
||||
}
|
||||
|
||||
AfxGetApp()->WriteProfileInt(_T("Settings"), _T("drive"), i);
|
||||
|
||||
AfxGetApp()->WriteProfileString(_T("Settings"), _T("iso"), m_iso);
|
||||
|
||||
OnOK();
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include "afxwin.h"
|
||||
#include "resource.h"
|
||||
|
||||
// CSettingsDlg dialog
|
||||
|
||||
class CSettingsDlg : public CDialog
|
||||
{
|
||||
DECLARE_DYNAMIC(CSettingsDlg)
|
||||
|
||||
protected:
|
||||
void InitDrive();
|
||||
void InitISO();
|
||||
|
||||
public:
|
||||
CSettingsDlg(CWnd* pParent = NULL); // standard constructor
|
||||
virtual ~CSettingsDlg();
|
||||
|
||||
virtual BOOL OnInitDialog();
|
||||
|
||||
enum { IDD = IDD_CONFIG };
|
||||
|
||||
CComboBox m_drive;
|
||||
CString m_iso;
|
||||
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
afx_msg void OnBrowse();
|
||||
afx_msg void OnBnClickedOk();
|
||||
};
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
* Copyright (C) 2007 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 "cdvd.h"
|
||||
#include "SettingsDlg.h"
|
||||
#include <winioctl.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
//
|
||||
// Note!
|
||||
//
|
||||
// If this DLL is dynamically linked against the MFC
|
||||
// DLLs, any functions exported from this DLL which
|
||||
// call into MFC must have the AFX_MANAGE_STATE macro
|
||||
// added at the very beginning of the function.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
|
||||
// {
|
||||
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
// // normal function body here
|
||||
// }
|
||||
//
|
||||
// It is very important that this macro appear in each
|
||||
// function, prior to any calls into MFC. This means that
|
||||
// it must appear as the first statement within the
|
||||
// function, even before any object variable declarations
|
||||
// as their constructors may generate calls into the MFC
|
||||
// DLL.
|
||||
//
|
||||
// Please see MFC Technical Notes 33 and 58 for additional
|
||||
// details.
|
||||
//
|
||||
|
||||
BEGIN_MESSAGE_MAP(cdvdApp, CWinApp)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
cdvdApp::cdvdApp()
|
||||
{
|
||||
}
|
||||
|
||||
cdvdApp theApp;
|
||||
|
||||
BOOL cdvdApp::InitInstance()
|
||||
{
|
||||
__super::InitInstance();
|
||||
|
||||
SetRegistryKey(_T("Gabest"));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
#define PS2E_LT_CDVD 0x08
|
||||
#define PS2E_CDVD_VERSION 0x0005
|
||||
|
||||
EXPORT_C_(UINT32) PS2EgetLibType()
|
||||
{
|
||||
return PS2E_LT_CDVD;
|
||||
}
|
||||
|
||||
EXPORT_C_(char*) PS2EgetLibName()
|
||||
{
|
||||
return "CDVDolio"; // olio = OverLapped I/O (duh)
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) PS2EgetLibVersion2(UINT32 type)
|
||||
{
|
||||
const UINT32 revision = 0;
|
||||
const UINT32 build = 1;
|
||||
const UINT32 minor = 0;
|
||||
|
||||
return (build << 0) | (revision << 8) | (PS2E_CDVD_VERSION << 16) | (minor << 24);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
CDVD::CDVD()
|
||||
: m_hFile(INVALID_HANDLE_VALUE)
|
||||
{
|
||||
memset(&m_overlapped, 0, sizeof(m_overlapped));
|
||||
m_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
m_cache.pending = false;
|
||||
m_cache.count = 0;
|
||||
}
|
||||
|
||||
CDVD::~CDVD()
|
||||
{
|
||||
CloseHandle(m_overlapped.hEvent);
|
||||
}
|
||||
|
||||
LARGE_INTEGER CDVD::MakeOffset(int lsn)
|
||||
{
|
||||
LARGE_INTEGER offset;
|
||||
offset.QuadPart = (LONGLONG)lsn * m_block.size + m_block.offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool CDVD::SyncRead(int lsn)
|
||||
{
|
||||
return Read(lsn) && GetBuffer();
|
||||
}
|
||||
|
||||
bool CDVD::Open(CString path)
|
||||
{
|
||||
m_label.Empty();
|
||||
|
||||
DWORD share = FILE_SHARE_READ;
|
||||
DWORD flags = FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED;
|
||||
|
||||
m_hFile = CreateFile(path, GENERIC_READ, share, NULL, OPEN_EXISTING, flags, (HANDLE)NULL);
|
||||
|
||||
if(m_hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_block.count = 0;
|
||||
m_block.size = 2048;
|
||||
m_block.offset = 0;
|
||||
|
||||
GET_LENGTH_INFORMATION info;
|
||||
DWORD ret = 0;
|
||||
|
||||
if(GetFileSizeEx(m_hFile, &info.Length) || DeviceIoControl(m_hFile, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &info, sizeof(info), &ret, NULL))
|
||||
{
|
||||
m_block.count = (int)(info.Length.QuadPart / m_block.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SyncRead(16) || memcmp(&m_buff[24 + 1], "CD001", 5) != 0)
|
||||
{
|
||||
Close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_label = CString(CStringA((char*)&m_buff[24 + 40], 32));
|
||||
m_label.Trim();
|
||||
|
||||
// m_block.count = *(DWORD*)&m_buff[24 + 80];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDVD::Close()
|
||||
{
|
||||
if(m_hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CancelIo(m_hFile);
|
||||
CloseHandle(m_hFile);
|
||||
m_hFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
m_cache.pending = false;
|
||||
m_cache.count = 0;
|
||||
|
||||
m_label.Empty();
|
||||
}
|
||||
|
||||
CString CDVD::GetLabel()
|
||||
{
|
||||
return m_label;
|
||||
}
|
||||
|
||||
bool CDVD::Read(int lsn, int mode)
|
||||
{
|
||||
if(mode != CDVD_MODE_2048) return false;
|
||||
|
||||
if(lsn < 0) lsn += m_block.count;
|
||||
|
||||
if(lsn < 0 || lsn >= m_block.count) return false;
|
||||
|
||||
if(m_cache.pending)
|
||||
{
|
||||
CancelIo(m_hFile);
|
||||
ResetEvent(m_overlapped.hEvent);
|
||||
m_cache.pending = false;
|
||||
}
|
||||
|
||||
if(lsn >= m_cache.start && lsn < m_cache.start + m_cache.count)
|
||||
{
|
||||
memcpy(&m_buff[24], &m_cache.buff[(lsn - m_cache.start) * 2048], 2048);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
m_cache.pending = true;
|
||||
m_cache.start = lsn;
|
||||
m_cache.count = min(CACHE_BLOCK_COUNT, m_block.count - m_cache.start);
|
||||
|
||||
LARGE_INTEGER offset = MakeOffset(lsn);
|
||||
|
||||
m_overlapped.Offset = offset.LowPart;
|
||||
m_overlapped.OffsetHigh = offset.HighPart;
|
||||
|
||||
if(!ReadFile(m_hFile, m_cache.buff, m_cache.count * 2048, NULL, &m_overlapped))
|
||||
{
|
||||
switch(GetLastError())
|
||||
{
|
||||
case ERROR_IO_PENDING:
|
||||
break;
|
||||
case ERROR_HANDLE_EOF:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BYTE* CDVD::GetBuffer()
|
||||
{
|
||||
DWORD size = 0;
|
||||
|
||||
if(m_cache.pending)
|
||||
{
|
||||
if(GetOverlappedResult(m_hFile, &m_overlapped, &size, TRUE))
|
||||
{
|
||||
memcpy(&m_buff[24], m_cache.buff, 2048);
|
||||
|
||||
m_cache.pending = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return &m_buff[24];
|
||||
}
|
||||
|
||||
UINT32 CDVD::GetTN(cdvdTN* buff)
|
||||
{
|
||||
buff->strack = 1;
|
||||
buff->etrack = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 CDVD::GetTD(BYTE track, cdvdTD* buff)
|
||||
{
|
||||
if(track == 0)
|
||||
{
|
||||
buff->lsn = m_block.count;
|
||||
}
|
||||
else
|
||||
{
|
||||
buff->type = CDVD_MODE1_TRACK;
|
||||
buff->lsn = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CDVD s_cdvd;
|
||||
|
||||
//
|
||||
|
||||
EXPORT_C_(UINT32) CDVDinit()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C CDVDshutdown()
|
||||
{
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDopen(const char* title)
|
||||
{
|
||||
CString path;
|
||||
|
||||
int i = AfxGetApp()->GetProfileInt(_T("Settings"), _T("drive"), -1);
|
||||
|
||||
if(i >= 'A' && i <= 'Z')
|
||||
{
|
||||
path.Format(_T("\\\\.\\%c:"), i);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = AfxGetApp()->GetProfileString(_T("Settings"), _T("iso"), _T(""));
|
||||
}
|
||||
|
||||
return s_cdvd.Open(path) ? 0 : -1;
|
||||
}
|
||||
|
||||
EXPORT_C CDVDclose()
|
||||
{
|
||||
s_cdvd.Close();
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDreadTrack(int lsn, int mode)
|
||||
{
|
||||
return s_cdvd.Read(lsn, mode) ? 0 : -1;
|
||||
}
|
||||
|
||||
EXPORT_C_(BYTE*) CDVDgetBuffer()
|
||||
{
|
||||
return s_cdvd.GetBuffer();
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDreadSubQ(UINT32 lsn, cdvdSubQ* subq)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDgetTN(cdvdTN* buff)
|
||||
{
|
||||
return s_cdvd.GetTN(buff);
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDgetTD(BYTE track, cdvdTD* buff)
|
||||
{
|
||||
return s_cdvd.GetTD(track, buff);
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDgetTOC(void* toc)
|
||||
{
|
||||
return -1; // TODO
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDgetDiskType()
|
||||
{
|
||||
return CDVD_TYPE_PS2DVD; // TODO
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDgetTrayStatus()
|
||||
{
|
||||
return CDVD_TRAY_CLOSE;
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDctrlTrayOpen()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDctrlTrayClose()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C CDVDconfigure()
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
CSettingsDlg dlg;
|
||||
|
||||
if(IDOK == dlg.DoModal())
|
||||
{
|
||||
CDVDshutdown();
|
||||
CDVDinit();
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_C CDVDabout()
|
||||
{
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) CDVDtest()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
; cdvd.def : Declares the module parameters for the DLL.
|
||||
|
||||
LIBRARY "cdvd"
|
||||
|
||||
EXPORTS
|
||||
; Explicit exports can go here
|
||||
PS2EgetLibType
|
||||
PS2EgetLibName
|
||||
PS2EgetLibVersion2
|
||||
CDVDinit
|
||||
CDVDshutdown
|
||||
CDVDopen
|
||||
CDVDclose
|
||||
CDVDreadTrack
|
||||
CDVDgetBuffer
|
||||
CDVDreadSubQ
|
||||
CDVDgetTN
|
||||
CDVDgetTD
|
||||
CDVDgetTOC
|
||||
CDVDgetDiskType
|
||||
CDVDgetTrayStatus
|
||||
CDVDctrlTrayOpen
|
||||
CDVDctrlTrayClose
|
||||
CDVDconfigure
|
||||
CDVDtest
|
||||
CDVDabout
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2007 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __AFXWIN_H__
|
||||
#error include 'stdafx.h' before including this file for PCH
|
||||
#endif
|
||||
|
||||
class cdvdApp : public CWinApp
|
||||
{
|
||||
public:
|
||||
cdvdApp();
|
||||
|
||||
public:
|
||||
virtual BOOL InitInstance();
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct cdvdSubQ
|
||||
{
|
||||
BYTE ctrl:4; // control and mode bits
|
||||
BYTE mode:4; // control and mode bits
|
||||
BYTE trackNum; // current track number (1 to 99)
|
||||
BYTE trackIndex; // current index within track (0 to 99)
|
||||
BYTE trackM; // current minute location on the disc (BCD encoded)
|
||||
BYTE trackS; // current sector location on the disc (BCD encoded)
|
||||
BYTE trackF; // current frame location on the disc (BCD encoded)
|
||||
BYTE pad; // unused
|
||||
BYTE discM; // current minute offset from first track (BCD encoded)
|
||||
BYTE discS; // current sector offset from first track (BCD encoded)
|
||||
BYTE discF; // current frame offset from first track (BCD encoded)
|
||||
};
|
||||
|
||||
struct cdvdTD // NOT bcd coded
|
||||
{
|
||||
UINT32 lsn;
|
||||
BYTE type;
|
||||
};
|
||||
|
||||
struct cdvdTN
|
||||
{
|
||||
BYTE strack; // number of the first track (usually 1)
|
||||
BYTE etrack; // number of the last track
|
||||
};
|
||||
|
||||
// CDVDreadTrack mode values:
|
||||
|
||||
#define CDVD_MODE_2352 0 // full 2352 bytes
|
||||
#define CDVD_MODE_2340 1 // skip sync (12) bytes
|
||||
#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes
|
||||
#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes
|
||||
#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq
|
||||
|
||||
// CDVDgetDiskType returns:
|
||||
|
||||
#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc
|
||||
#define CDVD_TYPE_DVDV 0xfe // DVD Video
|
||||
#define CDVD_TYPE_CDDA 0xfd // Audio CD
|
||||
#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD
|
||||
#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio)
|
||||
#define CDVD_TYPE_PS2CD 0x12 // PS2 CD
|
||||
#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio)
|
||||
#define CDVD_TYPE_PSCD 0x10 // PS CD
|
||||
#define CDVD_TYPE_UNKNOWN 0x05 // Unknown
|
||||
#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided
|
||||
#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided
|
||||
#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd
|
||||
#define CDVD_TYPE_DETCT 0x01 // Detecting
|
||||
#define CDVD_TYPE_NODISC 0x00 // No Disc
|
||||
|
||||
// CDVDgetTrayStatus returns:
|
||||
|
||||
#define CDVD_TRAY_CLOSE 0x00
|
||||
#define CDVD_TRAY_OPEN 0x01
|
||||
|
||||
// cdvdTD.type (track types for cds)
|
||||
|
||||
#define CDVD_AUDIO_TRACK 0x01
|
||||
#define CDVD_MODE1_TRACK 0x41
|
||||
#define CDVD_MODE2_TRACK 0x61
|
||||
|
||||
#define CDVD_AUDIO_MASK 0x00
|
||||
#define CDVD_DATA_MASK 0x40
|
||||
// CDROM_DATA_TRACK 0x04 // do not enable this! (from linux kernel)
|
||||
|
||||
//
|
||||
|
||||
#define CACHE_BLOCK_COUNT 16
|
||||
|
||||
class CDVD
|
||||
{
|
||||
HANDLE m_hFile;
|
||||
CString m_label;
|
||||
OVERLAPPED m_overlapped;
|
||||
struct {int count, size, offset;} m_block;
|
||||
struct {BYTE buff[2048 * CACHE_BLOCK_COUNT]; bool pending; int start, count;} m_cache;
|
||||
BYTE m_buff[2352];
|
||||
|
||||
LARGE_INTEGER MakeOffset(int lsn);
|
||||
bool SyncRead(int lsn);
|
||||
|
||||
public:
|
||||
CDVD();
|
||||
virtual ~CDVD();
|
||||
|
||||
bool Open(CString path);
|
||||
void Close();
|
||||
CString GetLabel();
|
||||
bool Read(int lsn, int mode = CDVD_MODE_2048);
|
||||
BYTE* GetBuffer();
|
||||
UINT32 GetTN(cdvdTN* buff);
|
||||
UINT32 GetTD(BYTE track, cdvdTD* buff);
|
||||
};
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Hungarian resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_HUN)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
|
||||
#pragma code_page(1250)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#define _AFX_NO_SPLITTER_RESOURCES\r\n"
|
||||
"#define _AFX_NO_OLE_RESOURCES\r\n"
|
||||
"#define _AFX_NO_TRACKER_RESOURCES\r\n"
|
||||
"#define _AFX_NO_PROPERTY_RESOURCES\r\n"
|
||||
"\r\n"
|
||||
"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
|
||||
"LANGUAGE 9, 1\r\n"
|
||||
"#pragma code_page(1252)\r\n"
|
||||
"#include ""res\\cdvd.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
|
||||
"#include ""afxres.rc"" // Standard components\r\n"
|
||||
"#endif\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // Hungarian resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,0
|
||||
PRODUCTVERSION 1,0,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904e4"
|
||||
BEGIN
|
||||
VALUE "Comments", "http://guliverkli.sf.net/"
|
||||
VALUE "CompanyName", "Gabest"
|
||||
VALUE "FileDescription", "CDVD plugin for ps2 emulators"
|
||||
VALUE "FileVersion", "1, 0, 0, 0"
|
||||
VALUE "InternalName", "xpad.dll"
|
||||
VALUE "LegalCopyright", "Copyright (c) 2007-2008 Gabest. All rights reserved."
|
||||
VALUE "OriginalFilename", "cdvd.dll"
|
||||
VALUE "ProductName", "cdvd"
|
||||
VALUE "ProductVersion", "1, 0, 0, 0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_CONFIG DIALOGEX 0, 0, 211, 71
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Settings..."
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
COMBOBOX IDC_COMBO1,7,7,197,85,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP
|
||||
EDITTEXT IDC_EDIT1,7,24,143,14,ES_AUTOHSCROLL | ES_READONLY
|
||||
PUSHBUTTON "Browse...",IDC_BUTTON1,154,24,50,14
|
||||
DEFPUSHBUTTON "OK",IDOK,53,50,50,14
|
||||
PUSHBUTTON "Cancel",IDCANCEL,107,50,50,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_CONFIG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 204
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 64
|
||||
HORZGUIDE, 13
|
||||
HORZGUIDE, 31
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
#define _AFX_NO_SPLITTER_RESOURCES
|
||||
#define _AFX_NO_OLE_RESOURCES
|
||||
#define _AFX_NO_TRACKER_RESOURCES
|
||||
#define _AFX_NO_PROPERTY_RESOURCES
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE 9, 1
|
||||
#pragma code_page(1252)
|
||||
#include "res\cdvd.rc2" // non-Microsoft Visual C++ edited resources
|
||||
#include "afxres.rc" // Standard components
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// cdvd.RC2 - resources Microsoft Visual C++ does not edit directly
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#error this file is not editable by Microsoft Visual C++
|
||||
#endif //APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Add manually edited resources here...
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,20 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by cdvd.rc
|
||||
//
|
||||
#define IDC_COMBO1 2000
|
||||
#define IDC_RADIO1 2001
|
||||
#define IDC_EDIT1 2003
|
||||
#define IDC_BUTTON1 2004
|
||||
#define IDD_CONFIG 10000
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 10001
|
||||
#define _APS_NEXT_COMMAND_VALUE 32768
|
||||
#define _APS_NEXT_CONTROL_VALUE 2005
|
||||
#define _APS_NEXT_SYMED_VALUE 5000
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// xpad.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
|
@ -0,0 +1,63 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma warning(disable: 4996)
|
||||
|
||||
#ifndef VC_EXTRALEAN
|
||||
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
|
||||
#endif
|
||||
|
||||
// Modify the following defines if you have to target a platform prior to the ones specified below.
|
||||
// Refer to MSDN for the latest info on corresponding values for different platforms.
|
||||
#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later.
|
||||
#define WINVER 0x0510 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later.
|
||||
#define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 2000 or later.
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later.
|
||||
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later.
|
||||
#define _WIN32_IE 0x0400 // Change this to the appropriate value to target IE 5.0 or later.
|
||||
#endif
|
||||
|
||||
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
|
||||
|
||||
#include <afxwin.h> // MFC core and standard components
|
||||
//#include <afxext.h> // MFC extensions
|
||||
#ifndef _AFX_NO_AFXCMN_SUPPORT
|
||||
#include <afxcmn.h> // MFC support for Windows Common Controls
|
||||
#endif // _AFX_NO_AFXCMN_SUPPORT
|
||||
//#include <afxmt.h>
|
||||
#include <atlbase.h>
|
||||
#include <atlcoll.h>
|
||||
#include <atlpath.h>
|
||||
#include <math.h>
|
||||
|
||||
#define countof(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
#define EXPORT_C extern "C" __declspec(dllexport) void __stdcall
|
||||
#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall
|
||||
|
||||
#ifndef RESTRICT
|
||||
#ifdef __INTEL_COMPILER
|
||||
#define RESTRICT restrict
|
||||
#elif _MSC_VER >= 1400
|
||||
#define RESTRICT __restrict
|
||||
#else
|
||||
#define RESTRICT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#pragma warning(disable : 4995 4324 4100)
|
||||
|
||||
#ifdef _M_SSE
|
||||
#error No SSE please!
|
||||
#endif
|
|
@ -0,0 +1,2 @@
|
|||
#define SVN_REV $WCREV$
|
||||
#define SVN_MODS $WCMODS?1:0$
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="windows-1250"?>
|
||||
<VisualStudioPropertySheet
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="common"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;_WINDOWS;_WIN32_WINNT=0x500"
|
||||
FloatingPointModel="2"
|
||||
RuntimeTypeInfo="false"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
DisableSpecificWarnings="4995;4324"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="d3d10.lib d3dx10.lib d3d9.lib d3dx9.lib ddraw.lib dxguid.lib winmm.lib strmiids.lib xinput.lib"
|
||||
OutputFile="..\..\..\bin\plugins\$(ProjectName).dll"
|
||||
DelayLoadDLLs="d3d9.dll;d3dx9_40.dll;d3d10.dll;d3dx10_40.dll"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
RandomizedBaseAddress="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
CommandLine="SubWCRev.exe $(ProjectDir) $(ProjectDir)svnrev_template.h $(ProjectDir)svnrev.h"
|
||||
/>
|
||||
</VisualStudioPropertySheet>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="windows-1250"?>
|
||||
<VisualStudioPropertySheet
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="debug"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="_DEBUG"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="1"
|
||||
RuntimeLibrary="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
/>
|
||||
</VisualStudioPropertySheet>
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="windows-1250"?>
|
||||
<VisualStudioPropertySheet
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="release"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
WholeProgramOptimization="true"
|
||||
PreprocessorDefinitions="NDEBUG"
|
||||
StringPooling="true"
|
||||
BufferSecurityCheck="false"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
/>
|
||||
</VisualStudioPropertySheet>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="windows-1250"?>
|
||||
<VisualStudioPropertySheet
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="sse2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
PreprocessorDefinitions="_M_SSE=0x200"
|
||||
/>
|
||||
</VisualStudioPropertySheet>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="windows-1250"?>
|
||||
<VisualStudioPropertySheet
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="sse4"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="_M_SSE=0x401"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
/>
|
||||
</VisualStudioPropertySheet>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="windows-1250"?>
|
||||
<VisualStudioPropertySheet
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="sse3"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
PreprocessorDefinitions="_M_SSE=0x301"
|
||||
/>
|
||||
</VisualStudioPropertySheet>
|
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
* 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 "GPURendererSW.h"
|
||||
#include "GSDevice7.h"
|
||||
#include "GSDevice9.h"
|
||||
#include "GSDevice10.h"
|
||||
#include "GPUSettingsDlg.h"
|
||||
|
||||
#define PSE_LT_GPU 2
|
||||
|
||||
static HRESULT s_hr = E_FAIL;
|
||||
static GPURendererBase* s_gpu = NULL;
|
||||
|
||||
EXPORT_C_(UINT32) PSEgetLibType()
|
||||
{
|
||||
return PSE_LT_GPU;
|
||||
}
|
||||
|
||||
EXPORT_C_(char*) PSEgetLibName()
|
||||
{
|
||||
return GSUtil::GetLibName();
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) PSEgetLibVersion()
|
||||
{
|
||||
static const UINT32 version = 1;
|
||||
static const UINT32 revision = 1;
|
||||
|
||||
return version << 16 | revision << 8 | PLUGIN_VERSION;
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GPUinit()
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
// TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GPUshutdown()
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
// TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GPUclose()
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
delete s_gpu;
|
||||
|
||||
s_gpu = NULL;
|
||||
|
||||
if(SUCCEEDED(s_hr))
|
||||
{
|
||||
::CoUninitialize();
|
||||
|
||||
s_hr = E_FAIL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GPUopen(HWND hWnd)
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
if(!GSUtil::CheckDirectX() || !GSUtil::CheckSSE())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
GPUclose();
|
||||
|
||||
GPURendererSettings rs;
|
||||
|
||||
rs.m_filter = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("filter"), 0);
|
||||
rs.m_dither = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("dithering"), 1);
|
||||
rs.m_aspectratio = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("AspectRatio"), 1);
|
||||
rs.m_vsync = !!AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("vsync"), FALSE);
|
||||
rs.m_scale.cx = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("scale_x"), 0);
|
||||
rs.m_scale.cy = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("scale_y"), 0);
|
||||
|
||||
int threads = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("swthreads"), 1);
|
||||
|
||||
int renderer = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("Renderer"), 1);
|
||||
|
||||
switch(renderer)
|
||||
{
|
||||
default:
|
||||
case 0: s_gpu = new GPURendererSW<GSDevice7>(rs, threads); break;
|
||||
case 1: s_gpu = new GPURendererSW<GSDevice9>(rs, threads); break;
|
||||
case 2: s_gpu = new GPURendererSW<GSDevice10>(rs, threads); break;
|
||||
// TODO: case 3: s_gpu = new GPURendererNull<GSDeviceNull>(rs, threads); break;
|
||||
}
|
||||
|
||||
s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
|
||||
if(!s_gpu->Create(hWnd))
|
||||
{
|
||||
GPUclose();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GPUconfigure()
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
GPUSettingsDlg dlg;
|
||||
|
||||
if(IDOK == dlg.DoModal())
|
||||
{
|
||||
GPUshutdown();
|
||||
GPUinit();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GPUtest()
|
||||
{
|
||||
// TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C GPUabout()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
EXPORT_C GPUwriteDataMem(const BYTE* mem, UINT32 size)
|
||||
{
|
||||
s_gpu->WriteData(mem, size);
|
||||
}
|
||||
|
||||
EXPORT_C GPUwriteData(UINT32 data)
|
||||
{
|
||||
s_gpu->WriteData((BYTE*)&data, 1);
|
||||
}
|
||||
|
||||
EXPORT_C GPUreadDataMem(BYTE* mem, UINT32 size)
|
||||
{
|
||||
s_gpu->ReadData(mem, size);
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) GPUreadData()
|
||||
{
|
||||
UINT32 data = 0;
|
||||
|
||||
s_gpu->ReadData((BYTE*)&data, 1);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
EXPORT_C GPUwriteStatus(UINT32 status)
|
||||
{
|
||||
s_gpu->WriteStatus(status);
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) GPUreadStatus()
|
||||
{
|
||||
return s_gpu->ReadStatus();
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) GPUdmaChain(const BYTE* mem, UINT32 addr)
|
||||
{
|
||||
// TODO
|
||||
|
||||
UINT32 last[3];
|
||||
|
||||
memset(last, 0xff, sizeof(last));
|
||||
|
||||
do
|
||||
{
|
||||
if(addr == last[1] || addr == last[2]) break;
|
||||
(addr < last[0] ? last[1] : last[2]) = addr;
|
||||
last[0] = addr;
|
||||
|
||||
BYTE size = mem[addr + 3];
|
||||
|
||||
if(size > 0)
|
||||
{
|
||||
s_gpu->WriteData(&mem[addr + 4], size);
|
||||
}
|
||||
|
||||
addr = *(UINT32*)&mem[addr] & 0xffffff;
|
||||
}
|
||||
while(addr != 0xffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) GPUgetMode()
|
||||
{
|
||||
// TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C GPUsetMode(UINT32)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
EXPORT_C GPUupdateLace()
|
||||
{
|
||||
s_gpu->VSync();
|
||||
}
|
||||
|
||||
EXPORT_C GPUmakeSnapshot()
|
||||
{
|
||||
LPCTSTR path = _T("C:\\"); // TODO
|
||||
|
||||
s_gpu->MakeSnapshot(path);
|
||||
}
|
||||
|
||||
EXPORT_C GPUdisplayText(char* text)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
EXPORT_C GPUdisplayFlags(UINT32 flags)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GPUfreeze(UINT32 type, GPUFreezeData* data)
|
||||
{
|
||||
if(!data || data->version != 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(type == 0)
|
||||
{
|
||||
s_gpu->Defrost(data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if(type == 1)
|
||||
{
|
||||
s_gpu->Freeze(data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if(type == 2)
|
||||
{
|
||||
int slot = *(int*)data + 1;
|
||||
|
||||
if(slot < 1 || slot > 9)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C GPUgetScreenPic(BYTE* mem)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
EXPORT_C GPUshowScreenPic(BYTE* mem)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
EXPORT_C GPUcursor(int player, int x, int y)
|
||||
{
|
||||
// TODO
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#include "GS.h"
|
||||
|
||||
enum
|
||||
{
|
||||
GPU_POLYGON = 1,
|
||||
GPU_LINE = 2,
|
||||
GPU_SPRITE = 3,
|
||||
};
|
||||
|
||||
REG32_(GPUReg, STATUS)
|
||||
UINT32 TX:4;
|
||||
UINT32 TY:1;
|
||||
UINT32 ABR:2;
|
||||
UINT32 TP:2;
|
||||
UINT32 DTD:1;
|
||||
UINT32 DFE:1;
|
||||
UINT32 MD:1;
|
||||
UINT32 ME:1;
|
||||
UINT32 _PAD0:3;
|
||||
UINT32 WIDTH1:1;
|
||||
UINT32 WIDTH0:2;
|
||||
UINT32 HEIGHT:1;
|
||||
UINT32 ISPAL:1;
|
||||
UINT32 ISRGB24:1;
|
||||
UINT32 ISINTER:1;
|
||||
UINT32 DEN:1;
|
||||
UINT32 _PAD1:2;
|
||||
UINT32 IDLE:1;
|
||||
UINT32 IMG:1;
|
||||
UINT32 COM:1;
|
||||
UINT32 DMA:2;
|
||||
UINT32 LCF:1;
|
||||
/*
|
||||
UINT32 TX:4;
|
||||
UINT32 TY:1;
|
||||
UINT32 ABR:2;
|
||||
UINT32 TP:2;
|
||||
UINT32 DTD:1;
|
||||
UINT32 DFE:1;
|
||||
UINT32 PBW:1;
|
||||
UINT32 PBC:1;
|
||||
UINT32 _PAD0:3;
|
||||
UINT32 HRES2:1;
|
||||
UINT32 HRES1:2;
|
||||
UINT32 VRES:1;
|
||||
UINT32 ISPAL:1;
|
||||
UINT32 ISRGB24:1;
|
||||
UINT32 ISINTER:1;
|
||||
UINT32 ISSTOP:1;
|
||||
UINT32 _PAD1:1;
|
||||
UINT32 DMARDY:1;
|
||||
UINT32 IDIDLE:1;
|
||||
UINT32 DATARDY:1;
|
||||
UINT32 ISEMPTY:1;
|
||||
UINT32 TMODE:2;
|
||||
UINT32 ODE:1;
|
||||
*/
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, PACKET)
|
||||
UINT32 _PAD:24;
|
||||
UINT32 OPTION:5;
|
||||
UINT32 TYPE:3;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, PRIM)
|
||||
UINT32 VTX:24;
|
||||
UINT32 TGE:1;
|
||||
UINT32 ABE:1;
|
||||
UINT32 TME:1;
|
||||
UINT32 _PAD2:1;
|
||||
UINT32 IIP:1;
|
||||
UINT32 TYPE:3;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, POLYGON)
|
||||
UINT32 _PAD:24;
|
||||
UINT32 TGE:1;
|
||||
UINT32 ABE:1;
|
||||
UINT32 TME:1;
|
||||
UINT32 VTX:1;
|
||||
UINT32 IIP:1;
|
||||
UINT32 TYPE:3;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, LINE)
|
||||
UINT32 _PAD:24;
|
||||
UINT32 ZERO1:1;
|
||||
UINT32 ABE:1;
|
||||
UINT32 ZERO2:1;
|
||||
UINT32 PLL:1;
|
||||
UINT32 IIP:1;
|
||||
UINT32 TYPE:3;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, SPRITE)
|
||||
UINT32 _PAD:24;
|
||||
UINT32 ZERO:1;
|
||||
UINT32 ABE:1;
|
||||
UINT32 TME:1;
|
||||
UINT32 SIZE:2;
|
||||
UINT32 TYPE:3;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, RESET)
|
||||
UINT32 _PAD:32;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, DEN)
|
||||
UINT32 DEN:1;
|
||||
UINT32 _PAD:31;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, DMA)
|
||||
UINT32 DMA:2;
|
||||
UINT32 _PAD:30;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, DAREA)
|
||||
UINT32 X:10;
|
||||
UINT32 Y:9;
|
||||
UINT32 _PAD:13;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, DHRANGE)
|
||||
UINT32 X1:12;
|
||||
UINT32 X2:12;
|
||||
UINT32 _PAD:8;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, DVRANGE)
|
||||
UINT32 Y1:10;
|
||||
UINT32 Y2:11;
|
||||
UINT32 _PAD:11;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, DMODE)
|
||||
UINT32 WIDTH0:2;
|
||||
UINT32 HEIGHT:1;
|
||||
UINT32 ISPAL:1;
|
||||
UINT32 ISRGB24:1;
|
||||
UINT32 ISINTER:1;
|
||||
UINT32 WIDTH1:1;
|
||||
UINT32 REVERSE:1;
|
||||
UINT32 _PAD:24;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, GPUINFO)
|
||||
UINT32 PARAM:24;
|
||||
UINT32 _PAD:8;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, MODE)
|
||||
UINT32 TX:4;
|
||||
UINT32 TY:1;
|
||||
UINT32 ABR:2;
|
||||
UINT32 TP:2;
|
||||
UINT32 DTD:1;
|
||||
UINT32 DFE:1;
|
||||
UINT32 _PAD:21;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, MASK)
|
||||
UINT32 MD:1;
|
||||
UINT32 ME:1;
|
||||
UINT32 _PAD:30;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, DRAREA)
|
||||
UINT32 X:10;
|
||||
UINT32 Y:10;
|
||||
UINT32 _PAD:12;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, DROFF)
|
||||
INT32 X:11;
|
||||
INT32 Y:11;
|
||||
INT32 _PAD:10;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, RGB)
|
||||
UINT32 R:8;
|
||||
UINT32 G:8;
|
||||
UINT32 B:8;
|
||||
UINT32 _PAD:8;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, XY)
|
||||
INT32 X:11;
|
||||
INT32 _PAD1:5;
|
||||
INT32 Y:11;
|
||||
INT32 _PAD2:5;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, UV)
|
||||
UINT32 U:8;
|
||||
UINT32 V:8;
|
||||
UINT32 _PAD:16;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, TWIN)
|
||||
UINT32 TWW:5;
|
||||
UINT32 TWH:5;
|
||||
UINT32 TWX:5;
|
||||
UINT32 TWY:5;
|
||||
UINT32 _PAD:12;
|
||||
REG_END
|
||||
|
||||
REG32_(GPUReg, CLUT)
|
||||
UINT32 _PAD1:16;
|
||||
UINT32 X:6;
|
||||
UINT32 Y:9;
|
||||
UINT32 _PAD2:1;
|
||||
REG_END
|
||||
|
||||
REG32_SET(GPUReg)
|
||||
GPURegSTATUS STATUS;
|
||||
GPURegPACKET PACKET;
|
||||
GPURegPRIM PRIM;
|
||||
GPURegPOLYGON POLYGON;
|
||||
GPURegLINE LINE;
|
||||
GPURegSPRITE SPRITE;
|
||||
GPURegRESET RESET;
|
||||
GPURegDEN DEN;
|
||||
GPURegDMA DMA;
|
||||
GPURegDAREA DAREA;
|
||||
GPURegDHRANGE DHRANGE;
|
||||
GPURegDVRANGE DVRANGE;
|
||||
GPURegDMODE DMODE;
|
||||
GPURegGPUINFO GPUINFO;
|
||||
GPURegMODE MODE;
|
||||
GPURegMASK MASK;
|
||||
GPURegDRAREA DRAREA;
|
||||
GPURegDROFF DROFF;
|
||||
GPURegRGB RGB;
|
||||
GPURegXY XY;
|
||||
GPURegUV UV;
|
||||
GPURegTWIN TWIN;
|
||||
GPURegCLUT CLUT;
|
||||
REG_SET_END
|
||||
|
||||
struct GPUFreezeData
|
||||
{
|
||||
UINT32 version; // == 1
|
||||
UINT32 status;
|
||||
UINT32 control[256];
|
||||
UINT16 vram[1024 * 1024];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
|
@ -0,0 +1,910 @@
|
|||
/*
|
||||
* 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 "GPUDrawScanline.h"
|
||||
|
||||
GPUDrawScanline::GPUDrawScanline(GPUState* state, int id)
|
||||
: m_state(state)
|
||||
, m_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
GPUDrawScanline::~GPUDrawScanline()
|
||||
{
|
||||
}
|
||||
|
||||
void GPUDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f)
|
||||
{
|
||||
GPUDrawingEnvironment& env = m_state->m_env;
|
||||
|
||||
const GPUScanlineParam* p = (const GPUScanlineParam*)data->param;
|
||||
|
||||
m_env.sel = p->sel;
|
||||
|
||||
m_env.mem = &m_state->m_mem;
|
||||
|
||||
if(m_env.sel.tme)
|
||||
{
|
||||
m_env.tex = p->tex;
|
||||
m_env.clut = p->clut;
|
||||
|
||||
if(m_env.sel.twin)
|
||||
{
|
||||
DWORD u, v;
|
||||
|
||||
u = ~(env.TWIN.TWW << 3) & 0xff;
|
||||
v = ~(env.TWIN.TWH << 3) & 0xff;
|
||||
|
||||
m_env.u[0] = GSVector4i((u << 16) | u);
|
||||
m_env.v[0] = GSVector4i((v << 16) | v);
|
||||
|
||||
u = env.TWIN.TWX << 3;
|
||||
v = env.TWIN.TWY << 3;
|
||||
|
||||
m_env.u[1] = GSVector4i((u << 16) | u) & ~m_env.u[0];
|
||||
m_env.v[1] = GSVector4i((v << 16) | v) & ~m_env.v[0];
|
||||
}
|
||||
}
|
||||
|
||||
m_env.a = GSVector4i(env.PRIM.ABE ? 0xffffffff : 0);
|
||||
m_env.md = GSVector4i(env.STATUS.MD ? 0x80008000 : 0);
|
||||
|
||||
f->sl = m_ds.Lookup(m_env.sel);
|
||||
|
||||
f->sr = NULL; // TODO
|
||||
|
||||
DWORD sel = 0;
|
||||
|
||||
sel |= (data->primclass == GS_SPRITE_CLASS ? 1 : 0) << 0;
|
||||
sel |= m_env.sel.tme << 1;
|
||||
sel |= m_env.sel.iip << 2;
|
||||
|
||||
f->sp = m_sp.Lookup(sel);
|
||||
}
|
||||
|
||||
template<DWORD sprite, DWORD tme, DWORD iip>
|
||||
void GPUDrawScanline::SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan)
|
||||
{
|
||||
if(m_env.sel.tme && !m_env.sel.twin)
|
||||
{
|
||||
if(sprite)
|
||||
{
|
||||
GSVector4i t;
|
||||
|
||||
t = (GSVector4i(vertices[1].t) >> 8) - GSVector4i::x00000001();
|
||||
t = t.ps32(t);
|
||||
t = t.upl16(t);
|
||||
|
||||
m_env.u[2] = t.xxxx();
|
||||
m_env.v[2] = t.yyyy();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_env.u[2] = GSVector4i::x00ff();
|
||||
m_env.v[2] = GSVector4i::x00ff();
|
||||
}
|
||||
}
|
||||
|
||||
GSVector4 ps0123 = GSVector4::ps0123();
|
||||
GSVector4 ps4567 = GSVector4::ps4567();
|
||||
|
||||
GSVector4 dt = dscan.t;
|
||||
GSVector4 dc = dscan.c;
|
||||
|
||||
GSVector4i dtc8 = GSVector4i(dt * 8.0f).ps32(GSVector4i(dc * 8.0f));
|
||||
|
||||
if(tme)
|
||||
{
|
||||
m_env.dst8 = dtc8.upl16(dtc8);
|
||||
|
||||
m_env.ds = GSVector4i(dt.xxxx() * ps0123).ps32(GSVector4i(dt.xxxx() * ps4567));
|
||||
m_env.dt = GSVector4i(dt.yyyy() * ps0123).ps32(GSVector4i(dt.yyyy() * ps4567));
|
||||
}
|
||||
|
||||
if(iip)
|
||||
{
|
||||
m_env.dc8 = dtc8.uph16(dtc8);
|
||||
|
||||
m_env.dr = GSVector4i(dc.xxxx() * ps0123).ps32(GSVector4i(dc.xxxx() * ps4567));
|
||||
m_env.dg = GSVector4i(dc.yyyy() * ps0123).ps32(GSVector4i(dc.yyyy() * ps4567));
|
||||
m_env.db = GSVector4i(dc.zzzz() * ps0123).ps32(GSVector4i(dc.zzzz() * ps4567));
|
||||
}
|
||||
}
|
||||
void GPUDrawScanline::SampleTexture(DWORD ltf, DWORD tlu, DWORD twin, GSVector4i& test, const GSVector4i& s, const GSVector4i& t, GSVector4i* c)
|
||||
{
|
||||
const void* RESTRICT tex = m_env.tex;
|
||||
const WORD* RESTRICT clut = m_env.clut;
|
||||
|
||||
if(ltf)
|
||||
{
|
||||
GSVector4i u = s.sub16(GSVector4i(0x00200020)); // - 0.125f
|
||||
GSVector4i v = t.sub16(GSVector4i(0x00200020)); // - 0.125f
|
||||
|
||||
GSVector4i u0 = u.srl16(8);
|
||||
GSVector4i v0 = v.srl16(8);
|
||||
|
||||
GSVector4i u1 = u0.add16(GSVector4i::x0001());
|
||||
GSVector4i v1 = v0.add16(GSVector4i::x0001());
|
||||
|
||||
GSVector4i uf = (u & GSVector4i::x00ff()) << 7;
|
||||
GSVector4i vf = (v & GSVector4i::x00ff()) << 7;
|
||||
|
||||
if(twin)
|
||||
{
|
||||
u0 = (u0 & m_env.u[0]).add16(m_env.u[1]);
|
||||
v0 = (v0 & m_env.v[0]).add16(m_env.v[1]);
|
||||
u1 = (u1 & m_env.u[0]).add16(m_env.u[1]);
|
||||
v1 = (v1 & m_env.v[0]).add16(m_env.v[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
u0 = u0.min_i16(m_env.u[2]);
|
||||
v0 = v0.min_i16(m_env.v[2]);
|
||||
u1 = u1.min_i16(m_env.u[2]);
|
||||
v1 = v1.min_i16(m_env.v[2]);
|
||||
}
|
||||
|
||||
GSVector4i addr00 = v0.sll16(8) | u0;
|
||||
GSVector4i addr01 = v0.sll16(8) | u1;
|
||||
GSVector4i addr10 = v1.sll16(8) | u0;
|
||||
GSVector4i addr11 = v1.sll16(8) | u1;
|
||||
|
||||
GSVector4i c00, c01, c10, c11;
|
||||
|
||||
if(tlu)
|
||||
{
|
||||
c00 = addr00.gather16_16((const BYTE*)tex, clut);
|
||||
c01 = addr01.gather16_16((const BYTE*)tex, clut);
|
||||
c10 = addr10.gather16_16((const BYTE*)tex, clut);
|
||||
c11 = addr11.gather16_16((const BYTE*)tex, clut);
|
||||
}
|
||||
else
|
||||
{
|
||||
c00 = addr00.gather16_16((const WORD*)tex);
|
||||
c01 = addr01.gather16_16((const WORD*)tex);
|
||||
c10 = addr00.gather16_16((const WORD*)tex);
|
||||
c11 = addr01.gather16_16((const WORD*)tex);
|
||||
}
|
||||
|
||||
GSVector4i r00 = (c00 & 0x001f001f) << 3;
|
||||
GSVector4i r01 = (c01 & 0x001f001f) << 3;
|
||||
GSVector4i r10 = (c10 & 0x001f001f) << 3;
|
||||
GSVector4i r11 = (c11 & 0x001f001f) << 3;
|
||||
|
||||
r00 = r00.lerp16<0>(r01, uf);
|
||||
r10 = r10.lerp16<0>(r11, uf);
|
||||
c[0] = r00.lerp16<0>(r10, vf);
|
||||
|
||||
GSVector4i g00 = (c00 & 0x03e003e0) >> 2;
|
||||
GSVector4i g01 = (c01 & 0x03e003e0) >> 2;
|
||||
GSVector4i g10 = (c10 & 0x03e003e0) >> 2;
|
||||
GSVector4i g11 = (c11 & 0x03e003e0) >> 2;
|
||||
|
||||
g00 = g00.lerp16<0>(g01, uf);
|
||||
g10 = g10.lerp16<0>(g11, uf);
|
||||
c[1] = g00.lerp16<0>(g10, vf);
|
||||
|
||||
GSVector4i b00 = (c00 & 0x7c007c00) >> 7;
|
||||
GSVector4i b01 = (c01 & 0x7c007c00) >> 7;
|
||||
GSVector4i b10 = (c10 & 0x7c007c00) >> 7;
|
||||
GSVector4i b11 = (c11 & 0x7c007c00) >> 7;
|
||||
|
||||
b00 = b00.lerp16<0>(b01, uf);
|
||||
b10 = b10.lerp16<0>(b11, uf);
|
||||
c[2] = b00.lerp16<0>(b10, vf);
|
||||
|
||||
GSVector4i a00 = (c00 & 0x80008000) >> 8;
|
||||
GSVector4i a01 = (c01 & 0x80008000) >> 8;
|
||||
GSVector4i a10 = (c10 & 0x80008000) >> 8;
|
||||
GSVector4i a11 = (c11 & 0x80008000) >> 8;
|
||||
|
||||
a00 = a00.lerp16<0>(a01, uf);
|
||||
a10 = a10.lerp16<0>(a11, uf);
|
||||
c[3] = a00.lerp16<0>(a10, vf).gt16(GSVector4i::zero());
|
||||
|
||||
// mask out blank pixels (not perfect)
|
||||
|
||||
test |=
|
||||
c[0].eq16(GSVector4i::zero()) &
|
||||
c[1].eq16(GSVector4i::zero()) &
|
||||
c[2].eq16(GSVector4i::zero()) &
|
||||
c[3].eq16(GSVector4i::zero());
|
||||
}
|
||||
else
|
||||
{
|
||||
GSVector4i u = s.srl16(8);
|
||||
GSVector4i v = t.srl16(8);
|
||||
|
||||
if(twin)
|
||||
{
|
||||
u = (u & m_env.u[0]).add16(m_env.u[1]);
|
||||
v = (v & m_env.v[0]).add16(m_env.v[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = u.min_i16(m_env.u[2]);
|
||||
v = v.min_i16(m_env.v[2]);
|
||||
}
|
||||
|
||||
GSVector4i addr = v.sll16(8) | u;
|
||||
|
||||
GSVector4i c00;
|
||||
|
||||
if(tlu)
|
||||
{
|
||||
c00 = addr.gather16_16((const BYTE*)tex, clut);
|
||||
}
|
||||
else
|
||||
{
|
||||
c00 = addr.gather16_16((const WORD*)tex);
|
||||
}
|
||||
|
||||
test |= c00.eq16(GSVector4i::zero()); // mask out blank pixels
|
||||
|
||||
c[0] = (c00 & 0x001f001f) << 3;
|
||||
c[1] = (c00 & 0x03e003e0) >> 2;
|
||||
c[2] = (c00 & 0x7c007c00) >> 7;
|
||||
c[3] = c00.sra16(15);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUDrawScanline::ColorTFX(DWORD tfx, const GSVector4i& r, const GSVector4i& g, const GSVector4i& b, GSVector4i* c)
|
||||
{
|
||||
switch(tfx)
|
||||
{
|
||||
case 0: // none (tfx = 0)
|
||||
case 1: // none (tfx = tge)
|
||||
c[0] = r.srl16(7);
|
||||
c[1] = g.srl16(7);
|
||||
c[2] = b.srl16(7);
|
||||
break;
|
||||
case 2: // modulate (tfx = tme | tge)
|
||||
c[0] = c[0].modulate16<1>(r).clamp8();
|
||||
c[1] = c[1].modulate16<1>(g).clamp8();
|
||||
c[2] = c[2].modulate16<1>(b).clamp8();
|
||||
break;
|
||||
case 3: // decal (tfx = tme)
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUDrawScanline::AlphaBlend(UINT32 abr, UINT32 tme, const GSVector4i& d, GSVector4i* c)
|
||||
{
|
||||
GSVector4i r = (d & 0x001f001f) << 3;
|
||||
GSVector4i g = (d & 0x03e003e0) >> 2;
|
||||
GSVector4i b = (d & 0x7c007c00) >> 7;
|
||||
|
||||
switch(abr)
|
||||
{
|
||||
case 0:
|
||||
r = r.avg8(c[0]);
|
||||
g = g.avg8(c[0]);
|
||||
b = b.avg8(c[0]);
|
||||
break;
|
||||
case 1:
|
||||
r = r.addus8(c[0]);
|
||||
g = g.addus8(c[1]);
|
||||
b = b.addus8(c[2]);
|
||||
break;
|
||||
case 2:
|
||||
r = r.subus8(c[0]);
|
||||
g = g.subus8(c[1]);
|
||||
b = b.subus8(c[2]);
|
||||
break;
|
||||
case 3:
|
||||
r = r.addus8(c[0].srl16(2));
|
||||
g = g.addus8(c[1].srl16(2));
|
||||
b = b.addus8(c[2].srl16(2));
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
if(tme) // per pixel
|
||||
{
|
||||
c[0] = c[0].blend8(r, c[3]);
|
||||
c[1] = c[1].blend8(g, c[3]);
|
||||
c[2] = c[2].blend8(b, c[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
c[0] = r;
|
||||
c[1] = g;
|
||||
c[2] = b;
|
||||
c[3] = GSVector4i::zero();
|
||||
}
|
||||
}
|
||||
|
||||
void GPUDrawScanline::WriteFrame(WORD* RESTRICT fb, const GSVector4i& test, const GSVector4i* c, int pixels)
|
||||
{
|
||||
GSVector4i r = (c[0] & 0x00f800f8) >> 3;
|
||||
GSVector4i g = (c[1] & 0x00f800f8) << 2;
|
||||
GSVector4i b = (c[2] & 0x00f800f8) << 7;
|
||||
GSVector4i a = (c[3] & 0x00800080) << 8;
|
||||
|
||||
GSVector4i s = r | g | b | a | m_env.md;
|
||||
|
||||
int i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if(test.u16[i] == 0)
|
||||
{
|
||||
fb[i] = s.u16[i];
|
||||
}
|
||||
}
|
||||
while(++i < pixels);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
__declspec(align(16)) static WORD s_dither[4][16] =
|
||||
{
|
||||
{7, 0, 6, 1, 7, 0, 6, 1, 7, 0, 6, 1, 7, 0, 6, 1},
|
||||
{2, 5, 3, 4, 2, 5, 3, 4, 2, 5, 3, 4, 2, 5, 3, 4},
|
||||
{1, 6, 0, 7, 1, 6, 0, 7, 1, 6, 0, 7, 1, 6, 0, 7},
|
||||
{4, 3, 5, 2, 4, 3, 5, 2, 4, 3, 5, 2, 4, 3, 5, 2},
|
||||
};
|
||||
|
||||
void GPUDrawScanline::DrawScanline(int top, int left, int right, const GSVertexSW& v)
|
||||
{
|
||||
GSVector4i s, t;
|
||||
GSVector4i r, g, b;
|
||||
|
||||
if(m_env.sel.tme)
|
||||
{
|
||||
GSVector4i vt = GSVector4i(v.t).xxzzl();
|
||||
|
||||
s = vt.xxxx().add16(m_env.ds);
|
||||
t = vt.yyyy().add16(m_env.dt);
|
||||
}
|
||||
|
||||
GSVector4i vc = GSVector4i(v.c).xxzzlh();
|
||||
|
||||
r = vc.xxxx();
|
||||
g = vc.yyyy();
|
||||
b = vc.zzzz();
|
||||
|
||||
if(m_env.sel.iip)
|
||||
{
|
||||
r = r.add16(m_env.dr);
|
||||
g = g.add16(m_env.dg);
|
||||
b = b.add16(m_env.db);
|
||||
}
|
||||
|
||||
GSVector4i dither;
|
||||
|
||||
if(m_env.sel.dtd)
|
||||
{
|
||||
dither = GSVector4i::load<false>(&s_dither[top & 3][left & 3]);
|
||||
}
|
||||
|
||||
int steps = right - left;
|
||||
|
||||
WORD* fb = m_env.mem->GetPixelAddress(left, top);
|
||||
|
||||
while(1)
|
||||
{
|
||||
do
|
||||
{
|
||||
int pixels = GSVector4i::min_i16(steps, 8);
|
||||
|
||||
GSVector4i test = GSVector4i::zero();
|
||||
|
||||
GSVector4i d = GSVector4i::zero();
|
||||
|
||||
if(m_env.sel.rfb) // me | abe
|
||||
{
|
||||
d = GSVector4i::load<false>(fb);
|
||||
|
||||
if(m_env.sel.me)
|
||||
{
|
||||
test = d.sra16(15);
|
||||
|
||||
if(test.alltrue())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GSVector4i c[4];
|
||||
|
||||
if(m_env.sel.tme)
|
||||
{
|
||||
SampleTexture(m_env.sel.ltf, m_env.sel.tlu, m_env.sel.twin, test, s, t, c);
|
||||
}
|
||||
|
||||
ColorTFX(m_env.sel.tfx, r, g, b, c);
|
||||
|
||||
if(m_env.sel.abe)
|
||||
{
|
||||
AlphaBlend(m_env.sel.abr, m_env.sel.tme, d, c);
|
||||
}
|
||||
|
||||
if(m_env.sel.dtd)
|
||||
{
|
||||
c[0] = c[0].addus8(dither);
|
||||
c[1] = c[1].addus8(dither);
|
||||
c[2] = c[2].addus8(dither);
|
||||
}
|
||||
|
||||
WriteFrame(fb, test, c, pixels);
|
||||
}
|
||||
while(0);
|
||||
|
||||
if(steps <= 8) break;
|
||||
|
||||
steps -= 8;
|
||||
|
||||
fb += 8;
|
||||
|
||||
if(m_env.sel.tme)
|
||||
{
|
||||
GSVector4i dst8 = m_env.dst8;
|
||||
|
||||
s = s.add16(dst8.xxxx());
|
||||
t = t.add16(dst8.yyyy());
|
||||
}
|
||||
|
||||
if(m_env.sel.iip)
|
||||
{
|
||||
GSVector4i dc8 = m_env.dc8;
|
||||
|
||||
r = r.add16(dc8.xxxx());
|
||||
g = g.add16(dc8.yyyy());
|
||||
b = b.add16(dc8.zzzz());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<DWORD sel>
|
||||
void GPUDrawScanline::DrawScanlineEx(int top, int left, int right, const GSVertexSW& v)
|
||||
{
|
||||
DWORD iip = (sel >> 0) & 1;
|
||||
DWORD me = (sel >> 1) & 1;
|
||||
DWORD abe = (sel >> 2) & 1;
|
||||
DWORD abr = (sel >> 3) & 3;
|
||||
// DWORD tge = (sel >> 5) & 1;
|
||||
DWORD tme = (sel >> 6) & 1;
|
||||
DWORD twin = (sel >> 7) & 1;
|
||||
DWORD rfb = (sel >> 1) & 3;
|
||||
DWORD tfx = (sel >> 5) & 3;
|
||||
|
||||
GSVector4i s, t;
|
||||
GSVector4i r, g, b;
|
||||
|
||||
if(tme)
|
||||
{
|
||||
GSVector4i vt = GSVector4i(v.t).xxzzl();
|
||||
|
||||
s = vt.xxxx().add16(m_env.ds);
|
||||
t = vt.yyyy().add16(m_env.dt);
|
||||
}
|
||||
|
||||
GSVector4i vc = GSVector4i(v.c).xxzzlh();
|
||||
|
||||
r = vc.xxxx();
|
||||
g = vc.yyyy();
|
||||
b = vc.zzzz();
|
||||
|
||||
if(iip)
|
||||
{
|
||||
r = r.add16(m_env.dr);
|
||||
g = g.add16(m_env.dg);
|
||||
b = b.add16(m_env.db);
|
||||
}
|
||||
|
||||
GSVector4i dither;
|
||||
|
||||
if(m_env.sel.dtd)
|
||||
{
|
||||
dither = GSVector4i::load<false>(&s_dither[top & 3][left & 3]);
|
||||
}
|
||||
|
||||
int steps = right - left;
|
||||
|
||||
WORD* fb = m_env.mem->GetPixelAddress(left, top);
|
||||
|
||||
while(1)
|
||||
{
|
||||
do
|
||||
{
|
||||
int pixels = GSVector4i::min_i16(steps, 8);
|
||||
|
||||
GSVector4i test = GSVector4i::zero();
|
||||
|
||||
GSVector4i d = GSVector4i::zero();
|
||||
|
||||
if(rfb) // me | abe
|
||||
{
|
||||
d = GSVector4i::load<false>(fb);
|
||||
|
||||
if(me)
|
||||
{
|
||||
test = d.sra16(15);
|
||||
|
||||
if(test.alltrue())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GSVector4i c[4];
|
||||
|
||||
if(tme)
|
||||
{
|
||||
SampleTexture(m_env.sel.ltf, m_env.sel.tlu, twin, test, s, t, c);
|
||||
}
|
||||
|
||||
ColorTFX(tfx, r, g, b, c);
|
||||
|
||||
if(abe)
|
||||
{
|
||||
AlphaBlend(abr, tme, d, c);
|
||||
}
|
||||
|
||||
if(m_env.sel.dtd)
|
||||
{
|
||||
c[0] = c[0].addus8(dither);
|
||||
c[1] = c[1].addus8(dither);
|
||||
c[2] = c[2].addus8(dither);
|
||||
}
|
||||
|
||||
WriteFrame(fb, test, c, pixels);
|
||||
}
|
||||
while(0);
|
||||
|
||||
if(steps <= 8) break;
|
||||
|
||||
steps -= 8;
|
||||
|
||||
fb += 8;
|
||||
|
||||
if(tme)
|
||||
{
|
||||
GSVector4i dst8 = m_env.dst8;
|
||||
|
||||
s = s.add16(dst8.xxxx());
|
||||
t = t.add16(dst8.yyyy());
|
||||
}
|
||||
|
||||
if(iip)
|
||||
{
|
||||
GSVector4i dc8 = m_env.dc8;
|
||||
|
||||
r = r.add16(dc8.xxxx());
|
||||
g = g.add16(dc8.yyyy());
|
||||
b = b.add16(dc8.zzzz());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GPUDrawScanline::GPUDrawScanlineMap::GPUDrawScanlineMap()
|
||||
{
|
||||
for(int i = 0; i < countof(m_default); i++)
|
||||
{
|
||||
m_default[i] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanline;
|
||||
}
|
||||
|
||||
#ifdef FAST_DRAWSCANLINE
|
||||
|
||||
m_default[0x00] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x00>;
|
||||
m_default[0x01] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x01>;
|
||||
m_default[0x02] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x02>;
|
||||
m_default[0x03] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x03>;
|
||||
m_default[0x04] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x04>;
|
||||
m_default[0x05] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x05>;
|
||||
m_default[0x06] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x06>;
|
||||
m_default[0x07] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x07>;
|
||||
m_default[0x08] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x08>;
|
||||
m_default[0x09] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x09>;
|
||||
m_default[0x0a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0a>;
|
||||
m_default[0x0b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0b>;
|
||||
m_default[0x0c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0c>;
|
||||
m_default[0x0d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0d>;
|
||||
m_default[0x0e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0e>;
|
||||
m_default[0x0f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0f>;
|
||||
m_default[0x10] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x10>;
|
||||
m_default[0x11] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x11>;
|
||||
m_default[0x12] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x12>;
|
||||
m_default[0x13] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x13>;
|
||||
m_default[0x14] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x14>;
|
||||
m_default[0x15] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x15>;
|
||||
m_default[0x16] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x16>;
|
||||
m_default[0x17] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x17>;
|
||||
m_default[0x18] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x18>;
|
||||
m_default[0x19] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x19>;
|
||||
m_default[0x1a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1a>;
|
||||
m_default[0x1b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1b>;
|
||||
m_default[0x1c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1c>;
|
||||
m_default[0x1d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1d>;
|
||||
m_default[0x1e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1e>;
|
||||
m_default[0x1f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1f>;
|
||||
m_default[0x20] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x20>;
|
||||
m_default[0x21] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x21>;
|
||||
m_default[0x22] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x22>;
|
||||
m_default[0x23] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x23>;
|
||||
m_default[0x24] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x24>;
|
||||
m_default[0x25] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x25>;
|
||||
m_default[0x26] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x26>;
|
||||
m_default[0x27] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x27>;
|
||||
m_default[0x28] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x28>;
|
||||
m_default[0x29] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x29>;
|
||||
m_default[0x2a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2a>;
|
||||
m_default[0x2b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2b>;
|
||||
m_default[0x2c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2c>;
|
||||
m_default[0x2d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2d>;
|
||||
m_default[0x2e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2e>;
|
||||
m_default[0x2f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2f>;
|
||||
m_default[0x30] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x30>;
|
||||
m_default[0x31] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x31>;
|
||||
m_default[0x32] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x32>;
|
||||
m_default[0x33] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x33>;
|
||||
m_default[0x34] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x34>;
|
||||
m_default[0x35] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x35>;
|
||||
m_default[0x36] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x36>;
|
||||
m_default[0x37] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x37>;
|
||||
m_default[0x38] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x38>;
|
||||
m_default[0x39] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x39>;
|
||||
m_default[0x3a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3a>;
|
||||
m_default[0x3b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3b>;
|
||||
m_default[0x3c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3c>;
|
||||
m_default[0x3d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3d>;
|
||||
m_default[0x3e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3e>;
|
||||
m_default[0x3f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3f>;
|
||||
m_default[0x40] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x40>;
|
||||
m_default[0x41] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x41>;
|
||||
m_default[0x42] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x42>;
|
||||
m_default[0x43] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x43>;
|
||||
m_default[0x44] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x44>;
|
||||
m_default[0x45] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x45>;
|
||||
m_default[0x46] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x46>;
|
||||
m_default[0x47] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x47>;
|
||||
m_default[0x48] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x48>;
|
||||
m_default[0x49] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x49>;
|
||||
m_default[0x4a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4a>;
|
||||
m_default[0x4b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4b>;
|
||||
m_default[0x4c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4c>;
|
||||
m_default[0x4d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4d>;
|
||||
m_default[0x4e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4e>;
|
||||
m_default[0x4f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4f>;
|
||||
m_default[0x50] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x50>;
|
||||
m_default[0x51] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x51>;
|
||||
m_default[0x52] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x52>;
|
||||
m_default[0x53] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x53>;
|
||||
m_default[0x54] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x54>;
|
||||
m_default[0x55] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x55>;
|
||||
m_default[0x56] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x56>;
|
||||
m_default[0x57] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x57>;
|
||||
m_default[0x58] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x58>;
|
||||
m_default[0x59] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x59>;
|
||||
m_default[0x5a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5a>;
|
||||
m_default[0x5b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5b>;
|
||||
m_default[0x5c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5c>;
|
||||
m_default[0x5d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5d>;
|
||||
m_default[0x5e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5e>;
|
||||
m_default[0x5f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5f>;
|
||||
m_default[0x60] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x60>;
|
||||
m_default[0x61] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x61>;
|
||||
m_default[0x62] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x62>;
|
||||
m_default[0x63] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x63>;
|
||||
m_default[0x64] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x64>;
|
||||
m_default[0x65] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x65>;
|
||||
m_default[0x66] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x66>;
|
||||
m_default[0x67] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x67>;
|
||||
m_default[0x68] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x68>;
|
||||
m_default[0x69] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x69>;
|
||||
m_default[0x6a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6a>;
|
||||
m_default[0x6b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6b>;
|
||||
m_default[0x6c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6c>;
|
||||
m_default[0x6d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6d>;
|
||||
m_default[0x6e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6e>;
|
||||
m_default[0x6f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6f>;
|
||||
m_default[0x70] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x70>;
|
||||
m_default[0x71] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x71>;
|
||||
m_default[0x72] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x72>;
|
||||
m_default[0x73] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x73>;
|
||||
m_default[0x74] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x74>;
|
||||
m_default[0x75] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x75>;
|
||||
m_default[0x76] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x76>;
|
||||
m_default[0x77] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x77>;
|
||||
m_default[0x78] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x78>;
|
||||
m_default[0x79] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x79>;
|
||||
m_default[0x7a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7a>;
|
||||
m_default[0x7b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7b>;
|
||||
m_default[0x7c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7c>;
|
||||
m_default[0x7d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7d>;
|
||||
m_default[0x7e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7e>;
|
||||
m_default[0x7f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7f>;
|
||||
m_default[0x80] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x80>;
|
||||
m_default[0x81] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x81>;
|
||||
m_default[0x82] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x82>;
|
||||
m_default[0x83] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x83>;
|
||||
m_default[0x84] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x84>;
|
||||
m_default[0x85] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x85>;
|
||||
m_default[0x86] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x86>;
|
||||
m_default[0x87] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x87>;
|
||||
m_default[0x88] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x88>;
|
||||
m_default[0x89] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x89>;
|
||||
m_default[0x8a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8a>;
|
||||
m_default[0x8b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8b>;
|
||||
m_default[0x8c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8c>;
|
||||
m_default[0x8d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8d>;
|
||||
m_default[0x8e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8e>;
|
||||
m_default[0x8f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8f>;
|
||||
m_default[0x90] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x90>;
|
||||
m_default[0x91] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x91>;
|
||||
m_default[0x92] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x92>;
|
||||
m_default[0x93] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x93>;
|
||||
m_default[0x94] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x94>;
|
||||
m_default[0x95] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x95>;
|
||||
m_default[0x96] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x96>;
|
||||
m_default[0x97] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x97>;
|
||||
m_default[0x98] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x98>;
|
||||
m_default[0x99] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x99>;
|
||||
m_default[0x9a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9a>;
|
||||
m_default[0x9b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9b>;
|
||||
m_default[0x9c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9c>;
|
||||
m_default[0x9d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9d>;
|
||||
m_default[0x9e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9e>;
|
||||
m_default[0x9f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9f>;
|
||||
m_default[0xa0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa0>;
|
||||
m_default[0xa1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa1>;
|
||||
m_default[0xa2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa2>;
|
||||
m_default[0xa3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa3>;
|
||||
m_default[0xa4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa4>;
|
||||
m_default[0xa5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa5>;
|
||||
m_default[0xa6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa6>;
|
||||
m_default[0xa7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa7>;
|
||||
m_default[0xa8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa8>;
|
||||
m_default[0xa9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa9>;
|
||||
m_default[0xaa] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xaa>;
|
||||
m_default[0xab] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xab>;
|
||||
m_default[0xac] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xac>;
|
||||
m_default[0xad] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xad>;
|
||||
m_default[0xae] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xae>;
|
||||
m_default[0xaf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xaf>;
|
||||
m_default[0xb0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb0>;
|
||||
m_default[0xb1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb1>;
|
||||
m_default[0xb2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb2>;
|
||||
m_default[0xb3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb3>;
|
||||
m_default[0xb4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb4>;
|
||||
m_default[0xb5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb5>;
|
||||
m_default[0xb6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb6>;
|
||||
m_default[0xb7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb7>;
|
||||
m_default[0xb8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb8>;
|
||||
m_default[0xb9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb9>;
|
||||
m_default[0xba] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xba>;
|
||||
m_default[0xbb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbb>;
|
||||
m_default[0xbc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbc>;
|
||||
m_default[0xbd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbd>;
|
||||
m_default[0xbe] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbe>;
|
||||
m_default[0xbf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbf>;
|
||||
m_default[0xc0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc0>;
|
||||
m_default[0xc1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc1>;
|
||||
m_default[0xc2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc2>;
|
||||
m_default[0xc3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc3>;
|
||||
m_default[0xc4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc4>;
|
||||
m_default[0xc5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc5>;
|
||||
m_default[0xc6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc6>;
|
||||
m_default[0xc7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc7>;
|
||||
m_default[0xc8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc8>;
|
||||
m_default[0xc9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc9>;
|
||||
m_default[0xca] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xca>;
|
||||
m_default[0xcb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcb>;
|
||||
m_default[0xcc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcc>;
|
||||
m_default[0xcd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcd>;
|
||||
m_default[0xce] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xce>;
|
||||
m_default[0xcf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcf>;
|
||||
m_default[0xd0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd0>;
|
||||
m_default[0xd1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd1>;
|
||||
m_default[0xd2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd2>;
|
||||
m_default[0xd3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd3>;
|
||||
m_default[0xd4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd4>;
|
||||
m_default[0xd5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd5>;
|
||||
m_default[0xd6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd6>;
|
||||
m_default[0xd7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd7>;
|
||||
m_default[0xd8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd8>;
|
||||
m_default[0xd9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd9>;
|
||||
m_default[0xda] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xda>;
|
||||
m_default[0xdb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdb>;
|
||||
m_default[0xdc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdc>;
|
||||
m_default[0xdd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdd>;
|
||||
m_default[0xde] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xde>;
|
||||
m_default[0xdf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdf>;
|
||||
m_default[0xe0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe0>;
|
||||
m_default[0xe1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe1>;
|
||||
m_default[0xe2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe2>;
|
||||
m_default[0xe3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe3>;
|
||||
m_default[0xe4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe4>;
|
||||
m_default[0xe5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe5>;
|
||||
m_default[0xe6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe6>;
|
||||
m_default[0xe7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe7>;
|
||||
m_default[0xe8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe8>;
|
||||
m_default[0xe9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe9>;
|
||||
m_default[0xea] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xea>;
|
||||
m_default[0xeb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xeb>;
|
||||
m_default[0xec] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xec>;
|
||||
m_default[0xed] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xed>;
|
||||
m_default[0xee] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xee>;
|
||||
m_default[0xef] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xef>;
|
||||
m_default[0xf0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf0>;
|
||||
m_default[0xf1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf1>;
|
||||
m_default[0xf2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf2>;
|
||||
m_default[0xf3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf3>;
|
||||
m_default[0xf4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf4>;
|
||||
m_default[0xf5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf5>;
|
||||
m_default[0xf6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf6>;
|
||||
m_default[0xf7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf7>;
|
||||
m_default[0xf8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf8>;
|
||||
m_default[0xf9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf9>;
|
||||
m_default[0xfa] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfa>;
|
||||
m_default[0xfb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfb>;
|
||||
m_default[0xfc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfc>;
|
||||
m_default[0xfd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfd>;
|
||||
m_default[0xfe] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfe>;
|
||||
m_default[0xff] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xff>;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
IDrawScanline::DrawScanlinePtr GPUDrawScanline::GPUDrawScanlineMap::GetDefaultFunction(DWORD dw)
|
||||
{
|
||||
GPUScanlineSelector sel;
|
||||
|
||||
sel.dw = dw;
|
||||
|
||||
return m_default[sel];
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
GPUDrawScanline::GPUSetupPrimMap::GPUSetupPrimMap()
|
||||
{
|
||||
#define InitSP_IIP(sprite, tme, iip) \
|
||||
m_default[sprite][tme][iip] = (SetupPrimPtr)&GPUDrawScanline::SetupPrim<sprite, tme, iip>; \
|
||||
|
||||
#define InitSP_TME(sprite, tme) \
|
||||
InitSP_IIP(sprite, tme, 0) \
|
||||
InitSP_IIP(sprite, tme, 1) \
|
||||
|
||||
#define InitSP_SPRITE(sprite) \
|
||||
InitSP_TME(sprite, 0) \
|
||||
InitSP_TME(sprite, 1) \
|
||||
|
||||
InitSP_SPRITE(0);
|
||||
InitSP_SPRITE(1);
|
||||
}
|
||||
|
||||
IDrawScanline::SetupPrimPtr GPUDrawScanline::GPUSetupPrimMap::GetDefaultFunction(DWORD dw)
|
||||
{
|
||||
DWORD sprite = (dw >> 0) & 1;
|
||||
DWORD tme = (dw >> 1) & 1;
|
||||
DWORD iip = (dw >> 2) & 1;
|
||||
|
||||
return m_default[sprite][tme][iip];
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPUState.h"
|
||||
#include "GSRasterizer.h"
|
||||
#include "GSAlignedClass.h"
|
||||
|
||||
union GPUScanlineSelector
|
||||
{
|
||||
struct
|
||||
{
|
||||
DWORD iip:1; // 0
|
||||
DWORD me:1; // 1
|
||||
DWORD abe:1; // 2
|
||||
DWORD abr:2; // 3
|
||||
DWORD tge:1; // 5
|
||||
DWORD tme:1; // 6
|
||||
DWORD twin:1; // 7
|
||||
DWORD tlu:1; // 8
|
||||
DWORD dtd:1; // 9
|
||||
DWORD ltf:1; // 10
|
||||
// DWORD dte:1: // 11
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
DWORD _pad1:1; // 0
|
||||
DWORD rfb:2; // 1
|
||||
DWORD _pad2:2; // 3
|
||||
DWORD tfx:2; // 5
|
||||
};
|
||||
|
||||
DWORD dw;
|
||||
|
||||
operator DWORD() {return dw & 0xff;}
|
||||
};
|
||||
|
||||
__declspec(align(16)) struct GPUScanlineEnvironment
|
||||
{
|
||||
GPUScanlineSelector sel;
|
||||
|
||||
GPULocalMemory* mem;
|
||||
const void* tex;
|
||||
const WORD* clut;
|
||||
|
||||
GSVector4i u[3];
|
||||
GSVector4i v[3];
|
||||
|
||||
GSVector4i a;
|
||||
GSVector4i md; // similar to gs fba
|
||||
|
||||
GSVector4i ds, dt, dst8;
|
||||
GSVector4i dr, dg, db, dc8;
|
||||
};
|
||||
|
||||
__declspec(align(16)) struct GPUScanlineParam
|
||||
{
|
||||
GPUScanlineSelector sel;
|
||||
|
||||
const void* tex;
|
||||
const WORD* clut;
|
||||
};
|
||||
|
||||
class GPUDrawScanline : public GSAlignedClass<16>, public IDrawScanline
|
||||
{
|
||||
GPUScanlineEnvironment m_env;
|
||||
|
||||
//
|
||||
|
||||
class GPUDrawScanlineMap : public GSFunctionMap<DrawScanlinePtr>
|
||||
{
|
||||
DrawScanlinePtr m_default[256];
|
||||
|
||||
public:
|
||||
GPUDrawScanlineMap();
|
||||
|
||||
DrawScanlinePtr GetDefaultFunction(DWORD dw);
|
||||
};
|
||||
|
||||
GPUDrawScanlineMap m_ds;
|
||||
|
||||
//
|
||||
|
||||
class GPUSetupPrimMap : public GSFunctionMap<SetupPrimPtr>
|
||||
{
|
||||
SetupPrimPtr m_default[2][2][2];
|
||||
|
||||
public:
|
||||
GPUSetupPrimMap();
|
||||
|
||||
SetupPrimPtr GetDefaultFunction(DWORD dw);
|
||||
};
|
||||
|
||||
GPUSetupPrimMap m_sp;
|
||||
|
||||
//
|
||||
|
||||
template<DWORD sprite, DWORD tme, DWORD iip>
|
||||
void SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan);
|
||||
|
||||
//
|
||||
|
||||
__forceinline void SampleTexture(DWORD ltf, DWORD tlu, DWORD twin, GSVector4i& test, const GSVector4i& s, const GSVector4i& t, GSVector4i* c);
|
||||
__forceinline void ColorTFX(DWORD tfx, const GSVector4i& r, const GSVector4i& g, const GSVector4i& b, GSVector4i* c);
|
||||
__forceinline void AlphaBlend(UINT32 abr, UINT32 tme, const GSVector4i& d, GSVector4i* c);
|
||||
__forceinline void WriteFrame(WORD* RESTRICT fb, const GSVector4i& test, const GSVector4i* c, int pixels);
|
||||
|
||||
void DrawScanline(int top, int left, int right, const GSVertexSW& v);
|
||||
|
||||
template<DWORD sel>
|
||||
void DrawScanlineEx(int top, int left, int right, const GSVertexSW& v);
|
||||
|
||||
protected:
|
||||
GPUState* m_state;
|
||||
int m_id;
|
||||
|
||||
public:
|
||||
GPUDrawScanline(GPUState* state, int id);
|
||||
virtual ~GPUDrawScanline();
|
||||
|
||||
// IDrawScanline
|
||||
|
||||
void BeginDraw(const GSRasterizerData* data, Functions* f);
|
||||
void EndDraw(const GSRasterizerStats& stats) {}
|
||||
void PrintStats() {}
|
||||
};
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPU.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
__declspec(align(16)) class GPUDrawingEnvironment
|
||||
{
|
||||
public:
|
||||
GPURegSTATUS STATUS;
|
||||
GPURegPRIM PRIM;
|
||||
GPURegDAREA DAREA;
|
||||
GPURegDHRANGE DHRANGE;
|
||||
GPURegDVRANGE DVRANGE;
|
||||
GPURegDRAREA DRAREATL;
|
||||
GPURegDRAREA DRAREABR;
|
||||
GPURegDROFF DROFF;
|
||||
GPURegTWIN TWIN;
|
||||
GPURegCLUT CLUT;
|
||||
|
||||
GPUDrawingEnvironment()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
|
||||
STATUS.IDLE = 1;
|
||||
STATUS.COM = 1;
|
||||
STATUS.WIDTH0 = 1;
|
||||
DVRANGE.Y1 = 16;
|
||||
DVRANGE.Y2 = 256;
|
||||
}
|
||||
|
||||
CRect GetDisplayRect()
|
||||
{
|
||||
static int s_width[] = {256, 320, 512, 640, 368, 384, 512, 640};
|
||||
static int s_height[] = {240, 480};
|
||||
|
||||
CRect r;
|
||||
|
||||
r.left = DAREA.X & ~7; // FIXME
|
||||
r.top = DAREA.Y;
|
||||
r.right = r.left + s_width[(STATUS.WIDTH1 << 2) | STATUS.WIDTH0];
|
||||
r.bottom = r.top + (DVRANGE.Y2 - DVRANGE.Y1) * s_height[STATUS.HEIGHT] / 240;
|
||||
|
||||
r &= CRect(0, 0, 1024, 512);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int GetFPS()
|
||||
{
|
||||
return STATUS.ISPAL ? 50 : 60;
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
|
@ -0,0 +1,666 @@
|
|||
/*
|
||||
* 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 "GPULocalMemory.h"
|
||||
|
||||
const GSVector4i GPULocalMemory::m_xxxa(0x00008000);
|
||||
const GSVector4i GPULocalMemory::m_xxbx(0x00007c00);
|
||||
const GSVector4i GPULocalMemory::m_xgxx(0x000003e0);
|
||||
const GSVector4i GPULocalMemory::m_rxxx(0x0000001f);
|
||||
|
||||
GPULocalMemory::GPULocalMemory(const CSize& scale)
|
||||
{
|
||||
m_scale.cx = min(max(scale.cx, 0), 2);
|
||||
m_scale.cy = min(max(scale.cy, 0), 2);
|
||||
|
||||
//
|
||||
|
||||
int size = (1 << (12 + 11)) * sizeof(WORD);
|
||||
|
||||
m_vm = (WORD*)VirtualAlloc(NULL, size * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
memset(m_vm, 0, size);
|
||||
|
||||
//
|
||||
|
||||
m_clut.buff = m_vm + size;
|
||||
m_clut.dirty = true;
|
||||
|
||||
//
|
||||
|
||||
size = 256 * 256 * (1 + 1 + 4) * 32;
|
||||
|
||||
m_texture.buff[0] = (BYTE*)VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
m_texture.buff[1] = m_texture.buff[0] + 256 * 256 * 32;
|
||||
m_texture.buff[2] = m_texture.buff[1] + 256 * 256 * 32;
|
||||
|
||||
memset(m_texture.buff[0], 0, size);
|
||||
|
||||
memset(m_texture.valid, 0, sizeof(m_texture.valid));
|
||||
|
||||
for(int y = 0, offset = 0; y < 2; y++)
|
||||
{
|
||||
for(int x = 0; x < 16; x++, offset += 256 * 256)
|
||||
{
|
||||
m_texture.page[0][y][x] = &((BYTE*)m_texture.buff[0])[offset];
|
||||
m_texture.page[1][y][x] = &((BYTE*)m_texture.buff[1])[offset];
|
||||
}
|
||||
}
|
||||
|
||||
for(int y = 0, offset = 0; y < 2; y++)
|
||||
{
|
||||
for(int x = 0; x < 16; x++, offset += 256 * 256)
|
||||
{
|
||||
m_texture.page[2][y][x] = &((DWORD*)m_texture.buff[2])[offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GPULocalMemory::~GPULocalMemory()
|
||||
{
|
||||
VirtualFree(m_vm, 0, MEM_RELEASE);
|
||||
|
||||
VirtualFree(m_texture.buff[0], 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
const WORD* GPULocalMemory::GetCLUT(int tp, int cx, int cy)
|
||||
{
|
||||
if(m_clut.dirty || m_clut.tp != tp || m_clut.cx != cx || m_clut.cy != cy)
|
||||
{
|
||||
WORD* src = GetPixelAddressScaled(cx << 4, cy);
|
||||
WORD* dst = m_clut.buff;
|
||||
|
||||
// TODO: at normal horizontal resolution just return src
|
||||
|
||||
if(m_scale.cx == 0)
|
||||
{
|
||||
memcpy(dst, src, (tp == 0 ? 16 : 256) * 2);
|
||||
}
|
||||
else if(m_scale.cx == 1)
|
||||
{
|
||||
if(tp == 0)
|
||||
{
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
dst[i] = src[i * 2];
|
||||
}
|
||||
}
|
||||
else if(tp == 1)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
dst[i] = src[i * 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 2)
|
||||
{
|
||||
if(tp == 0)
|
||||
{
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
dst[i] = src[i * 4];
|
||||
}
|
||||
}
|
||||
else if(tp == 1)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
dst[i] = src[i * 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
m_clut.tp = tp;
|
||||
m_clut.cx = cx;
|
||||
m_clut.cy = cy;
|
||||
m_clut.dirty = false;
|
||||
}
|
||||
|
||||
return m_clut.buff;
|
||||
}
|
||||
|
||||
const void* GPULocalMemory::GetTexture(int tp, int tx, int ty)
|
||||
{
|
||||
if(tp == 3)
|
||||
{
|
||||
ASSERT(0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* buff = m_texture.page[tp][ty][tx];
|
||||
|
||||
UINT32 flag = 1 << tx;
|
||||
|
||||
if((m_texture.valid[tp][ty] & flag) == 0)
|
||||
{
|
||||
int bpp = 0;
|
||||
|
||||
switch(tp)
|
||||
{
|
||||
case 0:
|
||||
ReadPage4(tx, ty, (BYTE*)buff);
|
||||
bpp = 4;
|
||||
break;
|
||||
case 1:
|
||||
ReadPage8(tx, ty, (BYTE*)buff);
|
||||
bpp = 8;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
ReadPage16(tx, ty, (WORD*)buff);
|
||||
bpp = 16;
|
||||
default:
|
||||
// FIXME: __assume(0); // vc9 generates bogus code in release mode
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: m_state->m_perfmon.Put(GSPerfMon::Unswizzle, 256 * 256 * bpp >> 3);
|
||||
|
||||
m_texture.valid[tp][ty] |= flag;
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
void GPULocalMemory::Invalidate(const CRect& r)
|
||||
{
|
||||
if(!m_clut.dirty)
|
||||
{
|
||||
if(r.top <= m_clut.cy && m_clut.cy < r.bottom)
|
||||
{
|
||||
int left = m_clut.cx << 4;
|
||||
int right = left + (m_clut.tp == 0 ? 16 : 256);
|
||||
|
||||
if(r.left < right && r.right > left)
|
||||
{
|
||||
m_clut.dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int y = 0, ye = min(r.bottom, 512), j = 0; y < ye; y += 256, j++)
|
||||
{
|
||||
if(r.top >= y + 256) continue;
|
||||
|
||||
for(int x = 0, xe = min(r.right, 1024), i = 0; x < xe; x += 64, i++)
|
||||
{
|
||||
DWORD flag = 1 << i;
|
||||
|
||||
if(r.left >= x + 256) continue;
|
||||
|
||||
m_texture.valid[2][j] &= ~flag;
|
||||
|
||||
if(r.left >= x + 128) continue;
|
||||
|
||||
m_texture.valid[1][j] &= ~flag;
|
||||
|
||||
if(r.left >= x + 64) continue;
|
||||
|
||||
m_texture.valid[0][j] &= ~flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::FillRect(const CRect& r, WORD c)
|
||||
{
|
||||
Invalidate(r);
|
||||
|
||||
WORD* RESTRICT dst = GetPixelAddressScaled(r.left, r.top);
|
||||
|
||||
int w = r.Width() << m_scale.cx;
|
||||
int h = r.Height() << m_scale.cy;
|
||||
|
||||
int pitch = GetWidth();
|
||||
|
||||
for(int j = 0; j < h; j++, dst += pitch)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
dst[i] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::WriteRect(const CRect& r, const WORD* RESTRICT src)
|
||||
{
|
||||
Invalidate(r);
|
||||
|
||||
WORD* RESTRICT dst = GetPixelAddressScaled(r.left, r.top);
|
||||
|
||||
int w = r.Width();
|
||||
int h = r.Height();
|
||||
|
||||
int pitch = GetWidth();
|
||||
|
||||
if(m_scale.cx == 0)
|
||||
{
|
||||
for(int j = 0; j < h; j++, src += w)
|
||||
{
|
||||
for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch)
|
||||
{
|
||||
memcpy(dst, src, w * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 1)
|
||||
{
|
||||
for(int j = 0; j < h; j++, src += w)
|
||||
{
|
||||
for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
dst[i * 2 + 0] = src[i];
|
||||
dst[i * 2 + 1] = src[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 2)
|
||||
{
|
||||
for(int j = 0; j < h; j++, src += w)
|
||||
{
|
||||
for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
dst[i * 4 + 0] = src[i];
|
||||
dst[i * 4 + 1] = src[i];
|
||||
dst[i * 4 + 2] = src[i];
|
||||
dst[i * 4 + 3] = src[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::ReadRect(const CRect& r, WORD* RESTRICT dst)
|
||||
{
|
||||
WORD* RESTRICT src = GetPixelAddressScaled(r.left, r.top);
|
||||
|
||||
int w = r.Width();
|
||||
int h = r.Height();
|
||||
|
||||
int pitch = GetWidth() << m_scale.cy;
|
||||
|
||||
if(m_scale.cx == 0)
|
||||
{
|
||||
for(int j = 0; j < h; j++, src += pitch, dst += w)
|
||||
{
|
||||
memcpy(dst, src, w * 2);
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 1)
|
||||
{
|
||||
for(int j = 0; j < h; j++, src += pitch, dst += w)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
dst[i] = src[i * 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 2)
|
||||
{
|
||||
for(int j = 0; j < h; j++, src += pitch, dst += w)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
dst[i] = src[i * 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::MoveRect(const CPoint& src, const CPoint& dst, int w, int h)
|
||||
{
|
||||
Invalidate(CRect(dst, CSize(w, h)));
|
||||
|
||||
WORD* s = GetPixelAddressScaled(src.x, src.y);
|
||||
WORD* d = GetPixelAddressScaled(dst.x, dst.y);
|
||||
|
||||
w <<= m_scale.cx;
|
||||
h <<= m_scale.cy;
|
||||
|
||||
int pitch = GetWidth();
|
||||
|
||||
for(int i = 0; i < h; i++, s += pitch, d += pitch)
|
||||
{
|
||||
memcpy(d, s, w * sizeof(WORD));
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::ReadPage4(int tx, int ty, BYTE* RESTRICT dst)
|
||||
{
|
||||
WORD* src = GetPixelAddressScaled(tx << 6, ty << 8);
|
||||
|
||||
int pitch = GetWidth() << m_scale.cy;
|
||||
|
||||
if(m_scale.cx == 0)
|
||||
{
|
||||
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
|
||||
{
|
||||
for(int i = 0; i < 64; i++)
|
||||
{
|
||||
dst[i * 4 + 0] = (src[i] >> 0) & 0xf;
|
||||
dst[i * 4 + 1] = (src[i] >> 4) & 0xf;
|
||||
dst[i * 4 + 2] = (src[i] >> 8) & 0xf;
|
||||
dst[i * 4 + 3] = (src[i] >> 12) & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 1)
|
||||
{
|
||||
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
|
||||
{
|
||||
for(int i = 0; i < 64; i++)
|
||||
{
|
||||
dst[i * 4 + 0] = (src[i * 2] >> 0) & 0xf;
|
||||
dst[i * 4 + 1] = (src[i * 2] >> 4) & 0xf;
|
||||
dst[i * 4 + 2] = (src[i * 2] >> 8) & 0xf;
|
||||
dst[i * 4 + 3] = (src[i * 2] >> 12) & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 2)
|
||||
{
|
||||
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
|
||||
{
|
||||
for(int i = 0; i < 64; i++)
|
||||
{
|
||||
dst[i * 4 + 0] = (src[i * 4] >> 0) & 0xf;
|
||||
dst[i * 4 + 1] = (src[i * 4] >> 4) & 0xf;
|
||||
dst[i * 4 + 2] = (src[i * 4] >> 8) & 0xf;
|
||||
dst[i * 4 + 3] = (src[i * 4] >> 12) & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::ReadPage8(int tx, int ty, BYTE* RESTRICT dst)
|
||||
{
|
||||
WORD* src = GetPixelAddressScaled(tx << 6, ty << 8);
|
||||
|
||||
int pitch = GetWidth() << m_scale.cy;
|
||||
|
||||
if(m_scale.cx == 0)
|
||||
{
|
||||
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
|
||||
{
|
||||
memcpy(dst, src, 256);
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 1)
|
||||
{
|
||||
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
|
||||
{
|
||||
for(int i = 0; i < 128; i++)
|
||||
{
|
||||
((WORD*)dst)[i] = src[i * 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 2)
|
||||
{
|
||||
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
|
||||
{
|
||||
for(int i = 0; i < 128; i++)
|
||||
{
|
||||
((WORD*)dst)[i] = src[i * 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::ReadPage16(int tx, int ty, WORD* RESTRICT dst)
|
||||
{
|
||||
WORD* src = GetPixelAddressScaled(tx << 6, ty << 8);
|
||||
|
||||
int pitch = GetWidth() << m_scale.cy;
|
||||
|
||||
if(m_scale.cx == 0)
|
||||
{
|
||||
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
|
||||
{
|
||||
memcpy(dst, src, 512);
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 1)
|
||||
{
|
||||
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
dst[i] = src[i * 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 2)
|
||||
{
|
||||
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
dst[i] = src[i * 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::ReadFrame32(const CRect& r, DWORD* RESTRICT dst, bool rgb24)
|
||||
{
|
||||
WORD* src = GetPixelAddress(r.left, r.top);
|
||||
|
||||
int pitch = GetWidth();
|
||||
|
||||
if(rgb24)
|
||||
{
|
||||
for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch)
|
||||
{
|
||||
Expand24(src, dst, r.Width());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch)
|
||||
{
|
||||
Expand16(src, dst, r.Width());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels)
|
||||
{
|
||||
GSVector4i rm = m_rxxx;
|
||||
GSVector4i gm = m_xgxx;
|
||||
GSVector4i bm = m_xxbx;
|
||||
GSVector4i am = m_xxxa;
|
||||
|
||||
GSVector4i* s = (GSVector4i*)src;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
for(int i = 0, j = pixels >> 3; i < j; i++)
|
||||
{
|
||||
GSVector4i c = s[i];
|
||||
|
||||
GSVector4i l = c.upl16();
|
||||
GSVector4i h = c.uph16();
|
||||
|
||||
d[i * 2 + 0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | ((l & am) << 16);
|
||||
d[i * 2 + 1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | ((h & am) << 16);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::Expand24(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels)
|
||||
{
|
||||
BYTE* s = (BYTE*)src;
|
||||
|
||||
if(m_scale.cx == 0)
|
||||
{
|
||||
for(int i = 0; i < pixels; i += 2, s += 6)
|
||||
{
|
||||
dst[i + 0] = (s[2] << 16) | (s[1] << 8) | s[0];
|
||||
dst[i + 1] = (s[5] << 16) | (s[4] << 8) | s[3];
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 1)
|
||||
{
|
||||
for(int i = 0; i < pixels; i += 4, s += 12)
|
||||
{
|
||||
dst[i + 0] = dst[i + 1] = (s[4] << 16) | (s[1] << 8) | s[0];
|
||||
dst[i + 2] = dst[i + 3] = (s[9] << 16) | (s[8] << 8) | s[5];
|
||||
}
|
||||
}
|
||||
else if(m_scale.cx == 2)
|
||||
{
|
||||
for(int i = 0; i < pixels; i += 8, s += 24)
|
||||
{
|
||||
dst[i + 0] = dst[i + 1] = dst[i + 2] = dst[i + 3] = (s[8] << 16) | (s[1] << 8) | s[0];
|
||||
dst[i + 4] = dst[i + 5] = dst[i + 6] = dst[i + 7] = (s[17] << 16) | (s[16] << 8) | s[9];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GPULocalMemory::SaveBMP(LPCTSTR path, CRect r, int tp, int cx, int cy)
|
||||
{
|
||||
r.left <<= m_scale.cx;
|
||||
r.top <<= m_scale.cy;
|
||||
r.right <<= m_scale.cx;
|
||||
r.bottom <<= m_scale.cy;
|
||||
|
||||
r.left &= ~1;
|
||||
r.right &= ~1;
|
||||
|
||||
if(FILE* fp = _tfopen(path, _T("wb")))
|
||||
{
|
||||
BITMAPINFOHEADER bih;
|
||||
memset(&bih, 0, sizeof(bih));
|
||||
bih.biSize = sizeof(bih);
|
||||
bih.biWidth = r.Width();
|
||||
bih.biHeight = r.Height();
|
||||
bih.biPlanes = 1;
|
||||
bih.biBitCount = 32;
|
||||
bih.biCompression = BI_RGB;
|
||||
bih.biSizeImage = bih.biWidth * bih.biHeight * 4;
|
||||
|
||||
BITMAPFILEHEADER bfh;
|
||||
memset(&bfh, 0, sizeof(bfh));
|
||||
bfh.bfType = 'MB';
|
||||
bfh.bfOffBits = sizeof(bfh) + sizeof(bih);
|
||||
bfh.bfSize = bfh.bfOffBits + bih.biSizeImage;
|
||||
bfh.bfReserved1 = bfh.bfReserved2 = 0;
|
||||
|
||||
fwrite(&bfh, 1, sizeof(bfh), fp);
|
||||
fwrite(&bih, 1, sizeof(bih), fp);
|
||||
|
||||
int pitch = GetWidth();
|
||||
|
||||
WORD* buff = (WORD*)_aligned_malloc(pitch * sizeof(WORD), 16);
|
||||
DWORD* buff32 = (DWORD*)_aligned_malloc(pitch * sizeof(DWORD), 16);
|
||||
WORD* src = GetPixelAddress(r.left, r.bottom - 1);
|
||||
const WORD* clut = GetCLUT(tp, cx, cy);
|
||||
|
||||
for(int j = r.bottom - 1; j >= r.top; j--, src -= pitch)
|
||||
{
|
||||
switch(tp)
|
||||
{
|
||||
case 0: // 4 bpp
|
||||
|
||||
for(int i = 0, k = r.Width() / 2; i < k; i++)
|
||||
{
|
||||
buff[i * 2 + 0] = clut[((BYTE*)src)[i] & 0xf];
|
||||
buff[i * 2 + 1] = clut[((BYTE*)src)[i] >> 4];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1: // 8 bpp
|
||||
|
||||
for(int i = 0, k = r.Width(); i < k; i++)
|
||||
{
|
||||
buff[i] = clut[((BYTE*)src)[i]];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2: // 16 bpp;
|
||||
|
||||
for(int i = 0, k = r.Width(); i < k; i++)
|
||||
{
|
||||
buff[i] = src[i];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3: // 24 bpp
|
||||
|
||||
// TODO
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Expand16(buff, buff32, r.Width());
|
||||
|
||||
for(int i = 0, k = r.Width(); i < k; i++)
|
||||
{
|
||||
buff32[i] = (buff32[i] & 0xff00ff00) | ((buff32[i] & 0x00ff0000) >> 16) | ((buff32[i] & 0x000000ff) << 16);
|
||||
}
|
||||
|
||||
fwrite(buff32, 1, r.Width() * 4, fp);
|
||||
}
|
||||
|
||||
_aligned_free(buff);
|
||||
_aligned_free(buff32);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPU.h"
|
||||
#include "GSVector.h"
|
||||
|
||||
class GPULocalMemory
|
||||
{
|
||||
static const GSVector4i m_xxxa;
|
||||
static const GSVector4i m_xxbx;
|
||||
static const GSVector4i m_xgxx;
|
||||
static const GSVector4i m_rxxx;
|
||||
|
||||
WORD* m_vm;
|
||||
|
||||
struct
|
||||
{
|
||||
WORD* buff;
|
||||
int tp, cx, cy;
|
||||
bool dirty;
|
||||
} m_clut;
|
||||
|
||||
struct
|
||||
{
|
||||
BYTE* buff[3];
|
||||
void* page[3][2][16];
|
||||
WORD valid[3][2];
|
||||
} m_texture;
|
||||
|
||||
CSize m_scale;
|
||||
|
||||
public:
|
||||
GPULocalMemory(const CSize& scale);
|
||||
virtual ~GPULocalMemory();
|
||||
|
||||
CSize GetScale() {return m_scale;}
|
||||
int GetWidth() {return 1 << (10 + m_scale.cx);}
|
||||
int GetHeight() {return 1 << (9 + m_scale.cy);}
|
||||
|
||||
WORD* GetPixelAddress(int x, int y) const {return &m_vm[(y << (10 + m_scale.cx)) + x];}
|
||||
WORD* GetPixelAddressScaled(int x, int y) const {return &m_vm[((y << m_scale.cy) << (10 + m_scale.cx)) + (x << m_scale.cx)];}
|
||||
|
||||
const WORD* GetCLUT(int tp, int cx, int cy);
|
||||
const void* GetTexture(int tp, int tx, int ty);
|
||||
|
||||
void Invalidate(const CRect& r);
|
||||
|
||||
void FillRect(const CRect& r, WORD c);
|
||||
void WriteRect(const CRect& r, const WORD* RESTRICT src);
|
||||
void ReadRect(const CRect& r, WORD* RESTRICT dst);
|
||||
void MoveRect(const CPoint& src, const CPoint& dst, int w, int h);
|
||||
|
||||
void ReadPage4(int tx, int ty, BYTE* RESTRICT dst);
|
||||
void ReadPage8(int tx, int ty, BYTE* RESTRICT dst);
|
||||
void ReadPage16(int tx, int ty, WORD* RESTRICT dst);
|
||||
|
||||
void ReadFrame32(const CRect& r, DWORD* RESTRICT dst, bool rgb24);
|
||||
|
||||
void Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels);
|
||||
void Expand24(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels);
|
||||
|
||||
void SaveBMP(LPCTSTR path, CRect r, int tp, int cx, int cy);
|
||||
};
|
||||
|
||||
#pragma warning(default: 4244)
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 "GPURenderer.h"
|
||||
|
||||
CAtlMap<HWND, GPURendererBase*> GPURendererBase::m_wnd2gpu;
|
|
@ -0,0 +1,399 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPUState.h"
|
||||
#include "GSVertexList.h"
|
||||
|
||||
struct GPURendererSettings
|
||||
{
|
||||
int m_filter;
|
||||
int m_dither;
|
||||
int m_aspectratio;
|
||||
bool m_vsync;
|
||||
CSize m_scale;
|
||||
};
|
||||
|
||||
class GPURendererBase : public GPUState, protected GPURendererSettings
|
||||
{
|
||||
protected:
|
||||
HWND m_hWnd;
|
||||
WNDPROC m_wndproc;
|
||||
static CAtlMap<HWND, GPURendererBase*> m_wnd2gpu;
|
||||
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if(CAtlMap<HWND, GPURendererBase*>::CPair* pair = m_wnd2gpu.Lookup(hWnd))
|
||||
{
|
||||
return pair->m_value->OnMessage(message, wParam, lParam);
|
||||
}
|
||||
|
||||
ASSERT(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if(message == WM_KEYUP)
|
||||
{
|
||||
if(wParam == VK_DELETE)
|
||||
{
|
||||
m_filter = (m_filter + 1) % 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(wParam == VK_END)
|
||||
{
|
||||
m_dither = m_dither ? 0 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(wParam == VK_NEXT)
|
||||
{
|
||||
m_aspectratio = (m_aspectratio + 1) % 3;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return m_wndproc(m_hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
public:
|
||||
GPURendererBase(const GPURendererSettings& rs)
|
||||
: GPUState(rs.m_scale)
|
||||
, m_hWnd(NULL)
|
||||
, m_wndproc(NULL)
|
||||
{
|
||||
m_filter = rs.m_filter;
|
||||
m_dither = rs.m_dither;
|
||||
m_aspectratio = rs.m_aspectratio;
|
||||
m_vsync = rs.m_vsync;
|
||||
m_scale = m_mem.GetScale();
|
||||
}
|
||||
|
||||
virtual ~GPURendererBase()
|
||||
{
|
||||
if(m_wndproc)
|
||||
{
|
||||
SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc);
|
||||
|
||||
m_wnd2gpu.RemoveKey(m_hWnd);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool Create(HWND hWnd)
|
||||
{
|
||||
m_hWnd = hWnd;
|
||||
|
||||
m_wndproc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
|
||||
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc);
|
||||
m_wnd2gpu.SetAt(hWnd, this);
|
||||
|
||||
DWORD style = GetWindowLong(hWnd, GWL_STYLE);
|
||||
style |= WS_OVERLAPPEDWINDOW;
|
||||
SetWindowLong(hWnd, GWL_STYLE, style);
|
||||
UpdateWindow(hWnd);
|
||||
|
||||
ShowWindow(hWnd, SW_SHOWNORMAL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void VSync() = 0;
|
||||
virtual bool MakeSnapshot(LPCTSTR path) = 0;
|
||||
};
|
||||
|
||||
template<class Device, class Vertex>
|
||||
class GPURenderer : public GPURendererBase
|
||||
{
|
||||
protected:
|
||||
typedef typename Device::Texture Texture;
|
||||
|
||||
Vertex* m_vertices;
|
||||
int m_count;
|
||||
int m_maxcount;
|
||||
GSVertexList<Vertex> m_vl;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
m_count = 0;
|
||||
m_vl.RemoveAll();
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
void VertexKick()
|
||||
{
|
||||
if(m_vl.GetCount() < m_env.PRIM.VTX)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_count > m_maxcount)
|
||||
{
|
||||
m_maxcount = max(10000, m_maxcount * 3/2);
|
||||
m_vertices = (Vertex*)_aligned_realloc(m_vertices, sizeof(Vertex) * m_maxcount, 16);
|
||||
m_maxcount -= 100;
|
||||
}
|
||||
|
||||
Vertex* v = &m_vertices[m_count];
|
||||
|
||||
int count = 0;
|
||||
|
||||
switch(m_env.PRIM.TYPE)
|
||||
{
|
||||
case GPU_POLYGON:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.GetAt(1, v[1]);
|
||||
m_vl.GetAt(2, v[2]);
|
||||
m_vl.RemoveAll();
|
||||
count = 3;
|
||||
break;
|
||||
case GPU_LINE:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.GetAt(1, v[1]);
|
||||
m_vl.RemoveAll();
|
||||
count = 2;
|
||||
break;
|
||||
case GPU_SPRITE:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.GetAt(1, v[1]);
|
||||
m_vl.RemoveAll();
|
||||
count = 2;
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
m_vl.RemoveAll();
|
||||
count = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
(this->*m_fpDrawingKickHandlers[m_env.PRIM.TYPE])(v, count);
|
||||
|
||||
m_count += count;
|
||||
}
|
||||
|
||||
typedef void (GPURenderer<Device, Vertex>::*DrawingKickHandler)(Vertex* v, int& count);
|
||||
|
||||
DrawingKickHandler m_fpDrawingKickHandlers[4];
|
||||
|
||||
void DrawingKickNull(Vertex* v, int& count)
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
void ResetPrim()
|
||||
{
|
||||
m_vl.RemoveAll();
|
||||
}
|
||||
|
||||
void FlushPrim()
|
||||
{
|
||||
if(m_count > 0)
|
||||
{
|
||||
/*
|
||||
Dump(_T("db"));
|
||||
|
||||
if(m_env.PRIM.TME)
|
||||
{
|
||||
CRect r;
|
||||
|
||||
r.left = m_env.STATUS.TX << 6;
|
||||
r.top = m_env.STATUS.TY << 8;
|
||||
r.right = r.left + 256;
|
||||
r.bottom = r.top + 256;
|
||||
|
||||
CString str;
|
||||
str.Format(_T("da_%d_%d_%d_%d_%d"), m_env.STATUS.TP, r);
|
||||
Dump(str, m_env.STATUS.TP, r, false);
|
||||
}
|
||||
*/
|
||||
|
||||
Draw();
|
||||
|
||||
m_count = 0;
|
||||
|
||||
//Dump(_T("dc"), false);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void ResetDevice() {}
|
||||
virtual void Draw() = 0;
|
||||
virtual bool GetOutput(Texture& t) = 0;
|
||||
|
||||
bool Merge()
|
||||
{
|
||||
Texture st[2];
|
||||
|
||||
if(!GetOutput(st[0]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CSize s;
|
||||
|
||||
s.cx = st[0].GetWidth();
|
||||
s.cy = st[0].GetHeight();
|
||||
|
||||
GSVector4 sr[2];
|
||||
|
||||
sr[0].x = 0;
|
||||
sr[0].y = 0;
|
||||
sr[0].z = 1.0f;
|
||||
sr[0].w = 1.0f;
|
||||
|
||||
GSVector4 dr[2];
|
||||
|
||||
dr[0].x = 0;
|
||||
dr[0].y = 0;
|
||||
dr[0].z = (float)s.cx;
|
||||
dr[0].w = (float)s.cy;
|
||||
|
||||
GSVector4 c(0, 0, 0, 1);
|
||||
|
||||
m_dev.Merge(st, sr, dr, s, 1, 1, c);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
Device m_dev;
|
||||
|
||||
public:
|
||||
GPURenderer(const GPURendererSettings& rs)
|
||||
: GPURendererBase(rs)
|
||||
, m_count(0)
|
||||
, m_maxcount(10000)
|
||||
{
|
||||
m_vertices = (Vertex*)_aligned_malloc(sizeof(Vertex) * m_maxcount, 16);
|
||||
m_maxcount -= 100;
|
||||
|
||||
for(int i = 0; i < countof(m_fpDrawingKickHandlers); i++)
|
||||
{
|
||||
m_fpDrawingKickHandlers[i] = &GPURenderer<Device, Vertex>::DrawingKickNull;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~GPURenderer()
|
||||
{
|
||||
if(m_vertices) _aligned_free(m_vertices);
|
||||
}
|
||||
|
||||
virtual bool Create(HWND hWnd)
|
||||
{
|
||||
if(!__super::Create(hWnd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_dev.Create(hWnd, m_vsync))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void VSync()
|
||||
{
|
||||
GSPerfMonAutoTimer pmat(m_perfmon);
|
||||
|
||||
// m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ?
|
||||
|
||||
if(!IsWindow(m_hWnd))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Flush();
|
||||
|
||||
m_perfmon.Put(GSPerfMon::Frame);
|
||||
|
||||
if(!Merge())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// osd
|
||||
|
||||
static UINT64 s_frame = 0;
|
||||
static CString s_stats;
|
||||
|
||||
if(m_perfmon.GetFrame() - s_frame >= 30)
|
||||
{
|
||||
m_perfmon.Update();
|
||||
|
||||
s_frame = m_perfmon.GetFrame();
|
||||
|
||||
double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame);
|
||||
|
||||
CRect r = m_env.GetDisplayRect();
|
||||
|
||||
int w = r.Width() << m_scale.cx;
|
||||
int h = r.Height() << m_scale.cy;
|
||||
|
||||
s_stats.Format(
|
||||
_T("%I64d | %d x %d | %.2f fps (%d%%) | %d/%d | %d%% CPU | %.2f | %.2f"),
|
||||
m_perfmon.GetFrame(), w, h, fps, (int)(100.0 * fps / m_env.GetFPS()),
|
||||
(int)m_perfmon.Get(GSPerfMon::Prim),
|
||||
(int)m_perfmon.Get(GSPerfMon::Draw),
|
||||
m_perfmon.CPU(),
|
||||
m_perfmon.Get(GSPerfMon::Swizzle) / 1024,
|
||||
m_perfmon.Get(GSPerfMon::Unswizzle) / 1024
|
||||
);
|
||||
|
||||
double fillrate = m_perfmon.Get(GSPerfMon::Fillrate);
|
||||
|
||||
if(fillrate > 0)
|
||||
{
|
||||
s_stats.Format(_T("%s | %.2f mpps"), CString(s_stats), fps * fillrate / (1024 * 1024));
|
||||
}
|
||||
|
||||
SetWindowText(m_hWnd, s_stats);
|
||||
}
|
||||
|
||||
if(m_dev.IsLost())
|
||||
{
|
||||
ResetDevice();
|
||||
}
|
||||
|
||||
CRect r;
|
||||
|
||||
GetClientRect(m_hWnd, &r);
|
||||
|
||||
GSUtil::FitRect(r, m_aspectratio);
|
||||
|
||||
m_dev.Present(r);
|
||||
}
|
||||
|
||||
virtual bool MakeSnapshot(LPCTSTR path)
|
||||
{
|
||||
CString fn;
|
||||
|
||||
fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S")));
|
||||
|
||||
return m_dev.SaveCurrent(fn + _T(".bmp"));
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 "GPURendererSW.h"
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPURenderer.h"
|
||||
#include "GPUDrawScanline.h"
|
||||
|
||||
template <class Device>
|
||||
class GPURendererSW : public GPURenderer<Device, GSVertexSW>
|
||||
{
|
||||
protected:
|
||||
GSRasterizerList m_rl;
|
||||
Texture m_texture;
|
||||
|
||||
void ResetDevice()
|
||||
{
|
||||
m_texture = Texture();
|
||||
}
|
||||
|
||||
bool GetOutput(Texture& t)
|
||||
{
|
||||
CRect r = m_env.GetDisplayRect();
|
||||
|
||||
r.left <<= m_scale.cx;
|
||||
r.top <<= m_scale.cy;
|
||||
r.right <<= m_scale.cx;
|
||||
r.bottom <<= m_scale.cy;
|
||||
|
||||
// TODO
|
||||
static DWORD* buff = (DWORD*)_aligned_malloc(m_mem.GetWidth() * m_mem.GetHeight() * sizeof(DWORD), 16);
|
||||
|
||||
m_mem.ReadFrame32(r, buff, !!m_env.STATUS.ISRGB24);
|
||||
|
||||
r.OffsetRect(-r.TopLeft());
|
||||
|
||||
if(m_texture.GetWidth() != r.Width() || m_texture.GetHeight() != r.Height())
|
||||
{
|
||||
m_texture = Texture();
|
||||
}
|
||||
|
||||
if(!m_texture && !m_dev.CreateTexture(m_texture, r.Width(), r.Height()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_texture.Update(r, buff, m_mem.GetWidth() * sizeof(DWORD));
|
||||
|
||||
t = m_texture;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexKick()
|
||||
{
|
||||
GSVertexSW& v = m_vl.AddTail();
|
||||
|
||||
// TODO: x/y + off.x/y should wrap around at +/-1024
|
||||
|
||||
int x = (int)(m_v.XY.X + m_env.DROFF.X) << m_scale.cx;
|
||||
int y = (int)(m_v.XY.Y + m_env.DROFF.Y) << m_scale.cy;
|
||||
|
||||
int s = m_v.UV.X;
|
||||
int t = m_v.UV.Y;
|
||||
|
||||
GSVector4 pt(x, y, s, t);
|
||||
|
||||
v.p = pt.xyxy(GSVector4::zero());
|
||||
v.t = (pt.zwzw(GSVector4::zero()) + GSVector4(0.125f)) * 256.0f;
|
||||
v.c = GSVector4((DWORD)m_v.RGB.ai32) * 128.0f;
|
||||
|
||||
__super::VertexKick();
|
||||
}
|
||||
|
||||
void DrawingKickTriangle(GSVertexSW* v, int& count)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void DrawingKickLine(GSVertexSW* v, int& count)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void DrawingKickSprite(GSVertexSW* v, int& count)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
GSVector4i GetScissor()
|
||||
{
|
||||
GSVector4i v;
|
||||
|
||||
v.x = (int)m_env.DRAREATL.X << m_scale.cx;
|
||||
v.y = (int)m_env.DRAREATL.Y << m_scale.cy;
|
||||
v.z = min((int)(m_env.DRAREABR.X + 1) << m_scale.cx, m_mem.GetWidth());
|
||||
v.w = min((int)(m_env.DRAREABR.Y + 1) << m_scale.cy, m_mem.GetHeight());
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void Draw()
|
||||
{
|
||||
const GPUDrawingEnvironment& env = m_env;
|
||||
|
||||
//
|
||||
|
||||
GPUScanlineParam p;
|
||||
|
||||
p.sel.dw = 0;
|
||||
p.sel.iip = env.PRIM.IIP;
|
||||
p.sel.me = env.STATUS.ME;
|
||||
p.sel.abe = env.PRIM.ABE;
|
||||
p.sel.abr = env.STATUS.ABR;
|
||||
p.sel.tge = env.PRIM.TGE;
|
||||
p.sel.tme = env.PRIM.TME;
|
||||
p.sel.tlu = env.STATUS.TP < 2;
|
||||
p.sel.twin = (env.TWIN.ai32 & 0xfffff) != 0;
|
||||
p.sel.dtd = m_dither ? env.STATUS.DTD : 0;
|
||||
p.sel.ltf = m_filter == 1 && env.PRIM.TYPE == GPU_POLYGON || m_filter == 2 ? 1 : 0;
|
||||
|
||||
if(env.PRIM.TME)
|
||||
{
|
||||
const void* t = m_mem.GetTexture(env.STATUS.TP, env.STATUS.TX, env.STATUS.TY);
|
||||
|
||||
if(!t) {ASSERT(0); return;}
|
||||
|
||||
p.tex = t;
|
||||
p.clut = m_mem.GetCLUT(env.STATUS.TP, env.CLUT.X, env.CLUT.Y);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
GSRasterizerData data;
|
||||
|
||||
data.scissor = GetScissor();
|
||||
data.vertices = m_vertices;
|
||||
data.count = m_count;
|
||||
data.param = &p;
|
||||
|
||||
switch(env.PRIM.TYPE)
|
||||
{
|
||||
case GPU_POLYGON: data.primclass = GS_TRIANGLE_CLASS; break;
|
||||
case GPU_LINE: data.primclass = GS_LINE_CLASS; break;
|
||||
case GPU_SPRITE: data.primclass = GS_SPRITE_CLASS; break;
|
||||
default: __assume(0);
|
||||
}
|
||||
|
||||
m_rl.Draw(&data);
|
||||
|
||||
GSRasterizerStats stats;
|
||||
|
||||
m_rl.GetStats(stats);
|
||||
|
||||
m_perfmon.Put(GSPerfMon::Draw, 1);
|
||||
m_perfmon.Put(GSPerfMon::Prim, stats.prims);
|
||||
m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels);
|
||||
|
||||
// TODO
|
||||
|
||||
{
|
||||
GSVector4 tl(+1e10f);
|
||||
GSVector4 br(-1e10f);
|
||||
|
||||
for(int i = 0, j = m_count; i < j; i++)
|
||||
{
|
||||
GSVector4 p = m_vertices[i].p;
|
||||
|
||||
tl = tl.minv(p);
|
||||
br = br.maxv(p);
|
||||
}
|
||||
|
||||
GSVector4i scissor = data.scissor;
|
||||
|
||||
CRect r;
|
||||
|
||||
r.left = max(scissor.x, min(scissor.z, (int)tl.x)) >> m_scale.cx;
|
||||
r.top = max(scissor.y, min(scissor.w, (int)tl.y)) >> m_scale.cy;
|
||||
r.right = max(scissor.x, min(scissor.z, (int)br.x)) >> m_scale.cx;
|
||||
r.bottom = max(scissor.y, min(scissor.w, (int)br.y)) >> m_scale.cy;
|
||||
|
||||
Invalidate(r);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
GPURendererSW(const GPURendererSettings& rs, int threads)
|
||||
: GPURenderer(rs)
|
||||
{
|
||||
m_rl.Create<GPUDrawScanline>(this, threads);
|
||||
|
||||
m_fpDrawingKickHandlers[GPU_POLYGON] = (DrawingKickHandler)&GPURendererSW::DrawingKickTriangle;
|
||||
m_fpDrawingKickHandlers[GPU_LINE] = (DrawingKickHandler)&GPURendererSW::DrawingKickLine;
|
||||
m_fpDrawingKickHandlers[GPU_SPRITE] = (DrawingKickHandler)&GPURendererSW::DrawingKickSprite;
|
||||
}
|
||||
|
||||
virtual ~GPURendererSW()
|
||||
{
|
||||
}
|
||||
};
|
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* 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 "GSdx.h"
|
||||
#include "GSUtil.h"
|
||||
#include "GPUSettingsDlg.h"
|
||||
#include <shlobj.h>
|
||||
#include <afxpriv.h>
|
||||
|
||||
GSSetting GPUSettingsDlg::g_renderers[] =
|
||||
{
|
||||
{0, _T("Direct3D7 (Software)"), NULL},
|
||||
{1, _T("Direct3D9 (Software)"), NULL},
|
||||
{2, _T("Direct3D10 (Software)"), NULL},
|
||||
// {3, _T("Null (Null)"), NULL},
|
||||
};
|
||||
|
||||
GSSetting GPUSettingsDlg::g_psversion[] =
|
||||
{
|
||||
{D3DPS_VERSION(3, 0), _T("Pixel Shader 3.0"), NULL},
|
||||
{D3DPS_VERSION(2, 0), _T("Pixel Shader 2.0"), NULL},
|
||||
//{D3DPS_VERSION(1, 4), _T("Pixel Shader 1.4"), NULL},
|
||||
//{D3DPS_VERSION(1, 1), _T("Pixel Shader 1.1"), NULL},
|
||||
//{D3DPS_VERSION(0, 0), _T("Fixed Pipeline (bogus)"), NULL},
|
||||
};
|
||||
|
||||
GSSetting GPUSettingsDlg::g_filter[] =
|
||||
{
|
||||
{0, _T("Nearest"), NULL},
|
||||
{1, _T("Bilinear (polygons only)"), NULL},
|
||||
{2, _T("Bilinear"), NULL},
|
||||
};
|
||||
|
||||
GSSetting GPUSettingsDlg::g_dithering[] =
|
||||
{
|
||||
{0, _T("Disabled"), NULL},
|
||||
{1, _T("Auto"), NULL},
|
||||
};
|
||||
|
||||
GSSetting GPUSettingsDlg::g_aspectratio[] =
|
||||
{
|
||||
{0, _T("Stretch"), NULL},
|
||||
{1, _T("4:3"), NULL},
|
||||
{2, _T("16:9"), NULL},
|
||||
};
|
||||
|
||||
GSSetting GPUSettingsDlg::g_internalresolution[] =
|
||||
{
|
||||
{0 | (0 << 2), _T("H x 1 - V x 1"), NULL},
|
||||
{1 | (0 << 2), _T("H x 2 - V x 1"), NULL},
|
||||
{0 | (1 << 2), _T("H x 1 - V x 2"), NULL},
|
||||
{1 | (1 << 2), _T("H x 2 - V x 2"), NULL},
|
||||
{2 | (1 << 2), _T("H x 4 - V x 2"), NULL},
|
||||
{1 | (2 << 2), _T("H x 2 - V x 4"), NULL},
|
||||
{2 | (2 << 2), _T("H x 4 - V x 4"), NULL},
|
||||
};
|
||||
|
||||
IMPLEMENT_DYNAMIC(GPUSettingsDlg, CDialog)
|
||||
|
||||
GPUSettingsDlg::GPUSettingsDlg(CWnd* pParent /*=NULL*/)
|
||||
: CDialog(GPUSettingsDlg::IDD, pParent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
GPUSettingsDlg::~GPUSettingsDlg()
|
||||
{
|
||||
}
|
||||
|
||||
LRESULT GPUSettingsDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
|
||||
|
||||
if(message == WM_INITDIALOG)
|
||||
{
|
||||
SendMessage(WM_KICKIDLE);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GPUSettingsDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
__super::DoDataExchange(pDX);
|
||||
DDX_Control(pDX, IDC_COMBO3, m_resolution);
|
||||
DDX_Control(pDX, IDC_COMBO1, m_renderer);
|
||||
DDX_Control(pDX, IDC_COMBO4, m_psversion);
|
||||
DDX_Control(pDX, IDC_COMBO2, m_filter);
|
||||
DDX_Control(pDX, IDC_COMBO5, m_dithering);
|
||||
DDX_Control(pDX, IDC_COMBO6, m_aspectratio);
|
||||
DDX_Control(pDX, IDC_COMBO7, m_internalresolution);
|
||||
DDX_Control(pDX, IDC_SPIN3, m_swthreads);
|
||||
DDX_Control(pDX, IDC_EDIT3, m_swthreadsedit);
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(GPUSettingsDlg, CDialog)
|
||||
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
|
||||
ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateD3D9Options)
|
||||
ON_UPDATE_COMMAND_UI(IDC_COMBO7, OnUpdateSWOptions)
|
||||
ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateSWOptions)
|
||||
ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateSWOptions)
|
||||
ON_CBN_SELCHANGE(IDC_COMBO1, &GPUSettingsDlg::OnCbnSelchangeCombo1)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
void GPUSettingsDlg::OnKickIdle()
|
||||
{
|
||||
UpdateDialogControls(this, false);
|
||||
}
|
||||
|
||||
BOOL GPUSettingsDlg::OnInitDialog()
|
||||
{
|
||||
__super::OnInitDialog();
|
||||
|
||||
CWinApp* pApp = AfxGetApp();
|
||||
|
||||
D3DCAPS9 caps;
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
caps.PixelShaderVersion = D3DPS_VERSION(0, 0);
|
||||
|
||||
m_modes.RemoveAll();
|
||||
|
||||
// windowed
|
||||
|
||||
{
|
||||
D3DDISPLAYMODE mode;
|
||||
memset(&mode, 0, sizeof(mode));
|
||||
m_modes.AddTail(mode);
|
||||
|
||||
int iItem = m_resolution.AddString(_T("Windowed"));
|
||||
m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition());
|
||||
m_resolution.SetCurSel(iItem);
|
||||
}
|
||||
|
||||
// fullscreen
|
||||
|
||||
if(CComPtr<IDirect3D9> d3d = Direct3DCreate9(D3D_SDK_VERSION))
|
||||
{
|
||||
UINT ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0);
|
||||
UINT ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0);
|
||||
UINT ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0);
|
||||
|
||||
UINT nModes = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8);
|
||||
|
||||
for(UINT i = 0; i < nModes; i++)
|
||||
{
|
||||
D3DDISPLAYMODE mode;
|
||||
|
||||
if(S_OK == d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode))
|
||||
{
|
||||
CString str;
|
||||
str.Format(_T("%dx%d %dHz"), mode.Width, mode.Height, mode.RefreshRate);
|
||||
int iItem = m_resolution.AddString(str);
|
||||
|
||||
m_modes.AddTail(mode);
|
||||
m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition());
|
||||
|
||||
if(ModeWidth == mode.Width && ModeHeight == mode.Height && ModeRefreshRate == mode.RefreshRate)
|
||||
{
|
||||
m_resolution.SetCurSel(iItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
|
||||
}
|
||||
|
||||
bool isdx10avail = GSUtil::IsDirect3D10Available();
|
||||
|
||||
CAtlArray<GSSetting> renderers;
|
||||
|
||||
for(size_t i = 0; i < countof(g_renderers); i++)
|
||||
{
|
||||
if(i == 2 && !isdx10avail) continue;
|
||||
|
||||
renderers.Add(g_renderers[i]);
|
||||
}
|
||||
|
||||
GSSetting::InitComboBox(renderers.GetData(), renderers.GetCount(), m_renderer, pApp->GetProfileInt(_T("GPUSettings"), _T("Renderer"), 1));
|
||||
GSSetting::InitComboBox(g_psversion, countof(g_psversion), m_psversion, pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)), caps.PixelShaderVersion);
|
||||
GSSetting::InitComboBox(g_filter, countof(g_filter), m_filter, pApp->GetProfileInt(_T("GPUSettings"), _T("filter"), 0));
|
||||
GSSetting::InitComboBox(g_dithering, countof(g_dithering), m_dithering, pApp->GetProfileInt(_T("GPUSettings"), _T("dithering"), 1));
|
||||
GSSetting::InitComboBox(g_aspectratio, countof(g_aspectratio), m_aspectratio, pApp->GetProfileInt(_T("GPUSettings"), _T("AspectRatio"), 1));
|
||||
GSSetting::InitComboBox(g_internalresolution, countof(g_internalresolution), m_internalresolution, pApp->GetProfileInt(_T("GPUSettings"), _T("scale_x"), 0) | (pApp->GetProfileInt(_T("GPUSettings"), _T("scale_y"), 0) << 2));
|
||||
|
||||
|
||||
OnCbnSelchangeCombo1();
|
||||
|
||||
//
|
||||
|
||||
m_swthreads.SetRange(1, 16);
|
||||
m_swthreads.SetPos(pApp->GetProfileInt(_T("GPUSettings"), _T("swthreads"), 1));
|
||||
|
||||
//
|
||||
|
||||
UpdateData(FALSE);
|
||||
|
||||
return TRUE; // return TRUE unless you set the focus to a control
|
||||
// EXCEPTION: OCX Property Pages should return FALSE
|
||||
}
|
||||
|
||||
void GPUSettingsDlg::OnOK()
|
||||
{
|
||||
CWinApp* pApp = AfxGetApp();
|
||||
|
||||
UpdateData();
|
||||
|
||||
if(m_resolution.GetCurSel() >= 0)
|
||||
{
|
||||
D3DDISPLAYMODE& mode = m_modes.GetAt((POSITION)m_resolution.GetItemData(m_resolution.GetCurSel()));
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("ModeWidth"), mode.Width);
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("ModeHeight"), mode.Height);
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("ModeRefreshRate"), mode.RefreshRate);
|
||||
}
|
||||
|
||||
if(m_renderer.GetCurSel() >= 0)
|
||||
{
|
||||
pApp->WriteProfileInt(_T("GPUSettings"), _T("Renderer"), (DWORD)m_renderer.GetItemData(m_renderer.GetCurSel()));
|
||||
}
|
||||
|
||||
if(m_psversion.GetCurSel() >= 0)
|
||||
{
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("PixelShaderVersion2"), (DWORD)m_psversion.GetItemData(m_psversion.GetCurSel()));
|
||||
}
|
||||
|
||||
if(m_filter.GetCurSel() >= 0)
|
||||
{
|
||||
pApp->WriteProfileInt(_T("GPUSettings"), _T("filter"), (DWORD)m_filter.GetItemData(m_filter.GetCurSel()));
|
||||
}
|
||||
|
||||
if(m_dithering.GetCurSel() >= 0)
|
||||
{
|
||||
pApp->WriteProfileInt(_T("GPUSettings"), _T("dithering"), (DWORD)m_dithering.GetItemData(m_dithering.GetCurSel()));
|
||||
}
|
||||
|
||||
if(m_aspectratio.GetCurSel() >= 0)
|
||||
{
|
||||
pApp->WriteProfileInt(_T("GPUSettings"), _T("AspectRatio"), (DWORD)m_aspectratio.GetItemData(m_aspectratio.GetCurSel()));
|
||||
}
|
||||
|
||||
if(m_internalresolution.GetCurSel() >= 0)
|
||||
{
|
||||
DWORD value = (DWORD)m_internalresolution.GetItemData(m_internalresolution.GetCurSel());
|
||||
|
||||
pApp->WriteProfileInt(_T("GPUSettings"), _T("scale_x"), value & 3);
|
||||
pApp->WriteProfileInt(_T("GPUSettings"), _T("scale_y"), (value >> 2) & 3);
|
||||
}
|
||||
|
||||
pApp->WriteProfileInt(_T("GPUSettings"), _T("swthreads"), m_swthreads.GetPos());
|
||||
|
||||
__super::OnOK();
|
||||
}
|
||||
|
||||
void GPUSettingsDlg::OnUpdateResolution(CCmdUI* pCmdUI)
|
||||
{
|
||||
UpdateData();
|
||||
|
||||
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
|
||||
|
||||
pCmdUI->Enable(i == 1);
|
||||
}
|
||||
|
||||
void GPUSettingsDlg::OnUpdateD3D9Options(CCmdUI* pCmdUI)
|
||||
{
|
||||
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
|
||||
|
||||
pCmdUI->Enable(i == 1);
|
||||
}
|
||||
|
||||
void GPUSettingsDlg::OnUpdateSWOptions(CCmdUI* pCmdUI)
|
||||
{
|
||||
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
|
||||
|
||||
pCmdUI->Enable(i >= 0 && i <= 2);
|
||||
}
|
||||
|
||||
void GPUSettingsDlg::OnCbnSelchangeCombo1()
|
||||
{
|
||||
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
|
||||
|
||||
GetDlgItem(IDC_LOGO9)->ShowWindow(i == 1 ? SW_SHOW : SW_HIDE);
|
||||
GetDlgItem(IDC_LOGO10)->ShowWindow(i == 2 ? SW_SHOW : SW_HIDE);
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSSetting.h"
|
||||
#include "resource.h"
|
||||
|
||||
class GPUSettingsDlg : public CDialog
|
||||
{
|
||||
DECLARE_DYNAMIC(GPUSettingsDlg)
|
||||
|
||||
private:
|
||||
CAtlList<D3DDISPLAYMODE> m_modes;
|
||||
|
||||
public:
|
||||
GPUSettingsDlg(CWnd* pParent = NULL); // standard constructor
|
||||
virtual ~GPUSettingsDlg();
|
||||
|
||||
static GSSetting g_renderers[];
|
||||
static GSSetting g_psversion[];
|
||||
static GSSetting g_filter[];
|
||||
static GSSetting g_dithering[];
|
||||
static GSSetting g_aspectratio[];
|
||||
static GSSetting g_internalresolution[];
|
||||
|
||||
// Dialog Data
|
||||
enum { IDD = IDD_GPUCONFIG };
|
||||
CComboBox m_resolution;
|
||||
CComboBox m_renderer;
|
||||
CComboBox m_psversion;
|
||||
CComboBox m_filter;
|
||||
CComboBox m_dithering;
|
||||
CComboBox m_aspectratio;
|
||||
CComboBox m_internalresolution;
|
||||
CSpinButtonCtrl m_swthreads;
|
||||
CEdit m_swthreadsedit;
|
||||
|
||||
protected:
|
||||
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
virtual BOOL OnInitDialog();
|
||||
virtual void OnOK();
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
public:
|
||||
afx_msg void OnKickIdle();
|
||||
afx_msg void OnUpdateResolution(CCmdUI* pCmdUI);
|
||||
afx_msg void OnUpdateD3D9Options(CCmdUI* pCmdUI);
|
||||
afx_msg void OnUpdateSWOptions(CCmdUI* pCmdUI);
|
||||
afx_msg void OnCbnSelchangeCombo1();
|
||||
};
|
|
@ -0,0 +1,747 @@
|
|||
/*
|
||||
* 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 "GPUState.h"
|
||||
|
||||
GPUState::GPUState(const CSize& scale)
|
||||
: m_mem(scale)
|
||||
, s_n(0)
|
||||
{
|
||||
memset(m_status, 0, sizeof(m_status));
|
||||
|
||||
for(int i = 0; i < countof(m_fpGPUStatusCommandHandlers); i++)
|
||||
{
|
||||
m_fpGPUStatusCommandHandlers[i] = &GPUState::SCH_Null;
|
||||
}
|
||||
|
||||
m_fpGPUStatusCommandHandlers[0x00] = &GPUState::SCH_ResetGPU;
|
||||
m_fpGPUStatusCommandHandlers[0x01] = &GPUState::SCH_ResetCommandBuffer;
|
||||
m_fpGPUStatusCommandHandlers[0x02] = &GPUState::SCH_ResetIRQ;
|
||||
m_fpGPUStatusCommandHandlers[0x03] = &GPUState::SCH_DisplayEnable;
|
||||
m_fpGPUStatusCommandHandlers[0x04] = &GPUState::SCH_DMASetup;
|
||||
m_fpGPUStatusCommandHandlers[0x05] = &GPUState::SCH_StartOfDisplayArea;
|
||||
m_fpGPUStatusCommandHandlers[0x06] = &GPUState::SCH_HorizontalDisplayRange;
|
||||
m_fpGPUStatusCommandHandlers[0x07] = &GPUState::SCH_VerticalDisplayRange;
|
||||
m_fpGPUStatusCommandHandlers[0x08] = &GPUState::SCH_DisplayMode;
|
||||
m_fpGPUStatusCommandHandlers[0x10] = &GPUState::SCH_GPUInfo;
|
||||
|
||||
m_fpGPUPacketHandler[0] = &GPUState::PH_Command;
|
||||
m_fpGPUPacketHandler[1] = &GPUState::PH_Polygon;
|
||||
m_fpGPUPacketHandler[2] = &GPUState::PH_Line;
|
||||
m_fpGPUPacketHandler[3] = &GPUState::PH_Sprite;
|
||||
m_fpGPUPacketHandler[4] = &GPUState::PH_Move;
|
||||
m_fpGPUPacketHandler[5] = &GPUState::PH_Write;
|
||||
m_fpGPUPacketHandler[6] = &GPUState::PH_Read;
|
||||
m_fpGPUPacketHandler[7] = &GPUState::PH_Environment;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
GPUState::~GPUState()
|
||||
{
|
||||
}
|
||||
|
||||
void GPUState::Reset()
|
||||
{
|
||||
m_env.Reset();
|
||||
|
||||
m_mem.Invalidate(CRect(0, 0, 1024, 512));
|
||||
|
||||
memset(&m_v, 0, sizeof(m_v));
|
||||
}
|
||||
|
||||
void GPUState::Flush()
|
||||
{
|
||||
FlushPrim();
|
||||
}
|
||||
|
||||
void GPUState::SetPrim(GPUReg* r)
|
||||
{
|
||||
if(m_env.PRIM.TYPE != r->PRIM.TYPE)
|
||||
{
|
||||
ResetPrim();
|
||||
}
|
||||
|
||||
GPURegPRIM PRIM = r->PRIM;
|
||||
|
||||
PRIM.VTX = 0;
|
||||
|
||||
switch(r->PRIM.TYPE)
|
||||
{
|
||||
case GPU_POLYGON:
|
||||
PRIM.ai32 = (r->PRIM.ai32 & 0xF7000000) | 3; // TYPE IIP TME ABE TGE
|
||||
break;
|
||||
case GPU_LINE:
|
||||
PRIM.ai32 = (r->PRIM.ai32 & 0xF2000000) | 2; // TYPE IIP ABE
|
||||
PRIM.TGE = 1; // ?
|
||||
break;
|
||||
case GPU_SPRITE:
|
||||
PRIM.ai32 = (r->PRIM.ai32 & 0xE7000000) | 2; // TYPE TME ABE TGE
|
||||
break;
|
||||
}
|
||||
|
||||
if(m_env.PRIM.ai32 != PRIM.ai32)
|
||||
{
|
||||
Flush();
|
||||
|
||||
m_env.PRIM = PRIM;
|
||||
}
|
||||
}
|
||||
|
||||
void GPUState::SetCLUT(GPUReg* r)
|
||||
{
|
||||
UINT32 mask = 0xFFFF0000; // X Y
|
||||
|
||||
UINT32 value = (m_env.CLUT.ai32 & ~mask) | (r->ai32 & mask);
|
||||
|
||||
if(m_env.CLUT.ai32 != value)
|
||||
{
|
||||
Flush();
|
||||
|
||||
m_env.CLUT.ai32 = value;
|
||||
}
|
||||
}
|
||||
|
||||
void GPUState::SetTPAGE(GPUReg* r)
|
||||
{
|
||||
UINT32 mask = 0x000001FF; // TP ABR TY TX
|
||||
|
||||
UINT32 value = (m_env.STATUS.ai32 & ~mask) | ((r->ai32 >> 16) & mask);
|
||||
|
||||
if(m_env.STATUS.ai32 != value)
|
||||
{
|
||||
Flush();
|
||||
|
||||
m_env.STATUS.ai32 = value;
|
||||
}
|
||||
}
|
||||
|
||||
void GPUState::Invalidate(const CRect& r)
|
||||
{
|
||||
m_mem.Invalidate(r);
|
||||
}
|
||||
|
||||
void GPUState::WriteData(const BYTE* mem, UINT32 size)
|
||||
{
|
||||
GSPerfMonAutoTimer pmat(m_perfmon);
|
||||
|
||||
size <<= 2;
|
||||
|
||||
m_write.Append(mem, size);
|
||||
|
||||
int i = 0;
|
||||
|
||||
while(i < m_write.bytes)
|
||||
{
|
||||
GPUReg* r = (GPUReg*)&m_write.buff[i];
|
||||
|
||||
int ret = (this->*m_fpGPUPacketHandler[r->PACKET.TYPE])(r, (m_write.bytes - i) >> 2);
|
||||
|
||||
if(ret == 0) return; // need more data
|
||||
|
||||
i += ret << 2;
|
||||
}
|
||||
|
||||
m_write.Remove(i);
|
||||
}
|
||||
|
||||
void GPUState::ReadData(BYTE* mem, UINT32 size)
|
||||
{
|
||||
GSPerfMonAutoTimer pmat(m_perfmon);
|
||||
|
||||
int remaining = m_read.bytes - m_read.cur;
|
||||
|
||||
int bytes = (int)size << 2;
|
||||
|
||||
if(bytes > remaining)
|
||||
{
|
||||
// ASSERT(0);
|
||||
|
||||
TRACE(_T("WARNING: ReadData\n"));
|
||||
|
||||
// memset(&mem[remaining], 0, bytes - remaining);
|
||||
|
||||
bytes = remaining;
|
||||
}
|
||||
|
||||
memcpy(mem, &m_read.buff[m_read.cur], bytes);
|
||||
|
||||
m_read.cur += bytes;
|
||||
|
||||
if(m_read.cur >= m_read.bytes)
|
||||
{
|
||||
m_env.STATUS.IMG = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GPUState::WriteStatus(UINT32 status)
|
||||
{
|
||||
GSPerfMonAutoTimer pmat(m_perfmon);
|
||||
|
||||
UINT32 b = status >> 24;
|
||||
|
||||
m_status[b] = status;
|
||||
|
||||
(this->*m_fpGPUStatusCommandHandlers[b])((GPUReg*)&status);
|
||||
}
|
||||
|
||||
UINT32 GPUState::ReadStatus()
|
||||
{
|
||||
GSPerfMonAutoTimer pmat(m_perfmon);
|
||||
|
||||
m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ?
|
||||
|
||||
return m_env.STATUS.ai32;
|
||||
}
|
||||
|
||||
void GPUState::Freeze(GPUFreezeData* data)
|
||||
{
|
||||
data->status = m_env.STATUS.ai32;
|
||||
memcpy(data->control, m_status, 256 * 4);
|
||||
m_mem.ReadRect(CRect(0, 0, 1024, 512), data->vram);
|
||||
}
|
||||
|
||||
void GPUState::Defrost(const GPUFreezeData* data)
|
||||
{
|
||||
m_env.STATUS.ai32 = data->status;
|
||||
memcpy(m_status, data->control, 256 * 4);
|
||||
m_mem.WriteRect(CRect(0, 0, 1024, 512), data->vram);
|
||||
|
||||
for(int i = 0; i <= 8; i++)
|
||||
{
|
||||
WriteStatus(m_status[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUState::SCH_Null(GPUReg* r)
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
void GPUState::SCH_ResetGPU(GPUReg* r)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void GPUState::SCH_ResetCommandBuffer(GPUReg* r)
|
||||
{
|
||||
// ?
|
||||
}
|
||||
|
||||
void GPUState::SCH_ResetIRQ(GPUReg* r)
|
||||
{
|
||||
// ?
|
||||
}
|
||||
|
||||
void GPUState::SCH_DisplayEnable(GPUReg* r)
|
||||
{
|
||||
m_env.STATUS.DEN = r->DEN.DEN;
|
||||
}
|
||||
|
||||
void GPUState::SCH_DMASetup(GPUReg* r)
|
||||
{
|
||||
m_env.STATUS.DMA = r->DMA.DMA;
|
||||
}
|
||||
|
||||
void GPUState::SCH_StartOfDisplayArea(GPUReg* r)
|
||||
{
|
||||
m_env.DAREA = r->DAREA;
|
||||
}
|
||||
|
||||
void GPUState::SCH_HorizontalDisplayRange(GPUReg* r)
|
||||
{
|
||||
m_env.DHRANGE = r->DHRANGE;
|
||||
}
|
||||
|
||||
void GPUState::SCH_VerticalDisplayRange(GPUReg* r)
|
||||
{
|
||||
m_env.DVRANGE = r->DVRANGE;
|
||||
}
|
||||
|
||||
void GPUState::SCH_DisplayMode(GPUReg* r)
|
||||
{
|
||||
m_env.STATUS.WIDTH0 = r->DMODE.WIDTH0;
|
||||
m_env.STATUS.HEIGHT = r->DMODE.HEIGHT;
|
||||
m_env.STATUS.ISPAL = r->DMODE.ISPAL;
|
||||
m_env.STATUS.ISRGB24 = r->DMODE.ISRGB24;
|
||||
m_env.STATUS.ISINTER = r->DMODE.ISINTER;
|
||||
m_env.STATUS.WIDTH1 = r->DMODE.WIDTH1;
|
||||
}
|
||||
|
||||
void GPUState::SCH_GPUInfo(GPUReg* r)
|
||||
{
|
||||
UINT32 value = 0;
|
||||
|
||||
switch(r->GPUINFO.PARAM)
|
||||
{
|
||||
case 0x2:
|
||||
value = m_env.TWIN.ai32;
|
||||
break;
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
case 0x3:
|
||||
value = m_env.DRAREATL.ai32;
|
||||
break;
|
||||
case 0x4:
|
||||
value = m_env.DRAREABR.ai32;
|
||||
break;
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
value = m_env.DROFF.ai32;
|
||||
break;
|
||||
case 0x7:
|
||||
value = 2;
|
||||
break;
|
||||
case 0x8:
|
||||
case 0xf:
|
||||
value = 0xBFC03720; // ?
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
m_read.RemoveAll();
|
||||
m_read.Append((BYTE*)&value, 4);
|
||||
m_read.cur = 0;
|
||||
}
|
||||
|
||||
int GPUState::PH_Command(GPUReg* r, int size)
|
||||
{
|
||||
switch(r->PACKET.OPTION)
|
||||
{
|
||||
case 0: // ???
|
||||
|
||||
return 1;
|
||||
|
||||
case 1: // clear cache
|
||||
|
||||
return 1;
|
||||
|
||||
case 2: // fillrect
|
||||
|
||||
if(size < 3) return 0;
|
||||
|
||||
Flush();
|
||||
|
||||
CRect r2;
|
||||
|
||||
r2.left = r[1].XY.X;
|
||||
r2.top = r[1].XY.Y;
|
||||
r2.right = r2.left + r[2].XY.X;
|
||||
r2.bottom = r2.top + r[2].XY.Y;
|
||||
|
||||
WORD c = (WORD)(((r[0].RGB.R >> 3) << 10) | ((r[0].RGB.R >> 3) << 5) | (r[0].RGB.R >> 3));
|
||||
|
||||
m_mem.FillRect(r2, c);
|
||||
|
||||
Invalidate(r2);
|
||||
|
||||
Dump(_T("f"));
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
ASSERT(0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GPUState::PH_Polygon(GPUReg* r, int size)
|
||||
{
|
||||
int required = 1;
|
||||
|
||||
int vertices = r[0].POLYGON.VTX ? 4 : 3;
|
||||
|
||||
required += vertices;
|
||||
|
||||
if(r[0].POLYGON.TME) required += vertices;
|
||||
|
||||
if(r[0].POLYGON.IIP) required += vertices - 1;
|
||||
|
||||
if(size < required) return 0;
|
||||
|
||||
//
|
||||
|
||||
SetPrim(r);
|
||||
|
||||
if(r[0].POLYGON.TME)
|
||||
{
|
||||
SetCLUT(&r[2]);
|
||||
|
||||
SetTPAGE(&r[r[0].POLYGON.IIP ? 5 : 4]);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
GPUVertex v[4];
|
||||
|
||||
for(int i = 0, j = 0; j < vertices; j++)
|
||||
{
|
||||
v[j].RGB = r[r[0].POLYGON.IIP ? i : 0].RGB;
|
||||
|
||||
if(j == 0 || r[0].POLYGON.IIP) i++;
|
||||
|
||||
v[j].XY = r[i++].XY;
|
||||
|
||||
if(r[0].POLYGON.TME)
|
||||
{
|
||||
v[j].UV.X = r[i].UV.U;
|
||||
v[j].UV.Y = r[i].UV.V;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i <= vertices - 3; i++)
|
||||
{
|
||||
for(int j = 0; j < 3; j++)
|
||||
{
|
||||
m_v = v[i + j];
|
||||
|
||||
VertexKick();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
int GPUState::PH_Line(GPUReg* r, int size)
|
||||
{
|
||||
int required = 1;
|
||||
|
||||
int vertices = 0;
|
||||
|
||||
if(r->LINE.PLL)
|
||||
{
|
||||
required++;
|
||||
|
||||
for(int i = 1; i < size; i++)
|
||||
{
|
||||
if(r[i].ai32 == 0x55555555)
|
||||
{
|
||||
vertices = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(vertices < 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vertices = 2;
|
||||
}
|
||||
|
||||
required += vertices;
|
||||
|
||||
if(r->LINE.IIP) required += vertices - 1;
|
||||
|
||||
//
|
||||
|
||||
SetPrim(r);
|
||||
|
||||
//
|
||||
|
||||
for(int i = 0, j = 0; j < vertices; j++)
|
||||
{
|
||||
if(j >= 2) VertexKick();
|
||||
|
||||
m_v.RGB = r[r[0].LINE.IIP ? i : 0].RGB;
|
||||
|
||||
if(j == 0 || r[0].LINE.IIP) i++;
|
||||
|
||||
m_v.XY = r[i++].XY;
|
||||
|
||||
VertexKick();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
int GPUState::PH_Sprite(GPUReg* r, int size)
|
||||
{
|
||||
int required = 2;
|
||||
|
||||
if(r[0].SPRITE.TME) required++;
|
||||
if(r[0].SPRITE.SIZE == 0) required++;
|
||||
|
||||
if(size < required) return 0;
|
||||
|
||||
//
|
||||
|
||||
SetPrim(r);
|
||||
|
||||
if(r[0].SPRITE.TME)
|
||||
{
|
||||
SetCLUT(&r[2]);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
int i = 0;
|
||||
|
||||
m_v.RGB = r[i++].RGB;
|
||||
|
||||
m_v.XY = r[i++].XY;
|
||||
|
||||
if(r[0].SPRITE.TME)
|
||||
{
|
||||
m_v.UV.X = r[i].UV.U;
|
||||
m_v.UV.Y = r[i].UV.V;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
VertexKick();
|
||||
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
|
||||
switch(r[0].SPRITE.SIZE)
|
||||
{
|
||||
case 0: w = r[i].XY.X; h = r[i].XY.Y; i++; break;
|
||||
case 1: w = h = 1; break;
|
||||
case 2: w = h = 8; break;
|
||||
case 3: w = h = 16; break;
|
||||
default: __assume(0);
|
||||
}
|
||||
|
||||
m_v.XY.X += w;
|
||||
m_v.XY.Y += h;
|
||||
|
||||
if(r[0].SPRITE.TME)
|
||||
{
|
||||
m_v.UV.X += w;
|
||||
m_v.UV.Y += h;
|
||||
}
|
||||
|
||||
VertexKick();
|
||||
|
||||
//
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
int GPUState::PH_Move(GPUReg* r, int size)
|
||||
{
|
||||
if(size < 4) return 0;
|
||||
|
||||
Flush();
|
||||
|
||||
CPoint src, dst;
|
||||
|
||||
src.x = r[1].XY.X;
|
||||
src.y = r[1].XY.Y;
|
||||
|
||||
dst.x = r[2].XY.X;
|
||||
dst.y = r[2].XY.Y;
|
||||
|
||||
int w = r[3].XY.X;
|
||||
int h = r[3].XY.Y;
|
||||
|
||||
m_mem.MoveRect(src, dst, w, h);
|
||||
|
||||
Invalidate(CRect(dst, CSize(w, h)));
|
||||
|
||||
// Dump(_T("m"));
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
int GPUState::PH_Write(GPUReg* r, int size)
|
||||
{
|
||||
if(size < 3) return 0;
|
||||
|
||||
int w = r[2].XY.X;
|
||||
int h = r[2].XY.Y;
|
||||
|
||||
int required = 3 + ((w * h + 1) >> 1);
|
||||
|
||||
if(size < required) return 0;
|
||||
|
||||
Flush();
|
||||
|
||||
CRect r2;
|
||||
|
||||
r2.left = r[1].XY.X;
|
||||
r2.top = r[1].XY.Y;
|
||||
r2.right = r2.left + w;
|
||||
r2.bottom = r2.top + h;
|
||||
|
||||
m_mem.WriteRect(r2, (const WORD*)&r[3]);
|
||||
|
||||
Invalidate(r2);
|
||||
|
||||
Dump(_T("w"));
|
||||
|
||||
m_perfmon.Put(GSPerfMon::Swizzle, w * h * 2);
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
int GPUState::PH_Read(GPUReg* r, int size)
|
||||
{
|
||||
if(size < 3) return 0;
|
||||
|
||||
Flush();
|
||||
|
||||
int w = r[2].XY.X;
|
||||
int h = r[2].XY.Y;
|
||||
|
||||
CRect r2;
|
||||
|
||||
r2.left = r[1].XY.X;
|
||||
r2.top = r[1].XY.Y;
|
||||
r2.right = r2.left + w;
|
||||
r2.bottom = r2.top + h;
|
||||
|
||||
m_read.bytes = ((w * h + 1) & ~1) * 2;
|
||||
m_read.cur = 0;
|
||||
m_read.Reserve(m_read.bytes);
|
||||
|
||||
m_mem.ReadRect(r2, (WORD*)m_read.buff);
|
||||
|
||||
Dump(_T("r"));
|
||||
|
||||
m_env.STATUS.IMG = 1;
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
int GPUState::PH_Environment(GPUReg* r, int size)
|
||||
{
|
||||
Flush(); // TODO: only call when something really changes
|
||||
|
||||
switch(r->PACKET.OPTION)
|
||||
{
|
||||
case 1: // draw mode setting
|
||||
|
||||
m_env.STATUS.TX = r->MODE.TX;
|
||||
m_env.STATUS.TY = r->MODE.TY;
|
||||
m_env.STATUS.ABR = r->MODE.ABR;
|
||||
m_env.STATUS.TP = r->MODE.TP;
|
||||
m_env.STATUS.DTD = r->MODE.DTD;
|
||||
m_env.STATUS.DFE = r->MODE.DFE;
|
||||
|
||||
return 1;
|
||||
|
||||
case 2: // texture window setting
|
||||
|
||||
m_env.TWIN = r->TWIN;
|
||||
|
||||
return 1;
|
||||
|
||||
case 3: // set drawing area top left
|
||||
|
||||
m_env.DRAREATL = r->DRAREA;
|
||||
|
||||
return 1;
|
||||
|
||||
case 4: // set drawing area bottom right
|
||||
|
||||
m_env.DRAREABR = r->DRAREA;
|
||||
|
||||
return 1;
|
||||
|
||||
case 5: // drawing offset
|
||||
|
||||
m_env.DROFF = r->DROFF;
|
||||
|
||||
return 1;
|
||||
|
||||
case 6: // mask setting
|
||||
|
||||
m_env.STATUS.MD = r->MASK.MD;
|
||||
m_env.STATUS.ME = r->MASK.ME;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ASSERT(0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
GPUState::Buffer::Buffer()
|
||||
{
|
||||
bytes = 0;
|
||||
maxbytes = 4096;
|
||||
buff = (BYTE*)_aligned_malloc(maxbytes, 16);
|
||||
cur = 0;
|
||||
}
|
||||
|
||||
GPUState::Buffer::~Buffer()
|
||||
{
|
||||
_aligned_free(buff);
|
||||
}
|
||||
|
||||
void GPUState::Buffer::Reserve(int size)
|
||||
{
|
||||
if(size > maxbytes)
|
||||
{
|
||||
maxbytes = (maxbytes + size + 1023) & ~1023;
|
||||
|
||||
buff = (BYTE*)_aligned_realloc(buff, maxbytes, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUState::Buffer::Append(const BYTE* src, int size)
|
||||
{
|
||||
Reserve(bytes + (int)size);
|
||||
|
||||
memcpy(&buff[bytes], src, size);
|
||||
|
||||
bytes += size;
|
||||
}
|
||||
|
||||
void GPUState::Buffer::Remove(int size)
|
||||
{
|
||||
ASSERT(size <= bytes);
|
||||
|
||||
if(size < bytes)
|
||||
{
|
||||
memmove(&buff[0], &buff[size], bytes - size);
|
||||
|
||||
bytes -= size;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
memset(&buff[bytes], 0xff, maxbytes - bytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GPUState::Buffer::RemoveAll()
|
||||
{
|
||||
bytes = 0;
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPU.h"
|
||||
#include "GPUDrawingEnvironment.h"
|
||||
#include "GPULocalMemory.h"
|
||||
#include "GPUVertex.h"
|
||||
#include "GSAlignedClass.h"
|
||||
#include "GSUtil.h"
|
||||
#include "GSPerfMon.h"
|
||||
|
||||
class GPUState : public GSAlignedClass<16>
|
||||
{
|
||||
typedef void (GPUState::*GPUStatusCommandHandler)(GPUReg* r);
|
||||
|
||||
GPUStatusCommandHandler m_fpGPUStatusCommandHandlers[256];
|
||||
|
||||
void SCH_Null(GPUReg* r);
|
||||
void SCH_ResetGPU(GPUReg* r);
|
||||
void SCH_ResetCommandBuffer(GPUReg* r);
|
||||
void SCH_ResetIRQ(GPUReg* r);
|
||||
void SCH_DisplayEnable(GPUReg* r);
|
||||
void SCH_DMASetup(GPUReg* r);
|
||||
void SCH_StartOfDisplayArea(GPUReg* r);
|
||||
void SCH_HorizontalDisplayRange(GPUReg* r);
|
||||
void SCH_VerticalDisplayRange(GPUReg* r);
|
||||
void SCH_DisplayMode(GPUReg* r);
|
||||
void SCH_GPUInfo(GPUReg* r);
|
||||
|
||||
typedef int (GPUState::*GPUPacketHandler)(GPUReg* r, int size);
|
||||
|
||||
GPUPacketHandler m_fpGPUPacketHandler[8];
|
||||
|
||||
int PH_Command(GPUReg* r, int size);
|
||||
int PH_Polygon(GPUReg* r, int size);
|
||||
int PH_Line(GPUReg* r, int size);
|
||||
int PH_Sprite(GPUReg* r, int size);
|
||||
int PH_Move(GPUReg* r, int size);
|
||||
int PH_Write(GPUReg* r, int size);
|
||||
int PH_Read(GPUReg* r, int size);
|
||||
int PH_Environment(GPUReg* r, int size);
|
||||
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
int bytes;
|
||||
int maxbytes;
|
||||
BYTE* buff;
|
||||
int cur;
|
||||
|
||||
public:
|
||||
Buffer();
|
||||
~Buffer();
|
||||
void Reserve(int size);
|
||||
void Append(const BYTE* src, int size);
|
||||
void Remove(int size);
|
||||
void RemoveAll();
|
||||
};
|
||||
|
||||
Buffer m_write;
|
||||
Buffer m_read;
|
||||
|
||||
void SetPrim(GPUReg* r);
|
||||
void SetCLUT(GPUReg* r);
|
||||
void SetTPAGE(GPUReg* r);
|
||||
|
||||
protected:
|
||||
|
||||
int s_n;
|
||||
|
||||
void Dump(LPCTSTR s, UINT32 TP, const CRect& r, int inc = true)
|
||||
{
|
||||
//if(m_perfmon.GetFrame() < 1000)
|
||||
//if((m_env.TWIN.ai32 & 0xfffff) == 0)
|
||||
//if(!m_env.STATUS.ME && !m_env.STATUS.MD)
|
||||
return;
|
||||
|
||||
if(inc) s_n++;
|
||||
|
||||
//if(s_n < 86) return;
|
||||
|
||||
int dir = 1;
|
||||
#ifdef DEBUG
|
||||
dir = 2;
|
||||
#endif
|
||||
CString str;
|
||||
str.Format(_T("c:\\temp%d\\%04d_%s.bmp"), dir, s_n, s);
|
||||
m_mem.SaveBMP(str, r, TP, m_env.CLUT.X, m_env.CLUT.Y);
|
||||
}
|
||||
|
||||
void Dump(LPCTSTR s, int inc = true)
|
||||
{
|
||||
Dump(s, 2, CRect(0, 0, 1024, 512), inc);
|
||||
}
|
||||
|
||||
public:
|
||||
GPUDrawingEnvironment m_env;
|
||||
GPULocalMemory m_mem;
|
||||
GPUVertex m_v;
|
||||
GSPerfMon m_perfmon;
|
||||
UINT32 m_status[256];
|
||||
|
||||
public:
|
||||
GPUState(const CSize& scale);
|
||||
virtual ~GPUState();
|
||||
|
||||
virtual void Reset();
|
||||
virtual void Flush();
|
||||
virtual void FlushPrim() = 0;
|
||||
virtual void ResetPrim() = 0;
|
||||
virtual void VertexKick() = 0;
|
||||
virtual void Invalidate(const CRect& r);
|
||||
|
||||
void WriteData(const BYTE* mem, UINT32 size);
|
||||
void ReadData(BYTE* mem, UINT32 size);
|
||||
|
||||
void WriteStatus(UINT32 status);
|
||||
UINT32 ReadStatus();
|
||||
|
||||
void Freeze(GPUFreezeData* data);
|
||||
void Defrost(const GPUFreezeData* data);
|
||||
};
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GPU.h"
|
||||
#include "GSVector.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
__declspec(align(16)) struct GPUVertex
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
GPURegRGB RGB;
|
||||
GPURegXY XY;
|
||||
GPURegXY UV;
|
||||
};
|
||||
|
||||
struct {__m128i m128i;};
|
||||
struct {__m128 m128;};
|
||||
};
|
||||
|
||||
GPUVertex() {memset(this, 0, sizeof(*this));}
|
||||
};
|
||||
|
||||
struct GPUVertexNull
|
||||
{
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
|
@ -0,0 +1,589 @@
|
|||
/*
|
||||
* 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 "GSRendererHW9.h"
|
||||
#include "GSRendererHW10.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 GSRendererBase* s_gs = NULL;
|
||||
static void (*s_irq)() = NULL;
|
||||
static BYTE* 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(BYTE* mem)
|
||||
{
|
||||
s_basemem = mem - 0x12000000;
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GSinit()
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C GSshutdown()
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
}
|
||||
|
||||
EXPORT_C GSclose()
|
||||
{
|
||||
delete s_gs;
|
||||
|
||||
s_gs = NULL;
|
||||
|
||||
if(SUCCEEDED(s_hr))
|
||||
{
|
||||
::CoUninitialize();
|
||||
|
||||
s_hr = E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static INT32 GSopen(void* dsp, char* title, int mt, int renderer)
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
if(!GSUtil::CheckDirectX() || !GSUtil::CheckSSE())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
GSclose();
|
||||
|
||||
// TODO
|
||||
|
||||
int nloophack = AfxGetApp()->GetProfileInt(_T("Settings"), _T("nloophack"), 2);
|
||||
|
||||
GSRendererSettings rs;
|
||||
|
||||
rs.m_interlace = AfxGetApp()->GetProfileInt(_T("Settings"), _T("interlace"), 0);
|
||||
rs.m_aspectratio = AfxGetApp()->GetProfileInt(_T("Settings"), _T("aspectratio"), 1);
|
||||
rs.m_filter = AfxGetApp()->GetProfileInt(_T("Settings"), _T("filter"), 1);
|
||||
rs.m_vsync = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("vsync"), FALSE);
|
||||
rs.m_nativeres = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("nativeres"), FALSE);
|
||||
|
||||
int threads = AfxGetApp()->GetProfileInt(_T("Settings"), _T("swthreads"), 1);
|
||||
|
||||
switch(renderer)
|
||||
{
|
||||
default:
|
||||
case 0: s_gs = new GSRendererHW9(s_basemem, !!mt, s_irq, nloophack, rs); break;
|
||||
case 1: s_gs = new GSRendererSW<GSDevice9>(s_basemem, !!mt, s_irq, nloophack, rs, threads); break;
|
||||
case 2: s_gs = new GSRendererNull<GSDevice9>(s_basemem, !!mt, s_irq, nloophack, rs); break;
|
||||
case 3: s_gs = new GSRendererHW10(s_basemem, !!mt, s_irq, nloophack, rs); break;
|
||||
case 4: s_gs = new GSRendererSW<GSDevice10>(s_basemem, !!mt, s_irq, nloophack, rs, threads); break;
|
||||
case 5: s_gs = new GSRendererNull<GSDevice10>(s_basemem, !!mt, s_irq, nloophack, rs); break;
|
||||
case 6: s_gs = new GSRendererSW<GSDeviceNull>(s_basemem, !!mt, s_irq, nloophack, rs, threads); break;
|
||||
case 7: s_gs = new GSRendererNull<GSDeviceNull>(s_basemem, !!mt, s_irq, nloophack, rs); break;
|
||||
}
|
||||
|
||||
s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
|
||||
if(!s_gs->Create(CString(title)))
|
||||
{
|
||||
GSclose();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
s_gs->m_wnd.Show();
|
||||
|
||||
*(HWND*)dsp = s_gs->m_wnd;
|
||||
|
||||
// if(mt) _mm_setcsr(MXCSR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GSopen(void* dsp, char* title, int mt)
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
int renderer = AfxGetApp()->GetProfileInt(_T("Settings"), _T("renderer"), 0);
|
||||
|
||||
return GSopen(dsp, title, mt, renderer);
|
||||
}
|
||||
|
||||
EXPORT_C GSreset()
|
||||
{
|
||||
s_gs->Reset();
|
||||
}
|
||||
|
||||
EXPORT_C GSgifSoftReset(int mask)
|
||||
{
|
||||
s_gs->SoftReset((BYTE)mask);
|
||||
}
|
||||
|
||||
EXPORT_C GSwriteCSR(UINT32 csr)
|
||||
{
|
||||
s_gs->WriteCSR(csr);
|
||||
}
|
||||
|
||||
EXPORT_C GSreadFIFO(BYTE* mem)
|
||||
{
|
||||
s_gs->ReadFIFO(mem, 1);
|
||||
}
|
||||
|
||||
EXPORT_C GSreadFIFO2(BYTE* mem, UINT32 size)
|
||||
{
|
||||
s_gs->ReadFIFO(mem, size);
|
||||
}
|
||||
|
||||
EXPORT_C GSgifTransfer1(BYTE* mem, UINT32 addr)
|
||||
{
|
||||
s_gs->Transfer<0>(mem + addr, (0x4000 - addr) / 16);
|
||||
}
|
||||
|
||||
EXPORT_C GSgifTransfer2(BYTE* mem, UINT32 size)
|
||||
{
|
||||
s_gs->Transfer<1>(mem, size);
|
||||
}
|
||||
|
||||
EXPORT_C GSgifTransfer3(BYTE* mem, UINT32 size)
|
||||
{
|
||||
s_gs->Transfer<2>(mem, size);
|
||||
}
|
||||
|
||||
EXPORT_C GSvsync(int field)
|
||||
{
|
||||
s_gs->VSync(field);
|
||||
}
|
||||
|
||||
EXPORT_C_(UINT32) GSmakeSnapshot(char* path)
|
||||
{
|
||||
return s_gs->MakeSnapshot(CString(path) + _T("gsdx"));
|
||||
}
|
||||
|
||||
EXPORT_C GSkeyEvent(keyEvent* ev)
|
||||
{
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) 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()
|
||||
{
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
GSSettingsDlg dlg;
|
||||
|
||||
if(IDOK == dlg.DoModal())
|
||||
{
|
||||
GSshutdown();
|
||||
GSinit();
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_C_(INT32) GStest()
|
||||
{
|
||||
return 0;
|
||||
|
||||
// TODO
|
||||
|
||||
/*
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
CComPtr<ID3D10Device> dev;
|
||||
|
||||
return SUCCEEDED(D3D10CreateDevice(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &dev)) ? 0 : -1;
|
||||
*/
|
||||
}
|
||||
|
||||
EXPORT_C GSabout()
|
||||
{
|
||||
}
|
||||
|
||||
EXPORT_C GSirqCallback(void (*irq)())
|
||||
{
|
||||
s_irq = irq;
|
||||
}
|
||||
|
||||
EXPORT_C GSsetGameCRC(DWORD 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 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);
|
||||
|
||||
CAtlArray<BYTE> buff;
|
||||
|
||||
if(FILE* fp = fopen(lpszCmdLine, "rb"))
|
||||
{
|
||||
GSinit();
|
||||
|
||||
BYTE regs[0x2000];
|
||||
GSsetBaseMem(regs);
|
||||
|
||||
HWND hWnd = NULL;
|
||||
GSopen(&hWnd, _T(""), true, renderer);
|
||||
|
||||
DWORD crc;
|
||||
fread(&crc, 4, 1, fp);
|
||||
GSsetGameCRC(crc, 0);
|
||||
|
||||
GSFreezeData fd;
|
||||
fread(&fd.size, 4, 1, fp);
|
||||
fd.data = new BYTE[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.GetCount() < 0x4000) buff.SetCount(0x4000);
|
||||
addr = 0x4000 - size;
|
||||
fread(buff.GetData() + addr, size, 1, fp);
|
||||
GSgifTransfer1(buff.GetData(), addr);
|
||||
break;
|
||||
case 1:
|
||||
if(buff.GetCount() < size) buff.SetCount(size);
|
||||
fread(buff.GetData(), size, 1, fp);
|
||||
GSgifTransfer2(buff.GetData(), size / 16);
|
||||
break;
|
||||
case 2:
|
||||
if(buff.GetCount() < size) buff.SetCount(size);
|
||||
fread(buff.GetData(), size, 1, fp);
|
||||
GSgifTransfer3(buff.GetData(), size / 16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
GSvsync(fgetc(fp));
|
||||
if(!IsWindowVisible(hWnd)) return;
|
||||
break;
|
||||
case 2:
|
||||
fread(&size, 4, 1, fp);
|
||||
if(buff.GetCount() < size) buff.SetCount(size);
|
||||
GSreadFIFO2(buff.GetData(), 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 = _tfopen(_T("c:\\log.txt"), _T("a"));
|
||||
|
||||
_ftprintf(file, _T("-------------------------\n\n"));
|
||||
|
||||
if(1)
|
||||
{
|
||||
GSLocalMemory mem;
|
||||
|
||||
static struct {int psm; LPCSTR 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"},
|
||||
};
|
||||
|
||||
BYTE* ptr = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16);
|
||||
|
||||
for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (BYTE)i;
|
||||
|
||||
//
|
||||
|
||||
for(int tbw = 5; tbw <= 10; tbw++)
|
||||
{
|
||||
int n = 256 << ((10 - tbw) * 2);
|
||||
|
||||
int w = 1 << tbw;
|
||||
int h = 1 << tbw;
|
||||
|
||||
_ftprintf(file, _T("%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;
|
||||
|
||||
CRect 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();
|
||||
|
||||
_ftprintf(file, _T("%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();
|
||||
|
||||
_ftprintf(file, _T("%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++)
|
||||
{
|
||||
(mem.*rtx)(r, ptr, w * 4, TEX0, TEXA);
|
||||
}
|
||||
|
||||
end = clock();
|
||||
|
||||
_ftprintf(file, _T("%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)(r, ptr, w, TEX0, TEXA);
|
||||
}
|
||||
|
||||
end = clock();
|
||||
|
||||
_ftprintf(file, _T("| %6d %6d "), (int)((float)len * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000));
|
||||
}
|
||||
|
||||
_ftprintf(file, _T("\n"));
|
||||
|
||||
fflush(file);
|
||||
}
|
||||
|
||||
_ftprintf(file, _T("\n"));
|
||||
}
|
||||
|
||||
_aligned_free(ptr);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
if(0)
|
||||
{
|
||||
GSLocalMemory mem;
|
||||
|
||||
BYTE* ptr = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16);
|
||||
|
||||
for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (BYTE)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);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 "GSAlignedClass.h"
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
template<int i> class GSAlignedClass
|
||||
{
|
||||
public:
|
||||
GSAlignedClass() {}
|
||||
|
||||
void* operator new (size_t size)
|
||||
{
|
||||
return _aligned_malloc(size, i);
|
||||
}
|
||||
|
||||
void operator delete (void* p)
|
||||
{
|
||||
_aligned_free(p);
|
||||
}
|
||||
|
||||
void* operator new [] (size_t size)
|
||||
{
|
||||
return _aligned_malloc(size, i);
|
||||
}
|
||||
|
||||
void operator delete [] (void* p)
|
||||
{
|
||||
_aligned_free(p);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 "GSBlock.h"
|
||||
|
||||
const GSVector4i GSBlock::m_r16mask(0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15);
|
||||
const GSVector4i GSBlock::m_r8mask(0, 4, 2, 6, 8, 12, 10, 14, 1, 5, 3, 7, 9, 13, 11, 15);
|
||||
const GSVector4i GSBlock::m_r4mask(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15);
|
||||
|
||||
const GSVector4i GSBlock::m_xxxa(0x00008000);
|
||||
const GSVector4i GSBlock::m_xxbx(0x00007c00);
|
||||
const GSVector4i GSBlock::m_xgxx(0x000003e0);
|
||||
const GSVector4i GSBlock::m_rxxx(0x0000001f);
|
||||
|
||||
const GSVector4i GSBlock::m_uw8hmask0 = GSVector4i(0, 0, 0, 0, 1, 1, 1, 1, 8, 8, 8, 8, 9, 9, 9, 9);
|
||||
const GSVector4i GSBlock::m_uw8hmask1 = GSVector4i(2, 2, 2, 2, 3, 3, 3, 3, 10, 10, 10, 10, 11, 11, 11, 11);
|
||||
const GSVector4i GSBlock::m_uw8hmask2 = GSVector4i(4, 4, 4, 4, 5, 5, 5, 5, 12, 12, 12, 12, 13, 13, 13, 13);
|
||||
const GSVector4i GSBlock::m_uw8hmask3 = GSVector4i(6, 6, 6, 6, 7, 7, 7, 7, 14, 14, 14, 14, 15, 15, 15, 15);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
* 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 "GSCapture.h"
|
||||
#include "GSVector.h"
|
||||
|
||||
//
|
||||
// GSSource
|
||||
//
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
interface __declspec(uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA"))
|
||||
#else
|
||||
[uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")] interface
|
||||
#endif
|
||||
IGSSource : public IUnknown
|
||||
{
|
||||
STDMETHOD(DeliverNewSegment)() PURE;
|
||||
STDMETHOD(DeliverFrame)(const void* bits, int pitch, bool rgba) PURE;
|
||||
STDMETHOD(DeliverEOS)() PURE;
|
||||
};
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
class __declspec(uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77"))
|
||||
#else
|
||||
[uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")] class
|
||||
#endif
|
||||
GSSource : public CBaseFilter, private CCritSec, public IGSSource
|
||||
{
|
||||
CSize m_size;
|
||||
REFERENCE_TIME m_atpf;
|
||||
REFERENCE_TIME m_now;
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
return
|
||||
QI(IGSSource)
|
||||
__super::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
class GSSourceOutputPin : public CBaseOutputPin
|
||||
{
|
||||
CSize m_size;
|
||||
CAtlArray<CMediaType> m_mts;
|
||||
|
||||
public:
|
||||
GSSourceOutputPin(CSize size, REFERENCE_TIME atpf, CBaseFilter* pFilter, CCritSec* pLock, HRESULT& hr)
|
||||
: CBaseOutputPin("GSSourceOutputPin", pFilter, pLock, &hr, L"Output")
|
||||
, m_size(size)
|
||||
{
|
||||
CMediaType mt;
|
||||
mt.majortype = MEDIATYPE_Video;
|
||||
mt.formattype = FORMAT_VideoInfo;
|
||||
|
||||
VIDEOINFOHEADER vih;
|
||||
memset(&vih, 0, sizeof(vih));
|
||||
vih.AvgTimePerFrame = atpf;
|
||||
vih.bmiHeader.biSize = sizeof(vih.bmiHeader);
|
||||
vih.bmiHeader.biWidth = m_size.cx;
|
||||
vih.bmiHeader.biHeight = m_size.cy;
|
||||
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
// YUY2
|
||||
|
||||
mt.subtype = MEDIASUBTYPE_YUY2;
|
||||
mt.lSampleSize = m_size.cx * m_size.cy * 2;
|
||||
|
||||
vih.bmiHeader.biCompression = '2YUY';
|
||||
vih.bmiHeader.biPlanes = 1;
|
||||
vih.bmiHeader.biBitCount = 16;
|
||||
vih.bmiHeader.biSizeImage = m_size.cx * m_size.cy * 2;
|
||||
mt.SetFormat((BYTE*)&vih, sizeof(vih));
|
||||
|
||||
m_mts.Add(mt);
|
||||
|
||||
#endif
|
||||
|
||||
// RGB32
|
||||
|
||||
mt.subtype = MEDIASUBTYPE_RGB32;
|
||||
mt.lSampleSize = m_size.cx * m_size.cy * 4;
|
||||
|
||||
vih.bmiHeader.biCompression = BI_RGB;
|
||||
vih.bmiHeader.biPlanes = 1;
|
||||
vih.bmiHeader.biBitCount = 32;
|
||||
vih.bmiHeader.biSizeImage = m_size.cx * m_size.cy * 4;
|
||||
mt.SetFormat((BYTE*)&vih, sizeof(vih));
|
||||
|
||||
m_mts.Add(mt);
|
||||
}
|
||||
|
||||
HRESULT GSSourceOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
|
||||
{
|
||||
ASSERT(pAlloc && pProperties);
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
pProperties->cBuffers = 1;
|
||||
pProperties->cbBuffer = m_mt.lSampleSize;
|
||||
|
||||
ALLOCATOR_PROPERTIES Actual;
|
||||
|
||||
if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual)))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
if(Actual.cbBuffer < pProperties->cbBuffer)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
ASSERT(Actual.cBuffers == pProperties->cBuffers);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CheckMediaType(const CMediaType* pmt)
|
||||
{
|
||||
for(int i = 0, j = m_mts.GetCount(); i < j; i++)
|
||||
{
|
||||
if(m_mts[i].majortype == pmt->majortype && m_mts[i].subtype == pmt->subtype)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT GetMediaType(int i, CMediaType* pmt)
|
||||
{
|
||||
CheckPointer(pmt, E_POINTER);
|
||||
|
||||
if(i < 0) return E_INVALIDARG;
|
||||
if(i > 1) return VFW_S_NO_MORE_ITEMS;
|
||||
|
||||
*pmt = m_mts[i];
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Notify(IBaseFilter* pSender, Quality q)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
const CMediaType& CurrentMediaType()
|
||||
{
|
||||
return m_mt;
|
||||
}
|
||||
};
|
||||
|
||||
CAutoPtr<GSSourceOutputPin> m_output;
|
||||
|
||||
public:
|
||||
|
||||
GSSource(int w, int h, int fps, IUnknown* pUnk, HRESULT& hr)
|
||||
: CBaseFilter(NAME("GSSource"), pUnk, this, __uuidof(this), &hr)
|
||||
, m_output(NULL)
|
||||
, m_size(w, h)
|
||||
, m_atpf(10000000i64 / fps)
|
||||
, m_now(0)
|
||||
{
|
||||
m_output.Attach(new GSSourceOutputPin(m_size, m_atpf, this, this, hr));
|
||||
|
||||
// FIXME
|
||||
if(fps == 60) m_atpf = 166834; // = 10000000i64 / 59.94
|
||||
}
|
||||
|
||||
DECLARE_IUNKNOWN;
|
||||
|
||||
int GetPinCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
CBasePin* GetPin(int n)
|
||||
{
|
||||
return n == 0 ? m_output.m_p : NULL;
|
||||
}
|
||||
|
||||
// IGSSource
|
||||
|
||||
STDMETHODIMP DeliverNewSegment()
|
||||
{
|
||||
m_now = 0;
|
||||
|
||||
return m_output->DeliverNewSegment(0, _I64_MAX, 1.0);
|
||||
}
|
||||
|
||||
STDMETHODIMP DeliverFrame(const void* bits, int pitch, bool rgba)
|
||||
{
|
||||
if(!m_output || !m_output->IsConnected())
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
CComPtr<IMediaSample> sample;
|
||||
|
||||
if(FAILED(m_output->GetDeliveryBuffer(&sample, NULL, NULL, 0)))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
REFERENCE_TIME start = m_now;
|
||||
REFERENCE_TIME stop = m_now + m_atpf;
|
||||
|
||||
sample->SetTime(&start, &stop);
|
||||
sample->SetSyncPoint(TRUE);
|
||||
|
||||
const CMediaType& mt = m_output->CurrentMediaType();
|
||||
|
||||
BYTE* src = (BYTE*)bits;
|
||||
|
||||
BYTE* dst = NULL;
|
||||
sample->GetPointer(&dst);
|
||||
|
||||
int w = m_size.cx;
|
||||
int h = m_size.cy;
|
||||
int srcpitch = pitch;
|
||||
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
if(mt.subtype == MEDIASUBTYPE_YUY2)
|
||||
{
|
||||
int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 2;
|
||||
|
||||
const GSVector4 ys(0.098f, 0.504f, 0.257f, 0.0f);
|
||||
const GSVector4 us(0.439f / 2, -0.291f / 2, -0.148f / 2, 0.0f);
|
||||
const GSVector4 vs(-0.071f / 2, -0.368f / 2, 0.439f / 2, 0.0f);
|
||||
const GSVector4 offset(16, 128, 16, 128);
|
||||
|
||||
if(rgba)
|
||||
{
|
||||
for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch)
|
||||
{
|
||||
DWORD* s = (DWORD*)src;
|
||||
WORD* d = (WORD*)dst;
|
||||
|
||||
for(int i = 0; i < w; i += 2)
|
||||
{
|
||||
GSVector4 c0 = GSVector4(s[i + 0]);
|
||||
GSVector4 c1 = GSVector4(s[i + 1]);
|
||||
GSVector4 c2 = c0 + c1;
|
||||
|
||||
GSVector4 lo = (c0 * ys).hadd(c2 * vs);
|
||||
GSVector4 hi = (c1 * ys).hadd(c2 * us);
|
||||
|
||||
GSVector4 c = lo.hadd(hi) + offset;
|
||||
|
||||
*((DWORD*)&d[i]) = GSVector4i(c).rgba32();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch)
|
||||
{
|
||||
DWORD* s = (DWORD*)src;
|
||||
WORD* d = (WORD*)dst;
|
||||
|
||||
for(int i = 0; i < w; i += 2)
|
||||
{
|
||||
GSVector4 c0 = GSVector4(s[i + 0]).zyxw();
|
||||
GSVector4 c1 = GSVector4(s[i + 1]).zyxw();
|
||||
GSVector4 c2 = c0 + c1;
|
||||
|
||||
GSVector4 lo = (c0 * ys).hadd(c2 * vs);
|
||||
GSVector4 hi = (c1 * ys).hadd(c2 * us);
|
||||
|
||||
GSVector4 c = lo.hadd(hi) + offset;
|
||||
|
||||
*((DWORD*)&d[i]) = GSVector4i(c).rgba32();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
#endif
|
||||
|
||||
if(mt.subtype == MEDIASUBTYPE_RGB32)
|
||||
{
|
||||
int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 4;
|
||||
|
||||
dst += dstpitch * (h - 1);
|
||||
dstpitch = -dstpitch;
|
||||
|
||||
for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch)
|
||||
{
|
||||
if(rgba)
|
||||
{
|
||||
#if _M_SSE >= 0x301
|
||||
|
||||
GSVector4i* s = (GSVector4i*)src;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
GSVector4i mask(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15);
|
||||
|
||||
for(int i = 0, w4 = w >> 2; i < w4; i++)
|
||||
{
|
||||
d[i] = s[i].shuffle8(mask);
|
||||
}
|
||||
|
||||
#elif _M_SSE >= 0x200
|
||||
|
||||
GSVector4i* s = (GSVector4i*)src;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
for(int i = 0, w4 = w >> 2; i < w4; i++)
|
||||
{
|
||||
d[i] = ((s[i] & 0x00ff0000) >> 16) | ((s[i] & 0x000000ff) << 16) | (s[i] & 0x0000ff00);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
DWORD* s = (DWORD*)src;
|
||||
DWORD* d = (DWORD*)dst;
|
||||
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
d[i] = ((s[i] & 0x00ff0000) >> 16) | ((s[i] & 0x000000ff) << 16) | (s[i] & 0x0000ff00);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(dst, src, w * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if(FAILED(m_output->Deliver(sample)))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
m_now = stop;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP DeliverEOS()
|
||||
{
|
||||
return m_output->DeliverEndOfStream();
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// GSCapture
|
||||
//
|
||||
|
||||
GSCapture::GSCapture()
|
||||
: m_capturing(false)
|
||||
{
|
||||
}
|
||||
|
||||
GSCapture::~GSCapture()
|
||||
{
|
||||
EndCapture();
|
||||
}
|
||||
|
||||
#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \
|
||||
{CComPtr<IEnumPins> pEnumPins; \
|
||||
if(pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) \
|
||||
{ \
|
||||
for(CComPtr<IPin> pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = NULL) \
|
||||
{ \
|
||||
|
||||
#define EndEnumPins }}}
|
||||
|
||||
static IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir)
|
||||
{
|
||||
if(!pBF) return(NULL);
|
||||
|
||||
BeginEnumPins(pBF, pEP, pPin)
|
||||
{
|
||||
PIN_DIRECTION dir2;
|
||||
pPin->QueryDirection(&dir2);
|
||||
if(dir == dir2)
|
||||
{
|
||||
IPin* pRet = pPin.Detach();
|
||||
pRet->Release();
|
||||
return(pRet);
|
||||
}
|
||||
}
|
||||
EndEnumPins
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
bool GSCapture::BeginCapture(int fps)
|
||||
{
|
||||
CAutoLock cAutoLock(this);
|
||||
|
||||
ASSERT(fps != 0);
|
||||
|
||||
EndCapture();
|
||||
|
||||
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||||
|
||||
GSCaptureDlg dlg;
|
||||
|
||||
if(IDOK != dlg.DoModal()) return false;
|
||||
|
||||
m_size.cx = (dlg.m_width + 7) & ~7;
|
||||
m_size.cy = (dlg.m_height + 7) & ~7;
|
||||
|
||||
//
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
CComPtr<ICaptureGraphBuilder2> cgb;
|
||||
CComPtr<IBaseFilter> mux;
|
||||
|
||||
if(FAILED(hr = m_graph.CoCreateInstance(CLSID_FilterGraph))
|
||||
|| FAILED(hr = cgb.CoCreateInstance(CLSID_CaptureGraphBuilder2))
|
||||
|| FAILED(hr = cgb->SetFiltergraph(m_graph))
|
||||
|| FAILED(hr = cgb->SetOutputFileName(&MEDIASUBTYPE_Avi, CStringW(dlg.m_filename), &mux, NULL)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_src = new GSSource(m_size.cx, m_size.cy, fps, NULL, hr);
|
||||
|
||||
if(FAILED(hr = m_graph->AddFilter(m_src, L"Source"))
|
||||
|| FAILED(hr = m_graph->AddFilter(dlg.m_enc, L"Encoder")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(dlg.m_enc, PINDIR_INPUT), NULL))
|
||||
|| FAILED(hr = m_graph->ConnectDirect(GetFirstPin(dlg.m_enc, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BeginEnumFilters(m_graph, pEF, pBF)
|
||||
{
|
||||
CFilterInfo fi;
|
||||
pBF->QueryFilterInfo(&fi);
|
||||
printf("Filter [%p]: %s\n", pBF.p, CStringA(fi.achName));
|
||||
|
||||
BeginEnumPins(pBF, pEP, pPin)
|
||||
{
|
||||
CComPtr<IPin> pPinTo;
|
||||
pPin->ConnectedTo(&pPinTo);
|
||||
|
||||
CPinInfo pi;
|
||||
pPin->QueryPinInfo(&pi);
|
||||
printf("- Pin [%p - %p]: %s (%s)\n", pPin.p, pPinTo.p, CStringA(pi.achName), pi.dir ? "out" : "in");
|
||||
|
||||
BeginEnumMediaTypes(pPin, pEMT, pmt)
|
||||
{
|
||||
}
|
||||
EndEnumMediaTypes(pmt)
|
||||
}
|
||||
EndEnumPins
|
||||
}
|
||||
EndEnumFilters
|
||||
|
||||
hr = CComQIPtr<IMediaControl>(m_graph)->Run();
|
||||
|
||||
CComQIPtr<IGSSource>(m_src)->DeliverNewSegment();
|
||||
|
||||
m_capturing = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSCapture::DeliverFrame(const void* bits, int pitch, bool rgba)
|
||||
{
|
||||
CAutoLock cAutoLock(this);
|
||||
|
||||
if(bits == NULL || pitch == 0)
|
||||
{
|
||||
ASSERT(0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_src)
|
||||
{
|
||||
CComQIPtr<IGSSource>(m_src)->DeliverFrame(bits, pitch, rgba);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GSCapture::EndCapture()
|
||||
{
|
||||
CAutoLock cAutoLock(this);
|
||||
|
||||
if(m_src)
|
||||
{
|
||||
CComQIPtr<IGSSource>(m_src)->DeliverEOS();
|
||||
|
||||
m_src = NULL;
|
||||
}
|
||||
|
||||
if(m_graph)
|
||||
{
|
||||
CComQIPtr<IMediaControl>(m_graph)->Stop();
|
||||
|
||||
m_graph = NULL;
|
||||
}
|
||||
|
||||
m_capturing = false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSCaptureDlg.h"
|
||||
|
||||
class GSCapture : protected CCritSec
|
||||
{
|
||||
bool m_capturing;
|
||||
CSize m_size;
|
||||
CComPtr<IGraphBuilder> m_graph;
|
||||
CComPtr<IBaseFilter> m_src;
|
||||
|
||||
public:
|
||||
GSCapture();
|
||||
virtual ~GSCapture();
|
||||
|
||||
bool BeginCapture(int fps);
|
||||
bool DeliverFrame(const void* bits, int pitch, bool rgba);
|
||||
bool EndCapture();
|
||||
|
||||
bool IsCapturing() {return m_capturing;}
|
||||
CSize GetSize() {return m_size;}
|
||||
};
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* 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 <afxpriv.h>
|
||||
#include "GSCaptureDlg.h"
|
||||
|
||||
// GSCaptureDlg dialog
|
||||
|
||||
IMPLEMENT_DYNAMIC(GSCaptureDlg, CDialog)
|
||||
GSCaptureDlg::GSCaptureDlg(CWnd* pParent /*=NULL*/)
|
||||
: CDialog(GSCaptureDlg::IDD, pParent)
|
||||
{
|
||||
m_width = AfxGetApp()->GetProfileInt(_T("Capture"), _T("Width"), 640);
|
||||
m_height = AfxGetApp()->GetProfileInt(_T("Capture"), _T("Height"), 480);
|
||||
m_filename = AfxGetApp()->GetProfileString(_T("Capture"), _T("FileName"));
|
||||
}
|
||||
|
||||
GSCaptureDlg::~GSCaptureDlg()
|
||||
{
|
||||
}
|
||||
|
||||
int GSCaptureDlg::GetSelCodec(Codec& c)
|
||||
{
|
||||
int iSel = m_codeclist.GetCurSel();
|
||||
|
||||
if(iSel < 0) return 0;
|
||||
|
||||
POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(iSel);
|
||||
|
||||
if(pos == NULL) return 2;
|
||||
|
||||
c = m_codecs.GetAt(pos);
|
||||
|
||||
if(!c.filter)
|
||||
{
|
||||
c.moniker->BindToObject(NULL, NULL, __uuidof(IBaseFilter), (void**)&c.filter);
|
||||
|
||||
if(!c.filter) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LRESULT GSCaptureDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
|
||||
|
||||
if(message == WM_INITDIALOG) SendMessage(WM_KICKIDLE);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void GSCaptureDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
__super::DoDataExchange(pDX);
|
||||
|
||||
DDX_Text(pDX, IDC_EDIT1, m_filename);
|
||||
DDX_Control(pDX, IDC_COMBO1, m_codeclist);
|
||||
DDX_Text(pDX, IDC_EDIT2, m_width);
|
||||
DDX_Text(pDX, IDC_EDIT4, m_height);
|
||||
}
|
||||
|
||||
BOOL GSCaptureDlg::OnInitDialog()
|
||||
{
|
||||
__super::OnInitDialog();
|
||||
|
||||
m_codecs.RemoveAll();
|
||||
|
||||
m_codeclist.ResetContent();
|
||||
m_codeclist.SetItemDataPtr(m_codeclist.AddString(_T("Uncompressed")), NULL);
|
||||
|
||||
BeginEnumSysDev(CLSID_VideoCompressorCategory, moniker)
|
||||
{
|
||||
Codec c;
|
||||
c.moniker = moniker;
|
||||
|
||||
LPOLESTR strName = NULL;
|
||||
if(FAILED(moniker->GetDisplayName(NULL, NULL, &strName)))
|
||||
continue;
|
||||
|
||||
c.DisplayName = strName;
|
||||
CoTaskMemFree(strName);
|
||||
|
||||
CComPtr<IPropertyBag> pPB;
|
||||
moniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPB);
|
||||
|
||||
CComVariant var;
|
||||
if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
|
||||
continue;
|
||||
|
||||
c.FriendlyName = var.bstrVal;
|
||||
|
||||
CStringW str = CStringW(c.DisplayName).MakeLower();
|
||||
CString prefix;
|
||||
if(str.Find(L"@device:dmo:") == 0) prefix = _T("(DMO) ");
|
||||
else if(str.Find(L"@device:sw:") == 0) prefix = _T("(DS) ");
|
||||
else if(str.Find(L"@device:cm:") == 0) prefix = _T("(VfW) ");
|
||||
c.FriendlyName = prefix + c.FriendlyName;
|
||||
|
||||
m_codeclist.SetItemDataPtr(m_codeclist.AddString(c.FriendlyName), m_codecs.AddTail(c));
|
||||
}
|
||||
EndEnumSysDev
|
||||
|
||||
//
|
||||
|
||||
CString DisplayNameToFind = AfxGetApp()->GetProfileString(_T("Capture"), _T("VideoCodecDisplayName"));
|
||||
|
||||
for(int i = 0; i < m_codeclist.GetCount(); i++)
|
||||
{
|
||||
CString DisplayName;
|
||||
|
||||
POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(i);
|
||||
|
||||
if(pos) DisplayName = m_codecs.GetAt(pos).DisplayName;
|
||||
|
||||
if(DisplayName == DisplayNameToFind)
|
||||
{
|
||||
m_codeclist.SetCurSel(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
UpdateData(FALSE);
|
||||
|
||||
return TRUE; // return TRUE unless you set the focus to a control
|
||||
// EXCEPTION: OCX Property Pages should return FALSE
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(GSCaptureDlg, CDialog)
|
||||
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
|
||||
ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1)
|
||||
ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2)
|
||||
ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateButton2)
|
||||
ON_BN_CLICKED(IDOK, OnBnClickedOk)
|
||||
ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOK)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
// GSCaptureDlg message handlers
|
||||
|
||||
void GSCaptureDlg::OnKickIdle()
|
||||
{
|
||||
UpdateDialogControls(this, false);
|
||||
}
|
||||
|
||||
void GSCaptureDlg::OnBnClickedButton1()
|
||||
{
|
||||
UpdateData();
|
||||
|
||||
DWORD flags = OFN_EXPLORER|OFN_ENABLESIZING|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST;
|
||||
|
||||
CFileDialog fd(FALSE, _T("avi"), m_filename, flags, _T("Avi files (*.avi)|*.avi||"), this, 0);
|
||||
|
||||
if(fd.DoModal() == IDOK)
|
||||
{
|
||||
m_filename = fd.GetPathName();
|
||||
|
||||
UpdateData(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void GSCaptureDlg::OnBnClickedButton2()
|
||||
{
|
||||
Codec c;
|
||||
|
||||
if(GetSelCodec(c) != 1) return;
|
||||
|
||||
if(CComQIPtr<ISpecifyPropertyPages> pSPP = c.filter)
|
||||
{
|
||||
CAUUID caGUID;
|
||||
|
||||
memset(&caGUID, 0, sizeof(caGUID));
|
||||
|
||||
if(SUCCEEDED(pSPP->GetPages(&caGUID)))
|
||||
{
|
||||
IUnknown* lpUnk = NULL;
|
||||
pSPP.QueryInterface(&lpUnk);
|
||||
OleCreatePropertyFrame(m_hWnd, 0, 0, CStringW(c.FriendlyName), 1, (IUnknown**)&lpUnk, caGUID.cElems, caGUID.pElems, 0, 0, NULL);
|
||||
lpUnk->Release();
|
||||
|
||||
if(caGUID.pElems) CoTaskMemFree(caGUID.pElems);
|
||||
}
|
||||
}
|
||||
else if(CComQIPtr<IAMVfwCompressDialogs> pAMVfWCD = c.filter)
|
||||
{
|
||||
if(pAMVfWCD->ShowDialog(VfwCompressDialog_QueryConfig, NULL) == S_OK)
|
||||
{
|
||||
pAMVfWCD->ShowDialog(VfwCompressDialog_Config, m_hWnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSCaptureDlg::OnUpdateButton2(CCmdUI* pCmdUI)
|
||||
{
|
||||
pCmdUI->Enable(m_codeclist.GetCurSel() >= 0 && m_codeclist.GetItemDataPtr(m_codeclist.GetCurSel()) != NULL);
|
||||
}
|
||||
|
||||
void GSCaptureDlg::OnBnClickedOk()
|
||||
{
|
||||
UpdateData();
|
||||
|
||||
Codec c;
|
||||
|
||||
if(GetSelCodec(c) == 0) return;
|
||||
|
||||
m_enc = c.filter;
|
||||
|
||||
AfxGetApp()->WriteProfileInt(_T("Capture"), _T("Width"), m_width);
|
||||
AfxGetApp()->WriteProfileInt(_T("Capture"), _T("Height"), m_height);
|
||||
AfxGetApp()->WriteProfileString(_T("Capture"), _T("FileName"), m_filename);
|
||||
AfxGetApp()->WriteProfileString(_T("Capture"), _T("VideoCodecDisplayName"), CString(c.DisplayName));
|
||||
|
||||
OnOK();
|
||||
}
|
||||
|
||||
void GSCaptureDlg::OnUpdateOK(CCmdUI* pCmdUI)
|
||||
{
|
||||
CString str;
|
||||
|
||||
GetDlgItem(IDC_EDIT1)->GetWindowText(str);
|
||||
|
||||
pCmdUI->Enable(!str.IsEmpty() && m_codeclist.GetCurSel() >= 0);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "resource.h"
|
||||
#include "baseclasses/streams.h"
|
||||
|
||||
// GSCaptureDlg dialog
|
||||
|
||||
class GSCaptureDlg : public CDialog
|
||||
{
|
||||
DECLARE_DYNAMIC(GSCaptureDlg)
|
||||
|
||||
private:
|
||||
struct Codec
|
||||
{
|
||||
CComPtr<IMoniker> moniker;
|
||||
CComPtr<IBaseFilter> filter;
|
||||
CString FriendlyName;
|
||||
CComBSTR DisplayName;
|
||||
};
|
||||
|
||||
CAtlList<Codec> m_codecs;
|
||||
|
||||
int GetSelCodec(Codec& c);
|
||||
|
||||
public:
|
||||
GSCaptureDlg(CWnd* pParent = NULL); // standard constructor
|
||||
virtual ~GSCaptureDlg();
|
||||
|
||||
CComPtr<IBaseFilter> m_enc;
|
||||
|
||||
// Dialog Data
|
||||
enum { IDD = IDD_CAPTURE };
|
||||
CString m_filename;
|
||||
CComboBox m_codeclist;
|
||||
|
||||
protected:
|
||||
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
virtual BOOL OnInitDialog();
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
public:
|
||||
afx_msg void OnKickIdle();
|
||||
afx_msg void OnBnClickedButton1();
|
||||
afx_msg void OnBnClickedButton2();
|
||||
afx_msg void OnUpdateButton2(CCmdUI* pCmdUI);
|
||||
afx_msg void OnBnClickedOk();
|
||||
afx_msg void OnUpdateOK(CCmdUI* pCmdUI);
|
||||
int m_width;
|
||||
int m_height;
|
||||
};
|
|
@ -0,0 +1,869 @@
|
|||
/*
|
||||
* 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 "GSClut.h"
|
||||
#include "GSLocalMemory.h"
|
||||
|
||||
GSClut::GSClut(const GSLocalMemory* mem)
|
||||
: m_mem(mem)
|
||||
{
|
||||
BYTE* p = (BYTE*)VirtualAlloc(NULL, 2 * 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
m_clut = (WORD*)&p[0]; // 1k + 1k for buffer overruns (sfex: PSM == PSM_PSMT8, CPSM == PSM_PSMCT32, CSA != 0)
|
||||
m_buff32 = (DWORD*)&p[2048]; // 1k
|
||||
m_buff64 = (UINT64*)&p[4096]; // 2k
|
||||
m_write.dirty = true;
|
||||
m_read.dirty = true;
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
for(int j = 0; j < 64; j++)
|
||||
{
|
||||
m_wc[0][i][j] = &GSClut::WriteCLUT_NULL;
|
||||
m_wc[1][i][j] = &GSClut::WriteCLUT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
m_wc[0][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1;
|
||||
m_wc[0][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1;
|
||||
m_wc[0][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1;
|
||||
m_wc[0][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1;
|
||||
m_wc[0][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_I8_CSM1;
|
||||
m_wc[0][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_I8_CSM1;
|
||||
m_wc[0][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_I8_CSM1;
|
||||
m_wc[0][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_I8_CSM1;
|
||||
m_wc[0][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_I4_CSM1;
|
||||
m_wc[0][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_I4_CSM1;
|
||||
|
||||
m_wc[1][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>;
|
||||
m_wc[1][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>;
|
||||
m_wc[1][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>;
|
||||
m_wc[1][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>;
|
||||
m_wc[1][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_CSM2<256>;
|
||||
m_wc[1][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_CSM2<256>;
|
||||
m_wc[1][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_CSM2<256>;
|
||||
m_wc[1][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_CSM2<256>;
|
||||
m_wc[1][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_CSM2<16>;
|
||||
m_wc[1][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_CSM2<16>;
|
||||
}
|
||||
|
||||
GSClut::~GSClut()
|
||||
{
|
||||
VirtualFree(m_clut, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
void GSClut::Invalidate()
|
||||
{
|
||||
m_write.dirty = true;
|
||||
}
|
||||
|
||||
bool GSClut::WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
switch(TEX0.CLD)
|
||||
{
|
||||
case 0: return false;
|
||||
case 1: break;
|
||||
case 2: m_CBP[0] = TEX0.CBP; break;
|
||||
case 3: m_CBP[1] = TEX0.CBP; break;
|
||||
case 4: if(m_CBP[0] == TEX0.CBP) return false; m_CBP[0] = TEX0.CBP; break;
|
||||
case 5: if(m_CBP[1] == TEX0.CBP) return false; m_CBP[1] = TEX0.CBP; break;
|
||||
case 6: ASSERT(0); return false;
|
||||
case 7: ASSERT(0); return false;
|
||||
default: __assume(0);
|
||||
}
|
||||
|
||||
return m_write.IsDirty(TEX0, TEXCLUT);
|
||||
}
|
||||
|
||||
void GSClut::Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
m_write.TEX0 = TEX0;
|
||||
m_write.TEXCLUT = TEXCLUT;
|
||||
m_write.dirty = false;
|
||||
m_read.dirty = true;
|
||||
|
||||
(this->*m_wc[TEX0.CSM][TEX0.CPSM][TEX0.PSM])(TEX0, TEXCLUT);
|
||||
}
|
||||
|
||||
void GSClut::WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
ASSERT(TEX0.CSA == 0);
|
||||
|
||||
WriteCLUT_T32_I8_CSM1(&m_mem->m_vm32[m_mem->BlockAddress32(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
|
||||
}
|
||||
|
||||
void GSClut::WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
ASSERT(TEX0.CSA < 16);
|
||||
|
||||
GSVector4i dummy; // this just forces stack alignment and enables inlining the next call
|
||||
|
||||
WriteCLUT_T32_I4_CSM1(&m_mem->m_vm32[m_mem->BlockAddress32(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
|
||||
}
|
||||
|
||||
void GSClut::WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
ASSERT(TEX0.CSA < 16);
|
||||
|
||||
WriteCLUT_T16_I8_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
|
||||
}
|
||||
|
||||
void GSClut::WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
ASSERT(TEX0.CSA < 32);
|
||||
|
||||
WriteCLUT_T16_I4_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
|
||||
}
|
||||
|
||||
void GSClut::WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
WriteCLUT_T16_I8_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16S(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
|
||||
}
|
||||
|
||||
void GSClut::WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
WriteCLUT_T16_I4_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16S(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
|
||||
}
|
||||
|
||||
template<int n> void GSClut::WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4);
|
||||
|
||||
DWORD base = m_mem->PixelAddress32(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW);
|
||||
int* offset = &m_mem->rowOffset32[TEXCLUT.COU << 4];
|
||||
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
DWORD c = m_mem->ReadPixel32(base + offset[i]);
|
||||
|
||||
clut[i] = (WORD)(c & 0xffff);
|
||||
clut[i + 256] = (WORD)(c >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
template<int n> void GSClut::WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4);
|
||||
|
||||
DWORD base = m_mem->PixelAddress16(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW);
|
||||
int* offset = &m_mem->rowOffset16[TEXCLUT.COU << 4];
|
||||
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
clut[i] = (WORD)m_mem->ReadPixel16(base + offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<int n> void GSClut::WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4);
|
||||
|
||||
DWORD base = m_mem->PixelAddress16S(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW);
|
||||
int* offset = &m_mem->rowOffset16S[TEXCLUT.COU << 4];
|
||||
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
clut[i] = (WORD)m_mem->ReadPixel16(base + offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void GSClut::Read(const GIFRegTEX0& TEX0)
|
||||
{
|
||||
if(m_read.IsDirty(TEX0))
|
||||
{
|
||||
m_read.TEX0 = TEX0;
|
||||
m_read.dirty = false;
|
||||
|
||||
WORD* clut = m_clut + (TEX0.CSA << 4);
|
||||
|
||||
if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24)
|
||||
{
|
||||
switch(TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMT8:
|
||||
case PSM_PSMT8H:
|
||||
ReadCLUT_T32_I8(clut, m_buff32);
|
||||
break;
|
||||
case PSM_PSMT4:
|
||||
case PSM_PSMT4HL:
|
||||
case PSM_PSMT4HH:
|
||||
ReadCLUT_T32_I4(clut, m_buff32, m_buff64);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S)
|
||||
{
|
||||
switch(TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMT8:
|
||||
case PSM_PSMT8H:
|
||||
ReadCLUT_T16_I8(clut, m_buff32);
|
||||
break;
|
||||
case PSM_PSMT4:
|
||||
case PSM_PSMT4HL:
|
||||
case PSM_PSMT4HH:
|
||||
ReadCLUT_T16_I4(clut, m_buff32, m_buff64);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
|
||||
{
|
||||
if(m_read.IsDirty(TEX0, TEXA))
|
||||
{
|
||||
m_read.TEX0 = TEX0;
|
||||
m_read.TEXA = TEXA;
|
||||
m_read.dirty = false;
|
||||
m_read.adirty = true;
|
||||
|
||||
WORD* clut = m_clut + (TEX0.CSA << 4);
|
||||
|
||||
if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24)
|
||||
{
|
||||
switch(TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMT8:
|
||||
case PSM_PSMT8H:
|
||||
ReadCLUT_T32_I8(clut, m_buff32);
|
||||
break;
|
||||
case PSM_PSMT4:
|
||||
case PSM_PSMT4HL:
|
||||
case PSM_PSMT4HH:
|
||||
// TODO: merge these functions
|
||||
ReadCLUT_T32_I4(clut, m_buff32);
|
||||
ExpandCLUT64_T32_I8(m_buff32, (UINT64*)m_buff64); // sw renderer does not need m_buff64 anymore
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S)
|
||||
{
|
||||
switch(TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMT8:
|
||||
case PSM_PSMT8H:
|
||||
Expand16(clut, m_buff32, 256, TEXA);
|
||||
break;
|
||||
case PSM_PSMT4:
|
||||
case PSM_PSMT4HL:
|
||||
case PSM_PSMT4HH:
|
||||
// TODO: merge these functions
|
||||
Expand16(clut, m_buff32, 16, TEXA);
|
||||
ExpandCLUT64_T32_I8(m_buff32, (UINT64*)m_buff64); // sw renderer does not need m_buff64 anymore
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSClut::GetAlphaMinMax32(int& amin, int& amax)
|
||||
{
|
||||
// call only after Read32
|
||||
|
||||
ASSERT(!m_read.dirty);
|
||||
|
||||
if(m_read.adirty)
|
||||
{
|
||||
m_read.adirty = false;
|
||||
|
||||
// DWORD bpp = GSLocalMemory::m_psm[m_read.TEX0.PSM].trbpp;
|
||||
DWORD cbpp = GSLocalMemory::m_psm[m_read.TEX0.CPSM].trbpp;
|
||||
DWORD pal = GSLocalMemory::m_psm[m_read.TEX0.PSM].pal;
|
||||
|
||||
if(cbpp == 24 && m_read.TEXA.AEM == 0)
|
||||
{
|
||||
m_read.amin = m_read.TEXA.TA0;
|
||||
m_read.amax = m_read.TEXA.TA0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int amin = 255;
|
||||
int amax = 0;
|
||||
|
||||
const GSVector4i* p = (const GSVector4i*)m_buff32;
|
||||
|
||||
for(int i = 0, j = pal >> 4; i < j; i++)
|
||||
{
|
||||
GSVector4i v0 = (p[i * 4 + 0] >> 24).ps32(p[i * 4 + 1] >> 24);
|
||||
GSVector4i v1 = (p[i * 4 + 2] >> 24).ps32(p[i * 4 + 3] >> 24);
|
||||
|
||||
GSVector4i v2 = v0.min_i16(v1);
|
||||
GSVector4i v3 = v0.max_i16(v1);
|
||||
|
||||
v2 = v2.min_i16(v2.zwxy());
|
||||
v3 = v3.max_i16(v3.zwxy());
|
||||
v2 = v2.min_i16(v2.zwxyl());
|
||||
v3 = v3.max_i16(v3.zwxyl());
|
||||
v2 = v2.min_i16(v2.yxwzl());
|
||||
v3 = v3.max_i16(v3.yxwzl());
|
||||
|
||||
amin = min(amin, v2.extract16<0>());
|
||||
amax = max(amax, v3.extract16<0>());
|
||||
}
|
||||
|
||||
m_read.amin = amin;
|
||||
m_read.amax = amax;
|
||||
}
|
||||
}
|
||||
|
||||
amin = m_read.amin;
|
||||
amax = m_read.amax;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void GSClut::WriteCLUT_T32_I8_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
for(int i = 0; i < 64; i += 16)
|
||||
{
|
||||
WriteCLUT_T32_I4_CSM1(&src[i + 0], &clut[i * 2 + 0]);
|
||||
WriteCLUT_T32_I4_CSM1(&src[i + 64], &clut[i * 2 + 16]);
|
||||
WriteCLUT_T32_I4_CSM1(&src[i + 128], &clut[i * 2 + 128]);
|
||||
WriteCLUT_T32_I4_CSM1(&src[i + 192], &clut[i * 2 + 144]);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
for(int j = 0; j < 2; j++, src += 128, clut += 128)
|
||||
{
|
||||
for(int i = 0; i < 128; i++)
|
||||
{
|
||||
DWORD c = src[clutTableT32I8[i]];
|
||||
clut[i] = (WORD)(c & 0xffff);
|
||||
clut[i + 256] = (WORD)(c >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void GSClut::WriteCLUT_T32_I4_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
GSVector4i* s = (GSVector4i*)src;
|
||||
GSVector4i* d = (GSVector4i*)clut;
|
||||
|
||||
GSVector4i v0 = s[0];
|
||||
GSVector4i v1 = s[1];
|
||||
GSVector4i v2 = s[2];
|
||||
GSVector4i v3 = s[3];
|
||||
|
||||
GSVector4i::sw64(v0, v1, v2, v3);
|
||||
GSVector4i::sw16(v0, v1, v2, v3);
|
||||
GSVector4i::sw16(v0, v2, v1, v3);
|
||||
GSVector4i::sw16(v0, v1, v2, v3);
|
||||
|
||||
d[0] = v0;
|
||||
d[1] = v1;
|
||||
d[32] = v2;
|
||||
d[33] = v3;
|
||||
|
||||
#else
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
DWORD c = src[clutTableT32I4[i]];
|
||||
clut[i] = (WORD)(c & 0xffff);
|
||||
clut[i + 256] = (WORD)(c >> 16);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSClut::WriteCLUT_T16_I8_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
GSVector4i* s = (GSVector4i*)src;
|
||||
GSVector4i* d = (GSVector4i*)clut;
|
||||
|
||||
for(int i = 0; i < 32; i += 4)
|
||||
{
|
||||
GSVector4i v0 = s[i + 0];
|
||||
GSVector4i v1 = s[i + 1];
|
||||
GSVector4i v2 = s[i + 2];
|
||||
GSVector4i v3 = s[i + 3];
|
||||
|
||||
GSVector4i::sw16(v0, v1, v2, v3);
|
||||
GSVector4i::sw32(v0, v1, v2, v3);
|
||||
GSVector4i::sw16(v0, v2, v1, v3);
|
||||
|
||||
d[i + 0] = v0;
|
||||
d[i + 1] = v2;
|
||||
d[i + 2] = v1;
|
||||
d[i + 3] = v3;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
for(int j = 0; j < 8; j++, src += 32, clut += 32)
|
||||
{
|
||||
for(int i = 0; i < 32; i++)
|
||||
{
|
||||
clut[i] = src[clutTableT16I8[i]];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void GSClut::WriteCLUT_T16_I4_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut)
|
||||
{
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
clut[i] = src[clutTableT16I4[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void GSClut::ReadCLUT_T32_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
for(int i = 0; i < 256; i += 16)
|
||||
{
|
||||
ReadCLUT_T32_I4(&clut[i], &dst[i]);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i];
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void GSClut::ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
GSVector4i* s = (GSVector4i*)clut;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
GSVector4i v0 = s[0];
|
||||
GSVector4i v1 = s[1];
|
||||
GSVector4i v2 = s[32];
|
||||
GSVector4i v3 = s[33];
|
||||
|
||||
GSVector4i::sw16(v0, v2, v1, v3);
|
||||
|
||||
d[0] = v0;
|
||||
d[1] = v1;
|
||||
d[2] = v2;
|
||||
d[3] = v3;
|
||||
|
||||
#else
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i];
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void GSClut::ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
GSVector4i* s = (GSVector4i*)clut;
|
||||
GSVector4i* d32 = (GSVector4i*)dst32;
|
||||
GSVector4i* d64 = (GSVector4i*)dst64;
|
||||
|
||||
GSVector4i s0 = s[0];
|
||||
GSVector4i s1 = s[1];
|
||||
GSVector4i s2 = s[32];
|
||||
GSVector4i s3 = s[33];
|
||||
|
||||
GSVector4i::sw16(s0, s2, s1, s3);
|
||||
|
||||
d32[0] = s0;
|
||||
d32[1] = s1;
|
||||
d32[2] = s2;
|
||||
d32[3] = s3;
|
||||
|
||||
ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d64[0]);
|
||||
ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d64[32]);
|
||||
ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d64[64]);
|
||||
ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d64[96]);
|
||||
|
||||
#else
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i];
|
||||
}
|
||||
|
||||
DWORD* d = (DWORD*)dst64;
|
||||
|
||||
for(int j = 0; j < 16; j++, d += 32)
|
||||
{
|
||||
DWORD hi = dst32[j];
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
d[i * 2 + 0] = dst32[i];
|
||||
d[i * 2 + 1] = hi;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSClut::ReadCLUT_T16_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
for(int i = 0; i < 256; i += 16)
|
||||
{
|
||||
ReadCLUT_T16_I4(&clut[i], &dst[i]);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
dst[i] = (DWORD)clut[i];
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void GSClut::ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
GSVector4i* s = (GSVector4i*)clut;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
GSVector4i v0 = s[0];
|
||||
GSVector4i v1 = s[1];
|
||||
|
||||
d[0] = v0.upl16();
|
||||
d[1] = v0.uph16();
|
||||
d[2] = v1.upl16();
|
||||
d[3] = v1.uph16();
|
||||
|
||||
#else
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
dst[i] = (DWORD)clut[i];
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void GSClut::ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
GSVector4i* s = (GSVector4i*)clut;
|
||||
GSVector4i* d32 = (GSVector4i*)dst32;
|
||||
GSVector4i* d64 = (GSVector4i*)dst64;
|
||||
|
||||
GSVector4i v0 = s[0];
|
||||
GSVector4i v1 = s[1];
|
||||
|
||||
GSVector4i s0 = v0.upl16();
|
||||
GSVector4i s1 = v0.uph16();
|
||||
GSVector4i s2 = v1.upl16();
|
||||
GSVector4i s3 = v1.uph16();
|
||||
|
||||
d32[0] = s0;
|
||||
d32[1] = s1;
|
||||
d32[2] = s2;
|
||||
d32[3] = s3;
|
||||
|
||||
ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d64[0]);
|
||||
ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d64[32]);
|
||||
ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d64[64]);
|
||||
ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d64[96]);
|
||||
|
||||
#else
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
dst32[i] = (DWORD)clut[i];
|
||||
}
|
||||
|
||||
DWORD* d = (DWORD*)dst64;
|
||||
|
||||
for(int j = 0; j < 16; j++, d += 32)
|
||||
{
|
||||
DWORD hi = dst32[j] << 16;
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
d[i * 2 + 0] = hi | (dst32[i] & 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSClut::ExpandCLUT64_T32_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
GSVector4i* s = (GSVector4i*)src;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
GSVector4i s0 = s[0];
|
||||
GSVector4i s1 = s[1];
|
||||
GSVector4i s2 = s[2];
|
||||
GSVector4i s3 = s[3];
|
||||
|
||||
ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d[0]);
|
||||
ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d[32]);
|
||||
ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d[64]);
|
||||
ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d[96]);
|
||||
|
||||
#else
|
||||
|
||||
DWORD* d = (DWORD*)dst;
|
||||
|
||||
for(int j = 0; j < 16; j++, d += 32)
|
||||
{
|
||||
DWORD hi = src[j];
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
d[i * 2 + 0] = src[i];
|
||||
d[i * 2 + 1] = hi;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst)
|
||||
{
|
||||
ExpandCLUT64_T32(hi.xxxx(), lo0, &dst[0]);
|
||||
ExpandCLUT64_T32(hi.xxxx(), lo1, &dst[2]);
|
||||
ExpandCLUT64_T32(hi.xxxx(), lo2, &dst[4]);
|
||||
ExpandCLUT64_T32(hi.xxxx(), lo3, &dst[6]);
|
||||
ExpandCLUT64_T32(hi.yyyy(), lo0, &dst[8]);
|
||||
ExpandCLUT64_T32(hi.yyyy(), lo1, &dst[10]);
|
||||
ExpandCLUT64_T32(hi.yyyy(), lo2, &dst[12]);
|
||||
ExpandCLUT64_T32(hi.yyyy(), lo3, &dst[14]);
|
||||
ExpandCLUT64_T32(hi.zzzz(), lo0, &dst[16]);
|
||||
ExpandCLUT64_T32(hi.zzzz(), lo1, &dst[18]);
|
||||
ExpandCLUT64_T32(hi.zzzz(), lo2, &dst[20]);
|
||||
ExpandCLUT64_T32(hi.zzzz(), lo3, &dst[22]);
|
||||
ExpandCLUT64_T32(hi.wwww(), lo0, &dst[24]);
|
||||
ExpandCLUT64_T32(hi.wwww(), lo1, &dst[26]);
|
||||
ExpandCLUT64_T32(hi.wwww(), lo2, &dst[28]);
|
||||
ExpandCLUT64_T32(hi.wwww(), lo3, &dst[30]);
|
||||
}
|
||||
|
||||
__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst)
|
||||
{
|
||||
dst[0] = lo.upl32(hi);
|
||||
dst[1] = lo.uph32(hi);
|
||||
}
|
||||
|
||||
void GSClut::ExpandCLUT64_T16_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
GSVector4i* s = (GSVector4i*)src;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
GSVector4i s0 = s[0];
|
||||
GSVector4i s1 = s[1];
|
||||
GSVector4i s2 = s[2];
|
||||
GSVector4i s3 = s[3];
|
||||
|
||||
ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d[0]);
|
||||
ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d[32]);
|
||||
ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d[64]);
|
||||
ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d[96]);
|
||||
|
||||
#else
|
||||
|
||||
DWORD* d = (DWORD*)dst;
|
||||
|
||||
for(int j = 0; j < 16; j++, d += 32)
|
||||
{
|
||||
DWORD hi = src[j] << 16;
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
d[i * 2 + 0] = hi | (src[i] & 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst)
|
||||
{
|
||||
ExpandCLUT64_T16(hi.xxxx(), lo0, &dst[0]);
|
||||
ExpandCLUT64_T16(hi.xxxx(), lo1, &dst[2]);
|
||||
ExpandCLUT64_T16(hi.xxxx(), lo2, &dst[4]);
|
||||
ExpandCLUT64_T16(hi.xxxx(), lo3, &dst[6]);
|
||||
ExpandCLUT64_T16(hi.yyyy(), lo0, &dst[8]);
|
||||
ExpandCLUT64_T16(hi.yyyy(), lo1, &dst[10]);
|
||||
ExpandCLUT64_T16(hi.yyyy(), lo2, &dst[12]);
|
||||
ExpandCLUT64_T16(hi.yyyy(), lo3, &dst[14]);
|
||||
ExpandCLUT64_T16(hi.zzzz(), lo0, &dst[16]);
|
||||
ExpandCLUT64_T16(hi.zzzz(), lo1, &dst[18]);
|
||||
ExpandCLUT64_T16(hi.zzzz(), lo2, &dst[20]);
|
||||
ExpandCLUT64_T16(hi.zzzz(), lo3, &dst[22]);
|
||||
ExpandCLUT64_T16(hi.wwww(), lo0, &dst[24]);
|
||||
ExpandCLUT64_T16(hi.wwww(), lo1, &dst[26]);
|
||||
ExpandCLUT64_T16(hi.wwww(), lo2, &dst[28]);
|
||||
ExpandCLUT64_T16(hi.wwww(), lo3, &dst[30]);
|
||||
}
|
||||
|
||||
__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst)
|
||||
{
|
||||
dst[0] = lo.upl16(hi);
|
||||
dst[1] = lo.uph16(hi);
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
static const GSVector4i s_am(0x00008000);
|
||||
static const GSVector4i s_bm(0x00007c00);
|
||||
static const GSVector4i s_gm(0x000003e0);
|
||||
static const GSVector4i s_rm(0x0000001f);
|
||||
|
||||
void GSClut::Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int w, const GIFRegTEXA& TEXA)
|
||||
{
|
||||
#if _M_SSE >= 0x200
|
||||
|
||||
ASSERT((w & 7) == 0);
|
||||
|
||||
const GSVector4i rm = s_rm;
|
||||
const GSVector4i gm = s_gm;
|
||||
const GSVector4i bm = s_bm;
|
||||
// const GSVector4i am = s_am;
|
||||
|
||||
GSVector4i TA0(TEXA.TA0 << 24);
|
||||
GSVector4i TA1(TEXA.TA1 << 24);
|
||||
|
||||
GSVector4i c, cl, ch;
|
||||
|
||||
const GSVector4i* s = (const GSVector4i*)src;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
if(!TEXA.AEM)
|
||||
{
|
||||
for(int i = 0, j = w >> 3; i < j; i++)
|
||||
{
|
||||
c = s[i];
|
||||
/*
|
||||
cl = c.upl16();
|
||||
ch = c.uph16();
|
||||
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA1.blend(TA0, cl < am);
|
||||
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA1.blend(TA0, ch < am);
|
||||
*/
|
||||
cl = c.upl16(c);
|
||||
ch = c.uph16(c);
|
||||
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15));
|
||||
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0, j = w >> 3; i < j; i++)
|
||||
{
|
||||
c = s[i];
|
||||
/*
|
||||
cl = c.upl16();
|
||||
ch = c.uph16();
|
||||
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA1.blend(TA0, cl < am).andnot(cl == GSVector4i::zero());
|
||||
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA1.blend(TA0, ch < am).andnot(ch == GSVector4i::zero());
|
||||
*/
|
||||
cl = c.upl16(c);
|
||||
ch = c.uph16(c);
|
||||
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15)).andnot(cl == GSVector4i::zero());
|
||||
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15)).andnot(ch == GSVector4i::zero());
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
DWORD TA0 = (DWORD)TEXA.TA0 << 24;
|
||||
DWORD TA1 = (DWORD)TEXA.TA1 << 24;
|
||||
|
||||
if(!TEXA.AEM)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
dst[i] = ((src[i] & 0x8000) ? TA1 : TA0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
{
|
||||
dst[i] = ((src[i] & 0x8000) ? TA1 : src[i] ? TA0 : 0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
bool GSClut::WriteState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
return dirty || !(GSVector4i::load<true>(this) == GSVector4i::load(&TEX0, &TEXCLUT)).alltrue();
|
||||
}
|
||||
|
||||
bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0)
|
||||
{
|
||||
return dirty || !(GSVector4i::load<true>(this) == GSVector4i::load(&TEX0, &this->TEXA)).alltrue();
|
||||
}
|
||||
|
||||
bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
|
||||
{
|
||||
return dirty || !(GSVector4i::load<true>(this) == GSVector4i::load(&TEX0, &TEXA)).alltrue();
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS.h"
|
||||
#include "GSVector.h"
|
||||
#include "GSTables.h"
|
||||
#include "GSAlignedClass.h"
|
||||
|
||||
class GSLocalMemory;
|
||||
|
||||
__declspec(align(16)) class GSClut : public GSAlignedClass<16>
|
||||
{
|
||||
const GSLocalMemory* m_mem;
|
||||
|
||||
DWORD m_CBP[2];
|
||||
WORD* m_clut;
|
||||
DWORD* m_buff32;
|
||||
UINT64* m_buff64;
|
||||
|
||||
__declspec(align(16)) struct WriteState
|
||||
{
|
||||
GIFRegTEX0 TEX0;
|
||||
GIFRegTEXCLUT TEXCLUT;
|
||||
bool dirty;
|
||||
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
} m_write;
|
||||
|
||||
__declspec(align(16)) struct ReadState
|
||||
{
|
||||
GIFRegTEX0 TEX0;
|
||||
GIFRegTEXA TEXA;
|
||||
bool dirty;
|
||||
bool adirty;
|
||||
int amin, amax;
|
||||
bool IsDirty(const GIFRegTEX0& TEX0);
|
||||
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
|
||||
} m_read;
|
||||
|
||||
typedef void (GSClut::*writeCLUT)(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
|
||||
writeCLUT m_wc[2][16][64];
|
||||
|
||||
void WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
void WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
void WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
void WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
void WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
void WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
|
||||
template<int n> void WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
template<int n> void WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
template<int n> void WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
|
||||
void WriteCLUT_NULL(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) {}
|
||||
|
||||
static void WriteCLUT_T32_I8_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut);
|
||||
static void WriteCLUT_T32_I4_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut);
|
||||
static void WriteCLUT_T16_I8_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut);
|
||||
static void WriteCLUT_T16_I4_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut);
|
||||
static void ReadCLUT_T32_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst);
|
||||
static void ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst);
|
||||
static void ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64);
|
||||
static void ReadCLUT_T16_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst);
|
||||
static void ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst);
|
||||
static void ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64);
|
||||
static void ExpandCLUT64_T32_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst);
|
||||
static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst);
|
||||
static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst);
|
||||
static void ExpandCLUT64_T16_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst);
|
||||
static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst);
|
||||
static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst);
|
||||
|
||||
static void Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int w, const GIFRegTEXA& TEXA);
|
||||
|
||||
public:
|
||||
GSClut(const GSLocalMemory* mem);
|
||||
virtual ~GSClut();
|
||||
|
||||
void Invalidate();
|
||||
bool WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
void Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
void Read(const GIFRegTEX0& TEX0);
|
||||
void Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
|
||||
void GetAlphaMinMax32(int& amin, int& amax);
|
||||
|
||||
DWORD operator [] (size_t i) const {return m_buff32[i];}
|
||||
|
||||
operator const DWORD*() const {return m_buff32;}
|
||||
operator const UINT64*() const {return m_buff64;}
|
||||
};
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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 "GSCrc.h"
|
||||
|
||||
CRC::Game CRC::m_games[] =
|
||||
{
|
||||
{0x00000000, None, Unknown, false},
|
||||
{0x2113EA2E, MetalSlug6, Unknown, false},
|
||||
{0x42E05BAF, TomoyoAfter, JP, false},
|
||||
{0x7800DC84, Clannad, JP, false},
|
||||
{0xa39517ab, FFX, EU, true},
|
||||
{0xa39517ae, FFX, FR, true},
|
||||
{0x941bb7d9, FFX, DE, true},
|
||||
{0xa39517a9, FFX, IT, true},
|
||||
{0x941bb7de, FFX, ES, true},
|
||||
{0xb4414ea1, FFX, RU, true},
|
||||
{0xee97db5b, FFX, RU, true},
|
||||
{0xaec495cc, FFX, RU, true},
|
||||
{0xbb3d833a, FFX, US, true},
|
||||
{0x6a4efe60, FFX, JP, true},
|
||||
{0x3866ca7e, FFX, ASIA, true}, // int.
|
||||
{0x658597e2, FFX, JP, true}, // int.
|
||||
{0x9aac5309, FFX2, EU, true},
|
||||
{0x9aac530c, FFX2, FR, true},
|
||||
{0x9aac530a, FFX2, FR, true}, // ?
|
||||
{0x9aac530d, FFX2, DE, true},
|
||||
{0x9aac530b, FFX2, IT, true},
|
||||
{0x48fe0c71, FFX2, US, true},
|
||||
{0xe1fd9a2d, FFX2, JP, true}, // int.
|
||||
{0x78da0252, FFXII, EU, false},
|
||||
{0xc1274668, FFXII, EU, false},
|
||||
{0xdc2a467e, FFXII, EU, false},
|
||||
{0xca284668, FFXII, EU, false},
|
||||
{0x280AD120, FFXII, JP, false},
|
||||
{0x8BE3D7B2, ShadowHearts, Unknown, false},
|
||||
{0xDEFA4763, ShadowHearts, US, false},
|
||||
{0x21068223, Okami, US, false},
|
||||
{0x891f223f, Okami, FR, false},
|
||||
{0xC5DEFEA0, Okami, JP, false},
|
||||
{0x053D2239, MetalGearSolid3, US, false},
|
||||
{0x086273D2, MetalGearSolid3, FR, false},
|
||||
{0x26A6E286, MetalGearSolid3, EU, false},
|
||||
{0xAA31B5BF, MetalGearSolid3, Unknown, false},
|
||||
{0x9F185CE1, MetalGearSolid3, Unknown, false},
|
||||
{0x98D4BC93, MetalGearSolid3, EU, false},
|
||||
{0x86BC3040, MetalGearSolid3, US, false}, //Subsistance disc 1
|
||||
{0x0481AD8A, MetalGearSolid3, JP, false},
|
||||
{0x278722BF, DBZBT2, US, false},
|
||||
{0xFE961D28, DBZBT2, US, false},
|
||||
{0x0393B6BE, DBZBT2, EU, false},
|
||||
{0xE2F289ED, DBZBT2, JP, false}, // Sparking Neo!
|
||||
{0x35AA84D1, DBZBT2, Unknown, false},
|
||||
{0x428113C2, DBZBT3, US, false},
|
||||
{0xA422BB13, DBZBT3, EU, false},
|
||||
{0x983c53d2, DBZBT3, Unknown, false},
|
||||
{0x72B3802A, SFEX3, US, false},
|
||||
{0x71521863, SFEX3, US, false},
|
||||
{0x28703748, Bully, US, false},
|
||||
{0xC78A495D, BullyCC, US, false},
|
||||
{0xC19A374E, SoTC, US, false},
|
||||
{0x7D8F539A, SoTC, EU, false},
|
||||
{0x3122B508, OnePieceGrandAdventure, US, false},
|
||||
{0x6F8545DB, ICO, US, false},
|
||||
{0xB01A4C95, ICO, JP, false},
|
||||
{0x5C991F4E, ICO, Unknown, false},
|
||||
{0xAEAD1CA3, GT4, JP, false},
|
||||
{0x44A61C8F, GT4, Unknown, false},
|
||||
{0x0086E35B, GT4, Unknown, false},
|
||||
{0x77E61C8A, GT4, Unknown, false},
|
||||
{0xC164550A, WildArms5, JPUNDUB, false},
|
||||
{0xC1640D2C, WildArms5, US, false},
|
||||
{0x0FCF8FE4, WildArms5, EU, false},
|
||||
{0x2294D322, WildArms5, JP, false},
|
||||
{0x565B6170, WildArms5, JP, false},
|
||||
{0x8B029334, Manhunt2, Unknown, false},
|
||||
{0x09F49E37, CrashBandicootWoC, Unknown, false},
|
||||
{0x013E349D, ResidentEvil4, US, false},
|
||||
{0x6BA2F6B9, ResidentEvil4, Unknown, false},
|
||||
{0x60FA8C69, ResidentEvil4, JP, false},
|
||||
{0x72E1E60E, Spartan, Unknown, false},
|
||||
{0x5ED8FB53, AceCombat4, JP, false},
|
||||
{0x1B9B7563, AceCombat4, Unknown, false},
|
||||
{0xEC432B24, Drakengard2, Unknown, false},
|
||||
{0xFC46EA61, Tekken5, JP, false},
|
||||
{0x1F88EE37, Tekken5, Unknown, false},
|
||||
{0x652050D2, Tekken5, Unknown, false},
|
||||
{0x9E98B8AE, IkkiTousen, JP, false},
|
||||
{0xD6385328, GodOfWar, US, false},
|
||||
{0xFB0E6D72, GodOfWar, EU, false},
|
||||
{0xA61A4C6D, GodOfWar, Unknown, false},
|
||||
{0xE23D532B, GodOfWar, Unknown, false},
|
||||
{0x2F123FD8, GodOfWar2, RU, false},
|
||||
{0x5D482F18, JackieChanAdv, Unknown, false},
|
||||
{0xf0a6d880, HarvestMoon, US, true},
|
||||
{0x75c01a04, NamcoXCapcom, US, false},
|
||||
{0xBF6F101F, GiTS, US, false},
|
||||
{0xA5768F53, GiTS, JP, false},
|
||||
{0x6BF11378, Onimusha3, US, false},
|
||||
{0xF442260C, MajokkoALaMode2, JP, false},
|
||||
{0x14FE77F7, TalesOfAbyss, US, false},
|
||||
{0x045D77E9, TalesOfAbyss, US, false}, // undub
|
||||
{0xAA5EC3A3, TalesOfAbyss, JP, false},
|
||||
};
|
||||
|
||||
CAtlMap<DWORD, CRC::Game*> CRC::m_map;
|
||||
|
||||
CRC::Game CRC::Lookup(DWORD crc)
|
||||
{
|
||||
if(m_map.IsEmpty())
|
||||
{
|
||||
for(int i = 0; i < countof(m_games); i++)
|
||||
{
|
||||
m_map[m_games[i].crc] = &m_games[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(CAtlMap<DWORD, Game*>::CPair* pair = m_map.Lookup(crc))
|
||||
{
|
||||
return *pair->m_value;
|
||||
}
|
||||
|
||||
return m_games[0];
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class CRC
|
||||
{
|
||||
public:
|
||||
enum Title
|
||||
{
|
||||
None,
|
||||
MetalSlug6,
|
||||
TomoyoAfter,
|
||||
Clannad,
|
||||
FFX,
|
||||
FFX2,
|
||||
FFXII,
|
||||
ShadowHearts,
|
||||
Okami,
|
||||
MetalGearSolid3,
|
||||
DBZBT2,
|
||||
DBZBT3,
|
||||
SFEX3,
|
||||
Bully,
|
||||
BullyCC,
|
||||
SoTC,
|
||||
OnePieceGrandAdventure,
|
||||
ICO,
|
||||
GT4,
|
||||
WildArms5,
|
||||
Manhunt2,
|
||||
CrashBandicootWoC,
|
||||
ResidentEvil4,
|
||||
Spartan,
|
||||
AceCombat4,
|
||||
Drakengard2,
|
||||
Tekken5,
|
||||
IkkiTousen,
|
||||
GodOfWar,
|
||||
GodOfWar2,
|
||||
JackieChanAdv,
|
||||
HarvestMoon,
|
||||
NamcoXCapcom,
|
||||
GiTS,
|
||||
Onimusha3,
|
||||
MajokkoALaMode2,
|
||||
TalesOfAbyss,
|
||||
TitleCount
|
||||
};
|
||||
|
||||
enum Region
|
||||
{
|
||||
Unknown,
|
||||
US,
|
||||
EU,
|
||||
JP,
|
||||
JPUNDUB,
|
||||
RU,
|
||||
FR,
|
||||
DE,
|
||||
IT,
|
||||
ES,
|
||||
ASIA
|
||||
};
|
||||
|
||||
struct Game
|
||||
{
|
||||
DWORD crc;
|
||||
Title title;
|
||||
Region region;
|
||||
bool nloophack;
|
||||
};
|
||||
|
||||
private:
|
||||
static Game m_games[];
|
||||
static CAtlMap<DWORD, Game*> m_map;
|
||||
|
||||
public:
|
||||
static Game Lookup(DWORD crc);
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 "GSDevice.h"
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSTexture.h"
|
||||
#include "GSVertex.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct MergeConstantBuffer
|
||||
{
|
||||
GSVector4 BGColor;
|
||||
|
||||
struct MergeConstantBuffer() {memset(this, 0, sizeof(*this));}
|
||||
};
|
||||
|
||||
struct InterlaceConstantBuffer
|
||||
{
|
||||
GSVector2 ZrH;
|
||||
float hH;
|
||||
float _pad[1];
|
||||
|
||||
struct InterlaceConstantBuffer() {memset(this, 0, sizeof(*this));}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
template<class Texture> class GSDevice
|
||||
{
|
||||
CAtlList<Texture> m_pool;
|
||||
|
||||
protected:
|
||||
HWND m_hWnd;
|
||||
bool m_vsync;
|
||||
Texture m_backbuffer;
|
||||
Texture m_merge;
|
||||
Texture m_weavebob;
|
||||
Texture m_blend;
|
||||
Texture m_1x1;
|
||||
Texture m_current;
|
||||
|
||||
bool Fetch(int type, Texture& t, int w, int h, int format)
|
||||
{
|
||||
Recycle(t);
|
||||
|
||||
for(POSITION pos = m_pool.GetHeadPosition(); pos; m_pool.GetNext(pos))
|
||||
{
|
||||
const Texture& t2 = m_pool.GetAt(pos);
|
||||
|
||||
if(t2.GetType() == type && t2.GetWidth() == w && t2.GetHeight() == h && t2.GetFormat() == format)
|
||||
{
|
||||
t = t2;
|
||||
|
||||
m_pool.RemoveAt(pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Create(type, t, w, h, format);
|
||||
}
|
||||
|
||||
virtual bool Create(int type, Texture& t, int w, int h, int format) = 0;
|
||||
virtual void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) = 0;
|
||||
virtual void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) = 0;
|
||||
|
||||
public:
|
||||
GSDevice() : m_hWnd(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~GSDevice()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Create(HWND hWnd, bool vsync)
|
||||
{
|
||||
m_hWnd = hWnd;
|
||||
m_vsync = vsync;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Reset(int w, int h, bool fs)
|
||||
{
|
||||
m_pool.RemoveAll();
|
||||
m_backbuffer = Texture();
|
||||
m_merge = Texture();
|
||||
m_weavebob = Texture();
|
||||
m_blend = Texture();
|
||||
m_1x1 = Texture();
|
||||
m_current = Texture();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool IsLost() = 0;
|
||||
|
||||
virtual void Present(const CRect& r) = 0;
|
||||
|
||||
virtual void BeginScene() = 0;
|
||||
|
||||
virtual void EndScene() = 0;
|
||||
|
||||
virtual void Draw(LPCTSTR str) = 0;
|
||||
|
||||
virtual bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) = 0;
|
||||
|
||||
virtual void ClearRenderTarget(Texture& t, const GSVector4& c) = 0;
|
||||
|
||||
virtual void ClearRenderTarget(Texture& t, DWORD c) = 0;
|
||||
|
||||
virtual void ClearDepth(Texture& t, float c) = 0;
|
||||
|
||||
virtual void ClearStencil(Texture& t, BYTE c) = 0;
|
||||
|
||||
virtual bool CreateRenderTarget(Texture& t, int w, int h, int format = 0)
|
||||
{
|
||||
return Fetch(GSTexture::RenderTarget, t, w, h, format);
|
||||
}
|
||||
|
||||
virtual bool CreateDepthStencil(Texture& t, int w, int h, int format = 0)
|
||||
{
|
||||
return Fetch(GSTexture::DepthStencil, t, w, h, format);
|
||||
}
|
||||
|
||||
virtual bool CreateTexture(Texture& t, int w, int h, int format = 0)
|
||||
{
|
||||
return Fetch(GSTexture::Texture, t, w, h, format);
|
||||
}
|
||||
|
||||
virtual bool CreateOffscreen(Texture& t, int w, int h, int format = 0)
|
||||
{
|
||||
return Fetch(GSTexture::Offscreen, t, w, h, format);
|
||||
}
|
||||
|
||||
void Recycle(Texture& t)
|
||||
{
|
||||
if(t)
|
||||
{
|
||||
m_pool.AddHead(t);
|
||||
|
||||
while(m_pool.GetCount() > 200)
|
||||
{
|
||||
m_pool.RemoveTail();
|
||||
}
|
||||
|
||||
t = Texture();
|
||||
}
|
||||
}
|
||||
|
||||
bool SaveCurrent(LPCTSTR fn)
|
||||
{
|
||||
return m_current.Save(fn);
|
||||
}
|
||||
|
||||
void GetCurrent(Texture& t)
|
||||
{
|
||||
t = m_current;
|
||||
}
|
||||
|
||||
void Merge(Texture* st, GSVector4* sr, GSVector4* dr, CSize fs, bool slbg, bool mmod, GSVector4& c)
|
||||
{
|
||||
if(!m_merge || m_merge.GetWidth() != fs.cx || m_merge.GetHeight() != fs.cy)
|
||||
{
|
||||
CreateRenderTarget(m_merge, fs.cx, fs.cy);
|
||||
}
|
||||
|
||||
// TODO: m_1x1
|
||||
|
||||
DoMerge(st, sr, dr, m_merge, slbg, mmod, c);
|
||||
|
||||
m_current = m_merge;
|
||||
}
|
||||
|
||||
bool Interlace(CSize ds, int field, int mode, float yoffset)
|
||||
{
|
||||
if(!m_weavebob || m_weavebob.GetWidth() != ds.cx || m_weavebob.GetHeight() != ds.cy)
|
||||
{
|
||||
CreateRenderTarget(m_weavebob, ds.cx, ds.cy);
|
||||
}
|
||||
|
||||
if(mode == 0 || mode == 2) // weave or blend
|
||||
{
|
||||
// weave first
|
||||
|
||||
DoInterlace(m_merge, m_weavebob, field, false, 0);
|
||||
|
||||
if(mode == 2)
|
||||
{
|
||||
// blend
|
||||
|
||||
if(!m_blend || m_blend.GetWidth() != ds.cx || m_blend.GetHeight() != ds.cy)
|
||||
{
|
||||
CreateRenderTarget(m_blend, ds.cx, ds.cy);
|
||||
}
|
||||
|
||||
DoInterlace(m_weavebob, m_blend, 2, false, 0);
|
||||
|
||||
m_current = m_blend;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_current = m_weavebob;
|
||||
}
|
||||
}
|
||||
else if(mode == 1) // bob
|
||||
{
|
||||
DoInterlace(m_merge, m_weavebob, 3, true, yoffset * field);
|
||||
|
||||
m_current = m_weavebob;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_current = m_merge;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool IsCurrentRGBA()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,833 @@
|
|||
/*
|
||||
* 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 "GSDevice10.h"
|
||||
#include "resource.h"
|
||||
|
||||
GSDevice10::GSDevice10()
|
||||
: m_vb(NULL)
|
||||
, m_vb_stride(0)
|
||||
, m_layout(NULL)
|
||||
, m_topology(D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED)
|
||||
, m_vs(NULL)
|
||||
, m_vs_cb(NULL)
|
||||
, m_gs(NULL)
|
||||
, m_ps(NULL)
|
||||
, m_ps_cb(NULL)
|
||||
, m_scissor(0, 0, 0, 0)
|
||||
, m_viewport(0, 0)
|
||||
, m_dss(NULL)
|
||||
, m_sref(0)
|
||||
, m_bs(NULL)
|
||||
, m_bf(-1)
|
||||
, m_rtv(NULL)
|
||||
, m_dsv(NULL)
|
||||
{
|
||||
memset(m_ps_srv, 0, sizeof(m_ps_srv));
|
||||
memset(m_ps_ss, 0, sizeof(m_ps_ss));
|
||||
}
|
||||
|
||||
GSDevice10::~GSDevice10()
|
||||
{
|
||||
}
|
||||
|
||||
bool GSDevice10::Create(HWND hWnd, bool vsync)
|
||||
{
|
||||
if(!__super::Create(hWnd, vsync))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC scd;
|
||||
D3D10_BUFFER_DESC bd;
|
||||
D3D10_SAMPLER_DESC sd;
|
||||
D3D10_DEPTH_STENCIL_DESC dsd;
|
||||
D3D10_RASTERIZER_DESC rd;
|
||||
D3D10_BLEND_DESC bsd;
|
||||
|
||||
memset(&scd, 0, sizeof(scd));
|
||||
|
||||
scd.BufferCount = 2;
|
||||
scd.BufferDesc.Width = 1;
|
||||
scd.BufferDesc.Height = 1;
|
||||
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
//scd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
//scd.BufferDesc.RefreshRate.Denominator = 1;
|
||||
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
scd.OutputWindow = hWnd;
|
||||
scd.SampleDesc.Count = 1;
|
||||
scd.SampleDesc.Quality = 0;
|
||||
scd.Windowed = TRUE;
|
||||
|
||||
UINT flags = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
flags |= D3D10_CREATE_DEVICE_DEBUG;
|
||||
#endif
|
||||
|
||||
hr = D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, flags, D3D10_SDK_VERSION, &scd, &m_swapchain, &m_dev);
|
||||
|
||||
if(FAILED(hr)) return false;
|
||||
|
||||
// font
|
||||
/*
|
||||
// TODO: the driver crashes on alt-enter when using a font...
|
||||
|
||||
D3DX10_FONT_DESC fd;
|
||||
memset(&fd, 0, sizeof(fd));
|
||||
_tcscpy(fd.FaceName, _T("Arial"));
|
||||
fd.Height = 20;
|
||||
D3DX10CreateFontIndirect(m_dev, &fd, &m_font);
|
||||
*/
|
||||
// convert
|
||||
|
||||
D3D10_INPUT_ELEMENT_DESC il_convert[] =
|
||||
{
|
||||
{"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
|
||||
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0},
|
||||
};
|
||||
|
||||
hr = CompileShader(IDR_CONVERT10_FX, "vs_main", NULL, &m_convert.vs, il_convert, countof(il_convert), &m_convert.il);
|
||||
|
||||
for(int i = 0; i < countof(m_convert.ps); i++)
|
||||
{
|
||||
CStringA main;
|
||||
main.Format("ps_main%d", i);
|
||||
hr = CompileShader(IDR_CONVERT10_FX, main, NULL, &m_convert.ps[i]);
|
||||
}
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
|
||||
bd.Usage = D3D10_USAGE_DEFAULT;
|
||||
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
|
||||
bd.CPUAccessFlags = 0;
|
||||
bd.MiscFlags = 0;
|
||||
bd.ByteWidth = 4 * sizeof(GSVertexPT1);
|
||||
|
||||
hr = m_dev->CreateBuffer(&bd, NULL, &m_convert.vb);
|
||||
|
||||
memset(&dsd, 0, sizeof(dsd));
|
||||
|
||||
dsd.DepthEnable = false;
|
||||
dsd.StencilEnable = false;
|
||||
|
||||
hr = m_dev->CreateDepthStencilState(&dsd, &m_convert.dss);
|
||||
|
||||
memset(&bsd, 0, sizeof(bsd));
|
||||
|
||||
bsd.BlendEnable[0] = false;
|
||||
bsd.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
||||
|
||||
hr = m_dev->CreateBlendState(&bsd, &m_convert.bs);
|
||||
|
||||
// merge
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
|
||||
bd.ByteWidth = sizeof(MergeConstantBuffer);
|
||||
bd.Usage = D3D10_USAGE_DEFAULT;
|
||||
bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
||||
bd.CPUAccessFlags = 0;
|
||||
bd.MiscFlags = 0;
|
||||
|
||||
hr = m_dev->CreateBuffer(&bd, NULL, &m_merge.cb);
|
||||
|
||||
for(int i = 0; i < countof(m_merge.ps); i++)
|
||||
{
|
||||
CStringA main;
|
||||
main.Format("ps_main%d", i);
|
||||
hr = CompileShader(IDR_MERGE10_FX, main, NULL, &m_merge.ps[i]);
|
||||
}
|
||||
|
||||
memset(&bsd, 0, sizeof(bsd));
|
||||
|
||||
bsd.BlendEnable[0] = true;
|
||||
bsd.BlendOp = D3D10_BLEND_OP_ADD;
|
||||
bsd.SrcBlend = D3D10_BLEND_SRC_ALPHA;
|
||||
bsd.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
|
||||
bsd.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
||||
bsd.SrcBlendAlpha = D3D10_BLEND_ONE;
|
||||
bsd.DestBlendAlpha = D3D10_BLEND_ZERO;
|
||||
bsd.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
||||
|
||||
hr = m_dev->CreateBlendState(&bsd, &m_merge.bs);
|
||||
|
||||
// interlace
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
|
||||
bd.ByteWidth = sizeof(InterlaceConstantBuffer);
|
||||
bd.Usage = D3D10_USAGE_DEFAULT;
|
||||
bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
||||
bd.CPUAccessFlags = 0;
|
||||
bd.MiscFlags = 0;
|
||||
|
||||
hr = m_dev->CreateBuffer(&bd, NULL, &m_interlace.cb);
|
||||
|
||||
for(int i = 0; i < countof(m_interlace.ps); i++)
|
||||
{
|
||||
CStringA main;
|
||||
main.Format("ps_main%d", i);
|
||||
hr = CompileShader(IDR_INTERLACE10_FX, main, NULL, &m_interlace.ps[i]);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
memset(&rd, 0, sizeof(rd));
|
||||
|
||||
rd.FillMode = D3D10_FILL_SOLID;
|
||||
rd.CullMode = D3D10_CULL_NONE;
|
||||
rd.FrontCounterClockwise = false;
|
||||
rd.DepthBias = false;
|
||||
rd.DepthBiasClamp = 0;
|
||||
rd.SlopeScaledDepthBias = 0;
|
||||
rd.DepthClipEnable = false; // ???
|
||||
rd.ScissorEnable = true;
|
||||
rd.MultisampleEnable = false;
|
||||
rd.AntialiasedLineEnable = false;
|
||||
|
||||
hr = m_dev->CreateRasterizerState(&rd, &m_rs);
|
||||
|
||||
m_dev->RSSetState(m_rs);
|
||||
|
||||
//
|
||||
|
||||
memset(&sd, 0, sizeof(sd));
|
||||
|
||||
sd.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
sd.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP;
|
||||
sd.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP;
|
||||
sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
|
||||
sd.MaxLOD = FLT_MAX;
|
||||
sd.MaxAnisotropy = 16;
|
||||
sd.ComparisonFunc = D3D10_COMPARISON_NEVER;
|
||||
|
||||
hr = m_dev->CreateSamplerState(&sd, &m_convert.ln);
|
||||
|
||||
sd.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT;
|
||||
|
||||
hr = m_dev->CreateSamplerState(&sd, &m_convert.pt);
|
||||
|
||||
//
|
||||
|
||||
Reset(1, 1, true);
|
||||
|
||||
//
|
||||
/*
|
||||
if(!m_mergefx.Create(this))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
//
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSDevice10::Reset(int w, int h, bool fs)
|
||||
{
|
||||
if(!__super::Reset(w, h, fs))
|
||||
return false;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC scd;
|
||||
memset(&scd, 0, sizeof(scd));
|
||||
m_swapchain->GetDesc(&scd);
|
||||
m_swapchain->ResizeBuffers(scd.BufferCount, w, h, scd.BufferDesc.Format, 0);
|
||||
|
||||
CComPtr<ID3D10Texture2D> backbuffer;
|
||||
m_swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)&backbuffer);
|
||||
m_backbuffer = Texture(backbuffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSDevice10::Present(const CRect& r)
|
||||
{
|
||||
CRect cr;
|
||||
|
||||
GetClientRect(m_hWnd, &cr);
|
||||
|
||||
if(m_backbuffer.GetWidth() != cr.Width() || m_backbuffer.GetHeight() != cr.Height())
|
||||
{
|
||||
Reset(cr.Width(), cr.Height(), false);
|
||||
}
|
||||
|
||||
float color[4] = {0, 0, 0, 0};
|
||||
|
||||
m_dev->ClearRenderTargetView(m_backbuffer, color);
|
||||
|
||||
if(m_current)
|
||||
{
|
||||
StretchRect(m_current, m_backbuffer, GSVector4(r));
|
||||
}
|
||||
|
||||
m_swapchain->Present(m_vsync ? 1 : 0, 0);
|
||||
}
|
||||
|
||||
void GSDevice10::BeginScene()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDevice10::EndScene()
|
||||
{
|
||||
PSSetShaderResources(NULL, NULL);
|
||||
|
||||
// not clearing the rt/ds gives a little fps boost in complex games (5-10%)
|
||||
|
||||
// OMSetRenderTargets(NULL, NULL);
|
||||
}
|
||||
|
||||
void GSDevice10::Draw(LPCTSTR str)
|
||||
{
|
||||
/*
|
||||
BOOL fs;
|
||||
CComPtr<IDXGIOutput> target;
|
||||
|
||||
m_swapchain->GetFullscreenState(&fs, &target);
|
||||
|
||||
if(fs)
|
||||
{
|
||||
BeginScene();
|
||||
|
||||
OMSetRenderTargets(m_backbuffer, NULL);
|
||||
|
||||
CRect r(0, 0, m_backbuffer.GetWidth(), m_backbuffer.GetHeight());
|
||||
|
||||
D3DCOLOR c = D3DCOLOR_ARGB(255, 0, 255, 0);
|
||||
|
||||
if(m_font->DrawText(NULL, str, -1, &r, DT_CALCRECT|DT_LEFT|DT_WORDBREAK, c))
|
||||
{
|
||||
m_font->DrawText(NULL, str, -1, &r, DT_LEFT|DT_WORDBREAK, c);
|
||||
}
|
||||
|
||||
EndScene();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool GSDevice10::CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format)
|
||||
{
|
||||
dst = Texture();
|
||||
|
||||
if(format == 0)
|
||||
{
|
||||
format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
|
||||
if(format != DXGI_FORMAT_R8G8B8A8_UNORM && format != DXGI_FORMAT_R16_UINT)
|
||||
{
|
||||
ASSERT(0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Texture rt;
|
||||
|
||||
if(CreateRenderTarget(rt, w, h, format))
|
||||
{
|
||||
GSVector4 dr(0, 0, w, h);
|
||||
|
||||
StretchRect(src, sr, rt, dr, m_convert.ps[format == DXGI_FORMAT_R16_UINT ? 1 : 0], NULL);
|
||||
|
||||
if(CreateOffscreen(dst, w, h, format))
|
||||
{
|
||||
m_dev->CopyResource(dst, rt);
|
||||
}
|
||||
}
|
||||
|
||||
Recycle(rt);
|
||||
|
||||
return !!dst;
|
||||
}
|
||||
|
||||
void GSDevice10::ClearRenderTarget(Texture& t, const GSVector4& c)
|
||||
{
|
||||
m_dev->ClearRenderTargetView(t, c.v);
|
||||
}
|
||||
|
||||
void GSDevice10::ClearRenderTarget(Texture& t, DWORD c)
|
||||
{
|
||||
GSVector4 color = GSVector4(c) * (1.0f / 255);
|
||||
|
||||
m_dev->ClearRenderTargetView(t, color.v);
|
||||
}
|
||||
|
||||
void GSDevice10::ClearDepth(Texture& t, float c)
|
||||
{
|
||||
m_dev->ClearDepthStencilView(t, D3D10_CLEAR_DEPTH, c, 0);
|
||||
}
|
||||
|
||||
void GSDevice10::ClearStencil(Texture& t, BYTE c)
|
||||
{
|
||||
m_dev->ClearDepthStencilView(t, D3D10_CLEAR_STENCIL, 0, c);
|
||||
}
|
||||
|
||||
bool GSDevice10::Create(int type, Texture& t, int w, int h, int format)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
|
||||
desc.Width = w;
|
||||
desc.Height = h;
|
||||
desc.Format = (DXGI_FORMAT)format;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = D3D10_USAGE_DEFAULT;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case GSTexture::RenderTarget:
|
||||
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
case GSTexture::DepthStencil:
|
||||
desc.BindFlags = D3D10_BIND_DEPTH_STENCIL;
|
||||
break;
|
||||
case GSTexture::Texture:
|
||||
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
case GSTexture::Offscreen:
|
||||
desc.Usage = D3D10_USAGE_STAGING;
|
||||
desc.CPUAccessFlags |= D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
CComPtr<ID3D10Texture2D> texture;
|
||||
|
||||
hr = m_dev->CreateTexture2D(&desc, NULL, &texture);
|
||||
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
t = Texture(texture);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case GSTexture::RenderTarget:
|
||||
ClearRenderTarget(t, 0);
|
||||
break;
|
||||
case GSTexture::DepthStencil:
|
||||
ClearDepth(t, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GSDevice10::CreateRenderTarget(Texture& t, int w, int h, int format)
|
||||
{
|
||||
return __super::CreateRenderTarget(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
}
|
||||
|
||||
bool GSDevice10::CreateDepthStencil(Texture& t, int w, int h, int format)
|
||||
{
|
||||
return __super::CreateDepthStencil(t, w, h, format ? format : DXGI_FORMAT_D32_FLOAT_S8X24_UINT);
|
||||
}
|
||||
|
||||
bool GSDevice10::CreateTexture(Texture& t, int w, int h, int format)
|
||||
{
|
||||
return __super::CreateTexture(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
}
|
||||
|
||||
bool GSDevice10::CreateOffscreen(Texture& t, int w, int h, int format)
|
||||
{
|
||||
return __super::CreateOffscreen(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
}
|
||||
|
||||
void GSDevice10::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c)
|
||||
{
|
||||
ClearRenderTarget(dt, c);
|
||||
|
||||
if(st[1] && !slbg)
|
||||
{
|
||||
StretchRect(st[1], sr[1], dt, dr[1], m_merge.ps[0], NULL, true);
|
||||
}
|
||||
|
||||
if(st[0])
|
||||
{
|
||||
m_dev->UpdateSubresource(m_merge.cb, 0, NULL, &c, 0, 0);
|
||||
|
||||
StretchRect(st[0], sr[0], dt, dr[0], m_merge.ps[mmod ? 1 : 0], m_merge.cb, m_merge.bs, true);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset)
|
||||
{
|
||||
GSVector4 sr(0, 0, 1, 1);
|
||||
GSVector4 dr(0.0f, yoffset, (float)dt.GetWidth(), (float)dt.GetHeight() + yoffset);
|
||||
|
||||
InterlaceConstantBuffer cb;
|
||||
|
||||
cb.ZrH = GSVector2(0, 1.0f / dt.GetHeight());
|
||||
cb.hH = (float)dt.GetHeight() / 2;
|
||||
|
||||
m_dev->UpdateSubresource(m_interlace.cb, 0, NULL, &cb, 0, 0);
|
||||
|
||||
StretchRect(st, sr, dt, dr, m_interlace.ps[shader], m_interlace.cb, linear);
|
||||
}
|
||||
|
||||
void GSDevice10::IASetVertexBuffer(ID3D10Buffer* vb, UINT stride)
|
||||
{
|
||||
if(m_vb != vb || m_vb_stride != stride)
|
||||
{
|
||||
UINT offset = 0;
|
||||
|
||||
m_dev->IASetVertexBuffers(0, 1, &vb, &stride, &offset);
|
||||
|
||||
m_vb = vb;
|
||||
m_vb_stride = stride;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::IASetInputLayout(ID3D10InputLayout* layout)
|
||||
{
|
||||
if(m_layout != layout)
|
||||
{
|
||||
m_dev->IASetInputLayout(layout);
|
||||
|
||||
m_layout = layout;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY topology)
|
||||
{
|
||||
if(m_topology != topology)
|
||||
{
|
||||
m_dev->IASetPrimitiveTopology(topology);
|
||||
|
||||
m_topology = topology;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::VSSetShader(ID3D10VertexShader* vs, ID3D10Buffer* vs_cb)
|
||||
{
|
||||
if(m_vs != vs)
|
||||
{
|
||||
m_dev->VSSetShader(vs);
|
||||
|
||||
m_vs = vs;
|
||||
}
|
||||
|
||||
if(m_vs_cb != vs_cb)
|
||||
{
|
||||
m_dev->VSSetConstantBuffers(0, 1, &vs_cb);
|
||||
|
||||
m_vs_cb = vs_cb;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::GSSetShader(ID3D10GeometryShader* gs)
|
||||
{
|
||||
if(m_gs != gs)
|
||||
{
|
||||
m_dev->GSSetShader(gs);
|
||||
|
||||
m_gs = gs;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::PSSetShaderResources(ID3D10ShaderResourceView* srv0, ID3D10ShaderResourceView* srv1)
|
||||
{
|
||||
if(m_ps_srv[0] != srv0 || m_ps_srv[1] != srv1)
|
||||
{
|
||||
ID3D10ShaderResourceView* srvs[] = {srv0, srv1};
|
||||
|
||||
m_dev->PSSetShaderResources(0, 2, srvs);
|
||||
|
||||
m_ps_srv[0] = srv0;
|
||||
m_ps_srv[1] = srv1;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::PSSetShader(ID3D10PixelShader* ps, ID3D10Buffer* ps_cb)
|
||||
{
|
||||
if(m_ps != ps)
|
||||
{
|
||||
m_dev->PSSetShader(ps);
|
||||
|
||||
m_ps = ps;
|
||||
}
|
||||
|
||||
if(m_ps_cb != ps_cb)
|
||||
{
|
||||
m_dev->PSSetConstantBuffers(0, 1, &ps_cb);
|
||||
|
||||
m_ps_cb = ps_cb;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::PSSetSamplerState(ID3D10SamplerState* ss0, ID3D10SamplerState* ss1)
|
||||
{
|
||||
if(m_ps_ss[0] != ss0 || m_ps_ss[1] != ss1)
|
||||
{
|
||||
ID3D10SamplerState* sss[] = {ss0, ss1};
|
||||
|
||||
m_dev->PSSetSamplers(0, 2, sss);
|
||||
|
||||
m_ps_ss[0] = ss0;
|
||||
m_ps_ss[1] = ss1;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::RSSet(int width, int height, const RECT* scissor)
|
||||
{
|
||||
if(m_viewport.cx != width || m_viewport.cy != height)
|
||||
{
|
||||
D3D10_VIEWPORT vp;
|
||||
|
||||
memset(&vp, 0, sizeof(vp));
|
||||
|
||||
vp.TopLeftX = 0;
|
||||
vp.TopLeftY = 0;
|
||||
vp.Width = width;
|
||||
vp.Height = height;
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
|
||||
m_dev->RSSetViewports(1, &vp);
|
||||
|
||||
m_viewport = CSize(width, height);
|
||||
}
|
||||
|
||||
CRect r = scissor ? *scissor : CRect(0, 0, width, height);
|
||||
|
||||
if(m_scissor != r)
|
||||
{
|
||||
m_dev->RSSetScissorRects(1, &r);
|
||||
|
||||
m_scissor = r;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::OMSetDepthStencilState(ID3D10DepthStencilState* dss, UINT sref)
|
||||
{
|
||||
if(m_dss != dss || m_sref != sref)
|
||||
{
|
||||
m_dev->OMSetDepthStencilState(dss, sref);
|
||||
|
||||
m_dss = dss;
|
||||
m_sref = sref;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::OMSetBlendState(ID3D10BlendState* bs, float bf)
|
||||
{
|
||||
if(m_bs != bs || m_bf != bf)
|
||||
{
|
||||
float BlendFactor[] = {bf, bf, bf, 0};
|
||||
|
||||
m_dev->OMSetBlendState(bs, BlendFactor, 0xffffffff);
|
||||
|
||||
m_bs = bs;
|
||||
m_bf = bf;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv)
|
||||
{
|
||||
if(m_rtv != rtv || m_dsv != dsv)
|
||||
{
|
||||
m_dev->OMSetRenderTargets(1, &rtv, dsv);
|
||||
|
||||
m_rtv = rtv;
|
||||
m_dsv = dsv;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice10::DrawPrimitive(UINT count, UINT start)
|
||||
{
|
||||
m_dev->Draw(count, start);
|
||||
}
|
||||
|
||||
void GSDevice10::StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear)
|
||||
{
|
||||
StretchRect(st, GSVector4(0, 0, 1, 1), dt, dr, linear);
|
||||
}
|
||||
|
||||
void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear)
|
||||
{
|
||||
StretchRect(st, sr, dt, dr, m_convert.ps[0], NULL, linear);
|
||||
}
|
||||
|
||||
void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear)
|
||||
{
|
||||
StretchRect(st, sr, dt, dr, ps, ps_cb, m_convert.bs, linear);
|
||||
}
|
||||
|
||||
void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear)
|
||||
{
|
||||
BeginScene();
|
||||
|
||||
// om
|
||||
|
||||
OMSetDepthStencilState(m_convert.dss, 0);
|
||||
OMSetBlendState(bs, 0);
|
||||
OMSetRenderTargets(dt, NULL);
|
||||
|
||||
// ia
|
||||
|
||||
float left = dr.x * 2 / dt.GetWidth() - 1.0f;
|
||||
float top = 1.0f - dr.y * 2 / dt.GetHeight();
|
||||
float right = dr.z * 2 / dt.GetWidth() - 1.0f;
|
||||
float bottom = 1.0f - dr.w * 2 / dt.GetHeight();
|
||||
|
||||
GSVertexPT1 vertices[] =
|
||||
{
|
||||
{GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)},
|
||||
{GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)},
|
||||
{GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)},
|
||||
{GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)},
|
||||
};
|
||||
|
||||
D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1};
|
||||
|
||||
m_dev->UpdateSubresource(m_convert.vb, 0, &box, vertices, 0, 0);
|
||||
|
||||
IASetVertexBuffer(m_convert.vb, sizeof(vertices[0]));
|
||||
IASetInputLayout(m_convert.il);
|
||||
IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
|
||||
// vs
|
||||
|
||||
VSSetShader(m_convert.vs, NULL);
|
||||
|
||||
// gs
|
||||
|
||||
GSSetShader(NULL);
|
||||
|
||||
// ps
|
||||
|
||||
PSSetShader(ps, ps_cb);
|
||||
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt, NULL);
|
||||
PSSetShaderResources(st, NULL);
|
||||
|
||||
// rs
|
||||
|
||||
RSSet(dt.GetWidth(), dt.GetHeight());
|
||||
|
||||
//
|
||||
|
||||
DrawPrimitive(countof(vertices));
|
||||
|
||||
//
|
||||
|
||||
EndScene();
|
||||
}
|
||||
|
||||
HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** ps, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
CComPtr<ID3D10Blob> shader, error;
|
||||
|
||||
hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "vs_4_0", 0, 0, NULL, &shader, &error, NULL);
|
||||
|
||||
if(error)
|
||||
{
|
||||
TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer()));
|
||||
}
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = m_dev->CreateVertexShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), ps);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = m_dev->CreateInputLayout(layout, count, shader->GetBufferPointer(), shader->GetBufferSize(), il);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10GeometryShader** gs)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
CComPtr<ID3D10Blob> shader, error;
|
||||
|
||||
hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "gs_4_0", 0, 0, NULL, &shader, &error, NULL);
|
||||
|
||||
if(error)
|
||||
{
|
||||
TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer()));
|
||||
}
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = m_dev->CreateGeometryShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), gs);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10PixelShader** ps)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
CComPtr<ID3D10Blob> shader, error;
|
||||
|
||||
hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "ps_4_0", 0, 0, NULL, &shader, &error, NULL);
|
||||
|
||||
if(error)
|
||||
{
|
||||
TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer()));
|
||||
}
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = m_dev->CreatePixelShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), ps);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSDevice.h"
|
||||
#include "GSTexture10.h"
|
||||
|
||||
class GSDevice10 : public GSDevice<GSTexture10>
|
||||
{
|
||||
public:
|
||||
typedef GSTexture10 Texture;
|
||||
|
||||
private:
|
||||
// state cache
|
||||
|
||||
ID3D10Buffer* m_vb;
|
||||
UINT m_vb_count;
|
||||
UINT m_vb_stride;
|
||||
ID3D10InputLayout* m_layout;
|
||||
D3D10_PRIMITIVE_TOPOLOGY m_topology;
|
||||
ID3D10VertexShader* m_vs;
|
||||
ID3D10Buffer* m_vs_cb;
|
||||
ID3D10GeometryShader* m_gs;
|
||||
ID3D10ShaderResourceView* m_ps_srv[2];
|
||||
ID3D10PixelShader* m_ps;
|
||||
ID3D10Buffer* m_ps_cb;
|
||||
ID3D10SamplerState* m_ps_ss[2];
|
||||
CSize m_viewport;
|
||||
CRect m_scissor;
|
||||
ID3D10DepthStencilState* m_dss;
|
||||
UINT m_sref;
|
||||
ID3D10BlendState* m_bs;
|
||||
float m_bf;
|
||||
ID3D10RenderTargetView* m_rtv;
|
||||
ID3D10DepthStencilView* m_dsv;
|
||||
|
||||
//
|
||||
|
||||
bool Create(int type, Texture& t, int w, int h, int format);
|
||||
void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c);
|
||||
void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0);
|
||||
|
||||
//
|
||||
|
||||
CComPtr<ID3D10Device> m_dev;
|
||||
CComPtr<IDXGISwapChain> m_swapchain;
|
||||
CComPtr<ID3DX10Font> m_font;
|
||||
|
||||
public: // TODO
|
||||
CComPtr<ID3D10RasterizerState> m_rs;
|
||||
|
||||
struct
|
||||
{
|
||||
CComPtr<ID3D10Buffer> vb;
|
||||
CComPtr<ID3D10InputLayout> il;
|
||||
CComPtr<ID3D10VertexShader> vs;
|
||||
CComPtr<ID3D10PixelShader> ps[5];
|
||||
CComPtr<ID3D10SamplerState> ln;
|
||||
CComPtr<ID3D10SamplerState> pt;
|
||||
CComPtr<ID3D10DepthStencilState> dss;
|
||||
CComPtr<ID3D10BlendState> bs;
|
||||
} m_convert;
|
||||
|
||||
struct
|
||||
{
|
||||
CComPtr<ID3D10PixelShader> ps[2];
|
||||
CComPtr<ID3D10Buffer> cb;
|
||||
CComPtr<ID3D10BlendState> bs;
|
||||
} m_merge;
|
||||
|
||||
struct
|
||||
{
|
||||
CComPtr<ID3D10PixelShader> ps[4];
|
||||
CComPtr<ID3D10Buffer> cb;
|
||||
} m_interlace;
|
||||
|
||||
public:
|
||||
GSDevice10();
|
||||
virtual ~GSDevice10();
|
||||
|
||||
bool Create(HWND hWnd, bool vsync);
|
||||
bool Reset(int w, int h, bool fs);
|
||||
bool IsLost() {return false;}
|
||||
void Present(const CRect& r);
|
||||
void BeginScene();
|
||||
void EndScene();
|
||||
void Draw(LPCTSTR str);
|
||||
bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0);
|
||||
|
||||
void ClearRenderTarget(Texture& t, const GSVector4& c);
|
||||
void ClearRenderTarget(Texture& t, DWORD c);
|
||||
void ClearDepth(Texture& t, float c);
|
||||
void ClearStencil(Texture& t, BYTE c);
|
||||
|
||||
bool CreateRenderTarget(Texture& t, int w, int h, int format = 0);
|
||||
bool CreateDepthStencil(Texture& t, int w, int h, int format = 0);
|
||||
bool CreateTexture(Texture& t, int w, int h, int format = 0);
|
||||
bool CreateOffscreen(Texture& t, int w, int h, int format = 0);
|
||||
|
||||
ID3D10Device* operator->() {return m_dev;}
|
||||
operator ID3D10Device*() {return m_dev;}
|
||||
|
||||
void IASetVertexBuffer(ID3D10Buffer* vb, UINT stride);
|
||||
void IASetInputLayout(ID3D10InputLayout* layout);
|
||||
void IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY topology);
|
||||
void VSSetShader(ID3D10VertexShader* vs, ID3D10Buffer* vs_cb);
|
||||
void GSSetShader(ID3D10GeometryShader* gs);
|
||||
void PSSetShaderResources(ID3D10ShaderResourceView* srv0, ID3D10ShaderResourceView* srv1);
|
||||
void PSSetShader(ID3D10PixelShader* ps, ID3D10Buffer* ps_cb);
|
||||
void PSSetSamplerState(ID3D10SamplerState* ss0, ID3D10SamplerState* ss1);
|
||||
void RSSet(int width, int height, const RECT* scissor = NULL);
|
||||
void OMSetDepthStencilState(ID3D10DepthStencilState* dss, UINT sref);
|
||||
void OMSetBlendState(ID3D10BlendState* bs, float bf);
|
||||
void OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv);
|
||||
void DrawPrimitive(UINT count, UINT start = 0);
|
||||
|
||||
void StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear = true);
|
||||
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear = true);
|
||||
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear = true);
|
||||
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear = true);
|
||||
|
||||
HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** vs, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il);
|
||||
HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10GeometryShader** gs);
|
||||
HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10PixelShader** ps);
|
||||
|
||||
// TODO
|
||||
bool SaveToFileD32S8X24(ID3D10Texture2D* ds, LPCTSTR fn);
|
||||
};
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
// dumb device implementation, only good for simple image output
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "GSDevice7.h"
|
||||
|
||||
GSDevice7::GSDevice7()
|
||||
{
|
||||
}
|
||||
|
||||
GSDevice7::~GSDevice7()
|
||||
{
|
||||
}
|
||||
|
||||
bool GSDevice7::Create(HWND hWnd, bool vsync)
|
||||
{
|
||||
if(!__super::Create(hWnd, vsync))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(FAILED(DirectDrawCreateEx(NULL, (VOID**)&m_dd, IID_IDirectDraw7, NULL)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: fullscreen
|
||||
|
||||
if(FAILED(m_dd->SetCooperativeLevel(hWnd, DDSCL_NORMAL)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DDSURFACEDESC2 desc;
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_CAPS;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||
|
||||
if(FAILED(m_dd->CreateSurface(&desc, &m_primary, NULL)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CComPtr<IDirectDrawClipper> clipper;
|
||||
|
||||
if(FAILED(m_dd->CreateClipper(0, &clipper, NULL))
|
||||
|| FAILED(clipper->SetHWnd(0, hWnd))
|
||||
|| FAILED(m_primary->SetClipper(clipper)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Reset(1, 1, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSDevice7::Reset(int w, int h, bool fs)
|
||||
{
|
||||
if(!__super::Reset(w, h, fs))
|
||||
return false;
|
||||
|
||||
m_backbuffer = NULL;
|
||||
|
||||
DDSURFACEDESC2 desc;
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_3DDEVICE;
|
||||
desc.dwWidth = w;
|
||||
desc.dwHeight = h;
|
||||
|
||||
if(FAILED(m_dd->CreateSurface(&desc, &m_backbuffer, NULL)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CComPtr<IDirectDrawClipper> clipper;
|
||||
|
||||
if(FAILED(m_dd->CreateClipper(0, &clipper, NULL)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// ???
|
||||
|
||||
HRGN hrgn = CreateRectRgn(0, 0, w, h);
|
||||
|
||||
BYTE buff[1024];
|
||||
|
||||
GetRegionData(hrgn, sizeof(buff), (RGNDATA*)buff);
|
||||
|
||||
DeleteObject(hrgn);
|
||||
|
||||
clipper->SetClipList((RGNDATA*)buff, 0);
|
||||
|
||||
if(FAILED(m_backbuffer->SetClipper(clipper)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSDevice7::Present(const CRect& r)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
CRect cr;
|
||||
GetClientRect(m_hWnd, &cr);
|
||||
|
||||
DDSURFACEDESC2 desc;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.dwSize = sizeof(desc);
|
||||
|
||||
hr = m_backbuffer->GetSurfaceDesc(&desc);
|
||||
|
||||
if(desc.dwWidth != cr.Width() || desc.dwHeight != cr.Height())
|
||||
{
|
||||
Reset(cr.Width(), cr.Height(), false);
|
||||
}
|
||||
|
||||
DDBLTFX fx;
|
||||
|
||||
memset(&fx, 0, sizeof(fx));
|
||||
|
||||
fx.dwSize = sizeof(fx);
|
||||
fx.dwFillColor = 0;
|
||||
|
||||
hr = m_backbuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
||||
|
||||
CRect r2 = r;
|
||||
|
||||
hr = m_backbuffer->Blt(&r2, m_merge, NULL, DDBLT_WAIT, NULL);
|
||||
|
||||
r2 = cr;
|
||||
|
||||
MapWindowPoints(m_hWnd, HWND_DESKTOP, (POINT*)&r2, 2);
|
||||
|
||||
if(m_vsync)
|
||||
{
|
||||
hr = m_dd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
|
||||
}
|
||||
|
||||
hr = m_primary->Blt(&r2, m_backbuffer, &cr, DDBLT_WAIT, NULL);
|
||||
|
||||
if(hr == DDERR_SURFACELOST)
|
||||
{
|
||||
// TODO
|
||||
|
||||
HRESULT hr = m_dd->TestCooperativeLevel();
|
||||
|
||||
if(hr == DDERR_WRONGMODE)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GSDevice7::Create(int type, Texture& t, int w, int h, int format)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
t = Texture();
|
||||
|
||||
DDSURFACEDESC2 desc;
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
|
||||
desc.dwWidth = w;
|
||||
desc.dwHeight = h;
|
||||
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
|
||||
desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
|
||||
desc.ddpfPixelFormat.dwRGBBitCount = 32;
|
||||
desc.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
|
||||
desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
|
||||
desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
|
||||
desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
|
||||
|
||||
CComPtr<IDirectDrawSurface7> system, video;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case GSTexture::RenderTarget:
|
||||
case GSTexture::DepthStencil:
|
||||
case GSTexture::Texture:
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
|
||||
if(FAILED(hr = m_dd->CreateSurface(&desc, &system, NULL))) return false;
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
|
||||
if(FAILED(hr = m_dd->CreateSurface(&desc, &video, NULL))) return false;
|
||||
t = Texture(type, system, video);
|
||||
break;
|
||||
case GSTexture::Offscreen:
|
||||
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
|
||||
if(FAILED(hr = m_dd->CreateSurface(&desc, &system, NULL))) return false;
|
||||
t = Texture(type, system);
|
||||
break;
|
||||
}
|
||||
|
||||
return !!t;
|
||||
}
|
||||
|
||||
void GSDevice7::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = dt->Blt(NULL, st[0], NULL, DDBLT_WAIT, NULL);
|
||||
}
|
||||
|
||||
void GSDevice7::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSDevice.h"
|
||||
#include "GSTexture7.h"
|
||||
|
||||
class GSDevice7 : public GSDevice<GSTexture7>
|
||||
{
|
||||
public:
|
||||
typedef GSTexture7 Texture;
|
||||
|
||||
private:
|
||||
CComPtr<IDirectDraw7> m_dd;
|
||||
CComPtr<IDirectDrawSurface7> m_primary;
|
||||
CComPtr<IDirectDrawSurface7> m_backbuffer;
|
||||
|
||||
bool Create(int type, Texture& t, int w, int h, int format);
|
||||
void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c);
|
||||
void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0);
|
||||
|
||||
public:
|
||||
GSDevice7();
|
||||
virtual ~GSDevice7();
|
||||
|
||||
bool Create(HWND hWnd, bool vsync);
|
||||
bool Reset(int w, int h, bool fs);
|
||||
bool IsLost() {return false;}
|
||||
void Present(const CRect& r);
|
||||
void BeginScene() {}
|
||||
void EndScene() {}
|
||||
void Draw(LPCTSTR str) {}
|
||||
bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) {return false;}
|
||||
|
||||
void ClearRenderTarget(Texture& t, const GSVector4& c) {}
|
||||
void ClearRenderTarget(Texture& t, DWORD c) {}
|
||||
void ClearDepth(Texture& t, float c) {}
|
||||
void ClearStencil(Texture& t, BYTE c) {}
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSDevice.h"
|
||||
#include "GSTexture9.h"
|
||||
|
||||
struct Direct3DSamplerState9
|
||||
{
|
||||
D3DTEXTUREFILTERTYPE FilterMin[2];
|
||||
D3DTEXTUREFILTERTYPE FilterMag[2];
|
||||
D3DTEXTUREADDRESS AddressU;
|
||||
D3DTEXTUREADDRESS AddressV;
|
||||
};
|
||||
|
||||
struct Direct3DDepthStencilState9
|
||||
{
|
||||
BOOL DepthEnable;
|
||||
BOOL DepthWriteMask;
|
||||
D3DCMPFUNC DepthFunc;
|
||||
BOOL StencilEnable;
|
||||
UINT8 StencilReadMask;
|
||||
UINT8 StencilWriteMask;
|
||||
D3DSTENCILOP StencilFailOp;
|
||||
D3DSTENCILOP StencilDepthFailOp;
|
||||
D3DSTENCILOP StencilPassOp;
|
||||
D3DCMPFUNC StencilFunc;
|
||||
};
|
||||
|
||||
struct Direct3DBlendState9
|
||||
{
|
||||
BOOL BlendEnable;
|
||||
D3DBLEND SrcBlend;
|
||||
D3DBLEND DestBlend;
|
||||
D3DBLENDOP BlendOp;
|
||||
D3DBLEND SrcBlendAlpha;
|
||||
D3DBLEND DestBlendAlpha;
|
||||
D3DBLENDOP BlendOpAlpha;
|
||||
UINT8 RenderTargetWriteMask;
|
||||
};
|
||||
|
||||
class GSDevice9 : public GSDevice<GSTexture9>
|
||||
{
|
||||
public:
|
||||
typedef GSTexture9 Texture;
|
||||
|
||||
private:
|
||||
// state cache
|
||||
|
||||
IDirect3DVertexBuffer9* m_vb;
|
||||
UINT m_vb_count;
|
||||
const void* m_vb_vertices;
|
||||
UINT m_vb_stride;
|
||||
IDirect3DVertexDeclaration9* m_layout;
|
||||
D3DPRIMITIVETYPE m_topology;
|
||||
IDirect3DVertexShader9* m_vs;
|
||||
float* m_vs_cb;
|
||||
int m_vs_cb_len;
|
||||
IDirect3DTexture9* m_ps_srvs[2];
|
||||
IDirect3DPixelShader9* m_ps;
|
||||
float* m_ps_cb;
|
||||
int m_ps_cb_len;
|
||||
Direct3DSamplerState9* m_ps_ss;
|
||||
CRect m_scissor;
|
||||
Direct3DDepthStencilState9* m_dss;
|
||||
UINT m_sref;
|
||||
Direct3DBlendState9* m_bs;
|
||||
DWORD m_bf;
|
||||
IDirect3DSurface9* m_rtv;
|
||||
IDirect3DSurface9* m_dsv;
|
||||
|
||||
//
|
||||
|
||||
bool Create(int type, Texture& t, int w, int h, int format);
|
||||
void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c);
|
||||
void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0);
|
||||
|
||||
//
|
||||
|
||||
DDCAPS m_ddcaps;
|
||||
D3DCAPS9 m_d3dcaps;
|
||||
CComPtr<IDirect3D9> m_d3d;
|
||||
CComPtr<IDirect3DDevice9> m_dev;
|
||||
CComPtr<IDirect3DSwapChain9> m_swapchain;
|
||||
Texture m_backbuffer;
|
||||
|
||||
public: // TODO
|
||||
D3DPRESENT_PARAMETERS m_pp;
|
||||
CComPtr<ID3DXFont> m_font;
|
||||
|
||||
struct
|
||||
{
|
||||
CComPtr<IDirect3DVertexShader9> vs;
|
||||
CComPtr<IDirect3DVertexDeclaration9> il;
|
||||
CComPtr<IDirect3DPixelShader9> ps[5];
|
||||
Direct3DSamplerState9 ln;
|
||||
Direct3DSamplerState9 pt;
|
||||
Direct3DDepthStencilState9 dss;
|
||||
Direct3DBlendState9 bs;
|
||||
} m_convert;
|
||||
|
||||
struct
|
||||
{
|
||||
CComPtr<IDirect3DPixelShader9> ps[2];
|
||||
Direct3DBlendState9 bs;
|
||||
} m_merge;
|
||||
|
||||
struct
|
||||
{
|
||||
CComPtr<IDirect3DPixelShader9> ps[4];
|
||||
} m_interlace;
|
||||
|
||||
public:
|
||||
GSDevice9();
|
||||
virtual ~GSDevice9();
|
||||
|
||||
bool Create(HWND hWnd, bool vsync);
|
||||
bool Reset(int w, int h, bool fs);
|
||||
bool IsLost();
|
||||
void Present(const CRect& r);
|
||||
void BeginScene();
|
||||
void EndScene();
|
||||
void Draw(LPCTSTR str);
|
||||
bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0);
|
||||
|
||||
void ClearRenderTarget(Texture& t, const GSVector4& c);
|
||||
void ClearRenderTarget(Texture& t, DWORD c);
|
||||
void ClearDepth(Texture& t, float c);
|
||||
void ClearStencil(Texture& t, BYTE c);
|
||||
|
||||
bool CreateRenderTarget(Texture& t, int w, int h, int format = 0);
|
||||
bool CreateDepthStencil(Texture& t, int w, int h, int format = 0);
|
||||
bool CreateTexture(Texture& t, int w, int h, int format = 0);
|
||||
bool CreateOffscreen(Texture& t, int w, int h, int format = 0);
|
||||
|
||||
IDirect3DDevice9* operator->() {return m_dev;}
|
||||
operator IDirect3DDevice9*() {return m_dev;}
|
||||
|
||||
// TODO: void IASetVertexBuffer(IDirect3DVertexBuffer9* vb, UINT count, const void* vertices, UINT stride);
|
||||
void IASetVertexBuffer(UINT count, const void* vertices, UINT stride);
|
||||
void IASetInputLayout(IDirect3DVertexDeclaration9* layout);
|
||||
void IASetPrimitiveTopology(D3DPRIMITIVETYPE topology);
|
||||
void VSSetShader(IDirect3DVertexShader9* vs, const float* vs_cb, int vs_cb_len);
|
||||
void PSSetShaderResources(IDirect3DTexture9* srv0, IDirect3DTexture9* srv1);
|
||||
void PSSetShader(IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len);
|
||||
void PSSetSamplerState(Direct3DSamplerState9* ss);
|
||||
void RSSet(int width, int height, const RECT* scissor = NULL);
|
||||
void OMSetDepthStencilState(Direct3DDepthStencilState9* dss, UINT sref);
|
||||
void OMSetBlendState(Direct3DBlendState9* bs, DWORD bf);
|
||||
void OMSetRenderTargets(IDirect3DSurface9* rtv, IDirect3DSurface9* dsv);
|
||||
void DrawPrimitive();
|
||||
|
||||
template<class T> void IASetVertexBuffer(UINT count, T* vertices)
|
||||
{
|
||||
IASetVertexBuffer(count, vertices, sizeof(T));
|
||||
}
|
||||
|
||||
void StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear = true);
|
||||
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear = true);
|
||||
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear = true);
|
||||
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear = true);
|
||||
|
||||
HRESULT CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DVertexShader9** vs, const D3DVERTEXELEMENT9* layout, int count, IDirect3DVertexDeclaration9** il);
|
||||
HRESULT CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DPixelShader9** ps);
|
||||
|
||||
virtual bool IsCurrentRGBA()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO
|
||||
bool SaveToFileD24S8(IDirect3DSurface9* ds, LPCTSTR fn);
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 "GSDeviceNull.h"
|
||||
|
||||
bool GSDeviceNull::Create(HWND hWnd, bool vsync)
|
||||
{
|
||||
if(!__super::Create(hWnd, vsync))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Reset(1, 1, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSDeviceNull::Reset(int w, int h, bool fs)
|
||||
{
|
||||
if(!__super::Reset(w, h, fs))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSDeviceNull::Create(int type, Texture& t, int w, int h, int format)
|
||||
{
|
||||
t = Texture(type, w, h, format);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSDevice.h"
|
||||
#include "GSTextureNull.h"
|
||||
|
||||
class GSDeviceNull : public GSDevice<GSTextureNull>
|
||||
{
|
||||
public:
|
||||
typedef GSTextureNull Texture;
|
||||
|
||||
private:
|
||||
bool Create(int type, Texture& t, int w, int h, int format);
|
||||
void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) {}
|
||||
void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0) {}
|
||||
|
||||
public:
|
||||
GSDeviceNull() {}
|
||||
|
||||
bool Create(HWND hWnd, bool vsync);
|
||||
bool Reset(int w, int h, bool fs);
|
||||
bool IsLost() {return false;}
|
||||
void Present(const CRect& r) {}
|
||||
void BeginScene() {}
|
||||
void EndScene() {}
|
||||
void Draw(LPCTSTR str) {}
|
||||
bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) {return false;}
|
||||
|
||||
void ClearRenderTarget(Texture& t, const GSVector4& c) {}
|
||||
void ClearRenderTarget(Texture& t, DWORD c) {}
|
||||
void ClearDepth(Texture& t, float c) {}
|
||||
void ClearStencil(Texture& t, BYTE c) {}
|
||||
};
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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 "GSDirtyRect.h"
|
||||
|
||||
GSDirtyRect::GSDirtyRect()
|
||||
: m_psm(PSM_PSMCT32)
|
||||
, m_rect(0, 0, 0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
GSDirtyRect::GSDirtyRect(DWORD psm, CRect rect)
|
||||
{
|
||||
m_psm = psm;
|
||||
m_rect = rect;
|
||||
}
|
||||
|
||||
CRect GSDirtyRect::GetDirtyRect(const GIFRegTEX0& TEX0)
|
||||
{
|
||||
CRect r = m_rect;
|
||||
|
||||
CSize src = GSLocalMemory::m_psm[m_psm].bs;
|
||||
|
||||
r.left = (r.left) & ~(src.cx-1);
|
||||
r.right = (r.right + (src.cx-1) /* + 1 */) & ~(src.cx-1);
|
||||
r.top = (r.top) & ~(src.cy-1);
|
||||
r.bottom = (r.bottom + (src.cy-1) /* + 1 */) & ~(src.cy-1);
|
||||
|
||||
if(m_psm != TEX0.PSM)
|
||||
{
|
||||
CSize dst = GSLocalMemory::m_psm[TEX0.PSM].bs;
|
||||
|
||||
r.left = MulDiv(m_rect.left, dst.cx, src.cx);
|
||||
r.right = MulDiv(m_rect.right, dst.cx, src.cx);
|
||||
r.top = MulDiv(m_rect.top, dst.cy, src.cy);
|
||||
r.bottom = MulDiv(m_rect.bottom, dst.cy, src.cy);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
CRect GSDirtyRectList::GetDirtyRect(const GIFRegTEX0& TEX0, CSize size)
|
||||
{
|
||||
if(IsEmpty()) return CRect(0, 0, 0, 0);
|
||||
CRect r(INT_MAX, INT_MAX, 0, 0);
|
||||
POSITION pos = GetHeadPosition();
|
||||
while(pos) r |= GetNext(pos).GetDirtyRect(TEX0);
|
||||
return r & CRect(0, 0, size.cx, size.cy);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSLocalMemory.h"
|
||||
|
||||
class GSDirtyRect
|
||||
{
|
||||
DWORD m_psm;
|
||||
CRect m_rect;
|
||||
|
||||
public:
|
||||
GSDirtyRect();
|
||||
GSDirtyRect(DWORD psm, CRect rect);
|
||||
CRect GetDirtyRect(const GIFRegTEX0& TEX0);
|
||||
};
|
||||
|
||||
class GSDirtyRectList : public CAtlList<GSDirtyRect>
|
||||
{
|
||||
public:
|
||||
GSDirtyRectList() {}
|
||||
CRect GetDirtyRect(const GIFRegTEX0& TEX0, CSize size);
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSState.h"
|
||||
#include "GSRasterizer.h"
|
||||
#include "GSAlignedClass.h"
|
||||
|
||||
union GSScanlineSelector
|
||||
{
|
||||
struct
|
||||
{
|
||||
DWORD fpsm:2; // 0
|
||||
DWORD zpsm:2; // 2
|
||||
DWORD ztst:2; // 4 (0: off, 1: write, 2: test (ge), 3: test (g))
|
||||
DWORD atst:3; // 6
|
||||
DWORD afail:2; // 9
|
||||
DWORD iip:1; // 11
|
||||
DWORD tfx:3; // 12
|
||||
DWORD tcc:1; // 15
|
||||
DWORD fst:1; // 16
|
||||
DWORD ltf:1; // 17
|
||||
DWORD tlu:1; // 18
|
||||
DWORD fge:1; // 19
|
||||
DWORD date:1; // 20
|
||||
DWORD abea:2; // 21
|
||||
DWORD abeb:2; // 23
|
||||
DWORD abec:2; // 25
|
||||
DWORD abed:2; // 27
|
||||
DWORD pabe:1; // 29
|
||||
DWORD rfb:1; // 30
|
||||
DWORD sprite:1; // 31
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
DWORD _pad1:21;
|
||||
DWORD abe:8;
|
||||
DWORD _pad2:3;
|
||||
};
|
||||
|
||||
DWORD dw;
|
||||
|
||||
operator DWORD() {return dw;}
|
||||
|
||||
bool IsSolidRect()
|
||||
{
|
||||
return sprite
|
||||
&& iip == 0
|
||||
&& tfx == TFX_NONE
|
||||
&& abe == 255
|
||||
&& ztst <= 1
|
||||
&& atst <= 1
|
||||
&& date == 0
|
||||
&& fge == 0;
|
||||
}
|
||||
};
|
||||
|
||||
__declspec(align(16)) struct GSScanlineEnvironment
|
||||
{
|
||||
GSScanlineSelector sel;
|
||||
|
||||
void* vm;
|
||||
const void* tex;
|
||||
const DWORD* clut;
|
||||
DWORD tw;
|
||||
|
||||
GSVector4i* fbr;
|
||||
GSVector4i* zbr;
|
||||
int** fbc;
|
||||
int** zbc;
|
||||
GSVector2i* fzbr;
|
||||
GSVector2i* fzbc;
|
||||
|
||||
GSVector4i fm, zm;
|
||||
struct {GSVector4i min, max, mask;} t; // [u] x 4 [v] x 4
|
||||
GSVector4i datm;
|
||||
GSVector4i colclamp;
|
||||
GSVector4i fba;
|
||||
GSVector4i aref;
|
||||
GSVector4i afix, afix2;
|
||||
GSVector4i frb, fga;
|
||||
|
||||
struct {GSVector4 z, s, t, q; GSVector4i rb, ga, f, si, ti, _pad[3];} d[4];
|
||||
struct {GSVector4 z, stq; GSVector4i c, f, st;} d4;
|
||||
struct {GSVector4i rb, ga;} c;
|
||||
struct {GSVector4i z, f;} p;
|
||||
struct {GSVector4i rb, ga;} c2;
|
||||
};
|
||||
|
||||
__declspec(align(16)) struct GSScanlineParam
|
||||
{
|
||||
GSScanlineSelector sel;
|
||||
|
||||
void* vm;
|
||||
const void* tex;
|
||||
const DWORD* clut;
|
||||
DWORD tw;
|
||||
|
||||
GSLocalMemory::Offset* fbo;
|
||||
GSLocalMemory::Offset* zbo;
|
||||
GSLocalMemory::Offset4* fzbo;
|
||||
|
||||
DWORD fm, zm;
|
||||
};
|
||||
|
||||
class GSDrawScanline : public GSAlignedClass<16>, public IDrawScanline
|
||||
{
|
||||
GSScanlineEnvironment m_env;
|
||||
|
||||
static const GSVector4 m_shift[4];
|
||||
static const GSVector4i m_test[8];
|
||||
|
||||
//
|
||||
|
||||
class GSDrawScanlineMap : public GSFunctionMap<DrawScanlinePtr>
|
||||
{
|
||||
DrawScanlinePtr m_default[4][4][4][2];
|
||||
|
||||
public:
|
||||
GSDrawScanlineMap();
|
||||
|
||||
DrawScanlinePtr GetDefaultFunction(DWORD dw);
|
||||
|
||||
void PrintStats();
|
||||
};
|
||||
|
||||
GSDrawScanlineMap m_ds;
|
||||
|
||||
//
|
||||
|
||||
class GSSetupPrimMap : public GSFunctionMap<SetupPrimPtr>
|
||||
{
|
||||
SetupPrimPtr m_default[2][2][2][2][2];
|
||||
|
||||
public:
|
||||
GSSetupPrimMap();
|
||||
|
||||
SetupPrimPtr GetDefaultFunction(DWORD dw);
|
||||
};
|
||||
|
||||
GSSetupPrimMap m_sp;
|
||||
|
||||
//
|
||||
|
||||
template<DWORD zbe, DWORD fge, DWORD tme, DWORD fst, DWORD iip>
|
||||
void SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan);
|
||||
|
||||
//
|
||||
|
||||
__forceinline GSVector4i Wrap(const GSVector4i& t);
|
||||
|
||||
__forceinline void SampleTexture(DWORD ltf, DWORD tlu, const GSVector4i& u, const GSVector4i& v, GSVector4i* c);
|
||||
__forceinline void ColorTFX(DWORD iip, DWORD tfx, const GSVector4i& rbf, const GSVector4i& gaf, GSVector4i& rbt, GSVector4i& gat);
|
||||
__forceinline void AlphaTFX(DWORD iip, DWORD tfx, DWORD tcc, const GSVector4i& gaf, GSVector4i& gat);
|
||||
__forceinline void Fog(DWORD fge, const GSVector4i& f, GSVector4i& rb, GSVector4i& ga);
|
||||
__forceinline bool TestZ(DWORD zpsm, DWORD ztst, const GSVector4i& zs, const GSVector4i& zd, GSVector4i& test);
|
||||
__forceinline bool TestAlpha(DWORD atst, DWORD afail, const GSVector4i& ga, GSVector4i& fm, GSVector4i& zm, GSVector4i& test);
|
||||
__forceinline bool TestDestAlpha(DWORD fpsm, DWORD date, const GSVector4i& fd, GSVector4i& test);
|
||||
|
||||
__forceinline void ReadPixel(int psm, int addr, GSVector4i& c) const;
|
||||
__forceinline static void WritePixel(int psm, WORD* RESTRICT vm16, DWORD c);
|
||||
__forceinline void WriteFrame(int fpsm, int rfb, GSVector4i* c, const GSVector4i& fd, const GSVector4i& fm, int addr, int fzm);
|
||||
__forceinline void WriteZBuf(int zpsm, int ztst, const GSVector4i& z, const GSVector4i& zd, const GSVector4i& zm, int addr, int fzm);
|
||||
|
||||
template<DWORD fpsm, DWORD zpsm, DWORD ztst, DWORD iip>
|
||||
void DrawScanline(int top, int left, int right, const GSVertexSW& v);
|
||||
|
||||
template<DWORD sel>
|
||||
void DrawScanlineEx(int top, int left, int right, const GSVertexSW& v);
|
||||
|
||||
//
|
||||
|
||||
void DrawSolidRect(const GSVector4i& r, const GSVertexSW& v);
|
||||
|
||||
template<class T, bool masked>
|
||||
void DrawSolidRectT(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m);
|
||||
|
||||
template<class T, bool masked>
|
||||
__forceinline void FillRect(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m);
|
||||
|
||||
template<class T, bool masked>
|
||||
__forceinline void FillBlock(const GSVector4i* row, int* col, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m);
|
||||
|
||||
protected:
|
||||
GSState* m_state;
|
||||
int m_id;
|
||||
|
||||
public:
|
||||
GSDrawScanline(GSState* state, int id);
|
||||
virtual ~GSDrawScanline();
|
||||
|
||||
// IDrawScanline
|
||||
|
||||
void BeginDraw(const GSRasterizerData* data, Functions* f);
|
||||
void EndDraw(const GSRasterizerStats& stats);
|
||||
void PrintStats() {m_ds.PrintStats();}
|
||||
};
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS.h"
|
||||
#include "GSLocalMemory.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
__declspec(align(16)) class GSDrawingContext
|
||||
{
|
||||
public:
|
||||
GIFRegXYOFFSET XYOFFSET;
|
||||
GIFRegTEX0 TEX0;
|
||||
GIFRegTEX1 TEX1;
|
||||
GIFRegTEX2 TEX2;
|
||||
GIFRegCLAMP CLAMP;
|
||||
GIFRegMIPTBP1 MIPTBP1;
|
||||
GIFRegMIPTBP2 MIPTBP2;
|
||||
GIFRegSCISSOR SCISSOR;
|
||||
GIFRegALPHA ALPHA;
|
||||
GIFRegTEST TEST;
|
||||
GIFRegFBA FBA;
|
||||
GIFRegFRAME FRAME;
|
||||
GIFRegZBUF ZBUF;
|
||||
|
||||
__declspec(align(16)) struct
|
||||
{
|
||||
GSVector4i dx10;
|
||||
GSVector4 dx9;
|
||||
GSVector4 in;
|
||||
GSVector4 ex;
|
||||
} scissor;
|
||||
|
||||
GSDrawingContext()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
memset(&XYOFFSET, 0, sizeof(XYOFFSET));
|
||||
memset(&TEX0, 0, sizeof(TEX0));
|
||||
memset(&TEX1, 0, sizeof(TEX1));
|
||||
memset(&TEX2, 0, sizeof(TEX2));
|
||||
memset(&CLAMP, 0, sizeof(CLAMP));
|
||||
memset(&MIPTBP1, 0, sizeof(MIPTBP1));
|
||||
memset(&MIPTBP2, 0, sizeof(MIPTBP2));
|
||||
memset(&SCISSOR, 0, sizeof(SCISSOR));
|
||||
memset(&ALPHA, 0, sizeof(ALPHA));
|
||||
memset(&TEST, 0, sizeof(TEST));
|
||||
memset(&FBA, 0, sizeof(FBA));
|
||||
memset(&FRAME, 0, sizeof(FRAME));
|
||||
memset(&ZBUF, 0, sizeof(ZBUF));
|
||||
}
|
||||
|
||||
void UpdateScissor()
|
||||
{
|
||||
scissor.dx10 = GSVector4i(
|
||||
(int)((SCISSOR.SCAX0 << 4) + XYOFFSET.OFX),
|
||||
(int)((SCISSOR.SCAY0 << 4) + XYOFFSET.OFY),
|
||||
(int)((SCISSOR.SCAX1 << 4) + XYOFFSET.OFX),
|
||||
(int)((SCISSOR.SCAY1 << 4) + XYOFFSET.OFY));
|
||||
|
||||
scissor.dx9 = GSVector4(scissor.dx10);
|
||||
|
||||
scissor.in = GSVector4(
|
||||
(int)SCISSOR.SCAX0,
|
||||
(int)SCISSOR.SCAY0,
|
||||
(int)SCISSOR.SCAX1 + 1,
|
||||
(int)SCISSOR.SCAY1 + 1);
|
||||
|
||||
scissor.ex = GSVector4i(
|
||||
(int)SCISSOR.SCAX0,
|
||||
(int)SCISSOR.SCAY0,
|
||||
(int)SCISSOR.SCAX1,
|
||||
(int)SCISSOR.SCAY1);
|
||||
}
|
||||
|
||||
bool DepthRead() const
|
||||
{
|
||||
return TEST.ZTE && TEST.ZTST >= 2;
|
||||
}
|
||||
|
||||
bool DepthWrite() const
|
||||
{
|
||||
if(TEST.ATE && TEST.ATST == ATST_NEVER && TEST.AFAIL != AFAIL_ZB_ONLY) // alpha test, all pixels fail, z buffer is not updated
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ZBUF.ZMSK == 0 && TEST.ZTE != 0; // ZTE == 0 is bug on the real hardware, write is blocked then
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
__declspec(align(16)) class GSDrawingEnvironment
|
||||
{
|
||||
public:
|
||||
GIFRegPRIM PRIM;
|
||||
GIFRegPRMODE PRMODE;
|
||||
GIFRegPRMODECONT PRMODECONT;
|
||||
GIFRegTEXCLUT TEXCLUT;
|
||||
GIFRegSCANMSK SCANMSK;
|
||||
GIFRegTEXA TEXA;
|
||||
GIFRegFOGCOL FOGCOL;
|
||||
GIFRegDIMX DIMX;
|
||||
GIFRegDTHE DTHE;
|
||||
GIFRegCOLCLAMP COLCLAMP;
|
||||
GIFRegPABE PABE;
|
||||
GIFRegBITBLTBUF BITBLTBUF;
|
||||
GIFRegTRXDIR TRXDIR;
|
||||
GIFRegTRXPOS TRXPOS;
|
||||
GIFRegTRXREG TRXREG;
|
||||
GIFRegTRXREG TRXREG2;
|
||||
GSDrawingContext CTXT[2];
|
||||
|
||||
GSDrawingEnvironment()
|
||||
{
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
memset(&PRIM, 0, sizeof(PRIM));
|
||||
memset(&PRMODE, 0, sizeof(PRMODE));
|
||||
memset(&PRMODECONT, 0, sizeof(PRMODECONT));
|
||||
memset(&TEXCLUT, 0, sizeof(TEXCLUT));
|
||||
memset(&SCANMSK, 0, sizeof(SCANMSK));
|
||||
memset(&TEXA, 0, sizeof(TEXA));
|
||||
memset(&FOGCOL, 0, sizeof(FOGCOL));
|
||||
memset(&DIMX, 0, sizeof(DIMX));
|
||||
memset(&DTHE, 0, sizeof(DTHE));
|
||||
memset(&COLCLAMP, 0, sizeof(COLCLAMP));
|
||||
memset(&PABE, 0, sizeof(PABE));
|
||||
memset(&BITBLTBUF, 0, sizeof(BITBLTBUF));
|
||||
memset(&TRXDIR, 0, sizeof(TRXDIR));
|
||||
memset(&TRXPOS, 0, sizeof(TRXPOS));
|
||||
memset(&TRXREG, 0, sizeof(TRXREG));
|
||||
memset(&TRXREG2, 0, sizeof(TRXREG2));
|
||||
|
||||
CTXT[0].Reset();
|
||||
CTXT[1].Reset();
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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 "GSDump.h"
|
||||
|
||||
GSDump::GSDump()
|
||||
: m_fp(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
GSDump::~GSDump()
|
||||
{
|
||||
if(m_fp)
|
||||
{
|
||||
fclose(m_fp);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDump::Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs)
|
||||
{
|
||||
m_fp = _tfopen(fn, _T("wb"));
|
||||
m_vsyncs = 0;
|
||||
|
||||
if(m_fp)
|
||||
{
|
||||
fwrite(&crc, 4, 1, m_fp);
|
||||
fwrite(&fd.size, 4, 1, m_fp);
|
||||
fwrite(fd.data, fd.size, 1, m_fp);
|
||||
fwrite(regs, 0x2000, 1, m_fp);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDump::Transfer(int index, BYTE* mem, size_t size)
|
||||
{
|
||||
if(m_fp && size > 0)
|
||||
{
|
||||
fputc(0, m_fp);
|
||||
fputc(index, m_fp);
|
||||
fwrite(&size, 4, 1, m_fp);
|
||||
fwrite(mem, size, 1, m_fp);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDump::ReadFIFO(UINT32 size)
|
||||
{
|
||||
if(m_fp && size > 0)
|
||||
{
|
||||
fputc(2, m_fp);
|
||||
fwrite(&size, 4, 1, m_fp);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDump::VSync(int field, bool last, const void* regs)
|
||||
{
|
||||
if(m_fp)
|
||||
{
|
||||
fputc(3, m_fp);
|
||||
fwrite(regs, 0x2000, 1, m_fp);
|
||||
|
||||
fputc(1, m_fp);
|
||||
fputc(field, m_fp);
|
||||
|
||||
if((++m_vsyncs & 1) == 0 && last)
|
||||
{
|
||||
fclose(m_fp);
|
||||
m_fp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS.h"
|
||||
|
||||
/*
|
||||
|
||||
Dump file format:
|
||||
- [crc/4] [state size/4] [state data/size] [PMODE/0x2000] [id/1] [data/?] .. [id/1] [data/?]
|
||||
|
||||
Transfer data (id == 0)
|
||||
- [0/1] [path index/1] [size/4] [data/size]
|
||||
|
||||
VSync data (id == 1)
|
||||
- [1/1] [field/1]
|
||||
|
||||
ReadFIFO2 data (id == 2)
|
||||
- [2/1] [size/?]
|
||||
|
||||
Regs data (id == 3)
|
||||
- [PMODE/0x2000]
|
||||
|
||||
*/
|
||||
|
||||
class GSDump
|
||||
{
|
||||
FILE* m_fp;
|
||||
int m_vsyncs;
|
||||
|
||||
public:
|
||||
GSDump();
|
||||
virtual ~GSDump();
|
||||
|
||||
void Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs);
|
||||
void ReadFIFO(UINT32 size);
|
||||
void Transfer(int index, BYTE* mem, size_t size);
|
||||
void VSync(int field, bool last, const void* regs);
|
||||
operator bool() {return m_fp != NULL;}
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 "GSFunctionMap.h"
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS.h"
|
||||
|
||||
struct GSRasterizerStats
|
||||
{
|
||||
__int64 ticks;
|
||||
int prims, pixels;
|
||||
|
||||
GSRasterizerStats()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
ticks = 0;
|
||||
pixels = prims = 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> class GSFunctionMap
|
||||
{
|
||||
protected:
|
||||
struct ActivePtr
|
||||
{
|
||||
UINT64 frame, frames;
|
||||
__int64 ticks, pixels;
|
||||
T f;
|
||||
};
|
||||
|
||||
CRBMap<DWORD, T> m_map;
|
||||
CRBMap<DWORD, ActivePtr*> m_map_active;
|
||||
ActivePtr* m_active;
|
||||
|
||||
virtual T GetDefaultFunction(DWORD sel) = 0;
|
||||
|
||||
public:
|
||||
GSFunctionMap()
|
||||
: m_active(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~GSFunctionMap()
|
||||
{
|
||||
POSITION pos = m_map_active.GetHeadPosition();
|
||||
|
||||
while(pos)
|
||||
{
|
||||
delete m_map_active.GetNextValue(pos);
|
||||
}
|
||||
|
||||
m_map_active.RemoveAll();
|
||||
}
|
||||
|
||||
void SetAt(DWORD sel, T f)
|
||||
{
|
||||
m_map.SetAt(sel, f);
|
||||
}
|
||||
|
||||
T Lookup(DWORD sel)
|
||||
{
|
||||
m_active = NULL;
|
||||
|
||||
if(!m_map_active.Lookup(sel, m_active))
|
||||
{
|
||||
CRBMap<DWORD, T>::CPair* pair = m_map.Lookup(sel);
|
||||
|
||||
ActivePtr* p = new ActivePtr();
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->frame = (UINT64)-1;
|
||||
|
||||
p->f = pair ? pair->m_value : GetDefaultFunction(sel);
|
||||
|
||||
m_map_active.SetAt(sel, p);
|
||||
|
||||
m_active = p;
|
||||
}
|
||||
|
||||
return m_active->f;
|
||||
}
|
||||
|
||||
void UpdateStats(const GSRasterizerStats& stats, UINT64 frame)
|
||||
{
|
||||
if(m_active)
|
||||
{
|
||||
if(m_active->frame != frame)
|
||||
{
|
||||
m_active->frame = frame;
|
||||
m_active->frames++;
|
||||
}
|
||||
|
||||
m_active->pixels += stats.pixels;
|
||||
m_active->ticks += stats.ticks;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void PrintStats()
|
||||
{
|
||||
__int64 ttpf = 0;
|
||||
|
||||
POSITION pos = m_map_active.GetHeadPosition();
|
||||
|
||||
while(pos)
|
||||
{
|
||||
ActivePtr* p = m_map_active.GetNextValue(pos);
|
||||
|
||||
if(p->frames)
|
||||
{
|
||||
ttpf += p->ticks / p->frames;
|
||||
}
|
||||
}
|
||||
|
||||
pos = m_map_active.GetHeadPosition();
|
||||
|
||||
while(pos)
|
||||
{
|
||||
DWORD sel;
|
||||
ActivePtr* p;
|
||||
|
||||
m_map_active.GetNextAssoc(pos, sel, p);
|
||||
|
||||
if(p->frames > 0)
|
||||
{
|
||||
__int64 tpp = p->pixels > 0 ? p->ticks / p->pixels : 0;
|
||||
__int64 tpf = p->frames > 0 ? p->ticks / p->frames : 0;
|
||||
__int64 ppf = p->frames > 0 ? p->pixels / p->frames : 0;
|
||||
|
||||
printf("[%08x]%c %6.2f%% | %5.2f%% | f %4I64d | p %10I64d | tpp %4I64d | tpf %9I64d | ppf %7I64d\n",
|
||||
sel, !m_map.Lookup(sel) ? '*' : ' ',
|
||||
(float)(tpf * 10000 / 50000000) / 100,
|
||||
(float)(tpf * 10000 / ttpf) / 100,
|
||||
p->frames, p->pixels,
|
||||
tpp, tpf, ppf);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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 "GSPerfMon.h"
|
||||
|
||||
extern "C" unsigned __int64 __rdtsc();
|
||||
|
||||
GSPerfMon::GSPerfMon()
|
||||
: m_total(0)
|
||||
, m_begin(0)
|
||||
, m_frame(0)
|
||||
, m_lastframe(0)
|
||||
, m_count(0)
|
||||
{
|
||||
memset(m_counters, 0, sizeof(m_counters));
|
||||
memset(m_stats, 0, sizeof(m_stats));
|
||||
memset(m_warnings, 0, sizeof(m_warnings));
|
||||
}
|
||||
|
||||
void GSPerfMon::Put(counter_t c, double val)
|
||||
{
|
||||
if(c == Frame)
|
||||
{
|
||||
clock_t now = clock();
|
||||
|
||||
if(m_lastframe != 0)
|
||||
{
|
||||
m_counters[c] += now - m_lastframe;
|
||||
}
|
||||
|
||||
m_lastframe = now;
|
||||
m_frame++;
|
||||
m_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_counters[c] += val;
|
||||
}
|
||||
}
|
||||
|
||||
void GSPerfMon::Update()
|
||||
{
|
||||
if(m_count > 0)
|
||||
{
|
||||
for(int i = 0; i < countof(m_counters); i++)
|
||||
{
|
||||
m_stats[i] = m_counters[i] / m_count;
|
||||
}
|
||||
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
memset(m_counters, 0, sizeof(m_counters));
|
||||
}
|
||||
|
||||
void GSPerfMon::Start()
|
||||
{
|
||||
m_start = __rdtsc();
|
||||
|
||||
if(m_begin == 0)
|
||||
{
|
||||
m_begin = m_start;
|
||||
}
|
||||
}
|
||||
|
||||
void GSPerfMon::Stop()
|
||||
{
|
||||
if(m_start > 0)
|
||||
{
|
||||
m_total += __rdtsc() - m_start;
|
||||
m_start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int GSPerfMon::CPU()
|
||||
{
|
||||
int percent = (int)(100 * m_total / (__rdtsc() - m_begin));
|
||||
|
||||
m_begin = 0;
|
||||
m_start = 0;
|
||||
m_total = 0;
|
||||
|
||||
return percent;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class GSPerfMon
|
||||
{
|
||||
public:
|
||||
enum counter_t {Frame, Prim, Draw, Swizzle, Unswizzle, Fillrate, Quad, CounterLast};
|
||||
enum warning_t {DATE, PABE, ABE, COLCLAMP, DepthTexture, WarningLast};
|
||||
|
||||
protected:
|
||||
double m_counters[CounterLast];
|
||||
double m_stats[CounterLast];
|
||||
bool m_warnings[WarningLast];
|
||||
UINT64 m_begin, m_total, m_start, m_frame;
|
||||
clock_t m_lastframe;
|
||||
int m_count;
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
friend class GSPerfMonAutoTimer;
|
||||
|
||||
public:
|
||||
GSPerfMon();
|
||||
|
||||
void SetFrame(UINT64 frame) {m_frame = frame;}
|
||||
UINT64 GetFrame() {return m_frame;}
|
||||
void Put(counter_t c, double val = 0);
|
||||
double Get(counter_t c) {return m_stats[c];}
|
||||
void Put(warning_t c) {m_warnings[c] = true;}
|
||||
bool Get(warning_t c) {bool b = m_warnings[c]; m_warnings[c] = false; return b;}
|
||||
void Update();
|
||||
int CPU();
|
||||
};
|
||||
|
||||
class GSPerfMonAutoTimer
|
||||
{
|
||||
GSPerfMon* m_pm;
|
||||
|
||||
public:
|
||||
GSPerfMonAutoTimer(GSPerfMon& pm) {(m_pm = &pm)->Start();}
|
||||
~GSPerfMonAutoTimer() {m_pm->Stop();}
|
||||
};
|
|
@ -0,0 +1,726 @@
|
|||
/*
|
||||
* 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 "GSRasterizer.h"
|
||||
|
||||
GSRasterizer::GSRasterizer(IDrawScanline* ds, int id, int threads)
|
||||
: m_ds(ds)
|
||||
, m_id(id)
|
||||
, m_threads(threads)
|
||||
{
|
||||
}
|
||||
|
||||
GSRasterizer::~GSRasterizer()
|
||||
{
|
||||
delete m_ds;
|
||||
}
|
||||
|
||||
void GSRasterizer::Draw(const GSRasterizerData* data)
|
||||
{
|
||||
m_dsf.sl = NULL;
|
||||
m_dsf.sr = NULL;
|
||||
m_dsf.sp = NULL;
|
||||
|
||||
m_ds->BeginDraw(data, &m_dsf);
|
||||
|
||||
const GSVector4i scissor = data->scissor;
|
||||
const GSVertexSW* vertices = data->vertices;
|
||||
const int count = data->count;
|
||||
|
||||
m_stats.Reset();
|
||||
|
||||
__int64 start = __rdtsc();
|
||||
|
||||
switch(data->primclass)
|
||||
{
|
||||
case GS_POINT_CLASS:
|
||||
m_stats.prims = count;
|
||||
for(int i = 0; i < count; i++) DrawPoint(&vertices[i], scissor);
|
||||
break;
|
||||
case GS_LINE_CLASS:
|
||||
ASSERT(!(count & 1));
|
||||
m_stats.prims = count / 2;
|
||||
for(int i = 0; i < count; i += 2) DrawLine(&vertices[i], scissor);
|
||||
break;
|
||||
case GS_TRIANGLE_CLASS:
|
||||
ASSERT(!(count % 3));
|
||||
m_stats.prims = count / 3;
|
||||
for(int i = 0; i < count; i += 3) DrawTriangle(&vertices[i], scissor);
|
||||
break;
|
||||
case GS_SPRITE_CLASS:
|
||||
ASSERT(!(count & 1));
|
||||
m_stats.prims = count / 2;
|
||||
for(int i = 0; i < count; i += 2) DrawSprite(&vertices[i], scissor);
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
m_stats.ticks = __rdtsc() - start;
|
||||
|
||||
m_ds->EndDraw(m_stats);
|
||||
}
|
||||
|
||||
void GSRasterizer::GetStats(GSRasterizerStats& stats)
|
||||
{
|
||||
stats = m_stats;
|
||||
}
|
||||
|
||||
void GSRasterizer::DrawPoint(const GSVertexSW* v, const GSVector4i& scissor)
|
||||
{
|
||||
// TODO: round to closest for point, prestep for line
|
||||
|
||||
GSVector4i p(v->p);
|
||||
|
||||
if(scissor.x <= p.x && p.x < scissor.z && scissor.y <= p.y && p.y < scissor.w)
|
||||
{
|
||||
if((p.y % m_threads) == m_id)
|
||||
{
|
||||
(m_ds->*m_dsf.sp)(v, *v);
|
||||
|
||||
(m_ds->*m_dsf.sl)(p.y, p.x, p.x + 1, *v);
|
||||
|
||||
m_stats.pixels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSRasterizer::DrawLine(const GSVertexSW* v, const GSVector4i& scissor)
|
||||
{
|
||||
GSVertexSW dv = v[1] - v[0];
|
||||
|
||||
GSVector4 dp = dv.p.abs();
|
||||
GSVector4i dpi(dp);
|
||||
|
||||
if(dpi.y == 0)
|
||||
{
|
||||
if(dpi.x > 0)
|
||||
{
|
||||
// shortcut for horizontal lines
|
||||
|
||||
GSVector4 mask = (v[0].p > v[1].p).xxxx();
|
||||
|
||||
GSVertexSW l, dl;
|
||||
|
||||
l.p = v[0].p.blend8(v[1].p, mask);
|
||||
l.t = v[0].t.blend8(v[1].t, mask);
|
||||
l.c = v[0].c.blend8(v[1].c, mask);
|
||||
|
||||
GSVector4 r;
|
||||
|
||||
r = v[1].p.blend8(v[0].p, mask);
|
||||
|
||||
GSVector4i p(l.p);
|
||||
|
||||
if(scissor.y <= p.y && p.y < scissor.w)
|
||||
{
|
||||
GSVertexSW dscan = dv / dv.p.xxxx();
|
||||
|
||||
(m_ds->*m_dsf.sp)(v, dscan);
|
||||
|
||||
l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y
|
||||
|
||||
DrawTriangleSection(p.y, p.y + 1, l, dl, dscan, scissor);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int i = dpi.x > dpi.y ? 0 : 1;
|
||||
|
||||
GSVertexSW edge = v[0];
|
||||
GSVertexSW dedge = dv / dp.v[i];
|
||||
|
||||
// TODO: prestep + clip with the scissor
|
||||
|
||||
int steps = dpi.v[i];
|
||||
|
||||
while(steps-- > 0)
|
||||
{
|
||||
DrawPoint(&edge, scissor);
|
||||
|
||||
edge += dedge;
|
||||
}
|
||||
}
|
||||
|
||||
static const int s_abc[8][4] =
|
||||
{
|
||||
{0, 1, 2, 0},
|
||||
{1, 0, 2, 0},
|
||||
{0, 0, 0, 0},
|
||||
{1, 2, 0, 0},
|
||||
{0, 2, 1, 0},
|
||||
{0, 0, 0, 0},
|
||||
{2, 0, 1, 0},
|
||||
{2, 1, 0, 0},
|
||||
};
|
||||
|
||||
void GSRasterizer::DrawTriangle(const GSVertexSW* vertices, const GSVector4i& scissor)
|
||||
{
|
||||
GSVertexSW v[3];
|
||||
|
||||
GSVector4 aabb = vertices[0].p.yyyy(vertices[1].p);
|
||||
GSVector4 bccb = vertices[1].p.yyyy(vertices[2].p).xzzx();
|
||||
|
||||
int i = (aabb > bccb).mask() & 7;
|
||||
|
||||
v[0] = vertices[s_abc[i][0]];
|
||||
v[1] = vertices[s_abc[i][1]];
|
||||
v[2] = vertices[s_abc[i][2]];
|
||||
|
||||
aabb = v[0].p.yyyy(v[1].p);
|
||||
bccb = v[1].p.yyyy(v[2].p).xzzx();
|
||||
|
||||
i = (aabb == bccb).mask() & 7;
|
||||
|
||||
switch(i)
|
||||
{
|
||||
case 0: // a < b < c
|
||||
DrawTriangleTopBottom(v, scissor);
|
||||
break;
|
||||
case 1: // a == b < c
|
||||
DrawTriangleBottom(v, scissor);
|
||||
break;
|
||||
case 4: // a < b == c
|
||||
DrawTriangleTop(v, scissor);
|
||||
break;
|
||||
case 7: // a == b == c
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GSRasterizer::DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor)
|
||||
{
|
||||
GSVertexSW longest;
|
||||
|
||||
longest.p = v[2].p - v[1].p;
|
||||
|
||||
int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask();
|
||||
|
||||
if(i & 2) return;
|
||||
|
||||
i &= 1;
|
||||
|
||||
GSVertexSW& l = v[0];
|
||||
GSVector4& r = v[0].p;
|
||||
|
||||
GSVector4i tb(l.p.xyxy(v[2].p).ceil());
|
||||
|
||||
int top = tb.extract32<1>();
|
||||
int bottom = tb.extract32<3>();
|
||||
|
||||
if(top < scissor.y) top = scissor.y;
|
||||
if(bottom > scissor.w) bottom = scissor.w;
|
||||
if(top >= bottom) return;
|
||||
|
||||
longest.t = v[2].t - v[1].t;
|
||||
longest.c = v[2].c - v[1].c;
|
||||
|
||||
GSVertexSW dscan = longest * longest.p.xxxx().rcp();
|
||||
|
||||
GSVertexSW vl = v[2 - i] - l;
|
||||
GSVector4 vr = v[1 + i].p - r;
|
||||
|
||||
GSVertexSW dl = vl / vl.p.yyyy();
|
||||
GSVector4 dr = vr / vr.yyyy();
|
||||
|
||||
float py = (float)top - l.p.y;
|
||||
|
||||
l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y
|
||||
dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y
|
||||
|
||||
if(py > 0) l += dl * py;
|
||||
|
||||
(m_ds->*m_dsf.sp)(v, dscan);
|
||||
|
||||
DrawTriangleSection(top, bottom, l, dl, dscan, scissor);
|
||||
}
|
||||
|
||||
void GSRasterizer::DrawTriangleBottom(GSVertexSW* v, const GSVector4i& scissor)
|
||||
{
|
||||
GSVertexSW longest;
|
||||
|
||||
longest.p = v[1].p - v[0].p;
|
||||
|
||||
int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask();
|
||||
|
||||
if(i & 2) return;
|
||||
|
||||
i &= 1;
|
||||
|
||||
GSVertexSW& l = v[1 - i];
|
||||
GSVector4& r = v[i].p;
|
||||
|
||||
GSVector4i tb(l.p.xyxy(v[2].p).ceil());
|
||||
|
||||
int top = tb.extract32<1>();
|
||||
int bottom = tb.extract32<3>();
|
||||
|
||||
if(top < scissor.y) top = scissor.y;
|
||||
if(bottom > scissor.w) bottom = scissor.w;
|
||||
if(top >= bottom) return;
|
||||
|
||||
longest.t = v[1].t - v[0].t;
|
||||
longest.c = v[1].c - v[0].c;
|
||||
|
||||
GSVertexSW dscan = longest * longest.p.xxxx().rcp();
|
||||
|
||||
GSVertexSW vl = v[2] - l;
|
||||
GSVector4 vr = v[2].p - r;
|
||||
|
||||
GSVertexSW dl = vl / vl.p.yyyy();
|
||||
GSVector4 dr = vr / vr.yyyy();
|
||||
|
||||
float py = (float)top - l.p.y;
|
||||
|
||||
l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y
|
||||
dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y
|
||||
|
||||
if(py > 0) l += dl * py;
|
||||
|
||||
(m_ds->*m_dsf.sp)(v, dscan);
|
||||
|
||||
DrawTriangleSection(top, bottom, l, dl, dscan, scissor);
|
||||
}
|
||||
|
||||
void GSRasterizer::DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scissor)
|
||||
{
|
||||
GSVertexSW dv[3];
|
||||
|
||||
dv[0] = v[1] - v[0];
|
||||
dv[1] = v[2] - v[0];
|
||||
|
||||
GSVertexSW longest = v[0] + dv[1] * (dv[0].p / dv[1].p).yyyy() - v[1];
|
||||
|
||||
int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask();
|
||||
|
||||
if(i & 2) return;
|
||||
|
||||
i &= 1;
|
||||
|
||||
GSVertexSW dscan = longest * longest.p.xxxx().rcp();
|
||||
|
||||
(m_ds->*m_dsf.sp)(v, dscan);
|
||||
|
||||
GSVertexSW& l = v[0];
|
||||
GSVector4 r = v[0].p;
|
||||
|
||||
GSVertexSW dl;
|
||||
GSVector4 dr;
|
||||
|
||||
dl = dv[1 - i] / dv[1 - i].p.yyyy();
|
||||
dr = dv[i].p / dv[i].p.yyyy();
|
||||
|
||||
GSVector4i tb(v[0].p.yyyy(v[1].p).xzyy(v[2].p).ceil());
|
||||
|
||||
int top = tb.x;
|
||||
int bottom = tb.y;
|
||||
|
||||
if(top < scissor.y) top = scissor.y;
|
||||
if(bottom > scissor.w) bottom = scissor.w;
|
||||
|
||||
float py = (float)top - l.p.y;
|
||||
|
||||
if(py > 0)
|
||||
{
|
||||
GSVector4 dy(py);
|
||||
|
||||
l += dl * dy;
|
||||
r += dr * dy;
|
||||
}
|
||||
|
||||
if(top < bottom)
|
||||
{
|
||||
DrawTriangleSection(top, bottom, l, dl, r, dr, dscan, scissor);
|
||||
}
|
||||
|
||||
if(i)
|
||||
{
|
||||
l = v[1];
|
||||
|
||||
dv[2] = v[2] - v[1];
|
||||
|
||||
dl = dv[2] / dv[2].p.yyyy();
|
||||
}
|
||||
else
|
||||
{
|
||||
r = v[1].p;
|
||||
|
||||
dv[2].p = v[2].p - v[1].p;
|
||||
|
||||
dr = dv[2].p / dv[2].p.yyyy();
|
||||
}
|
||||
|
||||
top = tb.y;
|
||||
bottom = tb.z;
|
||||
|
||||
if(top < scissor.y) top = scissor.y;
|
||||
if(bottom > scissor.w) bottom = scissor.w;
|
||||
|
||||
if(top < bottom)
|
||||
{
|
||||
py = (float)top - l.p.y;
|
||||
|
||||
if(py > 0) l += dl * py;
|
||||
|
||||
py = (float)top - r.y;
|
||||
|
||||
if(py > 0) r += dr * py;
|
||||
|
||||
l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y
|
||||
dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y
|
||||
|
||||
DrawTriangleSection(top, bottom, l, dl, dscan, scissor);
|
||||
}
|
||||
}
|
||||
|
||||
void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, GSVector4& r, const GSVector4& dr, const GSVertexSW& dscan, const GSVector4i& scissor)
|
||||
{
|
||||
ASSERT(top < bottom);
|
||||
|
||||
while(1)
|
||||
{
|
||||
do
|
||||
{
|
||||
if((top % m_threads) == m_id)
|
||||
{
|
||||
GSVector4i lr(l.p.xyxy(r).ceil());
|
||||
|
||||
int left = lr.extract32<0>();
|
||||
int right = lr.extract32<2>();
|
||||
|
||||
if(left < scissor.x) left = scissor.x;
|
||||
if(right > scissor.z) right = scissor.z;
|
||||
|
||||
int pixels = right - left;
|
||||
|
||||
if(pixels > 0)
|
||||
{
|
||||
m_stats.pixels += pixels;
|
||||
|
||||
GSVertexSW scan;
|
||||
|
||||
float px = (float)left - l.p.x;
|
||||
|
||||
if(px > 0)
|
||||
{
|
||||
scan = l + dscan * px;
|
||||
}
|
||||
else
|
||||
{
|
||||
scan = l;
|
||||
}
|
||||
|
||||
(m_ds->*m_dsf.sl)(top, left, right, scan);
|
||||
}
|
||||
}
|
||||
}
|
||||
while(0);
|
||||
|
||||
if(++top >= bottom) break;
|
||||
|
||||
l += dl;
|
||||
r += dr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, const GSVertexSW& dscan, const GSVector4i& scissor)
|
||||
{
|
||||
ASSERT(top < bottom);
|
||||
|
||||
while(1)
|
||||
{
|
||||
do
|
||||
{
|
||||
if((top % m_threads) == m_id)
|
||||
{
|
||||
GSVector4i lr(l.p.ceil());
|
||||
|
||||
int left = lr.extract32<0>();
|
||||
int right = lr.extract32<1>();
|
||||
|
||||
if(left < scissor.x) left = scissor.x;
|
||||
if(right > scissor.z) right = scissor.z;
|
||||
|
||||
int pixels = right - left;
|
||||
|
||||
if(pixels > 0)
|
||||
{
|
||||
m_stats.pixels += pixels;
|
||||
|
||||
GSVertexSW scan;
|
||||
|
||||
float px = (float)left - l.p.x;
|
||||
|
||||
if(px > 0)
|
||||
{
|
||||
scan = l + dscan * px;
|
||||
}
|
||||
else
|
||||
{
|
||||
scan = l;
|
||||
}
|
||||
|
||||
(m_ds->*m_dsf.sl)(top, left, right, scan);
|
||||
}
|
||||
}
|
||||
}
|
||||
while(0);
|
||||
|
||||
if(++top >= bottom) break;
|
||||
|
||||
l += dl;
|
||||
}
|
||||
}
|
||||
|
||||
void GSRasterizer::DrawSprite(const GSVertexSW* vertices, const GSVector4i& scissor)
|
||||
{
|
||||
GSVertexSW v[2];
|
||||
|
||||
GSVector4 mask = (vertices[0].p < vertices[1].p).xyzw(GSVector4::zero());
|
||||
|
||||
v[0].p = vertices[1].p.blend8(vertices[0].p, mask);
|
||||
v[0].t = vertices[1].t.blend8(vertices[0].t, mask);
|
||||
v[0].c = vertices[1].c;
|
||||
|
||||
v[1].p = vertices[0].p.blend8(vertices[1].p, mask);
|
||||
v[1].t = vertices[0].t.blend8(vertices[1].t, mask);
|
||||
|
||||
GSVector4i r(v[0].p.xyxy(v[1].p).ceil());
|
||||
|
||||
int& top = r.y;
|
||||
int& bottom = r.w;
|
||||
|
||||
int& left = r.x;
|
||||
int& right = r.z;
|
||||
|
||||
#if _M_SSE >= 0x401
|
||||
|
||||
r = r.sat_i32(scissor);
|
||||
|
||||
if((r < r.zwzw()).mask() != 0x00ff) return;
|
||||
|
||||
#else
|
||||
|
||||
if(top < scissor.y) top = scissor.y;
|
||||
if(bottom > scissor.w) bottom = scissor.w;
|
||||
if(top >= bottom) return;
|
||||
|
||||
if(left < scissor.x) left = scissor.x;
|
||||
if(right > scissor.z) right = scissor.z;
|
||||
if(left >= right) return;
|
||||
|
||||
#endif
|
||||
|
||||
GSVertexSW scan = v[0];
|
||||
|
||||
if(m_dsf.sr)
|
||||
{
|
||||
if(m_id == 0)
|
||||
{
|
||||
(m_ds->*m_dsf.sr)(r, scan);
|
||||
|
||||
m_stats.pixels += (r.z - r.x) * (r.w - r.y);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
GSVector4 zero = GSVector4::zero();
|
||||
|
||||
GSVertexSW dedge, dscan;
|
||||
|
||||
dedge.p = zero;
|
||||
dscan.p = zero;
|
||||
|
||||
dedge.c = zero;
|
||||
dscan.c = zero;
|
||||
|
||||
GSVertexSW dv = v[1] - v[0];
|
||||
|
||||
dedge.t = (dv.t / dv.p.yyyy()).xyxy(zero).wyww();
|
||||
dscan.t = (dv.t / dv.p.xxxx()).xyxy(zero).xwww();
|
||||
|
||||
if(scan.p.y < (float)top) scan.t += dedge.t * ((float)top - scan.p.y);
|
||||
if(scan.p.x < (float)left) scan.t += dscan.t * ((float)left - scan.p.x);
|
||||
|
||||
(m_ds->*m_dsf.sp)(v, dscan);
|
||||
|
||||
for(; top < bottom; top++, scan.t += dedge.t)
|
||||
{
|
||||
if((top % m_threads) == m_id)
|
||||
{
|
||||
(m_ds->*m_dsf.sl)(top, left, right, scan);
|
||||
|
||||
m_stats.pixels += right - left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
GSRasterizerMT::GSRasterizerMT(IDrawScanline* ds, int id, int threads, long* sync)
|
||||
: GSRasterizer(ds, id, threads)
|
||||
, m_sync(sync)
|
||||
, m_exit(false)
|
||||
, m_ThreadId(0)
|
||||
, m_hThread(NULL)
|
||||
, m_data(NULL)
|
||||
{
|
||||
if(id > 0)
|
||||
{
|
||||
m_hThread = CreateThread(NULL, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId);
|
||||
}
|
||||
}
|
||||
|
||||
GSRasterizerMT::~GSRasterizerMT()
|
||||
{
|
||||
if(m_hThread != NULL)
|
||||
{
|
||||
m_exit = true;
|
||||
|
||||
if(WaitForSingleObject(m_hThread, 5000) != WAIT_OBJECT_0)
|
||||
{
|
||||
TerminateThread(m_hThread, 1);
|
||||
}
|
||||
|
||||
CloseHandle(m_hThread);
|
||||
}
|
||||
}
|
||||
|
||||
void GSRasterizerMT::Draw(const GSRasterizerData* data)
|
||||
{
|
||||
if(m_id == 0)
|
||||
{
|
||||
__super::Draw(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_data = data;
|
||||
|
||||
InterlockedBitTestAndSet(m_sync, m_id);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI GSRasterizerMT::StaticThreadProc(LPVOID lpParam)
|
||||
{
|
||||
return ((GSRasterizerMT*)lpParam)->ThreadProc();
|
||||
}
|
||||
|
||||
DWORD GSRasterizerMT::ThreadProc()
|
||||
{
|
||||
// _mm_setcsr(MXCSR);
|
||||
|
||||
while(!m_exit)
|
||||
{
|
||||
if(*m_sync & (1 << m_id))
|
||||
{
|
||||
__super::Draw(m_data);
|
||||
|
||||
InterlockedBitTestAndReset(m_sync, m_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
GSRasterizerList::GSRasterizerList()
|
||||
{
|
||||
// get a whole cache line (twice the size for future cpus ;)
|
||||
|
||||
m_sync = (long*)_aligned_malloc(sizeof(*m_sync), 128);
|
||||
|
||||
*m_sync = 0;
|
||||
}
|
||||
|
||||
GSRasterizerList::~GSRasterizerList()
|
||||
{
|
||||
_aligned_free(m_sync);
|
||||
|
||||
FreeRasterizers();
|
||||
}
|
||||
|
||||
void GSRasterizerList::FreeRasterizers()
|
||||
{
|
||||
while(!IsEmpty())
|
||||
{
|
||||
delete RemoveHead();
|
||||
}
|
||||
}
|
||||
|
||||
void GSRasterizerList::Draw(const GSRasterizerData* data)
|
||||
{
|
||||
*m_sync = 0;
|
||||
|
||||
m_stats.Reset();
|
||||
|
||||
__int64 start = __rdtsc();
|
||||
|
||||
POSITION pos = GetTailPosition();
|
||||
|
||||
while(pos)
|
||||
{
|
||||
GetPrev(pos)->Draw(data);
|
||||
}
|
||||
|
||||
while(*m_sync)
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
|
||||
m_stats.ticks = __rdtsc() - start;
|
||||
|
||||
pos = GetHeadPosition();
|
||||
|
||||
while(pos)
|
||||
{
|
||||
GSRasterizerStats s;
|
||||
|
||||
GetNext(pos)->GetStats(s);
|
||||
|
||||
m_stats.pixels += s.pixels;
|
||||
m_stats.prims = max(m_stats.prims, s.prims);
|
||||
}
|
||||
}
|
||||
|
||||
void GSRasterizerList::GetStats(GSRasterizerStats& stats)
|
||||
{
|
||||
stats = m_stats;
|
||||
}
|
||||
|
||||
void GSRasterizerList::PrintStats()
|
||||
{
|
||||
if(!IsEmpty())
|
||||
{
|
||||
GetHead()->PrintStats();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS.h"
|
||||
#include "GSVertexSW.h"
|
||||
#include "GSFunctionMap.h"
|
||||
|
||||
//
|
||||
#define FAST_DRAWSCANLINE
|
||||
|
||||
__declspec(align(16)) class GSRasterizerData
|
||||
{
|
||||
public:
|
||||
GSVector4i scissor;
|
||||
GS_PRIM_CLASS primclass;
|
||||
const GSVertexSW* vertices;
|
||||
int count;
|
||||
const void* param;
|
||||
};
|
||||
|
||||
class IRasterizer
|
||||
{
|
||||
public:
|
||||
virtual ~IRasterizer() {}
|
||||
|
||||
virtual void Draw(const GSRasterizerData* data) = 0;
|
||||
virtual void GetStats(GSRasterizerStats& stats) = 0;
|
||||
virtual void PrintStats() = 0;
|
||||
};
|
||||
|
||||
class IDrawScanline
|
||||
{
|
||||
public:
|
||||
typedef void (IDrawScanline::*DrawScanlinePtr)(int top, int left, int right, const GSVertexSW& v);
|
||||
typedef void (IDrawScanline::*DrawSolidRectPtr)(const GSVector4i& r, const GSVertexSW& v);
|
||||
typedef void (IDrawScanline::*SetupPrimPtr)(const GSVertexSW* vertices, const GSVertexSW& dscan);
|
||||
|
||||
struct Functions
|
||||
{
|
||||
DrawScanlinePtr sl;
|
||||
DrawSolidRectPtr sr;
|
||||
SetupPrimPtr sp;
|
||||
};
|
||||
|
||||
virtual ~IDrawScanline() {}
|
||||
|
||||
virtual void BeginDraw(const GSRasterizerData* data, Functions* dsf) = 0;
|
||||
virtual void EndDraw(const GSRasterizerStats& stats) = 0;
|
||||
virtual void PrintStats() = 0;
|
||||
};
|
||||
|
||||
class GSRasterizer : public IRasterizer
|
||||
{
|
||||
protected:
|
||||
IDrawScanline* m_ds;
|
||||
IDrawScanline::Functions m_dsf;
|
||||
int m_id;
|
||||
int m_threads;
|
||||
GSRasterizerStats m_stats;
|
||||
|
||||
void DrawPoint(const GSVertexSW* v, const GSVector4i& scissor);
|
||||
void DrawLine(const GSVertexSW* v, const GSVector4i& scissor);
|
||||
void DrawTriangle(const GSVertexSW* v, const GSVector4i& scissor);
|
||||
void DrawSprite(const GSVertexSW* v, const GSVector4i& scissor);
|
||||
|
||||
void DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor);
|
||||
void DrawTriangleBottom(GSVertexSW* v, const GSVector4i& scissor);
|
||||
void DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scissor);
|
||||
|
||||
__forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, GSVector4& r, const GSVector4& dr, const GSVertexSW& dscan, const GSVector4i& scissor);
|
||||
__forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, const GSVertexSW& dscan, const GSVector4i& scissor);
|
||||
|
||||
public:
|
||||
GSRasterizer(IDrawScanline* ds, int id = 0, int threads = 0);
|
||||
virtual ~GSRasterizer();
|
||||
|
||||
// IRasterizer
|
||||
|
||||
void Draw(const GSRasterizerData* data);
|
||||
void GetStats(GSRasterizerStats& stats);
|
||||
void PrintStats() {m_ds->PrintStats();}
|
||||
};
|
||||
|
||||
class GSRasterizerMT : public GSRasterizer
|
||||
{
|
||||
long* m_sync;
|
||||
bool m_exit;
|
||||
DWORD m_ThreadId;
|
||||
HANDLE m_hThread;
|
||||
const GSRasterizerData* m_data;
|
||||
|
||||
static DWORD WINAPI StaticThreadProc(LPVOID lpParam);
|
||||
|
||||
DWORD ThreadProc();
|
||||
|
||||
public:
|
||||
GSRasterizerMT(IDrawScanline* ds, int id, int threads, long* sync);
|
||||
virtual ~GSRasterizerMT();
|
||||
|
||||
// IRasterizer
|
||||
|
||||
void Draw(const GSRasterizerData* data);
|
||||
};
|
||||
|
||||
class GSRasterizerList : protected CAtlList<IRasterizer*>, public IRasterizer
|
||||
{
|
||||
long* m_sync;
|
||||
GSRasterizerStats m_stats;
|
||||
|
||||
void FreeRasterizers();
|
||||
|
||||
public:
|
||||
GSRasterizerList();
|
||||
virtual ~GSRasterizerList();
|
||||
|
||||
template<class DS, class T> void Create(T* parent, int threads)
|
||||
{
|
||||
FreeRasterizers();
|
||||
|
||||
threads = max(threads, 1); // TODO: min(threads, number of cpu cores)
|
||||
|
||||
for(int i = 0; i < threads; i++)
|
||||
{
|
||||
AddTail(new GSRasterizerMT(new DS(parent, i), i, threads, m_sync));
|
||||
}
|
||||
}
|
||||
|
||||
// IRasterizer
|
||||
|
||||
void Draw(const GSRasterizerData* data);
|
||||
void GetStats(GSRasterizerStats& stats);
|
||||
void PrintStats();
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 "GSRenderer.h"
|
|
@ -0,0 +1,594 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSWnd.h"
|
||||
#include "GSState.h"
|
||||
#include "GSVertexList.h"
|
||||
#include "GSSettingsDlg.h"
|
||||
#include "GSCapture.h"
|
||||
|
||||
struct GSRendererSettings
|
||||
{
|
||||
int m_interlace;
|
||||
int m_aspectratio;
|
||||
int m_filter;
|
||||
bool m_vsync;
|
||||
bool m_nativeres;
|
||||
};
|
||||
|
||||
class GSRendererBase : public GSState, protected GSRendererSettings
|
||||
{
|
||||
protected:
|
||||
bool m_osd;
|
||||
int m_field;
|
||||
|
||||
void ProcessWindowMessages()
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
while(msg.message != WM_QUIT && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if(OnMessage(msg))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool OnMessage(const MSG& msg)
|
||||
{
|
||||
if(msg.message == WM_KEYDOWN)
|
||||
{
|
||||
int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1;
|
||||
|
||||
if(msg.wParam == VK_F5)
|
||||
{
|
||||
m_interlace = (m_interlace + 7 + step) % 7;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(msg.wParam == VK_F6)
|
||||
{
|
||||
m_aspectratio = (m_aspectratio + 3 + step) % 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(msg.wParam == VK_F7)
|
||||
{
|
||||
m_wnd.SetWindowText(_T("PCSX2"));
|
||||
m_osd = !m_osd;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
GSWnd m_wnd;
|
||||
|
||||
public:
|
||||
GSRendererBase(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
|
||||
: GSState(base, mt, irq, nloophack)
|
||||
, m_osd(true)
|
||||
, m_field(0)
|
||||
{
|
||||
m_interlace = rs.m_interlace;
|
||||
m_aspectratio = rs.m_aspectratio;
|
||||
m_filter = rs.m_filter;
|
||||
m_vsync = rs.m_vsync;
|
||||
m_nativeres = rs.m_nativeres;
|
||||
};
|
||||
|
||||
virtual bool Create(LPCTSTR title) = 0;
|
||||
virtual void VSync(int field) = 0;
|
||||
virtual bool MakeSnapshot(LPCTSTR path) = 0;
|
||||
};
|
||||
|
||||
template<class Device> class GSRenderer : public GSRendererBase
|
||||
{
|
||||
protected:
|
||||
typedef typename Device::Texture Texture;
|
||||
|
||||
virtual void ResetDevice() {}
|
||||
virtual bool GetOutput(int i, Texture& t) = 0;
|
||||
|
||||
bool Merge()
|
||||
{
|
||||
int baseline = INT_MAX;
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
if(IsEnabled(i))
|
||||
{
|
||||
baseline = min(GetDisplayPos(i).y, baseline);
|
||||
}
|
||||
}
|
||||
|
||||
CSize fs(0, 0);
|
||||
CSize ds(0, 0);
|
||||
|
||||
Texture st[2];
|
||||
GSVector4 sr[2];
|
||||
GSVector4 dr[2];
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
if(IsEnabled(i) && GetOutput(i, st[i]))
|
||||
{
|
||||
CRect r = GetFrameRect(i);
|
||||
|
||||
// overscan hack
|
||||
|
||||
if(GetDisplaySize(i).cy > 512) // hmm
|
||||
{
|
||||
int y = GetDeviceSize(i).cy;
|
||||
if(SMODE2->INT && SMODE2->FFMD) y /= 2;
|
||||
r.bottom = r.top + y;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
sr[i].x = st[i].m_scale.x * r.left / st[i].GetWidth();
|
||||
sr[i].y = st[i].m_scale.y * r.top / st[i].GetHeight();
|
||||
sr[i].z = st[i].m_scale.x * r.right / st[i].GetWidth();
|
||||
sr[i].w = st[i].m_scale.y * r.bottom / st[i].GetHeight();
|
||||
|
||||
GSVector2 o;
|
||||
|
||||
o.x = 0;
|
||||
o.y = 0;
|
||||
|
||||
CPoint p = GetDisplayPos(i);
|
||||
|
||||
if(p.y - baseline >= 4) // 2?
|
||||
{
|
||||
o.y = st[i].m_scale.y * (p.y - baseline);
|
||||
}
|
||||
|
||||
if(SMODE2->INT && SMODE2->FFMD) o.y /= 2;
|
||||
|
||||
dr[i].x = o.x;
|
||||
dr[i].y = o.y;
|
||||
dr[i].z = o.x + st[i].m_scale.x * r.Width();
|
||||
dr[i].w = o.y + st[i].m_scale.y * r.Height();
|
||||
|
||||
#ifdef _M_AMD64
|
||||
// schrödinger's bug, fs will be trashed unless we access these values
|
||||
CString str;
|
||||
str.Format(_T("%d %f %f %f %f "), i, o.x, o.y, dr[i].z, dr[i].w);
|
||||
//::MessageBox(NULL, str, _T(""), MB_OK);
|
||||
#endif
|
||||
fs.cx = max(fs.cx, (int)(dr[i].z + 0.5f));
|
||||
fs.cy = max(fs.cy, (int)(dr[i].w + 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
ds.cx = fs.cx;
|
||||
ds.cy = fs.cy;
|
||||
|
||||
if(SMODE2->INT && SMODE2->FFMD) ds.cy *= 2;
|
||||
|
||||
bool slbg = PMODE->SLBG;
|
||||
bool mmod = PMODE->MMOD;
|
||||
|
||||
if(st[0] || st[1])
|
||||
{
|
||||
GSVector4 c;
|
||||
|
||||
c.r = (float)BGCOLOR->R / 255;
|
||||
c.g = (float)BGCOLOR->G / 255;
|
||||
c.b = (float)BGCOLOR->B / 255;
|
||||
c.a = (float)PMODE->ALP / 255;
|
||||
|
||||
m_dev.Merge(st, sr, dr, fs, slbg, mmod, c);
|
||||
|
||||
if(SMODE2->INT && m_interlace > 0)
|
||||
{
|
||||
int field = 1 - ((m_interlace - 1) & 1);
|
||||
int mode = (m_interlace - 1) >> 1;
|
||||
|
||||
if(!m_dev.Interlace(ds, m_field ^ field, mode, st[1].m_scale.y)) // st[1].m_scale.y
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DoCapture()
|
||||
{
|
||||
if(!m_capture.IsCapturing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CSize size = m_capture.GetSize();
|
||||
|
||||
Texture current;
|
||||
|
||||
m_dev.GetCurrent(current);
|
||||
|
||||
Texture offscreen;
|
||||
|
||||
if(m_dev.CopyOffscreen(current, GSVector4(0, 0, 1, 1), offscreen, size.cx, size.cy))
|
||||
{
|
||||
BYTE* bits = NULL;
|
||||
int pitch = 0;
|
||||
|
||||
if(offscreen.Map(&bits, pitch))
|
||||
{
|
||||
m_capture.DeliverFrame(bits, pitch, m_dev.IsCurrentRGBA());
|
||||
|
||||
offscreen.Unmap();
|
||||
}
|
||||
|
||||
m_dev.Recycle(offscreen);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool OnMessage(const MSG& msg)
|
||||
{
|
||||
if(msg.message == WM_KEYDOWN)
|
||||
{
|
||||
if(msg.wParam == VK_F12)
|
||||
{
|
||||
if(m_capture.IsCapturing())
|
||||
{
|
||||
m_capture.EndCapture();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_capture.BeginCapture(GetFPS());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return __super::OnMessage(msg);
|
||||
}
|
||||
|
||||
public:
|
||||
Device m_dev;
|
||||
bool m_psrr;
|
||||
|
||||
int s_n;
|
||||
bool s_dump;
|
||||
bool s_save;
|
||||
bool s_savez;
|
||||
|
||||
GSCapture m_capture;
|
||||
|
||||
public:
|
||||
GSRenderer(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr)
|
||||
: GSRendererBase(base, mt, irq, nloophack, rs)
|
||||
, m_psrr(psrr)
|
||||
{
|
||||
s_n = 0;
|
||||
s_dump = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("dump"), 0);
|
||||
s_save = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("save"), 0);
|
||||
s_savez = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("savez"), 0);
|
||||
}
|
||||
|
||||
bool Create(LPCTSTR title)
|
||||
{
|
||||
if(!m_wnd.Create(title))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_dev.Create(m_wnd, m_vsync))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VSync(int field)
|
||||
{
|
||||
// printf("VSYNC\n");
|
||||
|
||||
GSPerfMonAutoTimer pmat(m_perfmon);
|
||||
|
||||
m_field = !!field;
|
||||
|
||||
Flush();
|
||||
|
||||
m_perfmon.Put(GSPerfMon::Frame);
|
||||
|
||||
ProcessWindowMessages();
|
||||
|
||||
if(m_dump)
|
||||
{
|
||||
m_dump.VSync(m_field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), PMODE);
|
||||
}
|
||||
|
||||
if(!Merge()) return;
|
||||
|
||||
// osd
|
||||
|
||||
static UINT64 s_frame = 0;
|
||||
static CString s_stats;
|
||||
|
||||
if(m_perfmon.GetFrame() - s_frame >= 30)
|
||||
{
|
||||
m_perfmon.Update();
|
||||
|
||||
s_frame = m_perfmon.GetFrame();
|
||||
|
||||
double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame);
|
||||
|
||||
s_stats.Format(
|
||||
_T("%I64d | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d/%d/%d | %d%% CPU | %.2f | %.2f"),
|
||||
m_perfmon.GetFrame(), GetDisplaySize().cx, GetDisplaySize().cy, fps, (int)(100.0 * fps / GetFPS()),
|
||||
SMODE2->INT ? (CString(_T("Interlaced ")) + (SMODE2->FFMD ? _T("(frame)") : _T("(field)"))) : _T("Progressive"),
|
||||
GSSettingsDlg::g_interlace[m_interlace].name,
|
||||
GSSettingsDlg::g_aspectratio[m_aspectratio].name,
|
||||
(int)m_perfmon.Get(GSPerfMon::Quad),
|
||||
(int)m_perfmon.Get(GSPerfMon::Prim),
|
||||
(int)m_perfmon.Get(GSPerfMon::Draw),
|
||||
m_perfmon.CPU(),
|
||||
m_perfmon.Get(GSPerfMon::Swizzle) / 1024,
|
||||
m_perfmon.Get(GSPerfMon::Unswizzle) / 1024
|
||||
);
|
||||
|
||||
double fillrate = m_perfmon.Get(GSPerfMon::Fillrate);
|
||||
|
||||
if(fillrate > 0)
|
||||
{
|
||||
s_stats.Format(_T("%s | %.2f mpps"), CString(s_stats), fps * fillrate / (1024 * 1024));
|
||||
}
|
||||
|
||||
if(m_capture.IsCapturing())
|
||||
{
|
||||
s_stats += _T(" | Recording...");
|
||||
}
|
||||
|
||||
if(m_perfmon.Get(GSPerfMon::COLCLAMP)) _tprintf(_T("*** NOT SUPPORTED: color wrap ***\n"));
|
||||
if(m_perfmon.Get(GSPerfMon::PABE)) _tprintf(_T("*** NOT SUPPORTED: per pixel alpha blend ***\n"));
|
||||
if(m_perfmon.Get(GSPerfMon::DATE)) _tprintf(_T("*** PERFORMANCE WARNING: destination alpha test used ***\n"));
|
||||
if(m_perfmon.Get(GSPerfMon::ABE)) _tprintf(_T("*** NOT SUPPORTED: alpha blending mode ***\n"));
|
||||
if(m_perfmon.Get(GSPerfMon::DepthTexture)) _tprintf(_T("*** NOT SUPPORTED: depth texture ***\n"));
|
||||
|
||||
m_wnd.SetWindowText(s_stats);
|
||||
}
|
||||
|
||||
if(m_osd)
|
||||
{
|
||||
m_dev.Draw(s_stats + _T("\n\nF5: interlace mode\nF6: aspect ratio\nF7: OSD"));
|
||||
}
|
||||
|
||||
if(m_frameskip)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
if(m_dev.IsLost())
|
||||
{
|
||||
ResetDevice();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
CRect r;
|
||||
|
||||
m_wnd.GetClientRect(&r);
|
||||
|
||||
GSUtil::FitRect(r, m_aspectratio);
|
||||
|
||||
m_dev.Present(r);
|
||||
|
||||
DoCapture();
|
||||
}
|
||||
|
||||
bool MakeSnapshot(LPCTSTR path)
|
||||
{
|
||||
CString fn;
|
||||
|
||||
fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S")));
|
||||
|
||||
if((::GetAsyncKeyState(VK_SHIFT) & 0x8000) && !m_dump)
|
||||
{
|
||||
GSFreezeData fd;
|
||||
fd.size = 0;
|
||||
fd.data = NULL;
|
||||
Freeze(&fd, true);
|
||||
fd.data = new BYTE[fd.size];
|
||||
Freeze(&fd, false);
|
||||
|
||||
m_dump.Open(fn + _T(".gs"), m_crc, fd, PMODE);
|
||||
|
||||
delete [] fd.data;
|
||||
}
|
||||
|
||||
return m_dev.SaveCurrent(fn + _T(".bmp"));
|
||||
}
|
||||
|
||||
virtual void MinMaxUV(int w, int h, CRect& r) {r = CRect(0, 0, w, h);}
|
||||
virtual bool CanUpscale() {return !m_nativeres;}
|
||||
};
|
||||
|
||||
template<class Device, class Vertex> class GSRendererT : public GSRenderer<Device>
|
||||
{
|
||||
protected:
|
||||
Vertex* m_vertices;
|
||||
int m_count;
|
||||
int m_maxcount;
|
||||
GSVertexList<Vertex> m_vl;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
m_count = 0;
|
||||
m_vl.RemoveAll();
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
void ResetPrim()
|
||||
{
|
||||
m_vl.RemoveAll();
|
||||
}
|
||||
|
||||
void FlushPrim()
|
||||
{
|
||||
if(m_count > 0)
|
||||
{
|
||||
/*
|
||||
TRACE(_T("[%d] Draw f %05x (%d) z %05x (%d %d %d %d) t %05x %05x (%d)\n"),
|
||||
(int)m_perfmon.GetFrame(),
|
||||
(int)m_context->FRAME.Block(),
|
||||
(int)m_context->FRAME.PSM,
|
||||
(int)m_context->ZBUF.Block(),
|
||||
(int)m_context->ZBUF.PSM,
|
||||
m_context->TEST.ZTE,
|
||||
m_context->TEST.ZTST,
|
||||
m_context->ZBUF.ZMSK,
|
||||
PRIM->TME ? (int)m_context->TEX0.TBP0 : 0xfffff,
|
||||
PRIM->TME && m_context->TEX0.PSM > PSM_PSMCT16S ? (int)m_context->TEX0.CBP : 0xfffff,
|
||||
PRIM->TME ? (int)m_context->TEX0.PSM : 0xff);
|
||||
*/
|
||||
|
||||
if(GSUtil::EncodePSM(m_context->FRAME.PSM) != 3 && GSUtil::EncodePSM(m_context->ZBUF.PSM) != 3)
|
||||
{
|
||||
// FIXME: berserk fpsm = 27 (8H)
|
||||
|
||||
Draw();
|
||||
}
|
||||
|
||||
m_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GrowVertexBuffer()
|
||||
{
|
||||
m_maxcount = max(10000, m_maxcount * 3/2);
|
||||
m_vertices = (Vertex*)_aligned_realloc(m_vertices, sizeof(Vertex) * m_maxcount, 16);
|
||||
m_maxcount -= 100;
|
||||
}
|
||||
|
||||
template<DWORD prim> __forceinline Vertex* DrawingKick(bool skip, DWORD& count)
|
||||
{
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST: count = 1; break;
|
||||
case GS_LINELIST: count = 2; break;
|
||||
case GS_LINESTRIP: count = 2; break;
|
||||
case GS_TRIANGLELIST: count = 3; break;
|
||||
case GS_TRIANGLESTRIP: count = 3; break;
|
||||
case GS_TRIANGLEFAN: count = 3; break;
|
||||
case GS_SPRITE: count = 2; break;
|
||||
case GS_INVALID: count = 1; break;
|
||||
default: __assume(0);
|
||||
}
|
||||
|
||||
if(m_vl.GetCount() < count)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(m_count >= m_maxcount)
|
||||
{
|
||||
GrowVertexBuffer();
|
||||
}
|
||||
|
||||
Vertex* v = &m_vertices[m_count];
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.RemoveAll();
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.GetAt(1, v[1]);
|
||||
m_vl.RemoveAll();
|
||||
break;
|
||||
case GS_LINESTRIP:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.GetAt(1, v[1]);
|
||||
m_vl.RemoveAt(0, 1);
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.GetAt(1, v[1]);
|
||||
m_vl.GetAt(2, v[2]);
|
||||
m_vl.RemoveAll();
|
||||
break;
|
||||
case GS_TRIANGLESTRIP:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.GetAt(1, v[1]);
|
||||
m_vl.GetAt(2, v[2]);
|
||||
m_vl.RemoveAt(0, 2);
|
||||
break;
|
||||
case GS_TRIANGLEFAN:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.GetAt(1, v[1]);
|
||||
m_vl.GetAt(2, v[2]);
|
||||
m_vl.RemoveAt(1, 1);
|
||||
break;
|
||||
case GS_SPRITE:
|
||||
m_vl.GetAt(0, v[0]);
|
||||
m_vl.GetAt(1, v[1]);
|
||||
m_vl.RemoveAll();
|
||||
break;
|
||||
case GS_INVALID:
|
||||
ASSERT(0);
|
||||
m_vl.RemoveAll();
|
||||
return NULL;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
return !skip ? v : NULL;
|
||||
}
|
||||
|
||||
virtual void Draw() = 0;
|
||||
|
||||
public:
|
||||
GSRendererT(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr = true)
|
||||
: GSRenderer<Device>(base, mt, irq, nloophack, rs, psrr)
|
||||
, m_count(0)
|
||||
, m_maxcount(0)
|
||||
, m_vertices(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~GSRendererT()
|
||||
{
|
||||
if(m_vertices) _aligned_free(m_vertices);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 "GSRendererHW.h"
|
|
@ -0,0 +1,633 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSRenderer.h"
|
||||
#include "GSTextureCache.h"
|
||||
#include "GSCrc.h"
|
||||
|
||||
template<class Device, class Vertex, class TextureCache>
|
||||
class GSRendererHW : public GSRendererT<Device, Vertex>
|
||||
{
|
||||
TextureCache* m_tc;
|
||||
int m_width;
|
||||
int m_height;
|
||||
int m_skip;
|
||||
bool m_reset;
|
||||
|
||||
protected:
|
||||
void Reset()
|
||||
{
|
||||
// TODO: GSreset can come from the main thread too => crash
|
||||
// m_tc->RemoveAll();
|
||||
|
||||
m_reset = true;
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
void MinMaxUV(int w, int h, CRect& r)
|
||||
{
|
||||
int wms = m_context->CLAMP.WMS;
|
||||
int wmt = m_context->CLAMP.WMT;
|
||||
|
||||
int minu = (int)m_context->CLAMP.MINU;
|
||||
int minv = (int)m_context->CLAMP.MINV;
|
||||
int maxu = (int)m_context->CLAMP.MAXU;
|
||||
int maxv = (int)m_context->CLAMP.MAXV;
|
||||
|
||||
GSVector4i vr = GSVector4i(0, 0, w, h);
|
||||
|
||||
GSVector4i wm[3];
|
||||
|
||||
if(wms + wmt < 6)
|
||||
{
|
||||
GSVector4 mm;
|
||||
|
||||
if(m_count < 100)
|
||||
{
|
||||
Vertex* v = m_vertices;
|
||||
|
||||
GSVector4 minv(+1e10f);
|
||||
GSVector4 maxv(-1e10f);
|
||||
|
||||
int i = 0;
|
||||
|
||||
if(PRIM->FST)
|
||||
{
|
||||
for(int j = m_count - 3; i < j; i += 4)
|
||||
{
|
||||
GSVector4 v0 = GSVector4(v[i + 0].m128[0]);
|
||||
GSVector4 v1 = GSVector4(v[i + 1].m128[0]);
|
||||
GSVector4 v2 = GSVector4(v[i + 2].m128[0]);
|
||||
GSVector4 v3 = GSVector4(v[i + 3].m128[0]);
|
||||
|
||||
minv = minv.minv((v0.minv(v1)).minv(v2.minv(v3)));
|
||||
maxv = maxv.maxv((v0.maxv(v1)).maxv(v2.maxv(v3)));
|
||||
}
|
||||
|
||||
for(int j = m_count; i < j; i++)
|
||||
{
|
||||
GSVector4 v0 = GSVector4(v[i + 0].m128[0]);
|
||||
|
||||
minv = minv.minv(v0);
|
||||
maxv = maxv.maxv(v0);
|
||||
}
|
||||
|
||||
mm = minv.xyxy(maxv) * GSVector4(16 << m_context->TEX0.TW, 16 << m_context->TEX0.TH, 16 << m_context->TEX0.TW, 16 << m_context->TEX0.TH).rcpnr();
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
for(int j = m_count - 3; i < j; i += 4)
|
||||
{
|
||||
GSVector4 v0 = GSVector4(v[i + 0].m128[0]) / GSVector4(v[i + 0].GetQ());
|
||||
GSVector4 v1 = GSVector4(v[i + 1].m128[0]) / GSVector4(v[i + 1].GetQ());
|
||||
GSVector4 v2 = GSVector4(v[i + 2].m128[0]) / GSVector4(v[i + 2].GetQ());
|
||||
GSVector4 v3 = GSVector4(v[i + 3].m128[0]) / GSVector4(v[i + 3].GetQ());
|
||||
|
||||
minv = minv.minv((v0.minv(v1)).minv(v2.minv(v3)));
|
||||
maxv = maxv.maxv((v0.maxv(v1)).maxv(v2.maxv(v3)));
|
||||
}
|
||||
|
||||
for(int j = m_count; i < j; i++)
|
||||
{
|
||||
GSVector4 v0 = GSVector4(v[i + 0].m128[0]) / GSVector4(v[i + 0].GetQ());;
|
||||
|
||||
minv = minv.minv(v0);
|
||||
maxv = maxv.maxv(v0);
|
||||
}
|
||||
|
||||
mm = minv.xyxy(maxv);
|
||||
*/
|
||||
|
||||
// just can't beat the compiler generated scalar sse code with packed div or rcp
|
||||
|
||||
mm.x = mm.y = +1e10;
|
||||
mm.z = mm.w = -1e10;
|
||||
|
||||
for(int j = m_count; i < j; i++)
|
||||
{
|
||||
float w = 1.0f / v[i].GetQ();
|
||||
|
||||
float x = v[i].t.x * w;
|
||||
|
||||
if(x < mm.x) mm.x = x;
|
||||
if(x > mm.z) mm.z = x;
|
||||
|
||||
float y = v[i].t.y * w;
|
||||
|
||||
if(y < mm.y) mm.y = y;
|
||||
if(y > mm.w) mm.w = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mm = GSVector4(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
GSVector4 v0 = GSVector4(vr);
|
||||
GSVector4 v1 = v0.zwzw();
|
||||
|
||||
GSVector4 mmf = mm.floor();
|
||||
GSVector4 mask = mmf.xyxy() == mmf.zwzw();
|
||||
|
||||
wm[0] = GSVector4i(v0.blend8((mm - mmf) * v1, mask));
|
||||
|
||||
mm *= v1;
|
||||
|
||||
wm[1] = GSVector4i(mm.sat(GSVector4::zero(), v1));
|
||||
wm[2] = GSVector4i(mm.sat(GSVector4(minu, minv, maxu, maxv)));
|
||||
}
|
||||
|
||||
GSVector4i v;
|
||||
|
||||
switch(wms)
|
||||
{
|
||||
case CLAMP_REPEAT:
|
||||
v = wm[0];
|
||||
if(v.x == 0 && v.z != w) v.z = w; // FIXME
|
||||
vr.x = v.x;
|
||||
vr.z = v.z;
|
||||
break;
|
||||
case CLAMP_CLAMP:
|
||||
case CLAMP_REGION_CLAMP:
|
||||
v = wm[wms];
|
||||
if(v.x > v.z) v.x = v.z;
|
||||
vr.x = v.x;
|
||||
vr.z = v.z;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT:
|
||||
if(m_psrr) {vr.x = maxu; vr.z = vr.x + (minu + 1);}
|
||||
//else {vr.x = 0; vr.z = w;}
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
switch(wmt)
|
||||
{
|
||||
case CLAMP_REPEAT:
|
||||
v = wm[0];
|
||||
if(v.y == 0 && v.w != h) v.w = h; // FIXME
|
||||
vr.y = v.y;
|
||||
vr.w = v.w;
|
||||
break;
|
||||
case CLAMP_CLAMP:
|
||||
case CLAMP_REGION_CLAMP:
|
||||
v = wm[wmt];
|
||||
if(v.y > v.w) v.y = v.w;
|
||||
vr.y = v.y;
|
||||
vr.w = v.w;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT:
|
||||
if(m_psrr) {vr.y = maxv; vr.w = vr.y + (minv + 1);}
|
||||
//else {r.y = 0; r.w = w;}
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
r = vr;
|
||||
|
||||
r.InflateRect(1, 1); // one more pixel because of bilinear filtering
|
||||
|
||||
CSize bs = GSLocalMemory::m_psm[m_context->TEX0.PSM].bs;
|
||||
CSize bsm(bs.cx - 1, bs.cy - 1);
|
||||
|
||||
r.left = max(r.left & ~bsm.cx, 0);
|
||||
r.right = min((r.right + bsm.cx) & ~bsm.cx, w);
|
||||
|
||||
r.top = max(r.top & ~bsm.cy, 0);
|
||||
r.bottom = min((r.bottom + bsm.cy) & ~bsm.cy, h);
|
||||
}
|
||||
|
||||
void VSync(int field)
|
||||
{
|
||||
__super::VSync(field);
|
||||
|
||||
m_tc->IncAge();
|
||||
|
||||
m_skip = 0;
|
||||
|
||||
if(m_reset)
|
||||
{
|
||||
m_tc->RemoveAll();
|
||||
|
||||
m_reset = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ResetDevice()
|
||||
{
|
||||
m_tc->RemoveAll();
|
||||
}
|
||||
|
||||
bool GetOutput(int i, Texture& t)
|
||||
{
|
||||
GIFRegTEX0 TEX0;
|
||||
|
||||
TEX0.TBP0 = DISPFB[i]->Block();
|
||||
TEX0.TBW = DISPFB[i]->FBW;
|
||||
TEX0.PSM = DISPFB[i]->PSM;
|
||||
|
||||
TRACE(_T("[%d] GetOutput %d %05x (%d)\n"), (int)m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM);
|
||||
|
||||
if(GSTextureCache<Device>::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height, true))
|
||||
{
|
||||
t = rt->m_texture;
|
||||
|
||||
if(s_dump)
|
||||
{
|
||||
CString str;
|
||||
str.Format(_T("c:\\temp2\\_%05d_f%I64d_fr%d_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM);
|
||||
if(s_save) rt->m_texture.Save(str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r)
|
||||
{
|
||||
TRACE(_T("[%d] InvalidateVideoMem %d,%d - %d,%d %05x (%d)\n"), (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.DBP, (int)BITBLTBUF.DPSM);
|
||||
|
||||
m_tc->InvalidateVideoMem(BITBLTBUF, r);
|
||||
}
|
||||
|
||||
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r)
|
||||
{
|
||||
TRACE(_T("[%d] InvalidateLocalMem %d,%d - %d,%d %05x (%d)\n"), (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.SBP, (int)BITBLTBUF.SPSM);
|
||||
|
||||
m_tc->InvalidateLocalMem(BITBLTBUF, r);
|
||||
}
|
||||
|
||||
void Draw()
|
||||
{
|
||||
if(IsBadFrame(m_skip))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GSDrawingEnvironment& env = m_env;
|
||||
GSDrawingContext* context = m_context;
|
||||
|
||||
GIFRegTEX0 TEX0;
|
||||
|
||||
TEX0.TBP0 = context->FRAME.Block();
|
||||
TEX0.TBW = context->FRAME.FBW;
|
||||
TEX0.PSM = context->FRAME.PSM;
|
||||
|
||||
GSTextureCache<Device>::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height);
|
||||
|
||||
TEX0.TBP0 = context->ZBUF.Block();
|
||||
TEX0.TBW = context->FRAME.FBW;
|
||||
TEX0.PSM = context->ZBUF.PSM;
|
||||
|
||||
GSTextureCache<Device>::GSDepthStencil* ds = m_tc->GetDepthStencil(TEX0, m_width, m_height);
|
||||
|
||||
GSTextureCache<Device>::GSTexture* tex = NULL;
|
||||
|
||||
if(PRIM->TME)
|
||||
{
|
||||
tex = m_tc->GetTexture();
|
||||
|
||||
if(!tex) return;
|
||||
}
|
||||
|
||||
if(s_dump)
|
||||
{
|
||||
CString str;
|
||||
str.Format(_T("c:\\temp2\\_%05d_f%I64d_tex_%05x_%d_%d%d_%02x_%02x_%02x_%02x.dds"),
|
||||
s_n++, m_perfmon.GetFrame(), (int)context->TEX0.TBP0, (int)context->TEX0.PSM,
|
||||
(int)context->CLAMP.WMS, (int)context->CLAMP.WMT,
|
||||
(int)context->CLAMP.MINU, (int)context->CLAMP.MAXU,
|
||||
(int)context->CLAMP.MINV, (int)context->CLAMP.MAXV);
|
||||
if(PRIM->TME) if(s_save) tex->m_texture.Save(str, true);
|
||||
str.Format(_T("c:\\temp2\\_%05d_f%I64d_tpx_%05x_%d.dds"), s_n-1, m_perfmon.GetFrame(), context->TEX0.CBP, context->TEX0.CPSM);
|
||||
if(PRIM->TME && tex->m_palette) if(s_save) tex->m_palette.Save(str, true);
|
||||
str.Format(_T("c:\\temp2\\_%05d_f%I64d_rt0_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), context->FRAME.Block(), context->FRAME.PSM);
|
||||
if(s_save) rt->m_texture.Save(str);
|
||||
str.Format(_T("c:\\temp2\\_%05d_f%I64d_rz0_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), context->ZBUF.Block(), context->ZBUF.PSM);
|
||||
if(s_savez) ds->m_texture.Save(str);
|
||||
// if(s_savez) m_dev.SaveToFileD32S8X24(ds->m_texture, str); // TODO
|
||||
// if(s_savez) m_dev.SaveToFileD24S8(ds->m_texture, str); // TODO
|
||||
}
|
||||
|
||||
int prim = PRIM->PRIM;
|
||||
|
||||
if(!OverrideInput(prim, rt->m_texture, ds->m_texture, tex ? &tex->m_texture : NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Draw(prim, rt->m_texture, ds->m_texture, tex);
|
||||
|
||||
OverrideOutput();
|
||||
|
||||
m_tc->InvalidateTextures(context->FRAME, context->ZBUF);
|
||||
|
||||
if(s_dump)
|
||||
{
|
||||
CString str;
|
||||
str.Format(_T("c:\\temp2\\_%05d_f%I64d_rt1_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), context->FRAME.Block(), context->FRAME.PSM);
|
||||
if(s_save) rt->m_texture.Save(str);
|
||||
str.Format(_T("c:\\temp2\\_%05d_f%I64d_rz1_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), context->ZBUF.Block(), context->ZBUF.PSM);
|
||||
if(s_savez) ds->m_texture.Save(str);
|
||||
// if(s_savez) m_dev.SaveToFileD32S8X24(ds->m_texture, str); // TODO
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Draw(int prim, Texture& rt, Texture& ds, typename GSTextureCache<Device>::GSTexture* tex) = 0;
|
||||
|
||||
virtual bool OverrideInput(int& prim, Texture& rt, Texture& ds, Texture* t)
|
||||
{
|
||||
#pragma region ffxii pal video conversion
|
||||
|
||||
if(m_game.title == CRC::FFXII && m_game.region == CRC::EU)
|
||||
{
|
||||
static DWORD* video = NULL;
|
||||
static bool ok = false;
|
||||
|
||||
if(prim == GS_POINTLIST && m_count >= 448*448 && m_count <= 448*512)
|
||||
{
|
||||
// incoming pixels are stored in columns, one column is 16x512, total res 448x512 or 448x454
|
||||
|
||||
if(!video) video = new DWORD[512*512];
|
||||
|
||||
for(int x = 0, i = 0, rows = m_count / 448; x < 448; x += 16)
|
||||
{
|
||||
DWORD* dst = &video[x];
|
||||
|
||||
for(int y = 0; y < rows; y++, dst += 512)
|
||||
{
|
||||
for(int j = 0; j < 16; j++, i++)
|
||||
{
|
||||
dst[j] = m_vertices[i].c0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
else if(prim == GS_LINELIST && m_count == 512*2 && ok)
|
||||
{
|
||||
// normally, this step would copy the video onto screen with 512 texture mapped horizontal lines,
|
||||
// but we use the stored video data to create a new texture, and replace the lines with two triangles
|
||||
|
||||
ok = false;
|
||||
|
||||
m_dev.CreateTexture(*t, 512, 512);
|
||||
|
||||
t->Update(CRect(0, 0, 448, 512), video, 512*4);
|
||||
|
||||
m_vertices[0] = m_vertices[0];
|
||||
m_vertices[1] = m_vertices[1];
|
||||
m_vertices[2] = m_vertices[m_count - 2];
|
||||
m_vertices[3] = m_vertices[1];
|
||||
m_vertices[4] = m_vertices[2];
|
||||
m_vertices[5] = m_vertices[m_count - 1];
|
||||
|
||||
prim = GS_TRIANGLELIST;
|
||||
m_count = 6;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ffx random battle transition (z buffer written directly, clear it now)
|
||||
|
||||
if(m_game.title == CRC::FFX)
|
||||
{
|
||||
DWORD FBP = m_context->FRAME.Block();
|
||||
DWORD ZBP = m_context->ZBUF.Block();
|
||||
DWORD TBP = m_context->TEX0.TBP0;
|
||||
|
||||
if((FBP == 0x00d00 || FBP == 0x00000) && ZBP == 0x02100 && PRIM->TME && TBP == 0x01a00 && m_context->TEX0.PSM == PSM_PSMCT16S)
|
||||
{
|
||||
m_dev.ClearDepth(ds, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region metal slug missing red channel fix
|
||||
|
||||
if(m_game.title == CRC::MetalSlug6)
|
||||
{
|
||||
for(int i = 0, j = m_count; i < j; i++)
|
||||
{
|
||||
if(m_vertices[i].r == 0 && m_vertices[i].g != 0 && m_vertices[i].b != 0)
|
||||
{
|
||||
m_vertices[i].r = (m_vertices[i].g + m_vertices[i].b) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region tomoyo after, clannad (palette uploaded in a point list, pure genius...)
|
||||
|
||||
if(m_game.title == CRC::TomoyoAfter || m_game.title == CRC::Clannad)
|
||||
{
|
||||
if(prim == GS_POINTLIST && !PRIM->TME)
|
||||
{
|
||||
DWORD bp = m_context->FRAME.Block();
|
||||
DWORD bw = m_context->FRAME.FBW;
|
||||
|
||||
if(bp >= 0x03f40 && (bp & 0x1f) == 0)
|
||||
{
|
||||
if(m_count == 16)
|
||||
{
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
m_vertices[i].a = m_vertices[i].a >= 0x80 ? 0xff : m_vertices[i].a * 2;
|
||||
|
||||
m_mem.WritePixel32(i & 7, i >> 3, m_vertices[i].c0, bp, bw);
|
||||
}
|
||||
|
||||
m_mem.m_clut.Invalidate();
|
||||
|
||||
return false;
|
||||
}
|
||||
else if(m_count == 256)
|
||||
{
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
m_vertices[i].a = m_vertices[i].a >= 0x80 ? 0xff : m_vertices[i].a * 2;
|
||||
|
||||
m_mem.WritePixel32(i & 15, i >> 4, m_vertices[i].c0, bp, bw);
|
||||
}
|
||||
|
||||
m_mem.m_clut.Invalidate();
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void OverrideOutput()
|
||||
{
|
||||
#pragma region dbzbt2 palette readback (cannot detect yet, when fetching the texture later)
|
||||
|
||||
if(m_game.title == CRC::DBZBT2)
|
||||
{
|
||||
DWORD FBP = m_context->FRAME.Block();
|
||||
DWORD TBP0 = m_context->TEX0.TBP0;
|
||||
|
||||
if(PRIM->TME && (FBP == 0x03c00 && TBP0 == 0x03c80 || FBP == 0x03ac0 && TBP0 == 0x03b40))
|
||||
{
|
||||
GIFRegBITBLTBUF BITBLTBUF;
|
||||
|
||||
BITBLTBUF.SBP = FBP;
|
||||
BITBLTBUF.SBW = 1;
|
||||
BITBLTBUF.SPSM = PSM_PSMCT32;
|
||||
|
||||
InvalidateLocalMem(BITBLTBUF, CRect(0, 0, 64, 64));
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region MajokkoALaMode2 palette readback
|
||||
|
||||
if(m_game.title == CRC::MajokkoALaMode2)
|
||||
{
|
||||
DWORD FBP = m_context->FRAME.Block();
|
||||
|
||||
if(!PRIM->TME && FBP == 0x03f40)
|
||||
{
|
||||
GIFRegBITBLTBUF BITBLTBUF;
|
||||
|
||||
BITBLTBUF.SBP = FBP;
|
||||
BITBLTBUF.SBW = 1;
|
||||
BITBLTBUF.SPSM = PSM_PSMCT32;
|
||||
|
||||
InvalidateLocalMem(BITBLTBUF, CRect(0, 0, 16, 16));
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
}
|
||||
|
||||
bool CanUpscale()
|
||||
{
|
||||
#pragma region dbzbt2 palette should stay 64 x 64
|
||||
|
||||
if(m_game.title == CRC::DBZBT2)
|
||||
{
|
||||
DWORD FBP = m_context->FRAME.Block();
|
||||
|
||||
if(FBP == 0x03c00 || FBP == 0x03ac0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region MajokkoALaMode2 palette should stay 16 x 16
|
||||
|
||||
if(m_game.title == CRC::MajokkoALaMode2)
|
||||
{
|
||||
DWORD FBP = m_context->FRAME.Block();
|
||||
|
||||
if(FBP == 0x03f40)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region TalesOfAbyss full image blur and brightening
|
||||
|
||||
if(m_game.title == CRC::TalesOfAbyss)
|
||||
{
|
||||
DWORD FBP = m_context->FRAME.Block();
|
||||
|
||||
if(FBP == 0x036e0 || FBP == 0x03560 || FBP == 0x038e0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
return __super::CanUpscale();
|
||||
}
|
||||
|
||||
public:
|
||||
GSRendererHW(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr)
|
||||
: GSRendererT<Device, Vertex>(base, mt, irq, nloophack, rs, psrr)
|
||||
, m_width(1024)
|
||||
, m_height(1024)
|
||||
, m_skip(0)
|
||||
, m_reset(false)
|
||||
{
|
||||
if(!m_nativeres)
|
||||
{
|
||||
m_width = AfxGetApp()->GetProfileInt(_T("Settings"), _T("resx"), m_width);
|
||||
m_height = AfxGetApp()->GetProfileInt(_T("Settings"), _T("resy"), m_height);
|
||||
}
|
||||
|
||||
m_tc = new TextureCache(this);
|
||||
}
|
||||
|
||||
virtual ~GSRendererHW()
|
||||
{
|
||||
delete m_tc;
|
||||
}
|
||||
|
||||
void SetGameCRC(DWORD crc, int options)
|
||||
{
|
||||
__super::SetGameCRC(crc, options);
|
||||
|
||||
if(m_game.title == CRC::JackieChanAdv)
|
||||
{
|
||||
m_width = 1280; // TODO: uses a 1280px wide 16 bit render target, but this only fixes half of the problem
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,586 @@
|
|||
/*
|
||||
* 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 "GSRendererHW10.h"
|
||||
#include "GSCrc.h"
|
||||
#include "resource.h"
|
||||
|
||||
GSRendererHW10::GSRendererHW10(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
|
||||
: GSRendererHW<Device, Vertex, TextureCache>(base, mt, irq, nloophack, rs, true)
|
||||
{
|
||||
InitVertexKick<GSRendererHW10>();
|
||||
}
|
||||
|
||||
bool GSRendererHW10::Create(LPCTSTR title)
|
||||
{
|
||||
if(!__super::Create(title))
|
||||
return false;
|
||||
|
||||
if(!m_tfx.Create(&m_dev))
|
||||
return false;
|
||||
|
||||
//
|
||||
|
||||
D3D10_DEPTH_STENCIL_DESC dsd;
|
||||
|
||||
memset(&dsd, 0, sizeof(dsd));
|
||||
|
||||
dsd.DepthEnable = false;
|
||||
dsd.StencilEnable = true;
|
||||
dsd.StencilReadMask = 1;
|
||||
dsd.StencilWriteMask = 1;
|
||||
dsd.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
||||
dsd.FrontFace.StencilPassOp = D3D10_STENCIL_OP_REPLACE;
|
||||
dsd.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
|
||||
dsd.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
|
||||
dsd.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
||||
dsd.BackFace.StencilPassOp = D3D10_STENCIL_OP_REPLACE;
|
||||
dsd.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
|
||||
dsd.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
|
||||
|
||||
m_dev->CreateDepthStencilState(&dsd, &m_date.dss);
|
||||
|
||||
D3D10_BLEND_DESC bd;
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
|
||||
m_dev->CreateBlendState(&bd, &m_date.bs);
|
||||
|
||||
//
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<DWORD prim, DWORD tme, DWORD fst>
|
||||
void GSRendererHW10::VertexKick(bool skip)
|
||||
{
|
||||
Vertex& dst = m_vl.AddTail();
|
||||
|
||||
dst.m128i[0] = m_v.m128i[0];
|
||||
dst.m128i[1] = m_v.m128i[1];
|
||||
|
||||
if(tme && fst)
|
||||
{
|
||||
GSVector4::storel(&dst.ST, m_v.GetUV());
|
||||
}
|
||||
|
||||
DWORD count = 0;
|
||||
|
||||
if(Vertex* v = DrawingKick<prim>(skip, count))
|
||||
{
|
||||
GSVector4i scissor = m_context->scissor.dx10;
|
||||
|
||||
#if _M_SSE >= 0x401
|
||||
|
||||
GSVector4i pmin, pmax, v0, v1, v2;
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
v0 = GSVector4i::load((int)v[0].p.xy).upl16();
|
||||
pmin = v0;
|
||||
pmax = v0;
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
case GS_SPRITE:
|
||||
v0 = GSVector4i::load((int)v[0].p.xy);
|
||||
v1 = GSVector4i::load((int)v[1].p.xy);
|
||||
pmin = v0.min_u16(v1).upl16();
|
||||
pmax = v0.max_u16(v1).upl16();
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
v0 = GSVector4i::load((int)v[0].p.xy);
|
||||
v1 = GSVector4i::load((int)v[1].p.xy);
|
||||
v2 = GSVector4i::load((int)v[2].p.xy);
|
||||
pmin = v0.min_u16(v1).min_u16(v2).upl16();
|
||||
pmax = v0.max_u16(v1).max_u16(v2).upl16();
|
||||
break;
|
||||
}
|
||||
|
||||
GSVector4i test = (pmax < scissor) | (pmin > scissor.zwxy());
|
||||
|
||||
if(test.mask() & 0xff)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
if(v[0].p.x < scissor.x
|
||||
|| v[0].p.x > scissor.z
|
||||
|| v[0].p.y < scissor.y
|
||||
|| v[0].p.y > scissor.w)
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
case GS_SPRITE:
|
||||
if(v[0].p.x < scissor.x && v[1].p.x < scissor.x
|
||||
|| v[0].p.x > scissor.z && v[1].p.x > scissor.z
|
||||
|| v[0].p.y < scissor.y && v[1].p.y < scissor.y
|
||||
|| v[0].p.y > scissor.w && v[1].p.y > scissor.w)
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
if(v[0].p.x < scissor.x && v[1].p.x < scissor.x && v[2].p.x < scissor.x
|
||||
|| v[0].p.x > scissor.z && v[1].p.x > scissor.z && v[2].p.x > scissor.z
|
||||
|| v[0].p.y < scissor.y && v[1].p.y < scissor.y && v[2].p.y < scissor.y
|
||||
|| v[0].p.y > scissor.w && v[1].p.y > scissor.w && v[2].p.y > scissor.w)
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
m_count += count;
|
||||
}
|
||||
}
|
||||
|
||||
void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex)
|
||||
{
|
||||
GSDrawingEnvironment& env = m_env;
|
||||
GSDrawingContext* context = m_context;
|
||||
/*
|
||||
if(s_dump)
|
||||
{
|
||||
TRACE(_T("\n"));
|
||||
|
||||
TRACE(_T("PRIM = %d, ZMSK = %d, ZTE = %d, ZTST = %d, ATE = %d, ATST = %d, AFAIL = %d, AREF = %02x\n"),
|
||||
PRIM->PRIM, context->ZBUF.ZMSK,
|
||||
context->TEST.ZTE, context->TEST.ZTST,
|
||||
context->TEST.ATE, context->TEST.ATST, context->TEST.AFAIL, context->TEST.AREF);
|
||||
|
||||
for(int i = 0; i < m_count; i++)
|
||||
{
|
||||
TRACE(_T("[%d] %3.0f %3.0f %3.0f %3.0f\n"), i, (float)m_vertices[i].p.x / 16, (float)m_vertices[i].p.y / 16, (float)m_vertices[i].p.z, (float)m_vertices[i].a);
|
||||
}
|
||||
}
|
||||
*/
|
||||
D3D10_PRIMITIVE_TOPOLOGY topology;
|
||||
int prims = 0;
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
topology = D3D10_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
prims = m_count;
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
case GS_SPRITE:
|
||||
topology = D3D10_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
prims = m_count / 2;
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
topology = D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
prims = m_count / 3;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
m_perfmon.Put(GSPerfMon::Prim, prims);
|
||||
m_perfmon.Put(GSPerfMon::Draw, 1);
|
||||
|
||||
// date
|
||||
|
||||
SetupDATE(rt, ds);
|
||||
|
||||
//
|
||||
|
||||
m_dev.BeginScene();
|
||||
|
||||
// om
|
||||
|
||||
GSTextureFX10::OMDepthStencilSelector om_dssel;
|
||||
|
||||
om_dssel.zte = context->TEST.ZTE;
|
||||
om_dssel.ztst = context->TEST.ZTST;
|
||||
om_dssel.zwe = !context->ZBUF.ZMSK;
|
||||
om_dssel.date = context->FRAME.PSM != PSM_PSMCT24 ? context->TEST.DATE : 0;
|
||||
|
||||
GSTextureFX10::OMBlendSelector om_bsel;
|
||||
|
||||
om_bsel.abe = PRIM->ABE || (prim == 1 || prim == 2) && PRIM->AA1;
|
||||
om_bsel.a = context->ALPHA.A;
|
||||
om_bsel.b = context->ALPHA.B;
|
||||
om_bsel.c = context->ALPHA.C;
|
||||
om_bsel.d = context->ALPHA.D;
|
||||
om_bsel.wr = (context->FRAME.FBMSK & 0x000000ff) != 0x000000ff;
|
||||
om_bsel.wg = (context->FRAME.FBMSK & 0x0000ff00) != 0x0000ff00;
|
||||
om_bsel.wb = (context->FRAME.FBMSK & 0x00ff0000) != 0x00ff0000;
|
||||
om_bsel.wa = (context->FRAME.FBMSK & 0xff000000) != 0xff000000;
|
||||
|
||||
float bf = (float)(int)context->ALPHA.FIX / 0x80;
|
||||
|
||||
// vs
|
||||
|
||||
GSTextureFX10::VSSelector vs_sel;
|
||||
|
||||
vs_sel.bpp = 0;
|
||||
vs_sel.bppz = 0;
|
||||
vs_sel.tme = PRIM->TME;
|
||||
vs_sel.fst = PRIM->FST;
|
||||
vs_sel.prim = prim;
|
||||
|
||||
if(tex)
|
||||
{
|
||||
vs_sel.bpp = tex->m_bpp2;
|
||||
}
|
||||
|
||||
if(om_dssel.zte && om_dssel.ztst > 0 && om_dssel.zwe)
|
||||
{
|
||||
if(context->ZBUF.PSM == PSM_PSMZ24)
|
||||
{
|
||||
if(WrapZ(0xffffff))
|
||||
{
|
||||
vs_sel.bppz = 1;
|
||||
om_dssel.ztst = 1;
|
||||
}
|
||||
}
|
||||
else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S)
|
||||
{
|
||||
if(WrapZ(0xffff))
|
||||
{
|
||||
vs_sel.bppz = 2;
|
||||
om_dssel.ztst = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GSTextureFX10::VSConstantBuffer vs_cb;
|
||||
|
||||
float sx = 2.0f * rt.m_scale.x / (rt.GetWidth() * 16);
|
||||
float sy = 2.0f * rt.m_scale.y / (rt.GetHeight() * 16);
|
||||
float ox = (float)(int)context->XYOFFSET.OFX;
|
||||
float oy = (float)(int)context->XYOFFSET.OFY;
|
||||
|
||||
vs_cb.VertexScale = GSVector4(sx, -sy, 1.0f / UINT_MAX, 0.0f);
|
||||
vs_cb.VertexOffset = GSVector4(ox * sx + 1, -(oy * sy + 1), 0.0f, -1.0f);
|
||||
vs_cb.TextureScale = GSVector2(1.0f, 1.0f);
|
||||
|
||||
if(PRIM->TME && PRIM->FST)
|
||||
{
|
||||
vs_cb.TextureScale.x = 1.0f / (16 << context->TEX0.TW);
|
||||
vs_cb.TextureScale.y = 1.0f / (16 << context->TEX0.TH);
|
||||
}
|
||||
|
||||
// gs
|
||||
|
||||
GSTextureFX10::GSSelector gs_sel;
|
||||
|
||||
gs_sel.iip = PRIM->IIP;
|
||||
gs_sel.prim = GSUtil::GetPrimClass(prim);
|
||||
|
||||
// ps
|
||||
|
||||
GSTextureFX10::PSSelector ps_sel;
|
||||
|
||||
ps_sel.fst = PRIM->FST;
|
||||
ps_sel.wms = context->CLAMP.WMS;
|
||||
ps_sel.wmt = context->CLAMP.WMT;
|
||||
ps_sel.bpp = 0;
|
||||
ps_sel.aem = env.TEXA.AEM;
|
||||
ps_sel.tfx = context->TEX0.TFX;
|
||||
ps_sel.tcc = context->TEX0.TCC;
|
||||
ps_sel.ate = context->TEST.ATE;
|
||||
ps_sel.atst = context->TEST.ATST;
|
||||
ps_sel.fog = PRIM->FGE;
|
||||
ps_sel.clr1 = om_bsel.abe && om_bsel.a == 1 && om_bsel.b == 2 && om_bsel.d == 1;
|
||||
ps_sel.fba = context->FBA.FBA;
|
||||
ps_sel.aout = context->FRAME.PSM == PSM_PSMCT16 || context->FRAME.PSM == PSM_PSMCT16S || (context->FRAME.FBMSK & 0xff000000) == 0x7f000000 ? 1 : 0;
|
||||
|
||||
GSTextureFX10::PSSamplerSelector ps_ssel;
|
||||
|
||||
ps_ssel.min = m_filter == 2 ? (context->TEX1.MMIN & 1) : m_filter;
|
||||
ps_ssel.mag = m_filter == 2 ? (context->TEX1.MMAG & 1) : m_filter;
|
||||
ps_ssel.tau = 0;
|
||||
ps_ssel.tav = 0;
|
||||
|
||||
GSTextureFX10::PSConstantBuffer ps_cb;
|
||||
|
||||
ps_cb.FogColor = GSVector4(env.FOGCOL.FCR, env.FOGCOL.FCG, env.FOGCOL.FCB, 0) / 255.0f;
|
||||
ps_cb.TA0 = (float)(int)env.TEXA.TA0 / 255;
|
||||
ps_cb.TA1 = (float)(int)env.TEXA.TA1 / 255;
|
||||
ps_cb.AREF = (float)(int)context->TEST.AREF / 255;
|
||||
|
||||
if(context->TEST.ATST == 2 || context->TEST.ATST == 5)
|
||||
{
|
||||
ps_cb.AREF -= 0.9f/256;
|
||||
}
|
||||
else if(context->TEST.ATST == 3 || context->TEST.ATST == 6)
|
||||
{
|
||||
ps_cb.AREF += 0.9f/256;
|
||||
}
|
||||
|
||||
if(tex)
|
||||
{
|
||||
ps_sel.bpp = tex->m_bpp2;
|
||||
|
||||
switch(context->CLAMP.WMS)
|
||||
{
|
||||
case 0:
|
||||
ps_ssel.tau = 1;
|
||||
break;
|
||||
case 1:
|
||||
ps_ssel.tau = 0;
|
||||
break;
|
||||
case 2:
|
||||
ps_cb.MINU = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW);
|
||||
ps_cb.MAXU = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW);
|
||||
ps_ssel.tau = 0;
|
||||
break;
|
||||
case 3:
|
||||
ps_cb.UMSK = context->CLAMP.MINU;
|
||||
ps_cb.UFIX = context->CLAMP.MAXU;
|
||||
ps_ssel.tau = 1;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
switch(context->CLAMP.WMT)
|
||||
{
|
||||
case 0:
|
||||
ps_ssel.tav = 1;
|
||||
break;
|
||||
case 1:
|
||||
ps_ssel.tav = 0;
|
||||
break;
|
||||
case 2:
|
||||
ps_cb.MINV = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH);
|
||||
ps_cb.MAXV = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH);
|
||||
ps_ssel.tav = 0;
|
||||
break;
|
||||
case 3:
|
||||
ps_cb.VMSK = context->CLAMP.MINV;
|
||||
ps_cb.VFIX = context->CLAMP.MAXV;
|
||||
ps_ssel.tav = 1;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
float w = (float)tex->m_texture.GetWidth();
|
||||
float h = (float)tex->m_texture.GetHeight();
|
||||
|
||||
ps_cb.WH = GSVector2(w, h);
|
||||
ps_cb.rWrH = GSVector2(1.0f / w, 1.0f / h);
|
||||
}
|
||||
else
|
||||
{
|
||||
ps_sel.tfx = 4;
|
||||
}
|
||||
|
||||
// rs
|
||||
|
||||
int w = rt.GetWidth();
|
||||
int h = rt.GetHeight();
|
||||
|
||||
CRect scissor = (CRect)GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in) & CRect(0, 0, w, h);
|
||||
|
||||
//
|
||||
|
||||
m_tfx.SetupOM(om_dssel, om_bsel, bf, rt, ds);
|
||||
m_tfx.SetupIA(m_vertices, m_count, topology);
|
||||
m_tfx.SetupVS(vs_sel, &vs_cb);
|
||||
m_tfx.SetupGS(gs_sel);
|
||||
m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel,
|
||||
tex ? (ID3D10ShaderResourceView*)tex->m_texture : NULL,
|
||||
tex ? (ID3D10ShaderResourceView*)tex->m_palette : NULL);
|
||||
m_tfx.SetupRS(w, h, scissor);
|
||||
|
||||
// draw
|
||||
|
||||
if(context->TEST.DoFirstPass())
|
||||
{
|
||||
m_tfx.Draw();
|
||||
}
|
||||
|
||||
if(context->TEST.DoSecondPass())
|
||||
{
|
||||
ASSERT(!env.PABE.PABE);
|
||||
|
||||
static const DWORD iatst[] = {1, 0, 5, 6, 7, 2, 3, 4};
|
||||
|
||||
ps_sel.atst = iatst[ps_sel.atst];
|
||||
|
||||
m_tfx.UpdatePS(ps_sel, &ps_cb, ps_ssel);
|
||||
|
||||
bool z = om_dssel.zwe;
|
||||
bool r = om_bsel.wr;
|
||||
bool g = om_bsel.wg;
|
||||
bool b = om_bsel.wb;
|
||||
bool a = om_bsel.wa;
|
||||
|
||||
switch(context->TEST.AFAIL)
|
||||
{
|
||||
case 0: z = r = g = b = a = false; break; // none
|
||||
case 1: z = false; break; // rgba
|
||||
case 2: r = g = b = a = false; break; // z
|
||||
case 3: z = a = false; break; // rgb
|
||||
default: __assume(0);
|
||||
}
|
||||
|
||||
if(z || r || g || b || a)
|
||||
{
|
||||
om_dssel.zwe = z;
|
||||
om_bsel.wr = r;
|
||||
om_bsel.wg = g;
|
||||
om_bsel.wb = b;
|
||||
om_bsel.wa = a;
|
||||
|
||||
m_tfx.UpdateOM(om_dssel, om_bsel, bf);
|
||||
|
||||
m_tfx.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
m_dev.EndScene();
|
||||
}
|
||||
|
||||
bool GSRendererHW10::WrapZ(DWORD maxz)
|
||||
{
|
||||
// should only run once if z values are in the z buffer range
|
||||
|
||||
for(int i = 0, j = m_count; i < j; i++)
|
||||
{
|
||||
if(m_vertices[i].p.z <= maxz)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSRendererHW10::SetupDATE(Texture& rt, Texture& ds)
|
||||
{
|
||||
if(!m_context->TEST.DATE) return; // || (::GetAsyncKeyState(VK_CONTROL) & 0x8000)
|
||||
|
||||
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows
|
||||
|
||||
GSVector4 mm;
|
||||
|
||||
// TODO
|
||||
|
||||
mm = GSVector4(-1, -1, 1, 1);
|
||||
/*
|
||||
MinMaxXY(mm);
|
||||
|
||||
int w = rt.GetWidth();
|
||||
int h = rt.GetHeight();
|
||||
|
||||
float sx = 2.0f * rt.m_scale.x / (w * 16);
|
||||
float sy = 2.0f * rt.m_scale.y / (h * 16);
|
||||
float ox = (float)(int)m_context->XYOFFSET.OFX;
|
||||
float oy = (float)(int)m_context->XYOFFSET.OFY;
|
||||
|
||||
mm.x = (mm.x - ox) * sx - 1;
|
||||
mm.y = (mm.y - oy) * sy - 1;
|
||||
mm.z = (mm.z - ox) * sx - 1;
|
||||
mm.w = (mm.w - oy) * sy - 1;
|
||||
|
||||
if(mm.x < -1) mm.x = -1;
|
||||
if(mm.y < -1) mm.y = -1;
|
||||
if(mm.z > +1) mm.z = +1;
|
||||
if(mm.w > +1) mm.w = +1;
|
||||
*/
|
||||
GSVector4 uv = (mm + 1.0f) / 2.0f;
|
||||
|
||||
//
|
||||
|
||||
m_dev.BeginScene();
|
||||
|
||||
// om
|
||||
|
||||
GSTexture10 tmp;
|
||||
|
||||
m_dev.CreateRenderTarget(tmp, rt.GetWidth(), rt.GetHeight());
|
||||
|
||||
m_dev.OMSetRenderTargets(tmp, ds);
|
||||
m_dev.OMSetDepthStencilState(m_date.dss, 1);
|
||||
m_dev.OMSetBlendState(m_date.bs, 0);
|
||||
|
||||
m_dev->ClearDepthStencilView(ds, D3D10_CLEAR_STENCIL, 0, 0);
|
||||
|
||||
// ia
|
||||
|
||||
GSVertexPT1 vertices[] =
|
||||
{
|
||||
{GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)},
|
||||
{GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)},
|
||||
{GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)},
|
||||
{GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)},
|
||||
};
|
||||
|
||||
D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1};
|
||||
m_dev->UpdateSubresource(m_dev.m_convert.vb, 0, &box, vertices, 0, 0);
|
||||
|
||||
m_dev.IASetVertexBuffer(m_dev.m_convert.vb, sizeof(vertices[0]));
|
||||
m_dev.IASetInputLayout(m_dev.m_convert.il);
|
||||
m_dev.IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
|
||||
// vs
|
||||
|
||||
m_dev.VSSetShader(m_dev.m_convert.vs, NULL);
|
||||
|
||||
// gs
|
||||
|
||||
m_dev.GSSetShader(NULL);
|
||||
|
||||
// ps
|
||||
|
||||
m_dev.PSSetShaderResources(rt, NULL);
|
||||
m_dev.PSSetShader(m_dev.m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL);
|
||||
m_dev.PSSetSamplerState(m_dev.m_convert.pt, NULL);
|
||||
|
||||
// rs
|
||||
|
||||
m_dev.RSSet(tmp.GetWidth(), tmp.GetHeight());
|
||||
|
||||
// set
|
||||
|
||||
m_dev.DrawPrimitive(countof(vertices));
|
||||
|
||||
//
|
||||
|
||||
m_dev.EndScene();
|
||||
|
||||
m_dev.Recycle(tmp);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSRendererHW.h"
|
||||
#include "GSVertexHW.h"
|
||||
#include "GSTextureCache10.h"
|
||||
#include "GSTextureFX10.h"
|
||||
|
||||
class GSRendererHW10 : public GSRendererHW<GSDevice10, GSVertexHW10, GSTextureCache10>
|
||||
{
|
||||
typedef GSDevice10 Device;
|
||||
typedef GSVertexHW10 Vertex;
|
||||
typedef GSTextureCache10 TextureCache;
|
||||
|
||||
bool WrapZ(DWORD maxz);
|
||||
|
||||
protected:
|
||||
GSTextureFX10 m_tfx;
|
||||
|
||||
void Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex);
|
||||
|
||||
struct
|
||||
{
|
||||
CComPtr<ID3D10DepthStencilState> dss;
|
||||
CComPtr<ID3D10BlendState> bs;
|
||||
} m_date;
|
||||
|
||||
void SetupDATE(Texture& rt, Texture& ds);
|
||||
|
||||
public:
|
||||
GSRendererHW10(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs);
|
||||
|
||||
bool Create(LPCTSTR title);
|
||||
|
||||
template<DWORD prim, DWORD tme, DWORD fst> void VertexKick(bool skip);
|
||||
};
|
|
@ -0,0 +1,594 @@
|
|||
/*
|
||||
* 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 "GSRendererHW9.h"
|
||||
#include "GSCrc.h"
|
||||
#include "resource.h"
|
||||
|
||||
GSRendererHW9::GSRendererHW9(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
|
||||
: GSRendererHW<Device, Vertex, TextureCache>(base, mt, irq, nloophack, rs, false)
|
||||
{
|
||||
m_fba.enabled = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("fba"), TRUE);
|
||||
m_logz = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("logz"), FALSE);
|
||||
|
||||
InitVertexKick<GSRendererHW9>();
|
||||
}
|
||||
|
||||
bool GSRendererHW9::Create(LPCTSTR title)
|
||||
{
|
||||
if(!__super::Create(title))
|
||||
return false;
|
||||
|
||||
if(!m_tfx.Create(&m_dev))
|
||||
return false;
|
||||
|
||||
//
|
||||
|
||||
memset(&m_date.dss, 0, sizeof(m_date.dss));
|
||||
|
||||
m_date.dss.StencilEnable = true;
|
||||
m_date.dss.StencilReadMask = 1;
|
||||
m_date.dss.StencilWriteMask = 1;
|
||||
m_date.dss.StencilFunc = D3DCMP_ALWAYS;
|
||||
m_date.dss.StencilPassOp = D3DSTENCILOP_REPLACE;
|
||||
|
||||
memset(&m_date.bs, 0, sizeof(m_date.bs));
|
||||
|
||||
//
|
||||
|
||||
memset(&m_fba.dss, 0, sizeof(m_fba.dss));
|
||||
|
||||
m_fba.dss.StencilEnable = true;
|
||||
m_fba.dss.StencilReadMask = 2;
|
||||
m_fba.dss.StencilWriteMask = 2;
|
||||
m_fba.dss.StencilFunc = D3DCMP_EQUAL;
|
||||
m_fba.dss.StencilPassOp = D3DSTENCILOP_ZERO;
|
||||
m_fba.dss.StencilFailOp = D3DSTENCILOP_ZERO;
|
||||
m_fba.dss.StencilDepthFailOp = D3DSTENCILOP_ZERO;
|
||||
|
||||
memset(&m_fba.bs, 0, sizeof(m_fba.bs));
|
||||
|
||||
m_fba.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_ALPHA;
|
||||
|
||||
//
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<DWORD prim, DWORD tme, DWORD fst>
|
||||
void GSRendererHW9::VertexKick(bool skip)
|
||||
{
|
||||
Vertex& dst = m_vl.AddTail();
|
||||
|
||||
dst.p.x = (float)m_v.XYZ.X;
|
||||
dst.p.y = (float)m_v.XYZ.Y;
|
||||
dst.p.z = (float)m_v.XYZ.Z;
|
||||
|
||||
dst.c0 = m_v.RGBAQ.ai32[0];
|
||||
dst.c1 = m_v.FOG.ai32[1];
|
||||
|
||||
if(tme)
|
||||
{
|
||||
if(fst)
|
||||
{
|
||||
GSVector4::storel(&dst.t, m_v.GetUV());
|
||||
}
|
||||
else
|
||||
{
|
||||
dst.t.x = m_v.ST.S;
|
||||
dst.t.y = m_v.ST.T;
|
||||
dst.p.w = m_v.RGBAQ.Q;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD count = 0;
|
||||
|
||||
if(Vertex* v = DrawingKick<prim>(skip, count))
|
||||
{
|
||||
GSVector4 scissor = m_context->scissor.dx9;
|
||||
|
||||
GSVector4 pmin, pmax;
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
pmin = v[0].p;
|
||||
pmax = v[0].p;
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
case GS_SPRITE:
|
||||
pmin = v[0].p.minv(v[1].p);
|
||||
pmax = v[0].p.maxv(v[1].p);
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
pmin = v[0].p.minv(v[1].p).minv(v[2].p);
|
||||
pmax = v[0].p.maxv(v[1].p).maxv(v[2].p);
|
||||
break;
|
||||
}
|
||||
|
||||
GSVector4 test = (pmax < scissor) | (pmin > scissor.zwxy());
|
||||
|
||||
if(test.mask() & 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
if(PRIM->IIP == 0) {v[0].c0 = v[1].c0;}
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
if(PRIM->IIP == 0) {v[0].c0 = v[1].c0 = v[2].c0;}
|
||||
break;
|
||||
case GS_SPRITE:
|
||||
if(PRIM->IIP == 0) {v[0].c0 = v[1].c0;}
|
||||
v[0].p.z = v[1].p.z;
|
||||
v[0].p.w = v[1].p.w;
|
||||
v[0].c1 = v[1].c1;
|
||||
v[2] = v[1];
|
||||
v[3] = v[1];
|
||||
v[1].p.y = v[0].p.y;
|
||||
v[1].t.y = v[0].t.y;
|
||||
v[2].p.x = v[0].p.x;
|
||||
v[2].t.x = v[0].t.x;
|
||||
v[4] = v[1];
|
||||
v[5] = v[2];
|
||||
count += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
m_count += count;
|
||||
}
|
||||
}
|
||||
|
||||
void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex)
|
||||
{
|
||||
GSDrawingEnvironment& env = m_env;
|
||||
GSDrawingContext* context = m_context;
|
||||
|
||||
D3DPRIMITIVETYPE topology;
|
||||
int prims = 0;
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
topology = D3DPT_POINTLIST;
|
||||
prims = m_count;
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
topology = D3DPT_LINELIST;
|
||||
prims = m_count / 2;
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
case GS_SPRITE:
|
||||
topology = D3DPT_TRIANGLELIST;
|
||||
prims = m_count / 3;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
m_perfmon.Put(GSPerfMon::Prim, prims);
|
||||
m_perfmon.Put(GSPerfMon::Draw, 1);
|
||||
|
||||
// date
|
||||
|
||||
SetupDATE(rt, ds);
|
||||
|
||||
//
|
||||
|
||||
m_dev.BeginScene();
|
||||
|
||||
m_dev->SetRenderState(D3DRS_SHADEMODE, PRIM->IIP ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); // TODO
|
||||
|
||||
// om
|
||||
|
||||
GSTextureFX9::OMDepthStencilSelector om_dssel;
|
||||
|
||||
om_dssel.zte = context->TEST.ZTE;
|
||||
om_dssel.ztst = context->TEST.ZTST;
|
||||
om_dssel.zwe = !context->ZBUF.ZMSK;
|
||||
om_dssel.date = context->FRAME.PSM != PSM_PSMCT24 ? context->TEST.DATE : 0;
|
||||
om_dssel.fba = m_fba.enabled ? context->FBA.FBA : 0;
|
||||
|
||||
GSTextureFX9::OMBlendSelector om_bsel;
|
||||
|
||||
om_bsel.abe = PRIM->ABE || (prim == 1 || prim == 2) && PRIM->AA1;
|
||||
om_bsel.a = context->ALPHA.A;
|
||||
om_bsel.b = context->ALPHA.B;
|
||||
om_bsel.c = context->ALPHA.C;
|
||||
om_bsel.d = context->ALPHA.D;
|
||||
om_bsel.wr = (context->FRAME.FBMSK & 0x000000ff) != 0x000000ff;
|
||||
om_bsel.wg = (context->FRAME.FBMSK & 0x0000ff00) != 0x0000ff00;
|
||||
om_bsel.wb = (context->FRAME.FBMSK & 0x00ff0000) != 0x00ff0000;
|
||||
om_bsel.wa = (context->FRAME.FBMSK & 0xff000000) != 0xff000000;
|
||||
|
||||
BYTE bf = context->ALPHA.FIX >= 0x80 ? 0xff : (BYTE)(context->ALPHA.FIX * 2);
|
||||
|
||||
// vs
|
||||
|
||||
GSTextureFX9::VSSelector vs_sel;
|
||||
|
||||
vs_sel.bppz = 0;
|
||||
vs_sel.tme = PRIM->TME;
|
||||
vs_sel.fst = PRIM->FST;
|
||||
vs_sel.logz = m_logz ? 1 : 0;
|
||||
|
||||
if(om_dssel.zte && om_dssel.ztst > 0 && om_dssel.zwe)
|
||||
{
|
||||
if(context->ZBUF.PSM == PSM_PSMZ24)
|
||||
{
|
||||
if(WrapZ(0xffffff))
|
||||
{
|
||||
vs_sel.bppz = 1;
|
||||
om_dssel.ztst = 1;
|
||||
}
|
||||
}
|
||||
else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S)
|
||||
{
|
||||
if(WrapZ(0xffff))
|
||||
{
|
||||
vs_sel.bppz = 2;
|
||||
om_dssel.ztst = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GSTextureFX9::VSConstantBuffer vs_cb;
|
||||
|
||||
float sx = 2.0f * rt.m_scale.x / (rt.GetWidth() * 16);
|
||||
float sy = 2.0f * rt.m_scale.y / (rt.GetHeight() * 16);
|
||||
float ox = (float)(int)context->XYOFFSET.OFX;
|
||||
float oy = (float)(int)context->XYOFFSET.OFY;
|
||||
|
||||
vs_cb.VertexScale = GSVector4(sx, -sy, 1.0f / UINT_MAX, 0.0f);
|
||||
vs_cb.VertexOffset = GSVector4(ox * sx + 1, -(oy * sy + 1), 0.0f, -1.0f);
|
||||
vs_cb.TextureScale = GSVector2(1.0f, 1.0f);
|
||||
|
||||
if(PRIM->TME && PRIM->FST)
|
||||
{
|
||||
vs_cb.TextureScale.x = 1.0f / (16 << context->TEX0.TW);
|
||||
vs_cb.TextureScale.y = 1.0f / (16 << context->TEX0.TH);
|
||||
}
|
||||
|
||||
// ps
|
||||
|
||||
GSTextureFX9::PSSelector ps_sel;
|
||||
|
||||
ps_sel.fst = PRIM->FST;
|
||||
ps_sel.wms = context->CLAMP.WMS;
|
||||
ps_sel.wmt = context->CLAMP.WMT;
|
||||
ps_sel.bpp = 0;
|
||||
ps_sel.aem = env.TEXA.AEM;
|
||||
ps_sel.tfx = context->TEX0.TFX;
|
||||
ps_sel.tcc = context->TEX0.TCC;
|
||||
ps_sel.ate = context->TEST.ATE;
|
||||
ps_sel.atst = context->TEST.ATST;
|
||||
ps_sel.fog = PRIM->FGE;
|
||||
ps_sel.clr1 = om_bsel.abe && om_bsel.a == 1 && om_bsel.b == 2 && om_bsel.d == 1;
|
||||
ps_sel.rt = tex && tex->m_rendered;
|
||||
|
||||
GSTextureFX9::PSSamplerSelector ps_ssel;
|
||||
|
||||
ps_ssel.min = m_filter == 2 ? (context->TEX1.MMIN & 1) : m_filter;
|
||||
ps_ssel.mag = m_filter == 2 ? (context->TEX1.MMAG & 1) : m_filter;
|
||||
ps_ssel.tau = 0;
|
||||
ps_ssel.tav = 0;
|
||||
|
||||
GSTextureFX9::PSConstantBuffer ps_cb;
|
||||
|
||||
ps_cb.FogColor = GSVector4(env.FOGCOL.FCR, env.FOGCOL.FCG, env.FOGCOL.FCB, 0) / 255.0f;
|
||||
ps_cb.TA0 = (float)(int)env.TEXA.TA0 / 255;
|
||||
ps_cb.TA1 = (float)(int)env.TEXA.TA1 / 255;
|
||||
ps_cb.AREF = (float)(int)context->TEST.AREF / 255;
|
||||
|
||||
if(context->TEST.ATST == 2 || context->TEST.ATST == 5)
|
||||
{
|
||||
ps_cb.AREF -= 0.9f/256;
|
||||
}
|
||||
else if(context->TEST.ATST == 3 || context->TEST.ATST == 6)
|
||||
{
|
||||
ps_cb.AREF += 0.9f/256;
|
||||
}
|
||||
|
||||
if(tex)
|
||||
{
|
||||
ps_sel.bpp = tex->m_bpp2;
|
||||
|
||||
switch(context->CLAMP.WMS)
|
||||
{
|
||||
case 0:
|
||||
ps_ssel.tau = 1;
|
||||
break;
|
||||
case 1:
|
||||
ps_ssel.tau = 0;
|
||||
break;
|
||||
case 2:
|
||||
ps_cb.MINU = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW);
|
||||
ps_cb.MAXU = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW);
|
||||
ps_ssel.tau = 0;
|
||||
break;
|
||||
case 3:
|
||||
ps_cb.UMSK = context->CLAMP.MINU;
|
||||
ps_cb.UFIX = context->CLAMP.MAXU;
|
||||
ps_ssel.tau = 1;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
switch(context->CLAMP.WMT)
|
||||
{
|
||||
case 0:
|
||||
ps_ssel.tav = 1;
|
||||
break;
|
||||
case 1:
|
||||
ps_ssel.tav = 0;
|
||||
break;
|
||||
case 2:
|
||||
ps_cb.MINV = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH);
|
||||
ps_cb.MAXV = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH);
|
||||
ps_ssel.tav = 0;
|
||||
break;
|
||||
case 3:
|
||||
ps_cb.VMSK = context->CLAMP.MINV;
|
||||
ps_cb.VFIX = context->CLAMP.MAXV;
|
||||
ps_ssel.tav = 1;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
float w = (float)tex->m_texture.GetWidth();
|
||||
float h = (float)tex->m_texture.GetHeight();
|
||||
|
||||
ps_cb.WH = GSVector2(w, h);
|
||||
ps_cb.rWrH = GSVector2(1.0f / w, 1.0f / h);
|
||||
}
|
||||
else
|
||||
{
|
||||
ps_sel.tfx = 4;
|
||||
}
|
||||
|
||||
// rs
|
||||
|
||||
int w = rt.GetWidth();
|
||||
int h = rt.GetHeight();
|
||||
|
||||
CRect scissor = (CRect)GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in) & CRect(0, 0, w, h);
|
||||
|
||||
//
|
||||
|
||||
m_tfx.SetupOM(om_dssel, om_bsel, bf, rt, ds);
|
||||
m_tfx.SetupIA(m_vertices, m_count, topology);
|
||||
m_tfx.SetupVS(vs_sel, &vs_cb);
|
||||
m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel,
|
||||
tex ? (IDirect3DTexture9*)tex->m_texture : NULL,
|
||||
tex ? (IDirect3DTexture9*)tex->m_palette : NULL,
|
||||
m_psrr);
|
||||
m_tfx.SetupRS(w, h, scissor);
|
||||
|
||||
// draw
|
||||
|
||||
if(context->TEST.DoFirstPass())
|
||||
{
|
||||
m_dev.DrawPrimitive();
|
||||
}
|
||||
|
||||
if(context->TEST.DoSecondPass())
|
||||
{
|
||||
ASSERT(!env.PABE.PABE);
|
||||
|
||||
static const DWORD iatst[] = {1, 0, 5, 6, 7, 2, 3, 4};
|
||||
|
||||
ps_sel.atst = iatst[ps_sel.atst];
|
||||
|
||||
m_tfx.UpdatePS(ps_sel, &ps_cb, ps_ssel, m_psrr);
|
||||
|
||||
bool z = om_dssel.zwe;
|
||||
bool r = om_bsel.wr;
|
||||
bool g = om_bsel.wg;
|
||||
bool b = om_bsel.wb;
|
||||
bool a = om_bsel.wa;
|
||||
|
||||
switch(context->TEST.AFAIL)
|
||||
{
|
||||
case 0: z = r = g = b = a = false; break; // none
|
||||
case 1: z = false; break; // rgba
|
||||
case 2: r = g = b = a = false; break; // z
|
||||
case 3: z = a = false; break; // rgb
|
||||
default: __assume(0);
|
||||
}
|
||||
|
||||
if(z || r || g || b || a)
|
||||
{
|
||||
om_dssel.zwe = z;
|
||||
om_bsel.wr = r;
|
||||
om_bsel.wg = g;
|
||||
om_bsel.wb = b;
|
||||
om_bsel.wa = a;
|
||||
|
||||
m_tfx.UpdateOM(om_dssel, om_bsel, bf);
|
||||
|
||||
m_dev.DrawPrimitive();
|
||||
}
|
||||
}
|
||||
|
||||
m_dev.EndScene();
|
||||
|
||||
if(om_dssel.fba) UpdateFBA(rt);
|
||||
}
|
||||
|
||||
bool GSRendererHW9::WrapZ(float maxz)
|
||||
{
|
||||
// should only run once if z values are in the z buffer range
|
||||
|
||||
for(int i = 0, j = m_count; i < j; i++)
|
||||
{
|
||||
if(m_vertices[i].p.z <= maxz)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSRendererHW9::SetupDATE(Texture& rt, Texture& ds)
|
||||
{
|
||||
if(!m_context->TEST.DATE) return; // || (::GetAsyncKeyState(VK_CONTROL) & 0x8000)
|
||||
|
||||
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows
|
||||
|
||||
GSVector4 mm;
|
||||
|
||||
// TODO
|
||||
|
||||
mm = GSVector4(-1, -1, 1, 1);
|
||||
/*
|
||||
MinMaxXY(mm);
|
||||
|
||||
int w = rt.GetWidth();
|
||||
int h = rt.GetHeight();
|
||||
|
||||
float sx = 2.0f * rt.m_scale.x / (w * 16);
|
||||
float sy = 2.0f * rt.m_scale.y / (h * 16);
|
||||
float ox = (float)(int)m_context->XYOFFSET.OFX;
|
||||
float oy = (float)(int)m_context->XYOFFSET.OFY;
|
||||
|
||||
mm.x = (mm.x - ox) * sx - 1;
|
||||
mm.y = (mm.y - oy) * sy - 1;
|
||||
mm.z = (mm.z - ox) * sx - 1;
|
||||
mm.w = (mm.w - oy) * sy - 1;
|
||||
|
||||
if(mm.x < -1) mm.x = -1;
|
||||
if(mm.y < -1) mm.y = -1;
|
||||
if(mm.z > +1) mm.z = +1;
|
||||
if(mm.w > +1) mm.w = +1;
|
||||
*/
|
||||
GSVector4 uv = (mm + 1.0f) / 2.0f;
|
||||
|
||||
//
|
||||
|
||||
m_dev.BeginScene();
|
||||
|
||||
// om
|
||||
|
||||
GSTexture9 tmp;
|
||||
|
||||
m_dev.CreateRenderTarget(tmp, rt.GetWidth(), rt.GetHeight());
|
||||
|
||||
m_dev.OMSetRenderTargets(tmp, ds);
|
||||
m_dev.OMSetDepthStencilState(&m_date.dss, 1);
|
||||
m_dev.OMSetBlendState(&m_date.bs, 0);
|
||||
|
||||
m_dev->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0, 0);
|
||||
|
||||
// ia
|
||||
|
||||
GSVertexPT1 vertices[] =
|
||||
{
|
||||
{GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)},
|
||||
{GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)},
|
||||
{GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)},
|
||||
{GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)},
|
||||
};
|
||||
|
||||
m_dev.IASetVertexBuffer(4, vertices);
|
||||
m_dev.IASetInputLayout(m_dev.m_convert.il);
|
||||
m_dev.IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP);
|
||||
|
||||
// vs
|
||||
|
||||
m_dev.VSSetShader(m_dev.m_convert.vs, NULL, 0);
|
||||
|
||||
// ps
|
||||
|
||||
m_dev.PSSetShaderResources(rt, NULL);
|
||||
m_dev.PSSetShader(m_dev.m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL, 0);
|
||||
m_dev.PSSetSamplerState(&m_dev.m_convert.pt);
|
||||
|
||||
// rs
|
||||
|
||||
m_dev.RSSet(tmp.GetWidth(), tmp.GetHeight());
|
||||
|
||||
//
|
||||
|
||||
m_dev.DrawPrimitive();
|
||||
|
||||
//
|
||||
|
||||
m_dev.EndScene();
|
||||
|
||||
m_dev.Recycle(tmp);
|
||||
}
|
||||
|
||||
void GSRendererHW9::UpdateFBA(Texture& rt)
|
||||
{
|
||||
m_dev.BeginScene();
|
||||
|
||||
// om
|
||||
|
||||
m_dev.OMSetDepthStencilState(&m_fba.dss, 2);
|
||||
m_dev.OMSetBlendState(&m_fba.bs, 0);
|
||||
|
||||
// vs
|
||||
|
||||
m_dev.VSSetShader(NULL, NULL, 0);
|
||||
|
||||
// ps
|
||||
|
||||
m_dev.PSSetShader(m_dev.m_convert.ps[4], NULL, 0);
|
||||
|
||||
//
|
||||
|
||||
int w = rt.GetWidth();
|
||||
int h = rt.GetHeight();
|
||||
|
||||
GSVertexP vertices[] =
|
||||
{
|
||||
{GSVector4(0, 0, 0, 0)},
|
||||
{GSVector4(w, 0, 0, 0)},
|
||||
{GSVector4(0, h, 0, 0)},
|
||||
{GSVector4(w, h, 0, 0)},
|
||||
};
|
||||
|
||||
m_dev->SetFVF(D3DFVF_XYZRHW);
|
||||
|
||||
m_dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertices, sizeof(vertices[0]));
|
||||
|
||||
//
|
||||
|
||||
m_dev.EndScene();
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSRendererHW.h"
|
||||
#include "GSVertexHW.h"
|
||||
#include "GSTextureCache9.h"
|
||||
#include "GSTextureFX9.h"
|
||||
|
||||
class GSRendererHW9 : public GSRendererHW<GSDevice9, GSVertexHW9, GSTextureCache9>
|
||||
{
|
||||
typedef GSDevice9 Device;
|
||||
typedef GSVertexHW9 Vertex;
|
||||
typedef GSTextureCache9 TextureCache;
|
||||
|
||||
bool WrapZ(float maxz);
|
||||
|
||||
protected:
|
||||
GSTextureFX9 m_tfx;
|
||||
bool m_logz;
|
||||
|
||||
void Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex);
|
||||
|
||||
struct
|
||||
{
|
||||
Direct3DDepthStencilState9 dss;
|
||||
Direct3DBlendState9 bs;
|
||||
} m_date;
|
||||
|
||||
struct
|
||||
{
|
||||
bool enabled;
|
||||
Direct3DDepthStencilState9 dss;
|
||||
Direct3DBlendState9 bs;
|
||||
} m_fba;
|
||||
|
||||
void SetupDATE(Texture& rt, Texture& ds);
|
||||
void UpdateFBA(Texture& rt);
|
||||
|
||||
public:
|
||||
GSRendererHW9(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs);
|
||||
|
||||
bool Create(LPCTSTR title);
|
||||
|
||||
template<DWORD prim, DWORD tme, DWORD fst> void VertexKick(bool skip);
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 "GSRendererNull.h"
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSRenderer.h"
|
||||
#include "GSDeviceNull.h"
|
||||
|
||||
template<class Device> class GSRendererNull : public GSRendererT<Device, GSVertexNull>
|
||||
{
|
||||
protected:
|
||||
void Draw()
|
||||
{
|
||||
}
|
||||
|
||||
bool GetOutput(int i, Texture& t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
GSRendererNull(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
|
||||
: GSRendererT<Device, GSVertexNull>(base, mt, irq, nloophack, rs)
|
||||
{
|
||||
InitVertexKick<GSRendererNull<Device> >();
|
||||
}
|
||||
|
||||
template<DWORD prim, DWORD tme, DWORD fst> void VertexKick(bool skip)
|
||||
{
|
||||
}
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 "GSRendererSW.h"
|
||||
|
||||
const GSVector4 g_pos_scale(1.0f / 16, 1.0f / 16, 1.0f, 128.0f);
|
|
@ -0,0 +1,858 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSRenderer.h"
|
||||
#include "GSTextureCacheSW.h"
|
||||
#include "GSDrawScanline.h"
|
||||
|
||||
extern const GSVector4 g_pos_scale;
|
||||
|
||||
template <class Device>
|
||||
class GSRendererSW : public GSRendererT<Device, GSVertexSW>
|
||||
{
|
||||
protected:
|
||||
GSRasterizerList m_rl;
|
||||
GSTextureCacheSW* m_tc;
|
||||
GSVertexTrace m_vtrace;
|
||||
Texture m_texture[2];
|
||||
bool m_reset;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
// TODO: GSreset can come from the main thread too => crash
|
||||
// m_tc->RemoveAll();
|
||||
|
||||
m_reset = true;
|
||||
|
||||
__super::Reset();
|
||||
}
|
||||
|
||||
void VSync(int field)
|
||||
{
|
||||
__super::VSync(field);
|
||||
|
||||
m_tc->IncAge();
|
||||
|
||||
if(m_reset)
|
||||
{
|
||||
m_tc->RemoveAll();
|
||||
|
||||
m_reset = false;
|
||||
}
|
||||
|
||||
// if((m_perfmon.GetFrame() & 255) == 0) m_rl.PrintStats();
|
||||
}
|
||||
|
||||
void ResetDevice()
|
||||
{
|
||||
m_texture[0] = Texture();
|
||||
m_texture[1] = Texture();
|
||||
}
|
||||
|
||||
bool GetOutput(int i, Texture& t)
|
||||
{
|
||||
CRect r(0, 0, DISPFB[i]->FBW * 64, GetFrameRect(i).bottom);
|
||||
|
||||
// TODO: round up bottom
|
||||
|
||||
if(m_texture[i].GetWidth() != r.Width() || m_texture[i].GetHeight() != r.Height())
|
||||
{
|
||||
m_texture[i] = Texture();
|
||||
}
|
||||
|
||||
if(!m_texture[i] && !m_dev.CreateTexture(m_texture[i], r.Width(), r.Height()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GIFRegTEX0 TEX0;
|
||||
|
||||
TEX0.TBP0 = DISPFB[i]->Block();
|
||||
TEX0.TBW = DISPFB[i]->FBW;
|
||||
TEX0.PSM = DISPFB[i]->PSM;
|
||||
|
||||
GIFRegCLAMP CLAMP;
|
||||
|
||||
CLAMP.WMS = CLAMP.WMT = 1;
|
||||
|
||||
// TODO
|
||||
static BYTE* buff = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16);
|
||||
static int pitch = 1024 * 4;
|
||||
|
||||
m_mem.ReadTexture(r, buff, pitch, TEX0, m_env.TEXA, CLAMP);
|
||||
|
||||
m_texture[i].Update(r, buff, pitch);
|
||||
|
||||
t = m_texture[i];
|
||||
|
||||
if(s_dump)
|
||||
{
|
||||
CString str;
|
||||
str.Format(_T("c:\\temp1\\_%05d_f%I64d_fr%d_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM);
|
||||
if(s_save) t.Save(str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryAlphaTest(DWORD& fm, DWORD& zm)
|
||||
{
|
||||
const GSDrawingEnvironment& env = m_env;
|
||||
const GSDrawingContext* context = m_context;
|
||||
|
||||
bool pass = true;
|
||||
|
||||
if(context->TEST.ATST == ATST_NEVER)
|
||||
{
|
||||
pass = false;
|
||||
}
|
||||
else if(context->TEST.ATST != ATST_ALWAYS)
|
||||
{
|
||||
GSVector4i af = GSVector4i(m_vtrace.m_min.c.wwww(m_vtrace.m_max.c)) >> 7;
|
||||
|
||||
int amin, amax;
|
||||
|
||||
if(PRIM->TME && (context->TEX0.TCC || context->TEX0.TFX == TFX_DECAL))
|
||||
{
|
||||
DWORD bpp = GSLocalMemory::m_psm[context->TEX0.PSM].trbpp;
|
||||
DWORD cbpp = GSLocalMemory::m_psm[context->TEX0.CPSM].trbpp;
|
||||
DWORD pal = GSLocalMemory::m_psm[context->TEX0.PSM].pal;
|
||||
|
||||
if(bpp == 32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(bpp == 24)
|
||||
{
|
||||
amin = env.TEXA.AEM ? 0 : env.TEXA.TA0;
|
||||
amax = env.TEXA.TA0;
|
||||
}
|
||||
else if(bpp == 16)
|
||||
{
|
||||
amin = env.TEXA.AEM ? 0 : min(env.TEXA.TA0, env.TEXA.TA1);
|
||||
amax = max(env.TEXA.TA0, env.TEXA.TA1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mem.m_clut.GetAlphaMinMax32(amin, amax);
|
||||
}
|
||||
|
||||
switch(context->TEX0.TFX)
|
||||
{
|
||||
case TFX_MODULATE:
|
||||
amin = (amin * af.x) >> 7;
|
||||
amax = (amax * af.z) >> 7;
|
||||
if(amin > 255) amin = 255;
|
||||
if(amax > 255) amax = 255;
|
||||
break;
|
||||
case TFX_DECAL:
|
||||
break;
|
||||
case TFX_HIGHLIGHT:
|
||||
amin = amin + af.x;
|
||||
amax = amax + af.z;
|
||||
if(amin > 255) amin = 255;
|
||||
if(amax > 255) amax = 255;
|
||||
break;
|
||||
case TFX_HIGHLIGHT2:
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
amin = af.x;
|
||||
amax = af.z;
|
||||
}
|
||||
|
||||
int aref = context->TEST.AREF;
|
||||
|
||||
switch(context->TEST.ATST)
|
||||
{
|
||||
case ATST_NEVER:
|
||||
pass = false;
|
||||
break;
|
||||
case ATST_ALWAYS:
|
||||
pass = true;
|
||||
break;
|
||||
case ATST_LESS:
|
||||
if(amax < aref) pass = true;
|
||||
else if(amin >= aref) pass = false;
|
||||
else return false;
|
||||
break;
|
||||
case ATST_LEQUAL:
|
||||
if(amax <= aref) pass = true;
|
||||
else if(amin > aref) pass = false;
|
||||
else return false;
|
||||
break;
|
||||
case ATST_EQUAL:
|
||||
if(amin == aref && amax == aref) pass = true;
|
||||
else if(amin > aref || amax < aref) pass = false;
|
||||
else return false;
|
||||
break;
|
||||
case ATST_GEQUAL:
|
||||
if(amin >= aref) pass = true;
|
||||
else if(amax < aref) pass = false;
|
||||
else return false;
|
||||
break;
|
||||
case ATST_GREATER:
|
||||
if(amin > aref) pass = true;
|
||||
else if(amax <= aref) pass = false;
|
||||
else return false;
|
||||
break;
|
||||
case ATST_NOTEQUAL:
|
||||
if(amin == aref && amax == aref) pass = false;
|
||||
else if(amin > aref || amax < aref) pass = true;
|
||||
else return false;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(!pass)
|
||||
{
|
||||
switch(context->TEST.AFAIL)
|
||||
{
|
||||
case AFAIL_KEEP: fm = zm = 0xffffffff; break;
|
||||
case AFAIL_FB_ONLY: zm = 0xffffffff; break;
|
||||
case AFAIL_ZB_ONLY: fm = 0xffffffff; break;
|
||||
case AFAIL_RGB_ONLY: fm |= 0xff000000; zm = 0xffffffff; break;
|
||||
default: __assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetScanlineParam(GSScanlineParam& p, GS_PRIM_CLASS primclass)
|
||||
{
|
||||
const GSDrawingEnvironment& env = m_env;
|
||||
const GSDrawingContext* context = m_context;
|
||||
|
||||
p.vm = m_mem.m_vm32;
|
||||
|
||||
p.fbo = m_mem.GetOffset(context->FRAME.Block(), context->FRAME.FBW, context->FRAME.PSM);
|
||||
p.zbo = m_mem.GetOffset(context->ZBUF.Block(), context->FRAME.FBW, context->ZBUF.PSM);
|
||||
p.fzbo = m_mem.GetOffset4(context->FRAME, context->ZBUF);
|
||||
|
||||
p.sel.dw = 0;
|
||||
|
||||
p.sel.fpsm = 3;
|
||||
p.sel.zpsm = 3;
|
||||
p.sel.atst = ATST_ALWAYS;
|
||||
p.sel.tfx = TFX_NONE;
|
||||
p.sel.abe = 255;
|
||||
p.sel.sprite = primclass == GS_SPRITE_CLASS ? 1 : 0;
|
||||
|
||||
p.fm = context->FRAME.FBMSK;
|
||||
p.zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0;
|
||||
|
||||
if(context->TEST.ZTE && context->TEST.ZTST == ZTST_NEVER)
|
||||
{
|
||||
p.fm = 0xffffffff;
|
||||
p.zm = 0xffffffff;
|
||||
}
|
||||
|
||||
if(PRIM->TME)
|
||||
{
|
||||
m_mem.m_clut.Read32(context->TEX0, env.TEXA);
|
||||
}
|
||||
|
||||
if(context->TEST.ATE)
|
||||
{
|
||||
if(!TryAlphaTest(p.fm, p.zm))
|
||||
{
|
||||
p.sel.atst = context->TEST.ATST;
|
||||
p.sel.afail = context->TEST.AFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
bool fwrite = p.fm != 0xffffffff;
|
||||
bool ftest = p.sel.atst != ATST_ALWAYS || context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24;
|
||||
|
||||
if(fwrite || ftest)
|
||||
{
|
||||
p.sel.fpsm = GSUtil::EncodePSM(context->FRAME.PSM);
|
||||
|
||||
if((primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS) && m_vtrace.m_eq.rgba != 15)
|
||||
{
|
||||
p.sel.iip = PRIM->IIP;
|
||||
}
|
||||
|
||||
if(PRIM->TME)
|
||||
{
|
||||
p.sel.tfx = context->TEX0.TFX;
|
||||
p.sel.tcc = context->TEX0.TCC;
|
||||
p.sel.fst = PRIM->FST;
|
||||
p.sel.ltf = context->TEX1.IsLinear();
|
||||
p.sel.tlu = GSLocalMemory::m_psm[context->TEX0.PSM].pal > 0;
|
||||
|
||||
if(p.sel.iip == 0 && p.sel.tfx == TFX_MODULATE && p.sel.tcc)
|
||||
{
|
||||
if(m_vtrace.m_eq.rgba == 15 && (m_vtrace.m_min.c == GSVector4(128.0f * 128.0f)).alltrue())
|
||||
{
|
||||
// modulate does not do anything when vertex color is 0x80
|
||||
|
||||
p.sel.tfx = TFX_DECAL;
|
||||
}
|
||||
}
|
||||
|
||||
if(p.sel.tfx == TFX_DECAL)
|
||||
{
|
||||
p.sel.tcc = 1;
|
||||
}
|
||||
|
||||
if(p.sel.fst == 0)
|
||||
{
|
||||
// skip per pixel division if q is constant
|
||||
|
||||
GSVertexSW* v = m_vertices;
|
||||
|
||||
if(m_vtrace.m_eq.q)
|
||||
{
|
||||
p.sel.fst = 1;
|
||||
|
||||
if(v[0].t.z != 1.0f)
|
||||
{
|
||||
GSVector4 w = v[0].t.zzzz().rcpnr();
|
||||
|
||||
for(int i = 0, j = m_count; i < j; i++)
|
||||
{
|
||||
v[i].t *= w;
|
||||
}
|
||||
|
||||
m_vtrace.m_min.t *= w;
|
||||
m_vtrace.m_max.t *= w;
|
||||
}
|
||||
}
|
||||
else if(primclass == GS_SPRITE_CLASS)
|
||||
{
|
||||
p.sel.fst = 1;
|
||||
|
||||
GSVector4 tmin = GSVector4(FLT_MAX);
|
||||
GSVector4 tmax = GSVector4(-FLT_MAX);
|
||||
|
||||
for(int i = 0, j = m_count; i < j; i += 2)
|
||||
{
|
||||
GSVector4 w = v[i + 1].t.zzzz().rcpnr();
|
||||
|
||||
GSVector4 v0 = v[i + 0].t * w;
|
||||
GSVector4 v1 = v[i + 1].t * w;
|
||||
|
||||
v[i + 0].t = v0;
|
||||
v[i + 1].t = v1;
|
||||
|
||||
tmin = tmin.minv(v0).minv(v1);
|
||||
tmax = tmax.maxv(v0).maxv(v1);
|
||||
}
|
||||
|
||||
m_vtrace.m_max.t = tmax;
|
||||
m_vtrace.m_min.t = tmin;
|
||||
}
|
||||
}
|
||||
|
||||
if(p.sel.fst)
|
||||
{
|
||||
// if q is constant we can do the half pel shift for bilinear sampling on the vertices
|
||||
|
||||
if(p.sel.ltf)
|
||||
{
|
||||
GSVector4 half(0x8000, 0x8000);
|
||||
|
||||
GSVertexSW* v = m_vertices;
|
||||
|
||||
for(int i = 0, j = m_count; i < j; i++)
|
||||
{
|
||||
v[i].t -= half;
|
||||
}
|
||||
|
||||
m_vtrace.m_min.t -= half;
|
||||
m_vtrace.m_max.t += half;
|
||||
}
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
GSVector4 tmin = GSVector4(FLT_MAX);
|
||||
GSVector4 tmax = GSVector4(-FLT_MAX);
|
||||
|
||||
GSVertexSW* v = m_vertices;
|
||||
|
||||
for(int i = 0, j = m_count; i < j; i++)
|
||||
{
|
||||
GSVector4 v0 = v[i].t * v[i].t.zzzz().rcpnr();
|
||||
|
||||
tmin = tmin.minv(v0);
|
||||
tmax = tmax.maxv(v0);
|
||||
}
|
||||
|
||||
if(p.sel.ltf)
|
||||
{
|
||||
GSVector4 half(0x8000, 0x8000);
|
||||
|
||||
tmin -= half;
|
||||
tmax += half;
|
||||
}
|
||||
|
||||
m_vtrace.min.t = tmin;
|
||||
m_vtrace.max.t = tmax;
|
||||
}
|
||||
*/
|
||||
|
||||
CRect r;
|
||||
|
||||
int w = 1 << context->TEX0.TW;
|
||||
int h = 1 << context->TEX0.TH;
|
||||
|
||||
MinMaxUV(w, h, r, p.sel.fst);
|
||||
|
||||
const GSTextureCacheSW::GSTexture* t = m_tc->Lookup(context->TEX0, env.TEXA, &r);
|
||||
|
||||
if(!t) {ASSERT(0); return;}
|
||||
|
||||
p.tex = t->m_buff;
|
||||
p.clut = m_mem.m_clut;
|
||||
p.tw = t->m_tw;
|
||||
}
|
||||
|
||||
p.sel.fge = PRIM->FGE;
|
||||
|
||||
if(context->FRAME.PSM != PSM_PSMCT24)
|
||||
{
|
||||
p.sel.date = context->TEST.DATE;
|
||||
}
|
||||
|
||||
if(PRIM->ABE)
|
||||
{
|
||||
if(!context->ALPHA.IsOpaque())
|
||||
{
|
||||
p.sel.abe = context->ALPHA.ai32[0];
|
||||
p.sel.pabe = env.PABE.PABE;
|
||||
}
|
||||
}
|
||||
|
||||
if(PRIM->AA1)
|
||||
{
|
||||
// TODO: automatic alpha blending (ABE=1, A=0 B=1 C=0 D=1)
|
||||
}
|
||||
|
||||
if(p.sel.date
|
||||
|| p.sel.abea == 1 || p.sel.abeb == 1 || p.sel.abec == 1 || p.sel.abed == 1
|
||||
|| p.sel.atst != ATST_ALWAYS && p.sel.afail == AFAIL_RGB_ONLY
|
||||
|| p.sel.fpsm == 0 && p.fm != 0 && p.fm != 0xffffffff
|
||||
|| p.sel.fpsm == 1 && (p.fm & 0x00ffffff) != 0 && (p.fm & 0x00ffffff) != 0x00ffffff
|
||||
|| p.sel.fpsm == 2 && (p.fm & 0x80f8f8f8) != 0 && (p.fm & 0x80f8f8f8) != 0x80f8f8f8)
|
||||
{
|
||||
p.sel.rfb = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool zwrite = p.zm != 0xffffffff;
|
||||
bool ztest = context->TEST.ZTE && context->TEST.ZTST > 1;
|
||||
|
||||
if(zwrite || ztest)
|
||||
{
|
||||
p.sel.zpsm = GSUtil::EncodePSM(context->ZBUF.PSM);
|
||||
p.sel.ztst = ztest ? context->TEST.ZTST : 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Draw()
|
||||
{
|
||||
m_vtrace.Update(m_vertices, m_count);
|
||||
|
||||
GS_PRIM_CLASS primclass = GSUtil::GetPrimClass(PRIM->PRIM);
|
||||
|
||||
GSScanlineParam p;
|
||||
|
||||
GetScanlineParam(p, primclass);
|
||||
|
||||
if((p.fm & p.zm) == 0xffffffff)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(s_dump)
|
||||
{
|
||||
CString str;
|
||||
str.Format(_T("c:\\temp1\\_%05d_f%I64d_tex_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), (int)m_context->TEX0.TBP0, (int)m_context->TEX0.PSM);
|
||||
if(PRIM->TME) if(s_save) {m_mem.SaveBMP(str, m_context->TEX0.TBP0, m_context->TEX0.TBW, m_context->TEX0.PSM, 1 << m_context->TEX0.TW, 1 << m_context->TEX0.TH);}
|
||||
str.Format(_T("c:\\temp1\\_%05d_f%I64d_rt0_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), m_context->FRAME.Block(), m_context->FRAME.PSM);
|
||||
if(s_save) {m_mem.SaveBMP(str, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameSize(1).cx, 512);}//GetFrameSize(1).cy);
|
||||
str.Format(_T("c:\\temp1\\_%05d_f%I64d_rz0_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), m_context->ZBUF.Block(), m_context->ZBUF.PSM);
|
||||
if(s_savez) {m_mem.SaveBMP(str, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameSize(1).cx, 512);}
|
||||
}
|
||||
|
||||
GSRasterizerData data;
|
||||
|
||||
data.scissor = GSVector4i(m_context->scissor.in);
|
||||
data.scissor.z = min(data.scissor.z, (int)m_context->FRAME.FBW * 64); // TODO: find a game that overflows and check which one is the right behaviour
|
||||
data.primclass = primclass;
|
||||
data.vertices = m_vertices;
|
||||
data.count = m_count;
|
||||
data.param = &p;
|
||||
|
||||
m_rl.Draw(&data);
|
||||
|
||||
GSRasterizerStats stats;
|
||||
|
||||
m_rl.GetStats(stats);
|
||||
|
||||
m_perfmon.Put(GSPerfMon::Draw, 1);
|
||||
m_perfmon.Put(GSPerfMon::Prim, stats.prims);
|
||||
m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels);
|
||||
|
||||
GSVector4i pos(m_vtrace.m_min.p.xyxy(m_vtrace.m_max.p));
|
||||
|
||||
GSVector4i scissor = data.scissor;
|
||||
|
||||
CRect r;
|
||||
|
||||
r.left = max(scissor.x, min(scissor.z, pos.x));
|
||||
r.top = max(scissor.y, min(scissor.w, pos.y));
|
||||
r.right = max(scissor.x, min(scissor.z, pos.z));
|
||||
r.bottom = max(scissor.y, min(scissor.w, pos.w));
|
||||
|
||||
GIFRegBITBLTBUF BITBLTBUF;
|
||||
|
||||
BITBLTBUF.DBW = m_context->FRAME.FBW;
|
||||
|
||||
if(p.fm != 0xffffffff)
|
||||
{
|
||||
BITBLTBUF.DBP = m_context->FRAME.Block();
|
||||
BITBLTBUF.DPSM = m_context->FRAME.PSM;
|
||||
|
||||
m_tc->InvalidateVideoMem(BITBLTBUF, r);
|
||||
}
|
||||
|
||||
if(p.zm != 0xffffffff)
|
||||
{
|
||||
BITBLTBUF.DBP = m_context->ZBUF.Block();
|
||||
BITBLTBUF.DPSM = m_context->ZBUF.PSM;
|
||||
|
||||
m_tc->InvalidateVideoMem(BITBLTBUF, r);
|
||||
}
|
||||
|
||||
if(s_dump)
|
||||
{
|
||||
CString str;
|
||||
str.Format(_T("c:\\temp1\\_%05d_f%I64d_rt1_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), m_context->FRAME.Block(), m_context->FRAME.PSM);
|
||||
if(s_save) {m_mem.SaveBMP(str, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameSize(1).cx, 512);}//GetFrameSize(1).cy);
|
||||
str.Format(_T("c:\\temp1\\_%05d_f%I64d_rz1_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), m_context->ZBUF.Block(), m_context->ZBUF.PSM);
|
||||
if(s_savez) {m_mem.SaveBMP(str, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameSize(1).cx, 512);}
|
||||
}
|
||||
}
|
||||
|
||||
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r)
|
||||
{
|
||||
m_tc->InvalidateVideoMem(BITBLTBUF, r);
|
||||
}
|
||||
|
||||
void MinMaxUV(int w, int h, CRect& r, DWORD fst)
|
||||
{
|
||||
const GSDrawingContext* context = m_context;
|
||||
|
||||
int wms = context->CLAMP.WMS;
|
||||
int wmt = context->CLAMP.WMT;
|
||||
|
||||
int minu = (int)context->CLAMP.MINU;
|
||||
int minv = (int)context->CLAMP.MINV;
|
||||
int maxu = (int)context->CLAMP.MAXU;
|
||||
int maxv = (int)context->CLAMP.MAXV;
|
||||
|
||||
GSVector4i vr(0, 0, w, h);
|
||||
|
||||
switch(wms)
|
||||
{
|
||||
case CLAMP_REPEAT:
|
||||
break;
|
||||
case CLAMP_CLAMP:
|
||||
break;
|
||||
case CLAMP_REGION_CLAMP:
|
||||
if(vr.x < minu) vr.x = minu;
|
||||
if(vr.z > maxu + 1) vr.z = maxu + 1;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT:
|
||||
vr.x = maxu;
|
||||
vr.z = vr.x + (minu + 1);
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
switch(wmt)
|
||||
{
|
||||
case CLAMP_REPEAT:
|
||||
break;
|
||||
case CLAMP_CLAMP:
|
||||
break;
|
||||
case CLAMP_REGION_CLAMP:
|
||||
if(vr.y < minv) vr.y = minv;
|
||||
if(vr.w > maxv + 1) vr.w = maxv + 1;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT:
|
||||
vr.y = maxv;
|
||||
vr.w = vr.y + (minv + 1);
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
if(fst)
|
||||
{
|
||||
GSVector4i uv = GSVector4i(m_vtrace.m_min.t.xyxy(m_vtrace.m_max.t)).sra32(16);
|
||||
/*
|
||||
int tw = context->TEX0.TW;
|
||||
int th = context->TEX0.TH;
|
||||
|
||||
GSVector4i u = uv & GSVector4i::xffffffff().srl32(32 - tw);
|
||||
GSVector4i v = uv & GSVector4i::xffffffff().srl32(32 - th);
|
||||
|
||||
GSVector4i uu = uv.sra32(tw);
|
||||
GSVector4i vv = uv.sra32(th);
|
||||
|
||||
int mask = (uu.upl32(vv) == uu.uph32(vv)).mask();
|
||||
*/
|
||||
switch(wms)
|
||||
{
|
||||
case CLAMP_REPEAT:
|
||||
/*
|
||||
if(mask & 0x000f)
|
||||
{
|
||||
if(vr.x < u.x) vr.x = u.x;
|
||||
if(vr.z > u.z + 1) vr.z = u.z + 1;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
case CLAMP_CLAMP:
|
||||
case CLAMP_REGION_CLAMP:
|
||||
if(vr.x < uv.x) vr.x = uv.x;
|
||||
if(vr.z > uv.z + 1) vr.z = uv.z + 1;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT: // TODO
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
switch(wmt)
|
||||
{
|
||||
case CLAMP_REPEAT:
|
||||
/*
|
||||
if(mask & 0xf000)
|
||||
{
|
||||
if(vr.y < v.y) vr.y = v.y;
|
||||
if(vr.w > v.w + 1) vr.w = v.w + 1;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
case CLAMP_CLAMP:
|
||||
case CLAMP_REGION_CLAMP:
|
||||
if(vr.y < uv.y) vr.y = uv.y;
|
||||
if(vr.w > uv.w + 1) vr.w = uv.w + 1;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT: // TODO
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
r = vr;
|
||||
|
||||
r &= CRect(0, 0, w, h);
|
||||
}
|
||||
|
||||
public:
|
||||
GSRendererSW(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, int threads)
|
||||
: GSRendererT(base, mt, irq, nloophack, rs)
|
||||
{
|
||||
m_rl.Create<GSDrawScanline>(this, threads);
|
||||
|
||||
m_tc = new GSTextureCacheSW(this);
|
||||
|
||||
InitVertexKick<GSRendererSW<Device> >();
|
||||
}
|
||||
|
||||
virtual ~GSRendererSW()
|
||||
{
|
||||
delete m_tc;
|
||||
}
|
||||
|
||||
template<DWORD prim, DWORD tme, DWORD fst>
|
||||
void VertexKick(bool skip)
|
||||
{
|
||||
const GSDrawingContext* context = m_context;
|
||||
|
||||
GSVector4i xy = GSVector4i::load((int)m_v.XYZ.ai32[0]);
|
||||
|
||||
xy = xy.insert16<3>(m_v.FOG.F);
|
||||
xy = xy.upl16();
|
||||
xy -= context->XYOFFSET;
|
||||
|
||||
GSVertexSW v;
|
||||
|
||||
v.p = GSVector4(xy) * g_pos_scale;
|
||||
|
||||
v.c = GSVector4(GSVector4i::load((int)m_v.RGBAQ.ai32[0]).u8to32() << 7);
|
||||
|
||||
if(tme)
|
||||
{
|
||||
float q;
|
||||
|
||||
if(fst)
|
||||
{
|
||||
v.t = GSVector4(((GSVector4i)m_v.UV).upl16() << (16 - 4));
|
||||
q = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
v.t = GSVector4(m_v.ST.S, m_v.ST.T);
|
||||
v.t *= GSVector4(0x10000 << context->TEX0.TW, 0x10000 << context->TEX0.TH);
|
||||
q = m_v.RGBAQ.Q;
|
||||
}
|
||||
|
||||
v.t = v.t.xyxy(GSVector4::load(q));
|
||||
}
|
||||
|
||||
GSVertexSW& dst = m_vl.AddTail();
|
||||
|
||||
dst = v;
|
||||
|
||||
dst.p.z = (float)min(m_v.XYZ.Z, 0xffffff00); // max value which can survive the DWORD => float => DWORD conversion
|
||||
|
||||
DWORD count = 0;
|
||||
|
||||
if(GSVertexSW* v = DrawingKick<prim>(skip, count))
|
||||
{
|
||||
GSVector4 pmin, pmax;
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
pmin = v[0].p;
|
||||
pmax = v[0].p;
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
case GS_SPRITE:
|
||||
pmin = v[0].p.minv(v[1].p);
|
||||
pmax = v[0].p.maxv(v[1].p);
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
pmin = v[0].p.minv(v[1].p).minv(v[2].p);
|
||||
pmax = v[0].p.maxv(v[1].p).maxv(v[2].p);
|
||||
break;
|
||||
}
|
||||
|
||||
GSVector4 scissor = context->scissor.ex;
|
||||
|
||||
GSVector4 test = (pmax < scissor) | (pmin > scissor.zwxy());
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
case GS_SPRITE:
|
||||
test |= pmin.ceil() == pmax.ceil();
|
||||
break;
|
||||
}
|
||||
|
||||
if(test.mask() & 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
case GS_LINESTRIP:
|
||||
if(PRIM->IIP == 0) {v[0].c = v[1].c;}
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
if(PRIM->IIP == 0) {v[0].c = v[2].c; v[1].c = v[2].c;}
|
||||
break;
|
||||
case GS_SPRITE:
|
||||
break;
|
||||
}
|
||||
|
||||
if(m_count >= 3 && m_count < 30)
|
||||
{
|
||||
GSVertexSW* v = &m_vertices[m_count - 3];
|
||||
|
||||
int tl = 0;
|
||||
int br = 0;
|
||||
|
||||
bool isquad = false;
|
||||
|
||||
switch(prim)
|
||||
{
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
case GS_TRIANGLELIST:
|
||||
isquad = GSVertexSW::IsQuad(v, tl, br);
|
||||
break;
|
||||
}
|
||||
|
||||
if(isquad)
|
||||
{
|
||||
m_count -= 3;
|
||||
|
||||
if(m_count > 0)
|
||||
{
|
||||
tl += m_count;
|
||||
br += m_count;
|
||||
|
||||
Flush();
|
||||
}
|
||||
|
||||
if(tl != 0) m_vertices[0] = m_vertices[tl];
|
||||
if(br != 1) m_vertices[1] = m_vertices[br];
|
||||
|
||||
m_count = 2;
|
||||
|
||||
UINT32 tmp = PRIM->PRIM;
|
||||
PRIM->PRIM = GS_SPRITE;
|
||||
|
||||
Flush();
|
||||
|
||||
PRIM->PRIM = tmp;
|
||||
|
||||
m_perfmon.Put(GSPerfMon::Quad, 1);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_count += count;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 "GSSetting.h"
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct GSSetting
|
||||
{
|
||||
DWORD id;
|
||||
const TCHAR* name;
|
||||
const TCHAR* note;
|
||||
|
||||
static void InitComboBox(const GSSetting* settings, int count, CComboBox& combobox, DWORD sel, DWORD maxid = ~0)
|
||||
{
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
if(settings[i].id <= maxid)
|
||||
{
|
||||
CString str = settings[i].name;
|
||||
if(settings[i].note != NULL) str = str + _T(" (") + settings[i].note + _T(")");
|
||||
int item = combobox.AddString(str);
|
||||
combobox.SetItemData(item, settings[i].id);
|
||||
if(settings[i].id == sel) combobox.SetCurSel(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* 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 "GSdx.h"
|
||||
#include "GSSettingsDlg.h"
|
||||
#include "GSUtil.h"
|
||||
#include <shlobj.h>
|
||||
#include <afxpriv.h>
|
||||
|
||||
GSSetting GSSettingsDlg::g_renderers[] =
|
||||
{
|
||||
{0, _T("Direct3D9 (Hardware)"), NULL},
|
||||
{1, _T("Direct3D9 (Software)"), NULL},
|
||||
{2, _T("Direct3D9 (Null)"), NULL},
|
||||
{3, _T("Direct3D10 (Hardware)"), NULL},
|
||||
{4, _T("Direct3D10 (Software)"), NULL},
|
||||
{5, _T("Direct3D10 (Null)"), NULL},
|
||||
{6, _T("Null (Software)"), NULL},
|
||||
{7, _T("Null (Null)"), NULL},
|
||||
};
|
||||
|
||||
GSSetting GSSettingsDlg::g_psversion[] =
|
||||
{
|
||||
{D3DPS_VERSION(3, 0), _T("Pixel Shader 3.0"), NULL},
|
||||
{D3DPS_VERSION(2, 0), _T("Pixel Shader 2.0"), NULL},
|
||||
//{D3DPS_VERSION(1, 4), _T("Pixel Shader 1.4"), NULL},
|
||||
//{D3DPS_VERSION(1, 1), _T("Pixel Shader 1.1"), NULL},
|
||||
//{D3DPS_VERSION(0, 0), _T("Fixed Pipeline (bogus)"), NULL},
|
||||
};
|
||||
|
||||
GSSetting GSSettingsDlg::g_interlace[] =
|
||||
{
|
||||
{0, _T("None"), NULL},
|
||||
{1, _T("Weave tff"), _T("saw-tooth")},
|
||||
{2, _T("Weave bff"), _T("saw-tooth")},
|
||||
{3, _T("Bob tff"), _T("use blend if shaking")},
|
||||
{4, _T("Bob bff"), _T("use blend if shaking")},
|
||||
{5, _T("Blend tff"), _T("slight blur, 1/2 fps")},
|
||||
{6, _T("Blend bff"), _T("slight blur, 1/2 fps")},
|
||||
};
|
||||
|
||||
GSSetting GSSettingsDlg::g_aspectratio[] =
|
||||
{
|
||||
{0, _T("Stretch"), NULL},
|
||||
{1, _T("4:3"), NULL},
|
||||
{2, _T("16:9"), NULL},
|
||||
};
|
||||
|
||||
IMPLEMENT_DYNAMIC(GSSettingsDlg, CDialog)
|
||||
GSSettingsDlg::GSSettingsDlg(CWnd* pParent /*=NULL*/)
|
||||
: CDialog(GSSettingsDlg::IDD, pParent)
|
||||
, m_tvout(FALSE)
|
||||
, m_filter(1)
|
||||
, m_nloophack(2)
|
||||
, m_nativeres(FALSE)
|
||||
, m_vsync(FALSE)
|
||||
, m_logz(FALSE)
|
||||
, m_fba(TRUE)
|
||||
{
|
||||
}
|
||||
|
||||
GSSettingsDlg::~GSSettingsDlg()
|
||||
{
|
||||
}
|
||||
|
||||
LRESULT GSSettingsDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
|
||||
|
||||
if(message == WM_INITDIALOG)
|
||||
{
|
||||
SendMessage(WM_KICKIDLE);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GSSettingsDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
__super::DoDataExchange(pDX);
|
||||
DDX_Control(pDX, IDC_COMBO3, m_resolution);
|
||||
DDX_Control(pDX, IDC_COMBO1, m_renderer);
|
||||
DDX_Control(pDX, IDC_COMBO4, m_psversion);
|
||||
DDX_Control(pDX, IDC_COMBO2, m_interlace);
|
||||
DDX_Control(pDX, IDC_COMBO5, m_aspectratio);
|
||||
DDX_Check(pDX, IDC_CHECK3, m_tvout);
|
||||
DDX_Check(pDX, IDC_CHECK4, m_filter);
|
||||
DDX_Check(pDX, IDC_CHECK6, m_nloophack);
|
||||
DDX_Control(pDX, IDC_SPIN1, m_resx);
|
||||
DDX_Control(pDX, IDC_SPIN2, m_resy);
|
||||
DDX_Control(pDX, IDC_SPIN3, m_swthreads);
|
||||
DDX_Check(pDX, IDC_CHECK1, m_nativeres);
|
||||
DDX_Control(pDX, IDC_EDIT1, m_resxedit);
|
||||
DDX_Control(pDX, IDC_EDIT2, m_resyedit);
|
||||
DDX_Control(pDX, IDC_EDIT3, m_swthreadsedit);
|
||||
DDX_Check(pDX, IDC_CHECK2, m_vsync);
|
||||
DDX_Check(pDX, IDC_CHECK5, m_logz);
|
||||
DDX_Check(pDX, IDC_CHECK7, m_fba);
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(GSSettingsDlg, CDialog)
|
||||
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
|
||||
ON_UPDATE_COMMAND_UI(IDC_SPIN1, OnUpdateResolution)
|
||||
ON_UPDATE_COMMAND_UI(IDC_SPIN2, OnUpdateResolution)
|
||||
ON_UPDATE_COMMAND_UI(IDC_EDIT1, OnUpdateResolution)
|
||||
ON_UPDATE_COMMAND_UI(IDC_EDIT2, OnUpdateResolution)
|
||||
ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateD3D9Options)
|
||||
ON_UPDATE_COMMAND_UI(IDC_CHECK3, OnUpdateD3D9Options)
|
||||
ON_UPDATE_COMMAND_UI(IDC_CHECK5, OnUpdateD3D9Options)
|
||||
ON_UPDATE_COMMAND_UI(IDC_CHECK7, OnUpdateD3D9Options)
|
||||
ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateSWOptions)
|
||||
ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateSWOptions)
|
||||
ON_CBN_SELCHANGE(IDC_COMBO1, &GSSettingsDlg::OnCbnSelchangeCombo1)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
void GSSettingsDlg::OnKickIdle()
|
||||
{
|
||||
UpdateDialogControls(this, false);
|
||||
}
|
||||
|
||||
BOOL GSSettingsDlg::OnInitDialog()
|
||||
{
|
||||
__super::OnInitDialog();
|
||||
|
||||
CWinApp* pApp = AfxGetApp();
|
||||
|
||||
D3DCAPS9 caps;
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
caps.PixelShaderVersion = D3DPS_VERSION(0, 0);
|
||||
|
||||
m_modes.RemoveAll();
|
||||
|
||||
// windowed
|
||||
|
||||
{
|
||||
D3DDISPLAYMODE mode;
|
||||
memset(&mode, 0, sizeof(mode));
|
||||
m_modes.AddTail(mode);
|
||||
|
||||
int iItem = m_resolution.AddString(_T("Windowed"));
|
||||
m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition());
|
||||
m_resolution.SetCurSel(iItem);
|
||||
}
|
||||
|
||||
// fullscreen
|
||||
|
||||
if(CComPtr<IDirect3D9> d3d = Direct3DCreate9(D3D_SDK_VERSION))
|
||||
{
|
||||
UINT ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0);
|
||||
UINT ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0);
|
||||
UINT ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0);
|
||||
|
||||
UINT nModes = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8);
|
||||
|
||||
for(UINT i = 0; i < nModes; i++)
|
||||
{
|
||||
D3DDISPLAYMODE mode;
|
||||
|
||||
if(S_OK == d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode))
|
||||
{
|
||||
CString str;
|
||||
str.Format(_T("%dx%d %dHz"), mode.Width, mode.Height, mode.RefreshRate);
|
||||
int iItem = m_resolution.AddString(str);
|
||||
|
||||
m_modes.AddTail(mode);
|
||||
m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition());
|
||||
|
||||
if(ModeWidth == mode.Width && ModeHeight == mode.Height && ModeRefreshRate == mode.RefreshRate)
|
||||
{
|
||||
m_resolution.SetCurSel(iItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
|
||||
}
|
||||
|
||||
bool isdx10avail = GSUtil::IsDirect3D10Available();
|
||||
|
||||
CAtlArray<GSSetting> renderers;
|
||||
|
||||
for(size_t i = 0; i < countof(g_renderers); i++)
|
||||
{
|
||||
if(i >= 3 && i <= 5 && !isdx10avail) continue;
|
||||
|
||||
renderers.Add(g_renderers[i]);
|
||||
}
|
||||
|
||||
GSSetting::InitComboBox(renderers.GetData(), renderers.GetCount(), m_renderer, pApp->GetProfileInt(_T("Settings"), _T("Renderer"), 0));
|
||||
GSSetting::InitComboBox(g_psversion, countof(g_psversion), m_psversion, pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)), caps.PixelShaderVersion);
|
||||
GSSetting::InitComboBox(g_interlace, countof(g_interlace), m_interlace, pApp->GetProfileInt(_T("Settings"), _T("Interlace"), 0));
|
||||
GSSetting::InitComboBox(g_aspectratio, countof(g_aspectratio), m_aspectratio, pApp->GetProfileInt(_T("Settings"), _T("AspectRatio"), 1));
|
||||
|
||||
OnCbnSelchangeCombo1();
|
||||
|
||||
//
|
||||
|
||||
m_filter = pApp->GetProfileInt(_T("Settings"), _T("filter"), 1);
|
||||
m_tvout = pApp->GetProfileInt(_T("Settings"), _T("tvout"), FALSE);
|
||||
m_nloophack = pApp->GetProfileInt(_T("Settings"), _T("nloophack"), 2);
|
||||
m_vsync = !!pApp->GetProfileInt(_T("Settings"), _T("vsync"), FALSE);
|
||||
m_logz = !!pApp->GetProfileInt(_T("Settings"), _T("logz"), FALSE);
|
||||
m_fba = !!pApp->GetProfileInt(_T("Settings"), _T("fba"), TRUE);
|
||||
|
||||
m_resx.SetRange(512, 4096);
|
||||
m_resy.SetRange(512, 4096);
|
||||
m_resx.SetPos(pApp->GetProfileInt(_T("Settings"), _T("resx"), 1024));
|
||||
m_resy.SetPos(pApp->GetProfileInt(_T("Settings"), _T("resy"), 1024));
|
||||
m_nativeres = !!pApp->GetProfileInt(_T("Settings"), _T("nativeres"), FALSE);
|
||||
|
||||
m_resx.EnableWindow(!m_nativeres);
|
||||
m_resy.EnableWindow(!m_nativeres);
|
||||
m_resxedit.EnableWindow(!m_nativeres);
|
||||
m_resyedit.EnableWindow(!m_nativeres);
|
||||
|
||||
m_swthreads.SetRange(1, 16);
|
||||
m_swthreads.SetPos(pApp->GetProfileInt(_T("Settings"), _T("swthreads"), 1));
|
||||
|
||||
//
|
||||
|
||||
UpdateData(FALSE);
|
||||
|
||||
return TRUE; // return TRUE unless you set the focus to a control
|
||||
// EXCEPTION: OCX Property Pages should return FALSE
|
||||
}
|
||||
|
||||
void GSSettingsDlg::OnOK()
|
||||
{
|
||||
CWinApp* pApp = AfxGetApp();
|
||||
|
||||
UpdateData();
|
||||
|
||||
if(m_resolution.GetCurSel() >= 0)
|
||||
{
|
||||
D3DDISPLAYMODE& mode = m_modes.GetAt((POSITION)m_resolution.GetItemData(m_resolution.GetCurSel()));
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("ModeWidth"), mode.Width);
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("ModeHeight"), mode.Height);
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("ModeRefreshRate"), mode.RefreshRate);
|
||||
}
|
||||
|
||||
if(m_renderer.GetCurSel() >= 0)
|
||||
{
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("Renderer"), (DWORD)m_renderer.GetItemData(m_renderer.GetCurSel()));
|
||||
}
|
||||
|
||||
if(m_psversion.GetCurSel() >= 0)
|
||||
{
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("PixelShaderVersion2"), (DWORD)m_psversion.GetItemData(m_psversion.GetCurSel()));
|
||||
}
|
||||
|
||||
if(m_interlace.GetCurSel() >= 0)
|
||||
{
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("Interlace"), (DWORD)m_interlace.GetItemData(m_interlace.GetCurSel()));
|
||||
}
|
||||
|
||||
if(m_aspectratio.GetCurSel() >= 0)
|
||||
{
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("AspectRatio"), (DWORD)m_aspectratio.GetItemData(m_aspectratio.GetCurSel()));
|
||||
}
|
||||
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("filter"), m_filter);
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("tvout"), m_tvout);
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("nloophack"), m_nloophack);
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("vsync"), m_vsync);
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("logz"), m_logz);
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("fba"), m_fba);
|
||||
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("resx"), m_resx.GetPos());
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("resy"), m_resy.GetPos());
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("swthreads"), m_swthreads.GetPos());
|
||||
pApp->WriteProfileInt(_T("Settings"), _T("nativeres"), m_nativeres);
|
||||
|
||||
__super::OnOK();
|
||||
}
|
||||
|
||||
void GSSettingsDlg::OnUpdateResolution(CCmdUI* pCmdUI)
|
||||
{
|
||||
UpdateData();
|
||||
|
||||
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
|
||||
|
||||
pCmdUI->Enable(!m_nativeres && (i == 0 || i == 3));
|
||||
}
|
||||
|
||||
void GSSettingsDlg::OnUpdateD3D9Options(CCmdUI* pCmdUI)
|
||||
{
|
||||
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
|
||||
|
||||
pCmdUI->Enable(i >= 0 && i <= 2);
|
||||
}
|
||||
|
||||
void GSSettingsDlg::OnUpdateSWOptions(CCmdUI* pCmdUI)
|
||||
{
|
||||
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
|
||||
|
||||
pCmdUI->Enable(i == 1 || i == 4 || i == 6);
|
||||
}
|
||||
|
||||
void GSSettingsDlg::OnCbnSelchangeCombo1()
|
||||
{
|
||||
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
|
||||
|
||||
GetDlgItem(IDC_LOGO9)->ShowWindow(i >= 0 && i <= 2 ? SW_SHOW : SW_HIDE);
|
||||
GetDlgItem(IDC_LOGO10)->ShowWindow(i >= 3 && i <= 5 ? SW_SHOW : SW_HIDE);
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSSetting.h"
|
||||
#include "resource.h"
|
||||
|
||||
class GSSettingsDlg : public CDialog
|
||||
{
|
||||
DECLARE_DYNAMIC(GSSettingsDlg)
|
||||
|
||||
private:
|
||||
CAtlList<D3DDISPLAYMODE> m_modes;
|
||||
|
||||
public:
|
||||
GSSettingsDlg(CWnd* pParent = NULL); // standard constructor
|
||||
virtual ~GSSettingsDlg();
|
||||
|
||||
static GSSetting g_renderers[];
|
||||
static GSSetting g_psversion[];
|
||||
static GSSetting g_interlace[];
|
||||
static GSSetting g_aspectratio[];
|
||||
|
||||
// Dialog Data
|
||||
enum { IDD = IDD_CONFIG };
|
||||
CComboBox m_resolution;
|
||||
CComboBox m_renderer;
|
||||
CComboBox m_psversion;
|
||||
CComboBox m_interlace;
|
||||
CComboBox m_aspectratio;
|
||||
BOOL m_tvout;
|
||||
int m_filter;
|
||||
int m_nloophack;
|
||||
CSpinButtonCtrl m_resx;
|
||||
CSpinButtonCtrl m_resy;
|
||||
CSpinButtonCtrl m_swthreads;
|
||||
BOOL m_nativeres;
|
||||
CEdit m_resxedit;
|
||||
CEdit m_resyedit;
|
||||
CEdit m_swthreadsedit;
|
||||
BOOL m_vsync;
|
||||
BOOL m_logz;
|
||||
BOOL m_fba;
|
||||
|
||||
protected:
|
||||
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
virtual BOOL OnInitDialog();
|
||||
virtual void OnOK();
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
public:
|
||||
afx_msg void OnKickIdle();
|
||||
afx_msg void OnUpdateResolution(CCmdUI* pCmdUI);
|
||||
afx_msg void OnUpdateD3D9Options(CCmdUI* pCmdUI);
|
||||
afx_msg void OnUpdateSWOptions(CCmdUI* pCmdUI);
|
||||
afx_msg void OnCbnSelchangeCombo1();
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS.h"
|
||||
#include "GSLocalMemory.h"
|
||||
#include "GSDrawingContext.h"
|
||||
#include "GSDrawingEnvironment.h"
|
||||
#include "GSVertex.h"
|
||||
#include "GSVertexList.h"
|
||||
#include "GSUtil.h"
|
||||
#include "GSDirtyRect.h"
|
||||
#include "GSPerfMon.h"
|
||||
#include "GSVector.h"
|
||||
#include "GSDevice.h"
|
||||
#include "GSCrc.h"
|
||||
#include "GSAlignedClass.h"
|
||||
#include "GSDump.h"
|
||||
|
||||
class GSState : public GSAlignedClass<16>
|
||||
{
|
||||
typedef void (GSState::*GIFPackedRegHandler)(GIFPackedReg* r);
|
||||
|
||||
GIFPackedRegHandler m_fpGIFPackedRegHandlers[16];
|
||||
|
||||
void GIFPackedRegHandlerNull(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerPRIM(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerRGBA(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerSTQ(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerUV(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerXYZF2(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerXYZ2(GIFPackedReg* r);
|
||||
template<int i> void GIFPackedRegHandlerTEX0(GIFPackedReg* r);
|
||||
template<int i> void GIFPackedRegHandlerCLAMP(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerFOG(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerXYZF3(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerXYZ3(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerA_D(GIFPackedReg* r);
|
||||
void GIFPackedRegHandlerA_D(GIFPackedReg* r, int size);
|
||||
void GIFPackedRegHandlerNOP(GIFPackedReg* r);
|
||||
|
||||
typedef void (GSState::*GIFRegHandler)(GIFReg* r);
|
||||
|
||||
GIFRegHandler m_fpGIFRegHandlers[256];
|
||||
|
||||
void GIFRegHandlerNull(GIFReg* r);
|
||||
void GIFRegHandlerPRIM(GIFReg* r);
|
||||
void GIFRegHandlerRGBAQ(GIFReg* r);
|
||||
void GIFRegHandlerST(GIFReg* r);
|
||||
void GIFRegHandlerUV(GIFReg* r);
|
||||
void GIFRegHandlerXYZF2(GIFReg* r);
|
||||
void GIFRegHandlerXYZ2(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerTEX0(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerCLAMP(GIFReg* r);
|
||||
void GIFRegHandlerFOG(GIFReg* r);
|
||||
void GIFRegHandlerXYZF3(GIFReg* r);
|
||||
void GIFRegHandlerXYZ3(GIFReg* r);
|
||||
void GIFRegHandlerNOP(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerTEX1(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerTEX2(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerXYOFFSET(GIFReg* r);
|
||||
void GIFRegHandlerPRMODECONT(GIFReg* r);
|
||||
void GIFRegHandlerPRMODE(GIFReg* r);
|
||||
void GIFRegHandlerTEXCLUT(GIFReg* r);
|
||||
void GIFRegHandlerSCANMSK(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerMIPTBP1(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerMIPTBP2(GIFReg* r);
|
||||
void GIFRegHandlerTEXA(GIFReg* r);
|
||||
void GIFRegHandlerFOGCOL(GIFReg* r);
|
||||
void GIFRegHandlerTEXFLUSH(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerSCISSOR(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerALPHA(GIFReg* r);
|
||||
void GIFRegHandlerDIMX(GIFReg* r);
|
||||
void GIFRegHandlerDTHE(GIFReg* r);
|
||||
void GIFRegHandlerCOLCLAMP(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerTEST(GIFReg* r);
|
||||
void GIFRegHandlerPABE(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerFBA(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerFRAME(GIFReg* r);
|
||||
template<int i> void GIFRegHandlerZBUF(GIFReg* r);
|
||||
void GIFRegHandlerBITBLTBUF(GIFReg* r);
|
||||
void GIFRegHandlerTRXPOS(GIFReg* r);
|
||||
void GIFRegHandlerTRXREG(GIFReg* r);
|
||||
void GIFRegHandlerTRXDIR(GIFReg* r);
|
||||
void GIFRegHandlerHWREG(GIFReg* r);
|
||||
void GIFRegHandlerSIGNAL(GIFReg* r);
|
||||
void GIFRegHandlerFINISH(GIFReg* r);
|
||||
void GIFRegHandlerLABEL(GIFReg* r);
|
||||
|
||||
int m_version;
|
||||
int m_sssize;
|
||||
|
||||
bool m_mt;
|
||||
void (*m_irq)();
|
||||
bool m_path3hack;
|
||||
int m_nloophack_org;
|
||||
|
||||
int m_x, m_y;
|
||||
int m_bytes;
|
||||
int m_maxbytes;
|
||||
BYTE* m_buff;
|
||||
|
||||
void FlushWrite();
|
||||
void FlushWrite(BYTE* mem, int len);
|
||||
|
||||
protected:
|
||||
bool IsBadFrame(int& skip);
|
||||
|
||||
typedef void (GSState::*VertexKickPtr)(bool skip);
|
||||
|
||||
VertexKickPtr m_vk[8][2][2];
|
||||
VertexKickPtr m_vkf;
|
||||
|
||||
template<class T> void InitVertexKick()
|
||||
{
|
||||
m_vk[GS_POINTLIST][0][0] = (VertexKickPtr)&T::VertexKick<GS_POINTLIST, 0, 0>;
|
||||
m_vk[GS_POINTLIST][0][1] = (VertexKickPtr)&T::VertexKick<GS_POINTLIST, 0, 0>;
|
||||
m_vk[GS_POINTLIST][1][0] = (VertexKickPtr)&T::VertexKick<GS_POINTLIST, 1, 0>;
|
||||
m_vk[GS_POINTLIST][1][1] = (VertexKickPtr)&T::VertexKick<GS_POINTLIST, 1, 1>;
|
||||
|
||||
m_vk[GS_LINELIST][0][0] = (VertexKickPtr)&T::VertexKick<GS_LINELIST, 0, 0>;
|
||||
m_vk[GS_LINELIST][0][1] = (VertexKickPtr)&T::VertexKick<GS_LINELIST, 0, 0>;
|
||||
m_vk[GS_LINELIST][1][0] = (VertexKickPtr)&T::VertexKick<GS_LINELIST, 1, 0>;
|
||||
m_vk[GS_LINELIST][1][1] = (VertexKickPtr)&T::VertexKick<GS_LINELIST, 1, 1>;
|
||||
|
||||
m_vk[GS_LINESTRIP][0][0] = (VertexKickPtr)&T::VertexKick<GS_LINESTRIP, 0, 0>;
|
||||
m_vk[GS_LINESTRIP][0][1] = (VertexKickPtr)&T::VertexKick<GS_LINESTRIP, 0, 0>;
|
||||
m_vk[GS_LINESTRIP][1][0] = (VertexKickPtr)&T::VertexKick<GS_LINESTRIP, 1, 0>;
|
||||
m_vk[GS_LINESTRIP][1][1] = (VertexKickPtr)&T::VertexKick<GS_LINESTRIP, 1, 1>;
|
||||
|
||||
m_vk[GS_TRIANGLELIST][0][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLELIST, 0, 0>;
|
||||
m_vk[GS_TRIANGLELIST][0][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLELIST, 0, 0>;
|
||||
m_vk[GS_TRIANGLELIST][1][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLELIST, 1, 0>;
|
||||
m_vk[GS_TRIANGLELIST][1][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLELIST, 1, 1>;
|
||||
|
||||
m_vk[GS_TRIANGLESTRIP][0][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLESTRIP, 0, 0>;
|
||||
m_vk[GS_TRIANGLESTRIP][0][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLESTRIP, 0, 0>;
|
||||
m_vk[GS_TRIANGLESTRIP][1][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLESTRIP, 1, 0>;
|
||||
m_vk[GS_TRIANGLESTRIP][1][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLESTRIP, 1, 1>;
|
||||
|
||||
m_vk[GS_TRIANGLEFAN][0][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLEFAN, 0, 0>;
|
||||
m_vk[GS_TRIANGLEFAN][0][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLEFAN, 0, 0>;
|
||||
m_vk[GS_TRIANGLEFAN][1][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLEFAN, 1, 0>;
|
||||
m_vk[GS_TRIANGLEFAN][1][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLEFAN, 1, 1>;
|
||||
|
||||
m_vk[GS_SPRITE][0][0] = (VertexKickPtr)&T::VertexKick<GS_SPRITE, 0, 0>;
|
||||
m_vk[GS_SPRITE][0][1] = (VertexKickPtr)&T::VertexKick<GS_SPRITE, 0, 0>;
|
||||
m_vk[GS_SPRITE][1][0] = (VertexKickPtr)&T::VertexKick<GS_SPRITE, 1, 0>;
|
||||
m_vk[GS_SPRITE][1][1] = (VertexKickPtr)&T::VertexKick<GS_SPRITE, 1, 1>;
|
||||
|
||||
m_vk[GS_INVALID][0][0] = &GSState::VertexKickNull;
|
||||
m_vk[GS_INVALID][0][1] = &GSState::VertexKickNull;
|
||||
m_vk[GS_INVALID][1][0] = &GSState::VertexKickNull;
|
||||
m_vk[GS_INVALID][1][1] = &GSState::VertexKickNull;
|
||||
}
|
||||
|
||||
void UpdateVertexKick()
|
||||
{
|
||||
m_vkf = m_vk[PRIM->PRIM][PRIM->TME][PRIM->FST];
|
||||
}
|
||||
|
||||
void VertexKickNull(bool skip)
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
void VertexKick(bool skip)
|
||||
{
|
||||
(this->*m_vkf)(skip);
|
||||
}
|
||||
|
||||
public:
|
||||
GIFRegPRIM* PRIM;
|
||||
GSRegPMODE* PMODE;
|
||||
GSRegSMODE1* SMODE1;
|
||||
GSRegSMODE2* SMODE2;
|
||||
GSRegDISPFB* DISPFB[2];
|
||||
GSRegDISPLAY* DISPLAY[2];
|
||||
GSRegEXTBUF* EXTBUF;
|
||||
GSRegEXTDATA* EXTDATA;
|
||||
GSRegEXTWRITE* EXTWRITE;
|
||||
GSRegBGCOLOR* BGCOLOR;
|
||||
GSRegCSR* CSR;
|
||||
GSRegIMR* IMR;
|
||||
GSRegBUSDIR* BUSDIR;
|
||||
GSRegSIGLBLID* SIGLBLID;
|
||||
|
||||
GIFPath m_path[3];
|
||||
GSLocalMemory m_mem;
|
||||
GSDrawingEnvironment m_env;
|
||||
GSDrawingContext* m_context;
|
||||
GSVertex m_v;
|
||||
float m_q;
|
||||
DWORD m_vprim;
|
||||
|
||||
GSPerfMon m_perfmon;
|
||||
bool m_nloophack;
|
||||
DWORD m_crc;
|
||||
int m_options;
|
||||
int m_frameskip;
|
||||
CRC::Game m_game;
|
||||
GSDump m_dump;
|
||||
|
||||
public:
|
||||
GSState(BYTE* base, bool mt, void (*irq)(), int nloophack);
|
||||
virtual ~GSState();
|
||||
|
||||
void ResetHandlers();
|
||||
|
||||
CPoint GetDisplayPos(int i);
|
||||
CSize GetDisplaySize(int i);
|
||||
CRect GetDisplayRect(int i);
|
||||
CSize GetDisplayPos();
|
||||
CSize GetDisplaySize();
|
||||
CRect GetDisplayRect();
|
||||
CPoint GetFramePos(int i);
|
||||
CSize GetFrameSize(int i);
|
||||
CRect GetFrameRect(int i);
|
||||
CSize GetFramePos();
|
||||
CSize GetFrameSize();
|
||||
CRect GetFrameRect();
|
||||
CSize GetDeviceSize(int i);
|
||||
CSize GetDeviceSize();
|
||||
bool IsEnabled(int i);
|
||||
int GetFPS();
|
||||
|
||||
virtual void Reset();
|
||||
virtual void Flush();
|
||||
virtual void FlushPrim() = 0;
|
||||
virtual void ResetPrim() = 0;
|
||||
virtual void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) {}
|
||||
virtual void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) {}
|
||||
virtual void InvalidateTextureCache() {}
|
||||
|
||||
void Move();
|
||||
void Write(BYTE* mem, int len);
|
||||
void Read(BYTE* mem, int len);
|
||||
|
||||
void SoftReset(BYTE mask);
|
||||
void WriteCSR(UINT32 csr) {CSR->ai32[1] = csr;}
|
||||
void ReadFIFO(BYTE* mem, int size);
|
||||
template<int index> void Transfer(BYTE* mem, UINT32 size);
|
||||
int Freeze(GSFreezeData* fd, bool sizeonly);
|
||||
int Defrost(const GSFreezeData* fd);
|
||||
void GetLastTag(UINT32* tag) {*tag = m_path3hack; m_path3hack = 0;}
|
||||
virtual void SetGameCRC(DWORD crc, int options);
|
||||
void SetFrameSkip(int frameskip);
|
||||
};
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* 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 "GSTables.h"
|
||||
|
||||
const BYTE blockTable32[4][8] = {
|
||||
{ 0, 1, 4, 5, 16, 17, 20, 21},
|
||||
{ 2, 3, 6, 7, 18, 19, 22, 23},
|
||||
{ 8, 9, 12, 13, 24, 25, 28, 29},
|
||||
{ 10, 11, 14, 15, 26, 27, 30, 31}
|
||||
};
|
||||
|
||||
const BYTE blockTable32Z[4][8] = {
|
||||
{ 24, 25, 28, 29, 8, 9, 12, 13},
|
||||
{ 26, 27, 30, 31, 10, 11, 14, 15},
|
||||
{ 16, 17, 20, 21, 0, 1, 4, 5},
|
||||
{ 18, 19, 22, 23, 2, 3, 6, 7}
|
||||
};
|
||||
|
||||
const BYTE blockTable16[8][4] = {
|
||||
{ 0, 2, 8, 10 },
|
||||
{ 1, 3, 9, 11 },
|
||||
{ 4, 6, 12, 14 },
|
||||
{ 5, 7, 13, 15 },
|
||||
{ 16, 18, 24, 26 },
|
||||
{ 17, 19, 25, 27 },
|
||||
{ 20, 22, 28, 30 },
|
||||
{ 21, 23, 29, 31 }
|
||||
};
|
||||
|
||||
const BYTE blockTable16S[8][4] = {
|
||||
{ 0, 2, 16, 18 },
|
||||
{ 1, 3, 17, 19 },
|
||||
{ 8, 10, 24, 26 },
|
||||
{ 9, 11, 25, 27 },
|
||||
{ 4, 6, 20, 22 },
|
||||
{ 5, 7, 21, 23 },
|
||||
{ 12, 14, 28, 30 },
|
||||
{ 13, 15, 29, 31 }
|
||||
};
|
||||
|
||||
const BYTE blockTable16Z[8][4] = {
|
||||
{ 24, 26, 16, 18 },
|
||||
{ 25, 27, 17, 19 },
|
||||
{ 28, 30, 20, 22 },
|
||||
{ 29, 31, 21, 23 },
|
||||
{ 8, 10, 0, 2 },
|
||||
{ 9, 11, 1, 3 },
|
||||
{ 12, 14, 4, 6 },
|
||||
{ 13, 15, 5, 7 }
|
||||
};
|
||||
|
||||
const BYTE blockTable16SZ[8][4] = {
|
||||
{ 24, 26, 8, 10 },
|
||||
{ 25, 27, 9, 11 },
|
||||
{ 16, 18, 0, 2 },
|
||||
{ 17, 19, 1, 3 },
|
||||
{ 28, 30, 12, 14 },
|
||||
{ 29, 31, 13, 15 },
|
||||
{ 20, 22, 4, 6 },
|
||||
{ 21, 23, 5, 7 }
|
||||
};
|
||||
|
||||
const BYTE blockTable8[4][8] = {
|
||||
{ 0, 1, 4, 5, 16, 17, 20, 21},
|
||||
{ 2, 3, 6, 7, 18, 19, 22, 23},
|
||||
{ 8, 9, 12, 13, 24, 25, 28, 29},
|
||||
{ 10, 11, 14, 15, 26, 27, 30, 31}
|
||||
};
|
||||
|
||||
const BYTE blockTable4[8][4] = {
|
||||
{ 0, 2, 8, 10 },
|
||||
{ 1, 3, 9, 11 },
|
||||
{ 4, 6, 12, 14 },
|
||||
{ 5, 7, 13, 15 },
|
||||
{ 16, 18, 24, 26 },
|
||||
{ 17, 19, 25, 27 },
|
||||
{ 20, 22, 28, 30 },
|
||||
{ 21, 23, 29, 31 }
|
||||
};
|
||||
|
||||
const BYTE columnTable32[8][8] = {
|
||||
{ 0, 1, 4, 5, 8, 9, 12, 13 },
|
||||
{ 2, 3, 6, 7, 10, 11, 14, 15 },
|
||||
{ 16, 17, 20, 21, 24, 25, 28, 29 },
|
||||
{ 18, 19, 22, 23, 26, 27, 30, 31 },
|
||||
{ 32, 33, 36, 37, 40, 41, 44, 45 },
|
||||
{ 34, 35, 38, 39, 42, 43, 46, 47 },
|
||||
{ 48, 49, 52, 53, 56, 57, 60, 61 },
|
||||
{ 50, 51, 54, 55, 58, 59, 62, 63 },
|
||||
};
|
||||
|
||||
const BYTE columnTable16[8][16] = {
|
||||
{ 0, 2, 8, 10, 16, 18, 24, 26,
|
||||
1, 3, 9, 11, 17, 19, 25, 27 },
|
||||
{ 4, 6, 12, 14, 20, 22, 28, 30,
|
||||
5, 7, 13, 15, 21, 23, 29, 31 },
|
||||
{ 32, 34, 40, 42, 48, 50, 56, 58,
|
||||
33, 35, 41, 43, 49, 51, 57, 59 },
|
||||
{ 36, 38, 44, 46, 52, 54, 60, 62,
|
||||
37, 39, 45, 47, 53, 55, 61, 63 },
|
||||
{ 64, 66, 72, 74, 80, 82, 88, 90,
|
||||
65, 67, 73, 75, 81, 83, 89, 91 },
|
||||
{ 68, 70, 76, 78, 84, 86, 92, 94,
|
||||
69, 71, 77, 79, 85, 87, 93, 95 },
|
||||
{ 96, 98, 104, 106, 112, 114, 120, 122,
|
||||
97, 99, 105, 107, 113, 115, 121, 123 },
|
||||
{ 100, 102, 108, 110, 116, 118, 124, 126,
|
||||
101, 103, 109, 111, 117, 119, 125, 127 },
|
||||
};
|
||||
|
||||
const BYTE columnTable8[16][16] = {
|
||||
{ 0, 4, 16, 20, 32, 36, 48, 52, // column 0
|
||||
2, 6, 18, 22, 34, 38, 50, 54 },
|
||||
{ 8, 12, 24, 28, 40, 44, 56, 60,
|
||||
10, 14, 26, 30, 42, 46, 58, 62 },
|
||||
{ 33, 37, 49, 53, 1, 5, 17, 21,
|
||||
35, 39, 51, 55, 3, 7, 19, 23 },
|
||||
{ 41, 45, 57, 61, 9, 13, 25, 29,
|
||||
43, 47, 59, 63, 11, 15, 27, 31 },
|
||||
{ 96, 100, 112, 116, 64, 68, 80, 84, // column 1
|
||||
98, 102, 114, 118, 66, 70, 82, 86 },
|
||||
{ 104, 108, 120, 124, 72, 76, 88, 92,
|
||||
106, 110, 122, 126, 74, 78, 90, 94 },
|
||||
{ 65, 69, 81, 85, 97, 101, 113, 117,
|
||||
67, 71, 83, 87, 99, 103, 115, 119 },
|
||||
{ 73, 77, 89, 93, 105, 109, 121, 125,
|
||||
75, 79, 91, 95, 107, 111, 123, 127 },
|
||||
{ 128, 132, 144, 148, 160, 164, 176, 180, // column 2
|
||||
130, 134, 146, 150, 162, 166, 178, 182 },
|
||||
{ 136, 140, 152, 156, 168, 172, 184, 188,
|
||||
138, 142, 154, 158, 170, 174, 186, 190 },
|
||||
{ 161, 165, 177, 181, 129, 133, 145, 149,
|
||||
163, 167, 179, 183, 131, 135, 147, 151 },
|
||||
{ 169, 173, 185, 189, 137, 141, 153, 157,
|
||||
171, 175, 187, 191, 139, 143, 155, 159 },
|
||||
{ 224, 228, 240, 244, 192, 196, 208, 212, // column 3
|
||||
226, 230, 242, 246, 194, 198, 210, 214 },
|
||||
{ 232, 236, 248, 252, 200, 204, 216, 220,
|
||||
234, 238, 250, 254, 202, 206, 218, 222 },
|
||||
{ 193, 197, 209, 213, 225, 229, 241, 245,
|
||||
195, 199, 211, 215, 227, 231, 243, 247 },
|
||||
{ 201, 205, 217, 221, 233, 237, 249, 253,
|
||||
203, 207, 219, 223, 235, 239, 251, 255 },
|
||||
};
|
||||
|
||||
const WORD columnTable4[16][32] = {
|
||||
{ 0, 8, 32, 40, 64, 72, 96, 104, // column 0
|
||||
2, 10, 34, 42, 66, 74, 98, 106,
|
||||
4, 12, 36, 44, 68, 76, 100, 108,
|
||||
6, 14, 38, 46, 70, 78, 102, 110 },
|
||||
{ 16, 24, 48, 56, 80, 88, 112, 120,
|
||||
18, 26, 50, 58, 82, 90, 114, 122,
|
||||
20, 28, 52, 60, 84, 92, 116, 124,
|
||||
22, 30, 54, 62, 86, 94, 118, 126 },
|
||||
{ 65, 73, 97, 105, 1, 9, 33, 41,
|
||||
67, 75, 99, 107, 3, 11, 35, 43,
|
||||
69, 77, 101, 109, 5, 13, 37, 45,
|
||||
71, 79, 103, 111, 7, 15, 39, 47 },
|
||||
{ 81, 89, 113, 121, 17, 25, 49, 57,
|
||||
83, 91, 115, 123, 19, 27, 51, 59,
|
||||
85, 93, 117, 125, 21, 29, 53, 61,
|
||||
87, 95, 119, 127, 23, 31, 55, 63 },
|
||||
{ 192, 200, 224, 232, 128, 136, 160, 168, // column 1
|
||||
194, 202, 226, 234, 130, 138, 162, 170,
|
||||
196, 204, 228, 236, 132, 140, 164, 172,
|
||||
198, 206, 230, 238, 134, 142, 166, 174 },
|
||||
{ 208, 216, 240, 248, 144, 152, 176, 184,
|
||||
210, 218, 242, 250, 146, 154, 178, 186,
|
||||
212, 220, 244, 252, 148, 156, 180, 188,
|
||||
214, 222, 246, 254, 150, 158, 182, 190 },
|
||||
{ 129, 137, 161, 169, 193, 201, 225, 233,
|
||||
131, 139, 163, 171, 195, 203, 227, 235,
|
||||
133, 141, 165, 173, 197, 205, 229, 237,
|
||||
135, 143, 167, 175, 199, 207, 231, 239 },
|
||||
{ 145, 153, 177, 185, 209, 217, 241, 249,
|
||||
147, 155, 179, 187, 211, 219, 243, 251,
|
||||
149, 157, 181, 189, 213, 221, 245, 253,
|
||||
151, 159, 183, 191, 215, 223, 247, 255 },
|
||||
{ 256, 264, 288, 296, 320, 328, 352, 360, // column 2
|
||||
258, 266, 290, 298, 322, 330, 354, 362,
|
||||
260, 268, 292, 300, 324, 332, 356, 364,
|
||||
262, 270, 294, 302, 326, 334, 358, 366 },
|
||||
{ 272, 280, 304, 312, 336, 344, 368, 376,
|
||||
274, 282, 306, 314, 338, 346, 370, 378,
|
||||
276, 284, 308, 316, 340, 348, 372, 380,
|
||||
278, 286, 310, 318, 342, 350, 374, 382 },
|
||||
{ 321, 329, 353, 361, 257, 265, 289, 297,
|
||||
323, 331, 355, 363, 259, 267, 291, 299,
|
||||
325, 333, 357, 365, 261, 269, 293, 301,
|
||||
327, 335, 359, 367, 263, 271, 295, 303 },
|
||||
{ 337, 345, 369, 377, 273, 281, 305, 313,
|
||||
339, 347, 371, 379, 275, 283, 307, 315,
|
||||
341, 349, 373, 381, 277, 285, 309, 317,
|
||||
343, 351, 375, 383, 279, 287, 311, 319 },
|
||||
{ 448, 456, 480, 488, 384, 392, 416, 424, // column 3
|
||||
450, 458, 482, 490, 386, 394, 418, 426,
|
||||
452, 460, 484, 492, 388, 396, 420, 428,
|
||||
454, 462, 486, 494, 390, 398, 422, 430 },
|
||||
{ 464, 472, 496, 504, 400, 408, 432, 440,
|
||||
466, 474, 498, 506, 402, 410, 434, 442,
|
||||
468, 476, 500, 508, 404, 412, 436, 444,
|
||||
470, 478, 502, 510, 406, 414, 438, 446 },
|
||||
{ 385, 393, 417, 425, 449, 457, 481, 489,
|
||||
387, 395, 419, 427, 451, 459, 483, 491,
|
||||
389, 397, 421, 429, 453, 461, 485, 493,
|
||||
391, 399, 423, 431, 455, 463, 487, 495 },
|
||||
{ 401, 409, 433, 441, 465, 473, 497, 505,
|
||||
403, 411, 435, 443, 467, 475, 499, 507,
|
||||
405, 413, 437, 445, 469, 477, 501, 509,
|
||||
407, 415, 439, 447, 471, 479, 503, 511 },
|
||||
};
|
||||
|
||||
const BYTE clutTableT32I8[128] =
|
||||
{
|
||||
0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15,
|
||||
64, 65, 68, 69, 72, 73, 76, 77, 66, 67, 70, 71, 74, 75, 78, 79,
|
||||
16, 17, 20, 21, 24, 25, 28, 29, 18, 19, 22, 23, 26, 27, 30, 31,
|
||||
80, 81, 84, 85, 88, 89, 92, 93, 82, 83, 86, 87, 90, 91, 94, 95,
|
||||
32, 33, 36, 37, 40, 41, 44, 45, 34, 35, 38, 39, 42, 43, 46, 47,
|
||||
96, 97, 100, 101, 104, 105, 108, 109, 98, 99, 102, 103, 106, 107, 110, 111,
|
||||
48, 49, 52, 53, 56, 57, 60, 61, 50, 51, 54, 55, 58, 59, 62, 63,
|
||||
112, 113, 116, 117, 120, 121, 124, 125, 114, 115, 118, 119, 122, 123, 126, 127
|
||||
};
|
||||
|
||||
const BYTE clutTableT32I4[16] =
|
||||
{
|
||||
0, 1, 4, 5, 8, 9, 12, 13,
|
||||
2, 3, 6, 7, 10, 11, 14, 15
|
||||
};
|
||||
|
||||
const BYTE clutTableT16I8[32] =
|
||||
{
|
||||
0, 2, 8, 10, 16, 18, 24, 26,
|
||||
4, 6, 12, 14, 20, 22, 28, 30,
|
||||
1, 3, 9, 11, 17, 19, 25, 27,
|
||||
5, 7, 13, 15, 21, 23, 29, 31
|
||||
};
|
||||
|
||||
const BYTE clutTableT16I4[16] =
|
||||
{
|
||||
0, 2, 8, 10, 16, 18, 24, 26,
|
||||
4, 6, 12, 14, 20, 22, 28, 30
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern const BYTE blockTable32[4][8];
|
||||
extern const BYTE blockTable32Z[4][8];
|
||||
extern const BYTE blockTable16[8][4];
|
||||
extern const BYTE blockTable16S[8][4];
|
||||
extern const BYTE blockTable16Z[8][4];
|
||||
extern const BYTE blockTable16SZ[8][4];
|
||||
extern const BYTE blockTable8[4][8];
|
||||
extern const BYTE blockTable4[8][4];
|
||||
extern const BYTE columnTable32[8][8];
|
||||
extern const BYTE columnTable16[8][16];
|
||||
extern const BYTE columnTable8[16][16];
|
||||
extern const WORD columnTable4[16][32];
|
||||
extern const BYTE clutTableT32I8[128];
|
||||
extern const BYTE clutTableT32I4[16];
|
||||
extern const BYTE clutTableT16I8[32];
|
||||
extern const BYTE clutTableT16I4[16];
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 "GSTexture.h"
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSVector.h"
|
||||
|
||||
class GSTexture
|
||||
{
|
||||
public:
|
||||
GSVector2 m_scale;
|
||||
|
||||
public:
|
||||
GSTexture() : m_scale(1, 1) {}
|
||||
virtual ~GSTexture() {}
|
||||
|
||||
enum {None, RenderTarget, DepthStencil, Texture, Offscreen};
|
||||
|
||||
virtual operator bool() = 0;
|
||||
virtual int GetType() const = 0;
|
||||
virtual int GetWidth() const = 0;
|
||||
virtual int GetHeight() const = 0;
|
||||
virtual int GetFormat() const = 0;
|
||||
virtual bool Update(const CRect& r, const void* data, int pitch) = 0;
|
||||
virtual bool Map(BYTE** bits, int& pitch, const RECT* r = NULL) = 0;
|
||||
virtual void Unmap() = 0;
|
||||
virtual bool Save(CString fn, bool dds = false) = 0;
|
||||
|
||||
CSize GetSize() {return CSize(GetWidth(), GetHeight());}
|
||||
};
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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 "GSTexture10.h"
|
||||
|
||||
GSTexture10::GSTexture10()
|
||||
{
|
||||
memset(&m_desc, 0, sizeof(m_desc));
|
||||
}
|
||||
|
||||
GSTexture10::GSTexture10(ID3D10Texture2D* texture)
|
||||
: m_texture(texture)
|
||||
{
|
||||
ASSERT(m_texture);
|
||||
|
||||
m_texture->GetDevice(&m_dev);
|
||||
m_texture->GetDesc(&m_desc);
|
||||
}
|
||||
|
||||
GSTexture10::~GSTexture10()
|
||||
{
|
||||
}
|
||||
|
||||
GSTexture10::operator bool()
|
||||
{
|
||||
return !!m_texture;
|
||||
}
|
||||
|
||||
int GSTexture10::GetType() const
|
||||
{
|
||||
if(m_desc.BindFlags & D3D10_BIND_RENDER_TARGET) return GSTexture::RenderTarget;
|
||||
if(m_desc.BindFlags & D3D10_BIND_DEPTH_STENCIL) return GSTexture::DepthStencil;
|
||||
if(m_desc.BindFlags & D3D10_BIND_SHADER_RESOURCE) return GSTexture::Texture;
|
||||
if(m_desc.Usage == D3D10_USAGE_STAGING) return GSTexture::Offscreen;
|
||||
return GSTexture::None;
|
||||
}
|
||||
|
||||
int GSTexture10::GetWidth() const
|
||||
{
|
||||
return m_desc.Width;
|
||||
}
|
||||
|
||||
int GSTexture10::GetHeight() const
|
||||
{
|
||||
return m_desc.Height;
|
||||
}
|
||||
|
||||
int GSTexture10::GetFormat() const
|
||||
{
|
||||
return m_desc.Format;
|
||||
}
|
||||
|
||||
bool GSTexture10::Update(const CRect& r, const void* data, int pitch)
|
||||
{
|
||||
if(m_dev && m_texture)
|
||||
{
|
||||
D3D10_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1};
|
||||
|
||||
m_dev->UpdateSubresource(m_texture, 0, &box, data, pitch, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GSTexture10::Map(BYTE** bits, int& pitch, const RECT* r)
|
||||
{
|
||||
if(m_texture)
|
||||
{
|
||||
D3D10_MAPPED_TEXTURE2D map;
|
||||
|
||||
if(SUCCEEDED(m_texture->Map(0, D3D10_MAP_READ_WRITE, 0, &map)))
|
||||
{
|
||||
*bits = (BYTE*)map.pData;
|
||||
pitch = (int)map.RowPitch;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GSTexture10::Unmap()
|
||||
{
|
||||
if(m_texture)
|
||||
{
|
||||
m_texture->Unmap(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool GSTexture10::Save(CString fn, bool dds)
|
||||
{
|
||||
CComPtr<ID3D10Resource> res;
|
||||
|
||||
if(m_desc.BindFlags & D3D10_BIND_DEPTH_STENCIL)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
|
||||
m_texture->GetDesc(&desc);
|
||||
|
||||
desc.Usage = D3D10_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
|
||||
|
||||
CComPtr<ID3D10Texture2D> src, dst;
|
||||
|
||||
hr = m_dev->CreateTexture2D(&desc, NULL, &src);
|
||||
|
||||
m_dev->CopyResource(src, m_texture);
|
||||
|
||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||
|
||||
hr = m_dev->CreateTexture2D(&desc, NULL, &dst);
|
||||
|
||||
D3D10_MAPPED_TEXTURE2D sm, dm;
|
||||
|
||||
hr = src->Map(0, D3D10_MAP_READ, 0, &sm);
|
||||
hr = dst->Map(0, D3D10_MAP_WRITE, 0, &dm);
|
||||
|
||||
BYTE* s = (BYTE*)sm.pData;
|
||||
BYTE* d = (BYTE*)dm.pData;
|
||||
|
||||
for(UINT y = 0; y < desc.Height; y++, s += sm.RowPitch, d += dm.RowPitch)
|
||||
{
|
||||
for(UINT x = 0; x < desc.Width; x++)
|
||||
{
|
||||
((UINT*)d)[x] = (UINT)(((float*)s)[x*2] * UINT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
src->Unmap(0);
|
||||
dst->Unmap(0);
|
||||
|
||||
res = dst;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = m_texture;
|
||||
}
|
||||
|
||||
return SUCCEEDED(D3DX10SaveTextureToFile(res, dds ? D3DX10_IFF_DDS : D3DX10_IFF_BMP, fn));
|
||||
}
|
||||
|
||||
ID3D10Texture2D* GSTexture10::operator->()
|
||||
{
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
GSTexture10::operator ID3D10Texture2D*()
|
||||
{
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
GSTexture10::operator ID3D10ShaderResourceView*()
|
||||
{
|
||||
if(!m_srv && m_dev && m_texture)
|
||||
{
|
||||
m_dev->CreateShaderResourceView(m_texture, NULL, &m_srv);
|
||||
}
|
||||
|
||||
return m_srv;
|
||||
}
|
||||
|
||||
GSTexture10::operator ID3D10RenderTargetView*()
|
||||
{
|
||||
ASSERT(m_dev);
|
||||
|
||||
if(!m_rtv && m_dev && m_texture)
|
||||
{
|
||||
m_dev->CreateRenderTargetView(m_texture, NULL, &m_rtv);
|
||||
}
|
||||
|
||||
return m_rtv;
|
||||
}
|
||||
|
||||
GSTexture10::operator ID3D10DepthStencilView*()
|
||||
{
|
||||
if(!m_dsv && m_dev && m_texture)
|
||||
{
|
||||
m_dev->CreateDepthStencilView(m_texture, NULL, &m_dsv);
|
||||
}
|
||||
|
||||
return m_dsv;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSTexture.h"
|
||||
|
||||
class GSTexture10 : public GSTexture
|
||||
{
|
||||
CComPtr<ID3D10Device> m_dev;
|
||||
CComPtr<ID3D10Texture2D> m_texture;
|
||||
D3D10_TEXTURE2D_DESC m_desc;
|
||||
CComPtr<ID3D10ShaderResourceView> m_srv;
|
||||
CComPtr<ID3D10RenderTargetView> m_rtv;
|
||||
CComPtr<ID3D10DepthStencilView> m_dsv;
|
||||
|
||||
public:
|
||||
GSTexture10();
|
||||
explicit GSTexture10(ID3D10Texture2D* texture);
|
||||
virtual ~GSTexture10();
|
||||
|
||||
operator bool();
|
||||
|
||||
int GetType() const;
|
||||
int GetWidth() const;
|
||||
int GetHeight() const;
|
||||
int GetFormat() const;
|
||||
bool Update(const CRect& r, const void* data, int pitch);
|
||||
bool Map(BYTE** bits, int& pitch, const RECT* r = NULL);
|
||||
void Unmap();
|
||||
bool Save(CString fn, bool dds = false);
|
||||
|
||||
ID3D10Texture2D* operator->(); // TODO: remove direct access
|
||||
|
||||
operator ID3D10Texture2D*();
|
||||
operator ID3D10ShaderResourceView*();
|
||||
operator ID3D10RenderTargetView*();
|
||||
operator ID3D10DepthStencilView*();
|
||||
};
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* 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 "GSTexture7.h"
|
||||
|
||||
GSTexture7::GSTexture7()
|
||||
: m_type(GSTexture::None)
|
||||
{
|
||||
memset(&m_desc, 0, sizeof(m_desc));
|
||||
}
|
||||
|
||||
GSTexture7::GSTexture7(int type, IDirectDrawSurface7* system)
|
||||
: m_type(type)
|
||||
, m_system(system)
|
||||
{
|
||||
memset(&m_desc, 0, sizeof(m_desc));
|
||||
|
||||
m_desc.dwSize = sizeof(m_desc);
|
||||
|
||||
system->GetSurfaceDesc(&m_desc);
|
||||
}
|
||||
|
||||
GSTexture7::GSTexture7(int type, IDirectDrawSurface7* system, IDirectDrawSurface7* video)
|
||||
: m_type(type)
|
||||
, m_system(system)
|
||||
, m_video(video)
|
||||
{
|
||||
memset(&m_desc, 0, sizeof(m_desc));
|
||||
|
||||
m_desc.dwSize = sizeof(m_desc);
|
||||
|
||||
video->GetSurfaceDesc(&m_desc);
|
||||
}
|
||||
|
||||
GSTexture7::~GSTexture7()
|
||||
{
|
||||
}
|
||||
|
||||
GSTexture7::operator bool()
|
||||
{
|
||||
return !!m_system;
|
||||
}
|
||||
|
||||
int GSTexture7::GetType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
int GSTexture7::GetWidth() const
|
||||
{
|
||||
return m_desc.dwWidth;
|
||||
}
|
||||
|
||||
int GSTexture7::GetHeight() const
|
||||
{
|
||||
return m_desc.dwHeight;
|
||||
}
|
||||
|
||||
int GSTexture7::GetFormat() const
|
||||
{
|
||||
return (int)m_desc.ddpfPixelFormat.dwFourCC;
|
||||
}
|
||||
|
||||
bool GSTexture7::Update(const CRect& r, const void* data, int pitch)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
CRect r2 = r;
|
||||
|
||||
DDSURFACEDESC2 desc;
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
|
||||
desc.dwSize = sizeof(desc);
|
||||
|
||||
if(SUCCEEDED(hr = m_system->Lock(&r2, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL)))
|
||||
{
|
||||
BYTE* src = (BYTE*)data;
|
||||
BYTE* dst = (BYTE*)desc.lpSurface;
|
||||
|
||||
int bytes = min(pitch, desc.lPitch);
|
||||
|
||||
for(int i = 0, j = r.Height(); i < j; i++, src += pitch, dst += desc.lPitch)
|
||||
{
|
||||
// memcpy(dst, src, bytes);
|
||||
|
||||
// HACK!!!
|
||||
|
||||
GSVector4i* s = (GSVector4i*)src;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
int w = bytes >> 4;
|
||||
|
||||
for(int x = 0; x < w; x++)
|
||||
{
|
||||
GSVector4i c = s[x];
|
||||
|
||||
c = (c & 0xff00ff00) | ((c & 0x00ff0000) >> 16) | ((c & 0x000000ff) << 16);
|
||||
|
||||
d[x] = c;
|
||||
}
|
||||
}
|
||||
|
||||
hr = m_system->Unlock(&r2);
|
||||
|
||||
if(m_video)
|
||||
{
|
||||
hr = m_video->Blt(&r2, m_system, &r2, DDBLT_WAIT, NULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GSTexture7::Map(BYTE** bits, int& pitch, const RECT* r)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
CRect r2 = r;
|
||||
|
||||
DDSURFACEDESC2 desc;
|
||||
|
||||
if(SUCCEEDED(hr = m_system->Lock(&r2, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL)))
|
||||
{
|
||||
*bits = (BYTE*)desc.lpSurface;
|
||||
pitch = (int)desc.lPitch;
|
||||
|
||||
m_lr = r;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GSTexture7::Unmap()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = m_system->Unlock(NULL);
|
||||
|
||||
if(m_video)
|
||||
{
|
||||
hr = m_video->Blt(&m_lr, m_system, &m_lr, DDBLT_WAIT, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool GSTexture7::Save(CString fn, bool dds)
|
||||
{
|
||||
// TODO
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IDirectDrawSurface7* GSTexture7::operator->()
|
||||
{
|
||||
return m_video ? m_video : m_system;
|
||||
}
|
||||
|
||||
GSTexture7::operator IDirectDrawSurface7*()
|
||||
{
|
||||
return m_video ? m_video : m_system;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSTexture.h"
|
||||
#include <ddraw.h>
|
||||
|
||||
class GSTexture7 : public GSTexture
|
||||
{
|
||||
int m_type;
|
||||
CComPtr<IDirectDrawSurface7> m_system;
|
||||
CComPtr<IDirectDrawSurface7> m_video;
|
||||
DDSURFACEDESC2 m_desc;
|
||||
CRect m_lr;
|
||||
|
||||
public:
|
||||
GSTexture7();
|
||||
explicit GSTexture7(int type, IDirectDrawSurface7* system);
|
||||
GSTexture7(int type, IDirectDrawSurface7* system, IDirectDrawSurface7* video);
|
||||
virtual ~GSTexture7();
|
||||
|
||||
operator bool();
|
||||
|
||||
int GetType() const;
|
||||
int GetWidth() const;
|
||||
int GetHeight() const;
|
||||
int GetFormat() const;
|
||||
bool Update(const CRect& r, const void* data, int pitch);
|
||||
bool Map(BYTE** bits, int& pitch, const RECT* r = NULL);
|
||||
void Unmap();
|
||||
bool Save(CString fn, bool dds = false);
|
||||
|
||||
IDirectDrawSurface7* operator->(); // TODO: remove direct access
|
||||
|
||||
operator IDirectDrawSurface7*();
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue