just a bunch of random code cleanup i did on the train bored, plus a d3d implementation of NativeVertexFormat which isn't actually used yet.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1658 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2008-12-25 15:56:36 +00:00
parent 3fd665502e
commit dcc48d6c41
28 changed files with 948 additions and 679 deletions

View File

@ -24,6 +24,7 @@
#endif
#include "Common.h"
#include "FileUtil.h"
#include "StringUtil.h"
#include "DynamicLibrary.h"
@ -32,11 +33,10 @@ DynamicLibrary::DynamicLibrary()
library = 0;
}
std::string GetLastErrorAsString()
{
#ifdef _WIN32
LPVOID lpMsgBuf = 0;
LPVOID lpMsgBuf = 0;
DWORD error = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
@ -64,13 +64,11 @@ std::string GetLastErrorAsString()
#endif
}
// ------------------------------------------------------------------
/* Loading means loading the dll with LoadLibrary() to get an instance to the dll.
This is done when Dolphin is started to determine which dlls are good, and
before opening the Config and Debugging windows from Plugin.cpp and
before opening the dll for running the emulation in Video_...cpp in Core. */
// -----------------------
// Loading means loading the dll with LoadLibrary() to get an instance to the dll.
// This is done when Dolphin is started to determine which dlls are good, and
// before opening the Config and Debugging windows from Plugin.cpp and
// before opening the dll for running the emulation in Video_...cpp in Core.
// Since this is fairly slow, TODO: think about implementing some sort of cache.
int DynamicLibrary::Load(const char* filename)
{
if (!filename || strlen(filename) == 0)
@ -80,7 +78,6 @@ int DynamicLibrary::Load(const char* filename)
return 0;
}
LOG(MASTER_LOG, "Trying to load library %s", filename);
if (IsLoaded())
{
LOG(MASTER_LOG, "Trying to load already loaded library %s", filename);
@ -93,9 +90,17 @@ int DynamicLibrary::Load(const char* filename)
library = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
#endif
if (!library) {
if (!library)
{
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, GetLastErrorAsString().c_str());
PanicAlert("Error loading DLL %s: %s\n", filename, GetLastErrorAsString().c_str());
if (File::Exists(filename))
{
PanicAlert("Error loading DLL %s: %s\n\nAre you missing SDL.DLL or another file that this plugin may depend on?", filename, GetLastErrorAsString().c_str());
}
else
{
PanicAlert("Error loading DLL %s: %s\n", filename, GetLastErrorAsString().c_str());
}
return 0;
}
@ -108,11 +113,9 @@ int DynamicLibrary::Unload()
{
int retval;
if (!IsLoaded()) {
LOG(MASTER_LOG, "Error unloading DLL %s: not loaded", library_file.c_str());
PanicAlert("Error unloading DLL %s: not loaded", library_file.c_str());
return 0;
}
#ifdef _WIN32
retval = FreeLibrary(library);
@ -120,8 +123,6 @@ int DynamicLibrary::Unload()
retval = dlclose(library)?0:1;
#endif
if (!retval) {
LOG(MASTER_LOG, "Error unloading DLL %s: %s", library_file.c_str(),
GetLastErrorAsString().c_str());
PanicAlert("Error unloading DLL %s: %s", library_file.c_str(),
GetLastErrorAsString().c_str());
}
@ -135,8 +136,8 @@ void* DynamicLibrary::Get(const char* funcname) const
void* retval;
if (!library)
{
LOG(MASTER_LOG, "Can't find function %s - Library not loaded.");
PanicAlert("Can't find function %s - Library not loaded.");
PanicAlert("Can't find function %s - Library not loaded.");
return NULL;
}
#ifdef _WIN32
retval = GetProcAddress(library, funcname);
@ -145,8 +146,8 @@ void* DynamicLibrary::Get(const char* funcname) const
#endif
if (!retval) {
LOG(MASTER_LOG, "Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), GetLastErrorAsString().c_str());
PanicAlert("Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), GetLastErrorAsString().c_str());
LOG(MASTER_LOG, "Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), GetLastErrorAsString().c_str());
PanicAlert("Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), GetLastErrorAsString().c_str());
}
return retval;

View File

@ -24,23 +24,23 @@
#include <string>
// Abstracts the (few) differences between dynamically loading DLLs under Windows
// and .so / .dylib under Linux/MacOSX.
class DynamicLibrary
{
public:
public:
DynamicLibrary();
int Load(const char *filename);
int Unload();
void *Get(const char *funcname) const;
bool IsLoaded() const { return library != 0; }
DynamicLibrary();
int Load(const char* filename);
int Unload();
void* Get(const char* funcname) const;
bool IsLoaded() const {return(library != 0);}
private:
std::string library_file;
private:
std::string library_file;
#ifdef _WIN32
HINSTANCE library;
HINSTANCE library;
#else
void* library;
void *library;
#endif
};

View File

@ -24,44 +24,44 @@ bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no);
static MsgAlertHandler msg_handler = DefaultMsgHandler;
void RegisterMsgAlertHandler(MsgAlertHandler handler) {
msg_handler = handler;
void RegisterMsgAlertHandler(MsgAlertHandler handler)
{
msg_handler = handler;
}
bool MsgAlert(const char* caption, bool yes_no,
const char* format, ...) {
char buffer[2048];
va_list args;
bool ret = false;
bool MsgAlert(const char* caption, bool yes_no, const char* format, ...)
{
char buffer[2048];
va_list args;
bool ret = false;
va_start(args, format);
CharArrayFromFormatV(buffer, 2048, format, args);
va_start(args, format);
CharArrayFromFormatV(buffer, 2048, format, args);
LOG(MASTER_LOG, "%s: %s", caption, buffer);
LOG(MASTER_LOG, "%s: %s", caption, buffer);
if (msg_handler) {
ret = msg_handler(caption, buffer, yes_no);
}
va_end(args);
return ret;
if (msg_handler)
{
ret = msg_handler(caption, buffer, yes_no);
}
va_end(args);
return ret;
}
bool DefaultMsgHandler(const char* caption, const char* text,
bool yes_no) {
bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no)
{
#ifdef _WIN32
if (yes_no)
return IDYES == MessageBox(0, text, caption,
MB_ICONQUESTION | MB_YESNO);
else {
MessageBox(0, text, caption, MB_ICONWARNING);
return true;
}
if (yes_no)
return IDYES == MessageBox(0, text, caption,
MB_ICONQUESTION | MB_YESNO);
else {
MessageBox(0, text, caption, MB_ICONWARNING);
return true;
}
#else
printf("%s\n", text);
return true;
printf("%s\n", text);
return true;
#endif
}

View File

@ -74,7 +74,7 @@ CEXIIPL::CEXIIPL() :
}
else
{
PanicAlert("Error: failed to load font_ansi.bin. Fonts may bug");
PanicAlert("Error: failed to load font_ansi.bin.\nFonts in a few games may not work, or crash the game.");
}
pStream = fopen(FONT_SJIS_FILE, "rb");
@ -89,7 +89,8 @@ CEXIIPL::CEXIIPL() :
}
else
{
PanicAlert("Error: failed to load font_sjis.bin. Fonts may bug");
// Heh, BIOS fonts don't really work in JAP games anyway ... we get bogus characters.
PanicAlert("Error: failed to load font_sjis.bin.\nFonts in a few Japanese games may not work or crash the game.");
}
memcpy(m_pIPL, iplver, sizeof(iplver));
@ -120,7 +121,6 @@ CEXIIPL::~CEXIIPL()
if (m_count > 0)
{
m_szBuffer[m_count] = 0x00;
//MessageBox(NULL, m_szBuffer, "last message", MB_OK);
}
if (m_pIPL != NULL)
@ -130,19 +130,19 @@ CEXIIPL::~CEXIIPL()
}
// SRAM
FILE* pStream = NULL;
pStream = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "wb");
if (pStream != NULL)
FILE *file = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "wb");
if (file)
{
fwrite(m_SRAM, 1, 64, pStream);
fclose(pStream);
fwrite(m_SRAM, 1, 64, file);
fclose(file);
}
}
void CEXIIPL::SetCS(int _iCS)
{
if (_iCS)
{ // cs transition to high
{
// cs transition to high
m_uPosition = 0;
}
}

View File

@ -63,10 +63,7 @@ LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
int accessType = (int)pPtrs->ExceptionRecord->ExceptionInformation[0];
if (accessType == 8) //Rule out DEP
{
if (PowerPC::state == PowerPC::CPU_POWERDOWN)
return EXCEPTION_CONTINUE_SEARCH;
MessageBox(0, _T("Tried to execute code that's not marked executable. This is likely a JIT bug.\n"), 0, 0);
return EXCEPTION_CONTINUE_SEARCH;
return (DWORD)EXCEPTION_CONTINUE_SEARCH;
}
//Where in the x86 code are we?

View File

@ -58,7 +58,7 @@ CPluginManager::~CPluginManager()
// ----------------------------------------
// Create list of avaliable plugins
// Create list of available plugins
// -------------
void CPluginManager::ScanForPlugins(wxWindow* _wxWindow)
{
@ -145,10 +145,11 @@ void CPluginManager::OpenDebug(void* _Parent, const char *_rFilename, bool Type,
//int ret = PluginVideo::LoadPlugin(_rFilename);
//int ret = PluginDSP::LoadPlugin(_rFilename);
if(Type)
if (Type)
{
//Common::CPlugin::Debug((HWND)_Parent);
if(!PluginVideo::IsLoaded()) PluginVideo::LoadPlugin(_rFilename);
if (!PluginVideo::IsLoaded())
PluginVideo::LoadPlugin(_rFilename);
PluginVideo::Debug((HWND)_Parent, Show);
}
else
@ -162,7 +163,6 @@ void CPluginManager::OpenDebug(void* _Parent, const char *_rFilename, bool Type,
//m_DllDebugger(NULL);
}
// ----------------------------------------
// Get dll info
// -------------
@ -179,6 +179,9 @@ CPluginInfo::CPluginInfo(const char *_rFileName)
Common::CPlugin::Release();
}
/*
The DLL loading code provides enough error messages already. Possibly make some return codes
and handle messages here instead?
else
{
if (!File::Exists(_rFileName)) {
@ -186,7 +189,7 @@ CPluginInfo::CPluginInfo(const char *_rFileName)
} else {
PanicAlert("Failed to load plugin %s - unknown error.\n", _rFileName);
}
}
}*/
}

View File

@ -89,14 +89,16 @@ struct PortableVertexDeclaration
// all the data loading code must always be made compatible.
class NativeVertexFormat
{
u8* m_compiledCode;
PortableVertexDeclaration vtx_decl;
public:
NativeVertexFormat();
~NativeVertexFormat();
protected:
NativeVertexFormat() {}
void Initialize(const PortableVertexDeclaration &vtx_decl);
void SetupVertexPointers() const;
public:
virtual ~NativeVertexFormat() {}
virtual void Initialize(const PortableVertexDeclaration &vtx_decl) = 0;
virtual void SetupVertexPointers() const = 0;
static NativeVertexFormat *Create();
// TODO: move these in under private:
u32 m_components; // VB_HAS_X. Bitmask telling what vertex components are present.

View File

@ -20,8 +20,16 @@
#include "Common.h"
// This must be called once before calling the two conversion functions
// below.
void InitXFBConvTables();
// These implementations could likely be made considerably faster by
// reducing precision so that intermediate calculations are done in
// 15-bit precision instead of 32-bit. However, this would complicate
// the code and since we have a GPU implementation too, there really
// isn't much point.
// Converts 4:2:2 YUV (YUYV) data to 32-bit RGBA data.
void ConvertFromXFB(u32 *dst, const u8* _pXFB, int width, int height);

View File

@ -1201,6 +1201,10 @@
RelativePath=".\Src\DecodedVArray.h"
>
</File>
<File
RelativePath=".\Src\NativeVertexFormat.cpp"
>
</File>
<File
RelativePath=".\Src\OpcodeDecoding.cpp"
>
@ -1273,6 +1277,14 @@
RelativePath=".\Src\PixelShader.h"
>
</File>
<File
RelativePath=".\Src\PixelShaderManager.cpp"
>
</File>
<File
RelativePath=".\Src\PixelShaderManager.h"
>
</File>
<File
RelativePath=".\Src\Render.cpp"
>
@ -1281,14 +1293,6 @@
RelativePath=".\Src\Render.h"
>
</File>
<File
RelativePath=".\Src\ShaderManager.cpp"
>
</File>
<File
RelativePath=".\Src\ShaderManager.h"
>
</File>
<File
RelativePath=".\Src\TextureCache.cpp"
>
@ -1317,6 +1321,14 @@
RelativePath=".\Src\VertexShader.h"
>
</File>
<File
RelativePath=".\Src\VertexShaderManager.cpp"
>
</File>
<File
RelativePath=".\Src\VertexShaderManager.h"
>
</File>
</Filter>
<Filter
Name="D3D"

View File

@ -0,0 +1,145 @@
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "D3DBase.h"
#include "Profiler.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "MemoryUtil.h"
#include "VertexShader.h"
#include "CPMemory.h"
#include "NativeVertexFormat.h"
class D3DVertexFormat : public NativeVertexFormat
{
PortableVertexDeclaration vtx_decl;
LPDIRECT3DVERTEXDECLARATION9 d3d_decl;
public:
D3DVertexFormat();
~D3DVertexFormat();
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
virtual void SetupVertexPointers() const;
};
NativeVertexFormat *NativeVertexFormat::Create()
{
return new D3DVertexFormat();
}
D3DVertexFormat::D3DVertexFormat() : d3d_decl(NULL)
{
}
D3DVertexFormat::~D3DVertexFormat()
{
if (d3d_decl)
{
d3d_decl->Release();
d3d_decl = NULL;
}
}
D3DDECLTYPE VarToD3D(VarType t)
{
static const D3DDECLTYPE lookup[5] =
{
D3DDECLTYPE_UBYTE4, D3DDECLTYPE_UBYTE4, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_USHORT4N, D3DDECLTYPE_FLOAT3,
};
return lookup[t];
}
// TODO: Ban signed bytes as normals - not likely that ATI supports them natively.
// We probably won't see much of a speed loss, and any speed loss will be regained anyway
// when we finally compile display lists.
void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
{
D3DVERTEXELEMENT9 *elems = new D3DVERTEXELEMENT9[32];
memset(elems, 0, sizeof(D3DVERTEXELEMENT9) * 32);
// There's only one stream and it's 0, so the above memset takes care of that - no need to set Stream.
// Same for method.
// So, here we go. First position:
int elem_idx = 0;
elems[elem_idx].Offset = 0; // Positions are always first, at position 0.
elems[elem_idx].Type = D3DDECLTYPE_FLOAT3;
elems[elem_idx].Usage = D3DDECLUSAGE_POSITION;
++elem_idx;
for (int i = 0; i < 3; i++)
{
if (_vtx_decl.normal_offset[i] >= 0)
{
elems[elem_idx].Offset = _vtx_decl.normal_offset[i];
elems[elem_idx].Type = VarToD3D(_vtx_decl.normal_gl_type);
elems[elem_idx].Usage = D3DDECLUSAGE_NORMAL;
elems[elem_idx].UsageIndex = i;
++elem_idx;
}
}
for (int i = 0; i < 2; i++)
{
if (_vtx_decl.color_offset[i] >= 0)
{
elems[elem_idx].Offset = _vtx_decl.color_offset[i];
elems[elem_idx].Type = VarToD3D(_vtx_decl.color_gl_type);
elems[elem_idx].Usage = D3DDECLUSAGE_COLOR;
elems[elem_idx].UsageIndex = i;
++elem_idx;
}
}
for (int i = 0; i < 8; i++)
{
if (_vtx_decl.texcoord_offset[i] >= 0)
{
elems[elem_idx].Offset = _vtx_decl.texcoord_offset[i];
elems[elem_idx].Type = VarToD3D(_vtx_decl.texcoord_gl_type[i]);
elems[elem_idx].Usage = D3DDECLUSAGE_TEXCOORD;
elems[elem_idx].UsageIndex = i;
++elem_idx;
}
}
if (vtx_decl.posmtx_offset != -1)
{
// glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)vtx_decl.posmtx_offset);
elems[elem_idx].Offset = _vtx_decl.posmtx_offset;
elems[elem_idx].Usage = D3DDECLUSAGE_BLENDINDICES;
elems[elem_idx].UsageIndex = 0;
++elem_idx;
}
if (FAILED(D3D::dev->CreateVertexDeclaration(elems, &d3d_decl)))
{
PanicAlert("Failed to create D3D vertex declaration!");
return;
}
}
void D3DVertexFormat::SetupVertexPointers() const
{
D3D::dev->SetVertexDeclaration(d3d_decl);
}

View File

@ -33,7 +33,8 @@
#include "TransformEngine.h"
#include "OpcodeDecoding.h"
#include "TextureCache.h"
#include "ShaderManager.h"
#include "VertexShaderManager.h"
#include "PixelShaderManager.h"
#include "BPStructs.h"
#include "XFStructs.h"

View File

@ -1,218 +1,134 @@
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "D3DBase.h"
#include "Statistics.h"
#include "Utils.h"
#include "Profiler.h"
#include "ShaderManager.h"
#include "VertexLoader.h"
#include "BPMemory.h"
#include "XFMemory.h"
//I hope we don't get too many hash collisions :p
//all these magic numbers are primes, it should help a bit
tevhash GetCurrentTEV()
{
u32 hash = bpmem.genMode.numindstages + bpmem.genMode.numtevstages*11 + bpmem.genMode.numtexgens*8*17;
for (int i = 0; i < (int)bpmem.genMode.numtevstages+1; i++)
{
hash = _rotl(hash,3) ^ (bpmem.combiners[i].colorC.hex*13);
hash = _rotl(hash,7) ^ ((bpmem.combiners[i].alphaC.hex&0xFFFFFFFC)*3);
hash = _rotl(hash,9) ^ xfregs.texcoords[i].texmtxinfo.projection*451;
}
for (int i = 0; i < (int)bpmem.genMode.numtevstages/2+1; i++)
{
hash = _rotl(hash,13) ^ (bpmem.tevorders[i].hex*7);
}
for (int i = 0; i < 8; i++)
{
hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap1;
hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap2;
}
hash ^= bpmem.dstalpha.enable ^ 0xc0debabe;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp0*7;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp1*13;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.logic*11;
return hash;
}
PShaderCache::PSCache PShaderCache::pshaders;
VShaderCache::VSCache VShaderCache::vshaders;
void PShaderCache::Init()
{
}
void PShaderCache::Shutdown()
{
PSCache::iterator iter = pshaders.begin();
for (;iter!=pshaders.end();iter++)
iter->second.Destroy();
pshaders.clear();
}
void PShaderCache::SetShader()
{
if (D3D::GetShaderVersion() < 2)
return; // we are screwed
static LPDIRECT3DPIXELSHADER9 lastShader = 0;
DVSTARTPROFILE();
tevhash currentHash = GetCurrentTEV();
PSCache::iterator iter;
iter = pshaders.find(currentHash);
if (iter != pshaders.end())
{
iter->second.frameCount = frameCount;
PSCacheEntry &entry = iter->second;
if (!lastShader || entry.shader != lastShader)
{
D3D::dev->SetPixelShader(entry.shader);
lastShader = entry.shader;
}
return;
}
const char *code = GeneratePixelShader();
LPDIRECT3DPIXELSHADER9 shader = D3D::CompilePShader(code, int(strlen(code)));
if (shader)
{
//Make an entry in the table
PSCacheEntry newentry;
newentry.shader = shader;
newentry.frameCount = frameCount;
pshaders[currentHash] = newentry;
}
D3D::dev->SetPixelShader(shader);
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size());
}
void PShaderCache::Cleanup()
{
PSCache::iterator iter;
iter = pshaders.begin();
while (iter != pshaders.end())
{
PSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount-30)
{
entry.Destroy();
iter = pshaders.erase(iter);
}
else
{
iter++;
}
}
SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size());
}
void VShaderCache::Init()
{
}
void VShaderCache::Shutdown()
{
VSCache::iterator iter = vshaders.begin();
for (; iter != vshaders.end(); iter++)
iter->second.Destroy();
vshaders.clear();
}
void VShaderCache::SetShader()
{
static LPDIRECT3DVERTEXSHADER9 shader = NULL;
if (D3D::GetShaderVersion() < 2)
return; // we are screwed
if (shader) {
//D3D::dev->SetVertexShader(shader);
return;
}
static LPDIRECT3DVERTEXSHADER9 lastShader = 0;
DVSTARTPROFILE();
tevhash currentHash = GetCurrentTEV();
VSCache::iterator iter;
iter = vshaders.find(currentHash);
if (iter != vshaders.end())
{
iter->second.frameCount=frameCount;
VSCacheEntry &entry = iter->second;
if (!lastShader || entry.shader != lastShader)
{
D3D::dev->SetVertexShader(entry.shader);
lastShader = entry.shader;
}
return;
}
const char *code = GenerateVertexShader();
shader = D3D::CompileVShader(code, int(strlen(code)));
if (shader)
{
//Make an entry in the table
VSCacheEntry entry;
entry.shader = shader;
entry.frameCount=frameCount;
vshaders[currentHash] = entry;
}
D3D::dev->SetVertexShader(shader);
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
}
void VShaderCache::Cleanup()
{
for (VSCache::iterator iter=vshaders.begin(); iter!=vshaders.end();)
{
VSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount - 30)
{
entry.Destroy();
iter = vshaders.erase(iter);
}
else
{
++iter;
}
}
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
}
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "D3DBase.h"
#include "Statistics.h"
#include "Utils.h"
#include "Profiler.h"
#include "PixelShaderManager.h"
#include "VertexLoader.h"
#include "BPMemory.h"
#include "XFMemory.h"
PShaderCache::PSCache PShaderCache::pshaders;
//I hope we don't get too many hash collisions :p
//all these magic numbers are primes, it should help a bit
tevhash GetCurrentTEV()
{
u32 hash = bpmem.genMode.numindstages + bpmem.genMode.numtevstages*11 + bpmem.genMode.numtexgens*8*17;
for (int i = 0; i < (int)bpmem.genMode.numtevstages+1; i++)
{
hash = _rotl(hash,3) ^ (bpmem.combiners[i].colorC.hex*13);
hash = _rotl(hash,7) ^ ((bpmem.combiners[i].alphaC.hex&0xFFFFFFFC)*3);
hash = _rotl(hash,9) ^ xfregs.texcoords[i].texmtxinfo.projection*451;
}
for (int i = 0; i < (int)bpmem.genMode.numtevstages/2+1; i++)
{
hash = _rotl(hash,13) ^ (bpmem.tevorders[i].hex*7);
}
for (int i = 0; i < 8; i++)
{
hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap1;
hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap2;
}
hash ^= bpmem.dstalpha.enable ^ 0xc0debabe;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp0*7;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp1*13;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.logic*11;
return hash;
}
void PShaderCache::Init()
{
}
void PShaderCache::Shutdown()
{
PSCache::iterator iter = pshaders.begin();
for (;iter!=pshaders.end();iter++)
iter->second.Destroy();
pshaders.clear();
}
void PShaderCache::SetShader()
{
if (D3D::GetShaderVersion() < 2)
return; // we are screwed
static LPDIRECT3DPIXELSHADER9 lastShader = 0;
DVSTARTPROFILE();
tevhash currentHash = GetCurrentTEV();
PSCache::iterator iter;
iter = pshaders.find(currentHash);
if (iter != pshaders.end())
{
iter->second.frameCount = frameCount;
PSCacheEntry &entry = iter->second;
if (!lastShader || entry.shader != lastShader)
{
D3D::dev->SetPixelShader(entry.shader);
lastShader = entry.shader;
}
return;
}
const char *code = GeneratePixelShader();
LPDIRECT3DPIXELSHADER9 shader = D3D::CompilePShader(code, int(strlen(code)));
if (shader)
{
//Make an entry in the table
PSCacheEntry newentry;
newentry.shader = shader;
newentry.frameCount = frameCount;
pshaders[currentHash] = newentry;
}
D3D::dev->SetPixelShader(shader);
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size());
}
void PShaderCache::Cleanup()
{
PSCache::iterator iter;
iter = pshaders.begin();
while (iter != pshaders.end())
{
PSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount-30)
{
entry.Destroy();
iter = pshaders.erase(iter);
}
else
{
iter++;
}
}
SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size());
}

View File

@ -1,97 +1,64 @@
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include "D3DBase.h"
#include <map>
#include "PixelShader.h"
#include "VertexShader.h"
typedef u32 tevhash;
tevhash GetCurrentTEV();
class PShaderCache
{
struct PSCacheEntry
{
LPDIRECT3DPIXELSHADER9 shader;
//CGPShader shader;
int frameCount;
PSCacheEntry()
{
shader=0;
frameCount=0;
}
void Destroy()
{
if (shader)
shader->Release();
}
};
typedef std::map<tevhash,PSCacheEntry> PSCache;
static PSCache pshaders;
public:
static void Init();
static void Cleanup();
static void Shutdown();
static void SetShader();
};
class VShaderCache
{
struct VSCacheEntry
{
LPDIRECT3DVERTEXSHADER9 shader;
//CGVShader shader;
int frameCount;
VSCacheEntry()
{
shader=0;
frameCount=0;
}
void Destroy()
{
if (shader)
shader->Release();
}
};
typedef std::map<tevhash,VSCacheEntry> VSCache;
static VSCache vshaders;
public:
static void Init();
static void Cleanup();
static void Shutdown();
static void SetShader();
};
void InitCG();
void ShutdownCG();
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PIXELSHADERMANAGER_H
#define _PIXELSHADERMANAGER_H
#include "D3DBase.h"
#include <map>
#include "PixelShader.h"
#include "VertexShader.h"
typedef u32 tevhash;
tevhash GetCurrentTEV();
class PShaderCache
{
struct PSCacheEntry
{
LPDIRECT3DPIXELSHADER9 shader;
//CGPShader shader;
int frameCount;
PSCacheEntry()
{
shader = 0;
frameCount = 0;
}
void Destroy()
{
if (shader)
shader->Release();
}
};
typedef std::map<tevhash, PSCacheEntry> PSCache;
static PSCache pshaders;
public:
static void Init();
static void Cleanup();
static void Shutdown();
static void SetShader();
};
#endif // _PIXELSHADERMANAGER_H

View File

@ -29,7 +29,8 @@
#include "XFStructs.h"
#include "D3DPostprocess.h"
#include "D3DUtil.h"
#include "ShaderManager.h"
#include "VertexShaderManager.h"
#include "PixelShaderManager.h"
#include "TextureCache.h"
#include "Utils.h"
#include "EmuWindow.h"
@ -171,7 +172,8 @@ void Renderer::ReinitView()
xScale = width/640.0f;
yScale = height/480.0f;
RECT rc = {
RECT rc =
{
(LONG)(m_x*xScale), (LONG)(m_y*yScale), (LONG)(m_width*xScale), (LONG)(m_height*yScale)
};
}
@ -198,24 +200,24 @@ void Renderer::SwapBuffers(void)
{
char st[2048];
char *p = st;
p+=sprintf(p,"Num textures created: %i\n",stats.numTexturesCreated);
p+=sprintf(p,"Num textures alive: %i\n",stats.numTexturesAlive);
p+=sprintf(p,"Num pshaders created: %i\n",stats.numPixelShadersCreated);
p+=sprintf(p,"Num pshaders alive: %i\n",stats.numPixelShadersAlive);
p+=sprintf(p,"Num vshaders created: %i\n",stats.numVertexShadersCreated);
p+=sprintf(p,"Num vshaders alive: %i\n",stats.numVertexShadersAlive);
p+=sprintf(p,"Num dlists called: %i\n",stats.numDListsCalled);
p+=sprintf(p,"Num dlists created: %i\n",stats.numDListsCreated);
p+=sprintf(p,"Num dlists alive: %i\n",stats.numDListsAlive);
p+=sprintf(p,"Num primitives: %i\n",stats.thisFrame.numPrims);
p+=sprintf(p,"Num primitive joins: %i\n",stats.thisFrame.numPrimitiveJoins);
p+=sprintf(p,"Num primitives (DL): %i\n",stats.thisFrame.numDLPrims);
p+=sprintf(p,"Num XF loads: %i\n",stats.thisFrame.numXFLoads);
p+=sprintf(p,"Num XF loads (DL): %i\n",stats.thisFrame.numXFLoadsInDL);
p+=sprintf(p,"Num CP loads: %i\n",stats.thisFrame.numCPLoads);
p+=sprintf(p,"Num CP loads (DL): %i\n",stats.thisFrame.numCPLoadsInDL);
p+=sprintf(p,"Num BP loads: %i\n",stats.thisFrame.numBPLoads);
p+=sprintf(p,"Num BP loads (DL): %i\n",stats.thisFrame.numBPLoadsInDL);
p+=sprintf(p,"textures created: %i\n",stats.numTexturesCreated);
p+=sprintf(p,"textures alive: %i\n",stats.numTexturesAlive);
p+=sprintf(p,"pshaders created: %i\n",stats.numPixelShadersCreated);
p+=sprintf(p,"pshaders alive: %i\n",stats.numPixelShadersAlive);
p+=sprintf(p,"vshaders created: %i\n",stats.numVertexShadersCreated);
p+=sprintf(p,"vshaders alive: %i\n",stats.numVertexShadersAlive);
p+=sprintf(p,"dlists called: %i\n",stats.numDListsCalled);
p+=sprintf(p,"dlists created: %i\n",stats.numDListsCreated);
p+=sprintf(p,"dlists alive: %i\n",stats.numDListsAlive);
p+=sprintf(p,"primitives: %i\n",stats.thisFrame.numPrims);
p+=sprintf(p,"primitive joins: %i\n",stats.thisFrame.numPrimitiveJoins);
p+=sprintf(p,"primitives (DL): %i\n",stats.thisFrame.numDLPrims);
p+=sprintf(p,"XF loads: %i\n",stats.thisFrame.numXFLoads);
p+=sprintf(p,"XF loads (DL): %i\n",stats.thisFrame.numXFLoadsInDL);
p+=sprintf(p,"CP loads: %i\n",stats.thisFrame.numCPLoads);
p+=sprintf(p,"CP loads (DL): %i\n",stats.thisFrame.numCPLoadsInDL);
p+=sprintf(p,"BP loads: %i\n",stats.thisFrame.numBPLoads);
p+=sprintf(p,"BP loads (DL): %i\n",stats.thisFrame.numBPLoadsInDL);
D3D::font.DrawTextScaled(0,30,20,20,0.0f,0xFF00FFFF,st,false);
@ -270,7 +272,7 @@ void Renderer::SwapBuffers(void)
u32 clearColor = (bpmem.clearcolorAR<<16)|bpmem.clearcolorGB;
// clearColor |= 0x003F003F;
// D3D::BeginFrame(true,clearColor,1.0f);
D3D::BeginFrame(false,clearColor,1.0f);
D3D::BeginFrame(false, clearColor, 1.0f);
// D3D::EnableAlphaToCoverage();
Postprocess::BeginFrame();
@ -280,15 +282,6 @@ void Renderer::SwapBuffers(void)
D3D::font.SetRenderStates(); //compatibility with low end cards
}
void Renderer::Flush(void)
{
// render the rest of the vertex buffer
//only to be used for debugging purposes
//D3D::EndFrame();
//D3D::BeginFrame(false,0);
}
void Renderer::SetViewport(float* _Viewport)
{
Viewport* pViewport = (Viewport*)_Viewport;

View File

@ -44,17 +44,15 @@ public:
static void Init(SVideoInitialize &_VideoInitialize);
static void Shutdown();
// initialize opengl standard values (like view port)
static void Initialize(void);
// must be called if the window size has changed
static void ReinitView(void);
//
// --- Render Functions ---
//
static void SwapBuffers(void);
static void Flush(void);
static float GetXScale(){return xScale;}
static float GetYScale(){return yScale;}
static float GetXScale() {return xScale;}
static float GetYScale() {return yScale;}
static void SetScissorBox(RECT &rc);
static void SetViewport(float* _Viewport);
@ -108,8 +106,8 @@ public:
* @param pVertexStreamZeroData User memory pointer to the vertex data.
* @param VertexStreamZeroStride The number of bytes of data for each vertex.
*/
static void DrawPrimitiveUP( D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
const void* pVertexStreamZeroData, UINT VertexStreamZeroStride );
static void DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
const void* pVertexStreamZeroData, UINT VertexStreamZeroStride);
/**
* Renders a sequence of non indexed, geometric primitives of the specified type from the current set of data input streams.
@ -117,7 +115,7 @@ public:
* @param StartVertex Index of the first vertex to load.
* @param PrimitiveCount Number of primitives to render.
*/
static void DrawPrimitive( D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount );
static void DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount);
};
#endif // __H_RENDER__

View File

@ -27,7 +27,8 @@
#include "IndexGenerator.h"
#include "BPStructs.h"
#include "XFStructs.h"
#include "ShaderManager.h"
#include "VertexShaderManager.h"
#include "PixelShaderManager.h"
#include "Utils.h"
using namespace D3D;

View File

@ -0,0 +1,110 @@
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <map>
#include "D3DBase.h"
#include "Statistics.h"
#include "Utils.h"
#include "Profiler.h"
#include "VertexShaderManager.h"
#include "VertexLoader.h"
#include "BPMemory.h"
#include "XFMemory.h"
VShaderCache::VSCache VShaderCache::vshaders;
void VShaderCache::Init()
{
}
void VShaderCache::Shutdown()
{
VSCache::iterator iter = vshaders.begin();
for (; iter != vshaders.end(); iter++)
iter->second.Destroy();
vshaders.clear();
}
void VShaderCache::SetShader()
{
static LPDIRECT3DVERTEXSHADER9 shader = NULL;
if (D3D::GetShaderVersion() < 2)
return; // we are screwed
if (shader) {
//D3D::dev->SetVertexShader(shader);
return;
}
static LPDIRECT3DVERTEXSHADER9 lastShader = 0;
DVSTARTPROFILE();
u32 currentHash = 0x1337; // GetCurrentTEV();
VSCache::iterator iter;
iter = vshaders.find(currentHash);
if (iter != vshaders.end())
{
iter->second.frameCount=frameCount;
VSCacheEntry &entry = iter->second;
if (!lastShader || entry.shader != lastShader)
{
D3D::dev->SetVertexShader(entry.shader);
lastShader = entry.shader;
}
return;
}
const char *code = GenerateVertexShader();
shader = D3D::CompileVShader(code, int(strlen(code)));
if (shader)
{
//Make an entry in the table
VSCacheEntry entry;
entry.shader = shader;
entry.frameCount=frameCount;
vshaders[currentHash] = entry;
}
D3D::dev->SetVertexShader(shader);
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
}
void VShaderCache::Cleanup()
{
for (VSCache::iterator iter=vshaders.begin(); iter!=vshaders.end();)
{
VSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount - 30)
{
entry.Destroy();
iter = vshaders.erase(iter);
}
else
{
++iter;
}
}
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
}

View File

@ -0,0 +1,57 @@
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _VERTEXSHADERMANAGER_H
#define _VERTEXSHADERMANAGER_H
#include "D3DBase.h"
#include <map>
#include "PixelShader.h"
#include "VertexShader.h"
class VShaderCache
{
struct VSCacheEntry
{
LPDIRECT3DVERTEXSHADER9 shader;
int frameCount;
VSCacheEntry()
{
shader = 0;
frameCount = 0;
}
void Destroy()
{
if (shader)
shader->Release();
}
};
typedef std::map<u32, VSCacheEntry> VSCache;
static VSCache vshaders;
public:
static void Init();
static void Cleanup();
static void Shutdown();
static void SetShader();
};
#endif // _VERTEXSHADERMANAGER_H

View File

@ -461,12 +461,12 @@ void BPWritten(int addr, int changes, int newval)
}
else {
// EFB to XFB
if(g_Config.bUseXFB)
if (g_Config.bUseXFB)
{
// the number of lines copied is determined by the y scale * source efb height
float yScale = bpmem.dispcopyyscale / 256.0f;
float xfbLines = bpmem.copyTexSrcWH.y + 1.0f * yScale;
XFB_Write(Memory_GetPtr(bpmem.copyTexDest<<5), multirc, (bpmem.copyMipMapStrideChannels << 4), (int)xfbLines);
XFB_Write(Memory_GetPtr(bpmem.copyTexDest << 5), multirc, (bpmem.copyMipMapStrideChannels << 4), (int)xfbLines);
}
else
{

View File

@ -140,7 +140,6 @@ void UpdateFPSDisplay(const char *text)
char temp[512];
sprintf(temp, "SVN R%s: GL: %s", SVN_REV_STR, text);
OpenGL_SetWindowText(temp);
}
// =======================================================================================
@ -148,9 +147,9 @@ void UpdateFPSDisplay(const char *text)
bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight)
{
int _twidth, _theight;
if(g_Config.bFullscreen)
if (g_Config.bFullscreen)
{
if(strlen(g_Config.iFSResolution) > 1)
if (strlen(g_Config.iFSResolution) > 1)
{
sscanf(g_Config.iFSResolution, "%dx%d", &_twidth, &_theight);
}
@ -162,7 +161,7 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight
}
else // Going Windowed
{
if(strlen(g_Config.iWindowedRes) > 1)
if (strlen(g_Config.iWindowedRes) > 1)
{
sscanf(g_Config.iWindowedRes, "%dx%d", &_twidth, &_theight);
}
@ -189,7 +188,7 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight
float FactorH = 480.0f / (float)nBackbufferHeight;
float Max = (FactorW < FactorH) ? FactorH : FactorW;
if(g_Config.bStretchToFit)
if (g_Config.bStretchToFit)
{
MValueX = 1.0f / FactorW;
MValueY = 1.0f / FactorH;
@ -608,7 +607,7 @@ void OpenGL_Update()
int height = rcWindow.bottom - rcWindow.top;
if (EmuWindow::GetParentWnd() != 0)
::MoveWindow(EmuWindow::GetWnd(), 0,0,width,height, FALSE);
::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE);
nBackbufferWidth = width;
nBackbufferHeight = height;

View File

@ -38,6 +38,17 @@
#define DEBUG_LOG(...)
#endif
enum {
EFB_WIDTH = 640,
EFB_HEIGHT = 528,
};
enum {
XFB_WIDTH = 640,
XFB_HEIGHT = 480, // 528 is max height ... ? or 538?
// TODO: figure out what to do with PAL
};
void DebugLog(const char* _fmt, ...);
void __Log(const char *format, ...);
void __Log(int type, const char *format, ...);

View File

@ -48,7 +48,25 @@ DECLARE_IMPORT(glColorPointer);
DECLARE_IMPORT(glTexCoordPointer);
#endif
NativeVertexFormat::NativeVertexFormat()
class GLVertexFormat : public NativeVertexFormat
{
u8 *m_compiledCode;
PortableVertexDeclaration vtx_decl;
public:
GLVertexFormat();
~GLVertexFormat();
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
virtual void SetupVertexPointers() const;
};
NativeVertexFormat *NativeVertexFormat::Create()
{
return new GLVertexFormat();
}
GLVertexFormat::GLVertexFormat()
{
#ifdef USE_JIT
m_compiledCode = (u8 *)AllocateExecutableMemory(COMPILED_CODE_SIZE, false);
@ -58,7 +76,7 @@ NativeVertexFormat::NativeVertexFormat()
#endif
}
NativeVertexFormat::~NativeVertexFormat()
GLVertexFormat::~GLVertexFormat()
{
#ifdef USE_JIT
FreeMemoryPages(m_compiledCode, COMPILED_CODE_SIZE);
@ -72,7 +90,7 @@ inline GLuint VarToGL(VarType t)
return lookup[t];
}
void NativeVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
void GLVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
{
using namespace Gen;
@ -148,7 +166,7 @@ void NativeVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
this->vtx_decl = _vtx_decl;
}
void NativeVertexFormat::SetupVertexPointers() const {
void GLVertexFormat::SetupVertexPointers() const {
// Cast a pointer to compiled code to a pointer to a function taking no parameters, through a (void *) cast first to
// get around type checking errors, and call it.
#ifdef USE_JIT

View File

@ -43,17 +43,17 @@
#include "VertexLoader.h"
#include "XFB.h"
#include "Timer.h"
#include "Logging/Logging.h" // for Logging()
#if defined(HAVE_WX) && HAVE_WX
#include "Debugger/Debugger.h" // for the CDebugger class
#endif
#include "Logging/Logging.h" // for Logging()
#ifdef _WIN32
#include "OS/Win32.h"
#else
#endif
//#define USE_AA
#define AA_AMMOUNT 16
struct MESSAGE
{
MESSAGE() {}
@ -63,31 +63,39 @@ struct MESSAGE
};
CGcontext g_cgcontext;
CGprofile g_cgvProf, g_cgfProf;
CGprofile g_cgvProf;
CGprofile g_cgfProf;
#if defined(HAVE_WX) && HAVE_WX
extern CDebugger* m_frame; // the debugging class
#endif
static int g_MaxTexWidth = 0, g_MaxTexHeight = 0;
static RasterFont* s_pfont = NULL;
static std::list<MESSAGE> s_listMsgs;
static bool s_bFullscreen = false;
static bool s_bOutputCgErrors = true;
static int nZBufferRender = 0; // if > 0, then using zbuffer render
static u32 s_uFramebuffer = 0;
static u32 s_RenderTargets[1] = {0}, s_DepthTarget = 0, s_ZBufferTarget = 0;
static int nZBufferRender = 0; // if > 0, then use zbuffer render, and count down.
// A framebuffer is a set of render targets: a color and a z buffer. They can be either RenderBuffers or Textures.
static GLuint s_uFramebuffer = 0;
// The size of these should be a (not necessarily even) multiple of the EFB size, 640x528, but isn't.
static GLuint s_RenderTarget = 0;
static GLuint s_DepthTarget = 0;
static GLuint s_ZBufferTarget = 0;
static bool s_bATIDrawBuffers = false;
static bool s_bHaveStencilBuffer = false;
static bool s_bATIDrawBuffers = false, s_bHaveStencilBuffer = false;
static Renderer::RenderMode s_RenderMode = Renderer::RM_Normal;
static int s_nCurTarget = 0;
bool g_bBlendLogicOp = false;
int frameCount;
void HandleCgError(CGcontext ctx, CGerror err, void* appdata);
void HandleCgError(CGcontext ctx, CGerror err, void *appdata);
bool Renderer::Create2()
bool Renderer::Init()
{
bool bSuccess = true;
GLenum err = GL_NO_ERROR;
@ -96,16 +104,16 @@ bool Renderer::Create2()
cgSetErrorHandler(HandleCgError, NULL);
// fill the opengl extension map
const char* ptoken = (const char*)glGetString( GL_EXTENSIONS );
const char* ptoken = (const char*)glGetString(GL_EXTENSIONS);
if (ptoken == NULL) return false;
__Log("Supported OpenGL Extensions:\n");
__Log(ptoken); // write to the log file
__Log("\n");
if( strstr(ptoken, "GL_EXT_blend_logic_op") != NULL )
if (strstr(ptoken, "GL_EXT_blend_logic_op") != NULL)
g_bBlendLogicOp = true;
if( strstr(ptoken, "ATI_draw_buffers") != NULL && strstr(ptoken, "ARB_draw_buffers") == NULL)
if (strstr(ptoken, "ATI_draw_buffers") != NULL && strstr(ptoken, "ARB_draw_buffers") == NULL)
//Checks if it ONLY has the ATI_draw_buffers extension, some have both
s_bATIDrawBuffers = true;
@ -154,8 +162,11 @@ bool Renderer::Create2()
#endif
// check the max texture width and height
glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&g_MaxTexWidth);
g_MaxTexHeight = g_MaxTexWidth;
GLint max_texture_size;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&max_texture_size);
if (max_texture_size < 1024) {
ERROR_LOG("GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024", max_texture_size);
}
GL_REPORT_ERROR();
if (err != GL_NO_ERROR) bSuccess = false;
@ -163,44 +174,40 @@ bool Renderer::Create2()
if (glDrawBuffers == NULL && !GLEW_ARB_draw_buffers)
glDrawBuffers = glDrawBuffersARB;
glGenFramebuffersEXT( 1, (GLuint *)&s_uFramebuffer);
glGenFramebuffersEXT(1, (GLuint *)&s_uFramebuffer);
if (s_uFramebuffer == 0) {
ERROR_LOG("failed to create the renderbuffer\n");
}
_assert_( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT );
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer );
_assert_(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
// The size of the framebuffer targets should really NOT be the size of the OpenGL viewport.
// The EFB is larger than 640x480 - in fact, it's 640x528, give or take a couple of lines.
// So the below is wrong.
int nBackbufferWidth = (int)OpenGL_GetWidth();
int nBackbufferHeight = (int)OpenGL_GetHeight();
// create the framebuffer targets
glGenTextures(ARRAYSIZE(s_RenderTargets), (GLuint *)s_RenderTargets);
for(u32 i = 0; i < ARRAYSIZE(s_RenderTargets); ++i) {
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTargets[i]);
// initialize to default
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, nBackbufferWidth, nBackbufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if( glGetError() != GL_NO_ERROR) {
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
GL_REPORT_ERROR();
}
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#ifdef USE_AA
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_RenderTargets[i]);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, AA_AMMOUNT, GL_RGBA, nBackbufferWidth, nBackbufferHeight);
#endif
// Create the framebuffer target
glGenTextures(1, (GLuint *)&s_RenderTarget);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
// initialize to default
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, nBackbufferWidth, nBackbufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (glGetError() != GL_NO_ERROR) {
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
GL_REPORT_ERROR();
}
s_nCurTarget = 0;
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
GL_REPORT_ERROR();
int nMaxMRT = 0;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, (GLint *)&nMaxMRT);
if (nMaxMRT > 1) {
// create zbuffer target
glGenTextures(1, (GLuint *)&s_ZBufferTarget);
@ -209,27 +216,19 @@ bool Renderer::Create2()
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if( glGetError() != GL_NO_ERROR) {
if (glGetError() != GL_NO_ERROR) {
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
GL_REPORT_ERROR();
}
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#ifdef USE_AA
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_ZBufferTarget);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, AA_AMMOUNT, GL_RGBA, nBackbufferWidth, nBackbufferHeight);
#endif
}
// create the depth buffer
glGenRenderbuffersEXT( 1, (GLuint *)&s_DepthTarget);
glGenRenderbuffersEXT(1, (GLuint *)&s_DepthTarget);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_DepthTarget);
#ifdef USE_AA
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, AA_AMMOUNT, GL_DEPTH24_STENCIL8_EXT, nBackbufferWidth, nBackbufferHeight);
#else
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, nBackbufferWidth, nBackbufferHeight);
#endif
if (glGetError() != GL_NO_ERROR) {
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, nBackbufferWidth, nBackbufferHeight);
@ -241,24 +240,18 @@ bool Renderer::Create2()
GL_REPORT_ERROR();
// set as render targets
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_RenderTargets[s_nCurTarget], 0 );
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget );
#ifdef USE_AA
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_RenderTargets[s_nCurTarget]);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_RenderTargets[s_nCurTarget]);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget);
#endif
GL_REPORT_ERROR();
GL_REPORT_ERROR();
if (s_ZBufferTarget != 0) {
// test to make sure it works
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, 0);
bool bFailed = glGetError() != GL_NO_ERROR || glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT;
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
if( bFailed ) {
if (bFailed) {
glDeleteTextures(1, (GLuint *)&s_ZBufferTarget);
s_ZBufferTarget = 0;
}
@ -267,7 +260,7 @@ bool Renderer::Create2()
if (s_ZBufferTarget == 0)
ERROR_LOG("disabling ztarget mrt feature (max mrt=%d)\n", nMaxMRT);
//glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget );
//glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget);
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
nZBufferRender = 0;
@ -278,9 +271,6 @@ bool Renderer::Create2()
s_pfont = new RasterFont();
SetAA(g_Config.iMultisampleMode);
GL_REPORT_ERROR();
// load the effect, find the best profiles (if any)
if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE) {
ERROR_LOG("arbvp1 not supported\n");
@ -292,7 +282,7 @@ bool Renderer::Create2()
}
g_cgvProf = cgGLGetLatestProfile(CG_GL_VERTEX);
g_cgfProf = cgGLGetLatestProfile(CG_GL_FRAGMENT);//CG_PROFILE_ARBFP1;
g_cgfProf = cgGLGetLatestProfile(CG_GL_FRAGMENT);
cgGLSetOptimalOptions(g_cgvProf);
cgGLSetOptimalOptions(g_cgfProf);
@ -305,22 +295,21 @@ bool Renderer::Create2()
__Log("max program env parameters: vert=%d, frag=%d\n", nenvvertparams, nenvfragparams);
__Log("max program address register parameters: vert=%d, frag=%d\n", naddrregisters[0], naddrregisters[1]);
if( nenvvertparams < 238 )
if (nenvvertparams < 238)
ERROR_LOG("not enough vertex shader environment constants!!\n");
#ifndef _DEBUG
cgGLSetDebugMode(GL_FALSE);
#endif
if( cgGetError() != CG_NO_ERROR ) {
if (cgGetError() != CG_NO_ERROR) {
ERROR_LOG("cg error\n");
return false;
}
//glEnable(GL_POLYGON_OFFSET_FILL);
//glEnable(GL_POLYGON_OFFSET_LINE);
//glPolygonOffset(0, 1);
if (!Initialize())
s_RenderMode = Renderer::RM_Normal;
if (!InitializeGL())
return false;
XFB_Init();
@ -334,26 +323,25 @@ void Renderer::Shutdown(void)
XFB_Shutdown();
if (g_cgcontext != 0) {
if (g_cgcontext) {
cgDestroyContext(g_cgcontext);
g_cgcontext = 0;
}
if (s_RenderTargets[0]) {
glDeleteTextures(ARRAYSIZE(s_RenderTargets), (GLuint *)s_RenderTargets);
memset(s_RenderTargets, 0, sizeof(s_RenderTargets));
if (s_RenderTarget) {
glDeleteTextures(1, &s_RenderTarget);
s_RenderTarget = 0;
}
if (s_DepthTarget) {
glDeleteRenderbuffersEXT(1, (GLuint *)&s_DepthTarget); s_DepthTarget = 0;
glDeleteRenderbuffersEXT(1, &s_DepthTarget);
s_DepthTarget = 0;
}
if (s_uFramebuffer != 0) {
glDeleteFramebuffersEXT( 1, (GLuint *)&s_uFramebuffer);
if (s_uFramebuffer) {
glDeleteFramebuffersEXT(1, &s_uFramebuffer);
s_uFramebuffer = 0;
}
}
bool Renderer::Initialize()
bool Renderer::InitializeGL()
{
glStencilFunc(GL_ALWAYS, 0, 0);
glBlendFunc(GL_ONE, GL_ONE);
@ -394,8 +382,6 @@ bool Renderer::Initialize()
glClientActiveTexture(GL_TEXTURE0);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
s_RenderMode = Renderer::RM_Normal;
GLenum err = GL_NO_ERROR;
GL_REPORT_ERROR();
@ -439,7 +425,7 @@ void Renderer::ProcessMessages()
}
}
if(!wasEnabled) glDisable(GL_BLEND);
if (!wasEnabled) glDisable(GL_BLEND);
}
void Renderer::RenderText(const char* pstr, int left, int top, u32 color)
@ -455,11 +441,6 @@ void Renderer::RenderText(const char* pstr, int left, int top, u32 color)
s_pfont->printMultilineText(pstr, left * 2.0f / (float)nBackbufferWidth - 1, 1 - top * 2.0f / (float)nBackbufferHeight,0,nBackbufferWidth,nBackbufferHeight);
}
void Renderer::SetAA(int aa)
{
}
void Renderer::ReinitView(int nNewWidth, int nNewHeight)
{
int oldscreen = s_bFullscreen;
@ -467,7 +448,7 @@ void Renderer::ReinitView(int nNewWidth, int nNewHeight)
OpenGL_Shutdown();
int oldwidth = (int)OpenGL_GetWidth(),
oldheight = (int)OpenGL_GetHeight();
if (!OpenGL_Create(g_VideoInitialize, nNewWidth, nNewHeight)) {//nNewWidth&~7, nNewHeight&~7) ) {
if (!OpenGL_Create(g_VideoInitialize, nNewWidth, nNewHeight)) {//nNewWidth&~7, nNewHeight&~7)) {
ERROR_LOG("Failed to recreate, reverting to old settings\n");
if (!OpenGL_Create(g_VideoInitialize, oldwidth, oldheight)) {
g_VideoInitialize.pSysMessage("Failed to revert, exiting...\n");
@ -487,7 +468,7 @@ void Renderer::ReinitView(int nNewWidth, int nNewHeight)
RECT rcdesktop;
GetWindowRect(GetDesktopWindow(), &rcdesktop);
SetWindowLong( EmuWindow::GetWnd(), GWL_STYLE, EmuWindow::g_winstyle );
SetWindowLong(EmuWindow::GetWnd(), GWL_STYLE, EmuWindow::g_winstyle);
SetWindowPos(EmuWindow::GetWnd(), HWND_TOP, ((rcdesktop.right-rcdesktop.left)-(rc.right-rc.left))/2,
((rcdesktop.bottom-rcdesktop.top)-(rc.bottom-rc.top))/2,
rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW);
@ -499,39 +480,48 @@ void Renderer::ReinitView(int nNewWidth, int nNewHeight)
OpenGL_SetSize(nNewWidth > 16 ? nNewWidth : 16,
nNewHeight > 16 ? nNewHeight : 16);
}
int Renderer::GetTargetWidth()
{
return (g_Config.bStretchToFit?640:(int)OpenGL_GetWidth());
return (g_Config.bStretchToFit ? 640 : (int)OpenGL_GetWidth());
}
int Renderer::GetTargetHeight()
{
return (g_Config.bStretchToFit?480:(int)OpenGL_GetHeight());
return (g_Config.bStretchToFit ? 480 : (int)OpenGL_GetHeight());
}
bool Renderer::CanBlendLogicOp()
{
return g_bBlendLogicOp;
return g_bBlendLogicOp;
}
void Renderer::SetRenderTarget(u32 targ)
void Renderer::SetRenderTarget(GLuint targ)
{
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, targ!=0?targ:s_RenderTargets[s_nCurTarget], 0 );
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,
targ != 0 ? targ : s_RenderTarget, 0);
}
void Renderer::SetDepthTarget(u32 targ)
void Renderer::SetDepthTarget(GLuint targ)
{
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, targ != 0 ? targ : s_DepthTarget );
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT,
targ != 0 ? targ : s_DepthTarget);
}
void Renderer::SetFramebuffer(u32 fb)
void Renderer::SetFramebuffer(GLuint fb)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : s_uFramebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,
fb != 0 ? fb : s_uFramebuffer);
}
u32 Renderer::GetRenderTarget()
GLuint Renderer::GetRenderTarget()
{
return s_RenderTargets[s_nCurTarget];
return s_RenderTarget;
}
GLuint Renderer::GetZBufferTarget()
{
return nZBufferRender > 0 ? s_ZBufferTarget : 0;
}
void Renderer::ResetGLState()
@ -554,7 +544,7 @@ void Renderer::RestoreGLState()
if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE);
if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST);
if (bpmem.blendmode.blendenable) glEnable(GL_BLEND);
if(bpmem.zmode.updateenable) glDepthMask(GL_TRUE);
if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE);
glEnable(GL_VERTEX_PROGRAM_ARB);
glEnable(GL_FRAGMENT_PROGRAM_ARB);
@ -571,8 +561,6 @@ void Renderer::SetColorMask()
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE);
}
// =======================================================================================
// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
// case 0x52 > SetScissorRect()
// ---------------
@ -581,7 +569,6 @@ void Renderer::SetColorMask()
// bpmem.scissorTL.x, y = 342x342
// bpmem.scissorBR.x, y = 981x821
// Renderer::GetTargetHeight() = the fixed ini file setting
// ---------------
bool Renderer::SetScissorRect()
{
int xoff = bpmem.scissorOffset.x * 2 - 342;
@ -610,11 +597,11 @@ bool Renderer::SetScissorRect()
xoff, yoff
);*/
if (rc_right >= rc_left && rc_bottom >= rc_top )
if (rc_right >= rc_left && rc_bottom >= rc_top)
{
glScissor(
(int)rc_left, // x = 0
Renderer::GetTargetHeight()-(int)(rc_bottom), // y = 0
Renderer::GetTargetHeight() - (int)(rc_bottom), // y = 0
(int)(rc_right-rc_left), // y = 0
(int)(rc_bottom-rc_top) // y = 0
);
@ -624,7 +611,6 @@ bool Renderer::SetScissorRect()
return false;
}
bool Renderer::IsUsingATIDrawBuffers()
{
return s_bATIDrawBuffers;
@ -662,7 +648,7 @@ void Renderer::FlushZBufferAlphaToTarget()
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget);
TextureMngr::EnableTexRECT(0);
// disable all other stages
for(int i = 1; i < 8; ++i)
for (int i = 1; i < 8; ++i)
TextureMngr::DisableStage(i);
GL_REPORT_ERRORD();
@ -670,14 +656,17 @@ void Renderer::FlushZBufferAlphaToTarget()
glStencilFunc(GL_EQUAL, 1, 0xff);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
if(g_Config.bStretchToFit)
// TODO: This code should not have to bother with stretchtofit checking -
// all necessary scale initialization should be done elsewhere.
// TODO: Investigate BlitFramebufferEXT.
if (g_Config.bStretchToFit)
{
//TODO: Do Correctly in a bit
float FactorW = (float)640 / (float)OpenGL_GetWidth();
float FactorH = (float)480 / (float)OpenGL_GetHeight();
float FactorW = 640.f / (float)OpenGL_GetWidth();
float FactorH = 480.f / (float)OpenGL_GetHeight();
float Max = (FactorW < FactorH) ? FactorH : FactorW;
float Temp = 1 / Max;
float Temp = 1.0f / Max;
FactorW *= Temp;
FactorH *= Temp;
@ -686,8 +675,7 @@ void Renderer::FlushZBufferAlphaToTarget()
glTexCoord2f(0, (float)GetTargetHeight()); glVertex2f(-FactorW,FactorH);
glTexCoord2f((float)GetTargetWidth(), (float)GetTargetHeight()); glVertex2f(FactorW,FactorH);
glTexCoord2f((float)GetTargetWidth(), 0); glVertex2f(FactorW,-FactorH);
__Log("%d, %d", FactorW, FactorH);
glEnd();
}
else
{
@ -696,8 +684,8 @@ void Renderer::FlushZBufferAlphaToTarget()
glTexCoord2f(0, (float)(GetTargetHeight())); glVertex2f(-1,1);
glTexCoord2f((float)(GetTargetWidth()), (float)(GetTargetHeight())); glVertex2f(1,1);
glTexCoord2f((float)(GetTargetWidth()), 0); glVertex2f(1,-1);
glEnd();
}
glEnd();
GL_REPORT_ERRORD();
@ -715,7 +703,7 @@ void Renderer::SetRenderMode(RenderMode mode)
if (mode == RM_Normal) {
// flush buffers
if( s_RenderMode == RM_ZBufferAlpha ) {
if (s_RenderMode == RM_ZBufferAlpha) {
FlushZBufferAlphaToTarget();
glDisable(GL_STENCIL_TEST);
}
@ -728,7 +716,7 @@ void Renderer::SetRenderMode(RenderMode mode)
// setup buffers
_assert_(GetZBufferTarget() && bpmem.zmode.updateenable);
if( mode == RM_ZBufferAlpha ) {
if (mode == RM_ZBufferAlpha) {
glEnable(GL_STENCIL_TEST);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
@ -744,7 +732,7 @@ void Renderer::SetRenderMode(RenderMode mode)
_assert_(GetZBufferTarget());
_assert_(s_bHaveStencilBuffer);
if( mode == RM_ZBufferOnly ) {
if (mode == RM_ZBufferOnly) {
// flush and remove stencil
_assert_(s_RenderMode==RM_ZBufferAlpha);
FlushZBufferAlphaToTarget();
@ -755,7 +743,7 @@ void Renderer::SetRenderMode(RenderMode mode)
GL_REPORT_ERRORD();
}
else {
_assert_(mode == RM_ZBufferAlpha&&s_RenderMode==RM_ZBufferOnly);
_assert_(mode == RM_ZBufferAlpha && s_RenderMode == RM_ZBufferOnly);
// setup stencil
glEnable(GL_STENCIL_TEST);
@ -774,11 +762,6 @@ Renderer::RenderMode Renderer::GetRenderMode()
return s_RenderMode;
}
u32 Renderer::GetZBufferTarget()
{
return nZBufferRender > 0 ? s_ZBufferTarget : 0;
}
void Renderer::Swap(const TRectangle& rc)
{
OpenGL_Update(); // just updates the render window position and the backbuffer size
@ -787,30 +770,35 @@ void Renderer::Swap(const TRectangle& rc)
Renderer::SetRenderMode(Renderer::RM_Normal);
// render to the real buffer now
#ifdef USE_AA
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_RenderTargets[0]);
#else
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer
#endif
glViewport(OpenGL_GetXoff(),OpenGL_GetYoff() , (int)OpenGL_GetWidth(), (int)OpenGL_GetHeight());
#if 0
// Not working?
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
glBlitFramebufferEXT(0, 0, 640, 480, 0, 0, OpenGL_GetWidth(), OpenGL_GetHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
#else
// render to the real buffer now
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer
glViewport(OpenGL_GetXoff(), OpenGL_GetYoff(), (int)OpenGL_GetWidth(), (int)OpenGL_GetHeight());
ResetGLState();
// texture map s_RenderTargets[s_curtarget] onto the main buffer
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTargets[s_nCurTarget]);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
TextureMngr::EnableTexRECT(0);
// disable all other stages
for(int i = 1; i < 8; ++i) TextureMngr::DisableStage(i);
for (int i = 1; i < 8; ++i)
TextureMngr::DisableStage(i);
GL_REPORT_ERRORD();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(-1,-1);
glTexCoord2f(0, (float)GetTargetHeight()); glVertex2f(-1,1);
glTexCoord2f((float)GetTargetWidth(), (float)GetTargetHeight()); glVertex2f(1,1);
glTexCoord2f((float)GetTargetWidth(), 0); glVertex2f(1,-1);
glTexCoord2f(0, 0); glVertex2f(-1,-1);
glTexCoord2f(0, (float)GetTargetHeight()); glVertex2f(-1,1);
glTexCoord2f((float)GetTargetWidth(), (float)GetTargetHeight()); glVertex2f(1,1);
glTexCoord2f((float)GetTargetWidth(), 0); glVertex2f(1,-1);
glEnd();
if (g_Config.bWireFrame)
@ -822,14 +810,8 @@ void Renderer::Swap(const TRectangle& rc)
SwapBuffers();
RestoreGLState();
#ifdef USE_AA
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_RenderTargets[s_nCurTarget]);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
glBlitFramebufferEXT(0, 0, nBackbufferWidth, nBackbufferHeight, 0, 0, nBackbufferWidth, nBackbufferHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
#endif
GL_REPORT_ERRORD();
#endif
GL_REPORT_ERRORD();
g_Config.iSaveTargetId = 0;
@ -844,7 +826,7 @@ void Renderer::SwapBuffers()
static int s_fps;
static unsigned long lasttime;
++fpscount;
if( timeGetTime() - lasttime > 1000 )
if (timeGetTime() - lasttime > 1000)
{
lasttime = timeGetTime();
s_fps = fpscount;
@ -853,41 +835,38 @@ void Renderer::SwapBuffers()
// Write logging data to debugger
#if defined(HAVE_WX) && HAVE_WX
if(m_frame)
{
if (m_frame)
Logging(0);
}
#endif
if (g_Config.bOverlayStats) {
char st[2048];
char *p = st;
if(g_Config.bShowFPS)
if (g_Config.bShowFPS)
p+=sprintf(p, "FPS: %d\n", s_fps); // So it shows up before the stats and doesn't make anyting ugly
p+=sprintf(p,"Num textures created: %i\n",stats.numTexturesCreated);
p+=sprintf(p,"Num textures alive: %i\n",stats.numTexturesAlive);
p+=sprintf(p,"Num pshaders created: %i\n",stats.numPixelShadersCreated);
p+=sprintf(p,"Num pshaders alive: %i\n",stats.numPixelShadersAlive);
p+=sprintf(p,"Num vshaders created: %i\n",stats.numVertexShadersCreated);
p+=sprintf(p,"Num vshaders alive: %i\n",stats.numVertexShadersAlive);
p+=sprintf(p,"Num dlists called: %i\n",stats.numDListsCalled);
p+=sprintf(p,"Num dlists called (frame): %i\n",stats.thisFrame.numDListsCalled);
p+=sprintf(p,"textures created: %i\n",stats.numTexturesCreated);
p+=sprintf(p,"textures alive: %i\n",stats.numTexturesAlive);
p+=sprintf(p,"pshaders created: %i\n",stats.numPixelShadersCreated);
p+=sprintf(p,"pshaders alive: %i\n",stats.numPixelShadersAlive);
p+=sprintf(p,"vshaders created: %i\n",stats.numVertexShadersCreated);
p+=sprintf(p,"vshaders alive: %i\n",stats.numVertexShadersAlive);
p+=sprintf(p,"dlists called: %i\n",stats.numDListsCalled);
p+=sprintf(p,"dlists called(f): %i\n",stats.thisFrame.numDListsCalled);
// not used.
//p+=sprintf(p,"Num dlists created: %i\n",stats.numDListsCreated);
//p+=sprintf(p,"Num dlists alive: %i\n",stats.numDListsAlive);
//p+=sprintf(p,"Num strip joins: %i\n",stats.numJoins);
p+=sprintf(p,"Num primitives: %i\n",stats.thisFrame.numPrims);
p+=sprintf(p,"Num primitive joins: %i\n",stats.thisFrame.numPrimitiveJoins);
p+=sprintf(p,"Num buffer splits: %i\n",stats.thisFrame.numBufferSplits);
p+=sprintf(p,"Num draw calls: %i\n",stats.thisFrame.numDrawCalls);
p+=sprintf(p,"Num primitives (DL): %i\n",stats.thisFrame.numDLPrims);
p+=sprintf(p,"Num XF loads: %i\n",stats.thisFrame.numXFLoads);
p+=sprintf(p,"Num XF loads (DL): %i\n",stats.thisFrame.numXFLoadsInDL);
p+=sprintf(p,"Num CP loads: %i\n",stats.thisFrame.numCPLoads);
p+=sprintf(p,"Num CP loads (DL): %i\n",stats.thisFrame.numCPLoadsInDL);
p+=sprintf(p,"Num BP loads: %i\n",stats.thisFrame.numBPLoads);
p+=sprintf(p,"Num BP loads (DL): %i\n",stats.thisFrame.numBPLoadsInDL);
p+=sprintf(p,"Num vertex loaders: %i\n",stats.numVertexLoaders);
//p+=sprintf(p,"dlists created: %i\n",stats.numDListsCreated);
//p+=sprintf(p,"dlists alive: %i\n",stats.numDListsAlive);
//p+=sprintf(p,"strip joins: %i\n",stats.numJoins);
p+=sprintf(p,"primitives: %i\n",stats.thisFrame.numPrims);
p+=sprintf(p,"primitive joins: %i\n",stats.thisFrame.numPrimitiveJoins);
p+=sprintf(p,"buffer splits: %i\n",stats.thisFrame.numBufferSplits);
p+=sprintf(p,"draw calls: %i\n",stats.thisFrame.numDrawCalls);
p+=sprintf(p,"primitives (DL): %i\n",stats.thisFrame.numDLPrims);
p+=sprintf(p,"XF loads: %i\n",stats.thisFrame.numXFLoads);
p+=sprintf(p,"XF loads (DL): %i\n",stats.thisFrame.numXFLoadsInDL);
p+=sprintf(p,"CP loads: %i\n",stats.thisFrame.numCPLoads);
p+=sprintf(p,"CP loads (DL): %i\n",stats.thisFrame.numCPLoadsInDL);
p+=sprintf(p,"BP loads: %i\n",stats.thisFrame.numBPLoads);
p+=sprintf(p,"BP loads (DL): %i\n",stats.thisFrame.numBPLoadsInDL);
p+=sprintf(p,"vertex loaders: %i\n",stats.numVertexLoaders);
std::string text = st;
VertexLoaderManager::AppendListToString(&text);
@ -896,7 +875,7 @@ void Renderer::SwapBuffers()
}
else
{
if(g_Config.bShowFPS)
if (g_Config.bShowFPS)
{
char strfps[25];
sprintf(strfps, "%d\n", s_fps);
@ -928,14 +907,15 @@ void Renderer::SwapBuffers()
GL_REPORT_ERRORD();
//clean out old stuff from caches
frameCount++;
PixelShaderMngr::Cleanup();
TextureMngr::Cleanup();
frameCount++;
// New frame
stats.ResetFrame();
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer );
// Render to the framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
if (nZBufferRender > 0) {
if (--nZBufferRender == 0) {
@ -962,7 +942,7 @@ bool Renderer::SaveRenderTarget(const char* filename, int jpeg)
if (bflip) {
// swap scanlines
std::vector<u32> scanline(nBackbufferWidth);
for(int i = 0; i < nBackbufferHeight/2; ++i) {
for (int i = 0; i < nBackbufferHeight/2; ++i) {
memcpy(&scanline[0], &data[i*nBackbufferWidth], nBackbufferWidth*4);
memcpy(&data[i*nBackbufferWidth], &data[(nBackbufferHeight-i-1)*nBackbufferWidth], nBackbufferWidth*4);
memcpy(&data[(nBackbufferHeight-i-1)*nBackbufferWidth], &scanline[0], nBackbufferWidth*4);

View File

@ -15,6 +15,55 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// How the non-true-XFB mode COULD work:
//
// The game renders to the EFB:
//
// ----------------------+
// | |
// | |
// | |
// | |
// | |
// | | efb_height
// | |
// | |
// | - - - - - - - - - - |
// | |
// +---------------------+
// efb_width
//
// At XFB blit time, the top 640-xxx X XXX part of the above buffer (size dotted below),
// should be stretch blitted into the inner rectangle of the window:
// +-----------------------------------------+
// | | | |
// | | . | |
// | | | |
// | | . | |
// | | | |
// | | . | | OpenGL_Height()
// | | | |
// | | . | |
// | | - - - - - - - - - - | |
// | | \ | |
// +-------+---------------------------------+
// OpenGL_Width()
//
//
// efb_width and efb_height can even be adjusted so that the last blit will result
// in a 1:1 rather than a stretch. That would require creating a bigger efb from the
// start though.
//
// The above is not how it works today.
/*
int win_w = OpenGL_Width();
int win_h = OpenGL_Height();
int blit_w_640 = last_xfb_specified_width;
int blit_h_640 = last_xfb_specified_height;
*/
#ifndef GCOGL_RENDER
#define GCOGL_RENDER
@ -35,22 +84,21 @@ class Renderer
public:
enum RenderMode
{
RM_Normal=0, // normal target as color0, ztarget as color1
RM_ZBufferOnly, // zbuffer as color 0
RM_ZBufferAlpha // zbuffer as color0, also will dump alpha info to regular target once mode is switched
// use stencil buffer to indicate what pixels were written
RM_Normal=0, // normal target as color0, ztarget as color1
RM_ZBufferOnly, // zbuffer as color0
RM_ZBufferAlpha, // zbuffer as color0, also will dump alpha info to regular target once mode is switched
// use stencil buffer to indicate what pixels were written
};
static bool Create2();
static bool Init();
static void Shutdown();
// initialize opengl standard values (like viewport)
static bool Initialize();
static bool InitializeGL();
static void AddMessage(const char* str, u32 ms);
static void ProcessMessages(); // draw the current messages on the screen
static void RenderText(const char* pstr, int left, int top, u32 color);
static void SetAA(int aa); // sets the anti-aliasing level
static void ReinitView(int nNewWidth, int nNewHeight);
@ -65,7 +113,7 @@ public:
static bool HaveStencilBuffer();
static void SetZBufferRender(); // sets rendering of the zbuffer using MRTs
static u32 GetZBufferTarget();
static GLuint GetZBufferTarget();
static void SetColorMask();
static bool SetScissorRect();
@ -73,10 +121,12 @@ public:
static void SetRenderMode(RenderMode mode);
static RenderMode GetRenderMode();
static void SetRenderTarget(u32 targ); // if targ is 0, sets to original render target
static void SetDepthTarget(u32 targ);
static void SetFramebuffer(u32 fb);
static u32 GetRenderTarget();
static void SetRenderTarget(GLuint targ); // if targ is 0, sets to original render target
static void SetDepthTarget(GLuint targ);
static void SetFramebuffer(GLuint fb);
static GLuint GetRenderTarget();
// Finish up the current frame, print some stats
static void Swap(const TRectangle& rc);

View File

@ -120,7 +120,7 @@ VertexLoader::VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr)
m_numLoadedVertices = 0;
m_VertexSize = 0;
m_numPipelineStages = 0;
m_NativeFmt = new NativeVertexFormat();
m_NativeFmt = NativeVertexFormat::Create();
loop_counter = 0;
VertexLoader_Normal::Init();

View File

@ -344,10 +344,11 @@ void VertexShaderMngr::SetConstants()
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
// [0] = width/2
// [1] = height/2
// [2] = 16777215 * (farz-nearz)
// [2] = 16777215 * (farz - nearz)
// [3] = xorig + width/2 + 342
// [4] = yorig + height/2 + 342
// [5] = 16777215 * farz
/*INFO_LOG("view: topleft=(%f,%f), wh=(%f,%f), z=(%f,%f)\n",
rawViewport[3]-rawViewport[0]-342, rawViewport[4]+rawViewport[1]-342,
2 * rawViewport[0], 2 * rawViewport[1],
@ -363,9 +364,10 @@ void VertexShaderMngr::SetConstants()
int overfl;
int xoffs = 0, yoffs = 0;
int wid, hei, actualWid, actualHei;
int winw = OpenGL_GetWidth();
int winh = OpenGL_GetHeight();
float ratio = (float)winw / (float)winh / fourThree;
float ratio = (float)winw / (float)winh / fourThree;
if (g_Config.bKeepAR)
{
// Check if height or width is the limiting factor
@ -421,6 +423,7 @@ void VertexShaderMngr::SetConstants()
Renderer::GetTargetHeight()-((int)(xfregs.rawViewport[4]-xfregs.rawViewport[1]-342-scissorYOff)) * MValueY,
abs((int)(2 * xfregs.rawViewport[0])) * MValueX, abs((int)(2 * xfregs.rawViewport[1])) * MValueY);
}
glDepthRange((xfregs.rawViewport[5]- xfregs.rawViewport[2])/16777215.0f, xfregs.rawViewport[5]/16777215.0f);
}
@ -448,11 +451,11 @@ void VertexShaderMngr::SetConstants()
g_fProjectionMatrix[11] = -(0.0f - xfregs.rawProjection[5]);
// Before R945 Hack
if(g_Config.bProjectionHax1 && !g_Config.bProjectionHax2)
if (g_Config.bProjectionHax1 && !g_Config.bProjectionHax2)
g_fProjectionMatrix[11] = -(1.0f - xfregs.rawProjection[5]);
// R844 Hack
if(!g_Config.bProjectionHax1 && g_Config.bProjectionHax2)
if (!g_Config.bProjectionHax1 && g_Config.bProjectionHax2)
g_fProjectionMatrix[11] = xfregs.rawProjection[5];
//--------------------------------
@ -802,9 +805,9 @@ void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData)
}
break;
case 0x1012: // dual tex transform
if (xfregs.bEnableDualTexTransform != (data&1)) {
if (xfregs.bEnableDualTexTransform != (data & 1)) {
VertexManager::Flush();
xfregs.bEnableDualTexTransform = data&1;
xfregs.bEnableDualTexTransform = data & 1;
}
break;

View File

@ -30,8 +30,6 @@
#define XFB_USE_SHADERS 1
enum {
XFB_WIDTH = 640,
XFB_HEIGHT = 480, // 528 is max height.
XFB_BUF_HEIGHT = 538, //480,
// TODO: figure out what to do with PAL
};
@ -121,7 +119,7 @@ void XFB_Init()
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, xfb_buffer);
// used to render EFB
glGenFramebuffersEXT( 1, &s_xfbFrameBuffer);
glGenFramebuffersEXT(1, &s_xfbFrameBuffer);
glGenRenderbuffersEXT(1, &s_xfbRenderBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_xfbRenderBuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, nBackbufferWidth, nBackbufferHeight);
@ -145,10 +143,9 @@ void XFB_Shutdown()
void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt)
{
Renderer::SetRenderMode(Renderer::RM_Normal);
Renderer::ResetGLState();
// switch to XFB frame buffer
// Switch to XFB frame buffer.
Renderer::SetFramebuffer(s_xfbFrameBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_xfbRenderBuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_xfbRenderBuffer);
@ -172,7 +169,7 @@ void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt)
GL_REPORT_ERRORD();
int width = sourceRc.right - sourceRc.left;
int height = sourceRc.bottom - sourceRc.top;
int height = sourceRc.bottom - sourceRc.top;
glReadPixels(sourceRc.left, sourceRc.top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, efb_buffer);
GL_REPORT_ERRORD();
@ -215,10 +212,10 @@ void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset)
GL_REPORT_ERRORD();
glBegin(GL_QUADS);
glTexCoord2f(width, height + yOffset); glVertex2f(1,-1);
glTexCoord2f(width, 0 + yOffset); glVertex2f(1,1);
glTexCoord2f(0, 0 + yOffset); glVertex2f(-1,1);
glTexCoord2f(0, height + yOffset); glVertex2f(-1,-1);
glTexCoord2f(width, height + yOffset); glVertex2f( 1,-1);
glTexCoord2f(width, 0 + yOffset); glVertex2f( 1, 1);
glTexCoord2f(0, 0 + yOffset); glVertex2f(-1, 1);
glTexCoord2f(0, height + yOffset); glVertex2f(-1,-1);
glEnd();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);

View File

@ -262,8 +262,8 @@ void Video_DoState(unsigned char **ptr, int mode) {
void Video_Prepare(void)
{
OpenGL_MakeCurrent();
if (!Renderer::Create2()) {
g_VideoInitialize.pLog("Renderer::Create2 failed\n", TRUE);
if (!Renderer::Init()) {
g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE);
PanicAlert("Can't create opengl renderer. You might be missing some required opengl extensions, check the logs for more info");
exit(1);
}