Merge branch 'master' into perfqueries.
Conflicts: Source/Core/VideoCommon/Src/VideoConfig.h Source/Core/VideoCommon/VideoCommon.vcxproj.filters Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp Source/Plugins/Plugin_VideoSoftware/Src/Rasterizer.cpp Source/Plugins/Plugin_VideoSoftware/Src/Tev.cpp
This commit is contained in:
@@ -157,9 +157,21 @@ void AVIDump::Stop()
|
||||
NOTICE_LOG(VIDEO, "Stop");
|
||||
}
|
||||
|
||||
void AVIDump::AddFrame(char *data)
|
||||
void AVIDump::AddFrame(const u8* data, int w, int h)
|
||||
{
|
||||
AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, (LPVOID) data, m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer);
|
||||
static bool shown_error = false;
|
||||
if ((w != m_bitmap.biWidth || h != m_bitmap.biHeight) && !shown_error)
|
||||
{
|
||||
PanicAlert("You have resized the window while dumping frames.\n"
|
||||
"Nothing sane can be done to handle this.\n"
|
||||
"Your video will likely be broken.");
|
||||
shown_error = true;
|
||||
|
||||
m_bitmap.biWidth = w;
|
||||
m_bitmap.biHeight = h;
|
||||
}
|
||||
|
||||
AVIStreamWrite(m_streamCompressed, ++m_frameCount, 1, const_cast<u8*>(data), m_bitmap.biSizeImage, AVIIF_KEYFRAME, NULL, &m_byteBuffer);
|
||||
m_totalBytes += m_byteBuffer;
|
||||
// Close the recording if the file is more than 2gb
|
||||
// VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb.
|
||||
@@ -252,7 +264,7 @@ bool AVIDump::CreateFile()
|
||||
File::CreateFullPath(s_FormatContext->filename);
|
||||
|
||||
if (!(s_FormatContext->oformat = av_guess_format("avi", NULL, NULL)) ||
|
||||
!(s_Stream = av_new_stream(s_FormatContext, 0)))
|
||||
!(s_Stream = avformat_new_stream(s_FormatContext, codec)))
|
||||
{
|
||||
CloseFile();
|
||||
return false;
|
||||
@@ -269,7 +281,7 @@ bool AVIDump::CreateFile()
|
||||
s_Stream->codec->pix_fmt = g_Config.bUseFFV1 ? PIX_FMT_BGRA : PIX_FMT_YUV420P;
|
||||
|
||||
if (!(codec = avcodec_find_encoder(s_Stream->codec->codec_id)) ||
|
||||
(avcodec_open(s_Stream->codec, codec) < 0))
|
||||
(avcodec_open2(s_Stream->codec, codec, NULL) < 0))
|
||||
{
|
||||
CloseFile();
|
||||
return false;
|
||||
@@ -298,9 +310,9 @@ bool AVIDump::CreateFile()
|
||||
return true;
|
||||
}
|
||||
|
||||
void AVIDump::AddFrame(uint8_t *data, int width, int height)
|
||||
void AVIDump::AddFrame(const u8* data, int width, int height)
|
||||
{
|
||||
avpicture_fill((AVPicture *)s_BGRFrame, data, PIX_FMT_BGR24, width, height);
|
||||
avpicture_fill((AVPicture *)s_BGRFrame, const_cast<u8*>(data), PIX_FMT_BGR24, width, height);
|
||||
|
||||
// Convert image from BGR24 to desired pixel format, and scale to initial
|
||||
// width and height
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "CommonTypes.h"
|
||||
|
||||
class AVIDump
|
||||
{
|
||||
private:
|
||||
@@ -36,11 +38,11 @@ class AVIDump
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
static bool Start(HWND hWnd, int w, int h);
|
||||
static void AddFrame(char *data);
|
||||
#else
|
||||
static bool Start(int w, int h);
|
||||
static void AddFrame(uint8_t *data, int width, int height);
|
||||
#endif
|
||||
static void AddFrame(const u8* data, int width, int height);
|
||||
|
||||
static void Stop();
|
||||
};
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@ void GetBPRegInfo(const u8* data, char* name, size_t name_size, char* desc, size
|
||||
snprintf(name, name_size, #reg); \
|
||||
(void)(reg);
|
||||
|
||||
case BPMEM_GENMODE: // 0x00
|
||||
SetRegName(BPMEM_GENMODE);
|
||||
// TODO: Description
|
||||
break;
|
||||
|
||||
case BPMEM_DISPLAYCOPYFILER: // 0x01
|
||||
// TODO: This is actually the sample pattern used for copies from an antialiased EFB
|
||||
SetRegName(BPMEM_DISPLAYCOPYFILER);
|
||||
@@ -75,6 +80,28 @@ void GetBPRegInfo(const u8* data, char* name, size_t name_size, char* desc, size
|
||||
}
|
||||
break;
|
||||
|
||||
case BPMEM_BLENDMODE: // 0x41
|
||||
{
|
||||
SetRegName(BPMEM_BLENDMODE);
|
||||
BlendMode mode; mode.hex = cmddata;
|
||||
const char* dstfactors[] = { "0", "1", "src_color", "1-src_color", "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha" };
|
||||
const char* srcfactors[] = { "0", "1", "dst_color", "1-dst_color", "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha" };
|
||||
const char* logicmodes[] = { "0", "s & d", "s & ~d", "s", "~s & d", "d", "s ^ d", "s | d", "~(s | d)", "~(s ^ d)", "~d", "s | ~d", "~s", "~s | d", "~(s & d)", "1" };
|
||||
snprintf(desc, desc_size, "Enable: %s\n"
|
||||
"Logic ops: %s\n"
|
||||
"Dither: %s\n"
|
||||
"Color write: %s\n"
|
||||
"Alpha write: %s\n"
|
||||
"Dest factor: %s\n"
|
||||
"Source factor: %s\n"
|
||||
"Subtract: %s\n"
|
||||
"Logic mode: %s\n",
|
||||
no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither],
|
||||
no_yes[mode.colorupdate], no_yes[mode.alphaupdate], dstfactors[mode.dstfactor],
|
||||
srcfactors[mode.srcfactor], no_yes[mode.subtract], logicmodes[mode.logicmode]);
|
||||
}
|
||||
break;
|
||||
|
||||
case BPMEM_EFB_BR: // 0x4A
|
||||
{
|
||||
// TODO: Misleading name, should be BPMEM_EFB_WH instead
|
||||
@@ -148,6 +175,147 @@ void GetBPRegInfo(const u8* data, char* name, size_t name_size, char* desc, size
|
||||
// TODO: Description
|
||||
break;
|
||||
|
||||
#undef SET_REG_NAME
|
||||
case BPMEM_TEV_COLOR_ENV: // 0xC0
|
||||
case BPMEM_TEV_COLOR_ENV+2:
|
||||
case BPMEM_TEV_COLOR_ENV+4:
|
||||
case BPMEM_TEV_COLOR_ENV+8:
|
||||
case BPMEM_TEV_COLOR_ENV+10:
|
||||
case BPMEM_TEV_COLOR_ENV+12:
|
||||
case BPMEM_TEV_COLOR_ENV+14:
|
||||
case BPMEM_TEV_COLOR_ENV+16:
|
||||
case BPMEM_TEV_COLOR_ENV+18:
|
||||
case BPMEM_TEV_COLOR_ENV+20:
|
||||
case BPMEM_TEV_COLOR_ENV+22:
|
||||
case BPMEM_TEV_COLOR_ENV+24:
|
||||
case BPMEM_TEV_COLOR_ENV+26:
|
||||
case BPMEM_TEV_COLOR_ENV+28:
|
||||
case BPMEM_TEV_COLOR_ENV+30:
|
||||
{
|
||||
SetRegName(BPMEM_TEV_COLOR_ENV);
|
||||
TevStageCombiner::ColorCombiner cc; cc.hex = cmddata;
|
||||
const char* tevin[] =
|
||||
{
|
||||
"prev.rgb", "prev.aaa",
|
||||
"c0.rgb", "c0.aaa",
|
||||
"c1.rgb", "c1.aaa",
|
||||
"c2.rgb", "c2.aaa",
|
||||
"tex.rgb", "tex.aaa",
|
||||
"ras.rgb", "ras.aaa",
|
||||
"ONE", "HALF", "konst.rgb", "ZERO",
|
||||
};
|
||||
const char* tevbias[] = { "0", "+0.5", "-0.5", "compare" };
|
||||
const char* tevop[] = { "add", "sub" };
|
||||
const char* tevscale[] = { "1", "2", "4", "0.5" };
|
||||
const char* tevout[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" };
|
||||
snprintf(desc, desc_size, "tev stage: %d\n"
|
||||
"a: %s\n"
|
||||
"b: %s\n"
|
||||
"c: %s\n"
|
||||
"d: %s\n"
|
||||
"bias: %s\n"
|
||||
"op: %s\n"
|
||||
"clamp: %s\n"
|
||||
"scale factor: %s\n"
|
||||
"dest: %s\n",
|
||||
(data[0] - BPMEM_TEV_COLOR_ENV)/2, tevin[cc.a], tevin[cc.b], tevin[cc.c], tevin[cc.d],
|
||||
tevbias[cc.bias], tevop[cc.op], no_yes[cc.clamp], tevscale[cc.shift], tevout[cc.dest]);
|
||||
break;
|
||||
}
|
||||
|
||||
case BPMEM_TEV_ALPHA_ENV: // 0xC1
|
||||
case BPMEM_TEV_ALPHA_ENV+2:
|
||||
case BPMEM_TEV_ALPHA_ENV+4:
|
||||
case BPMEM_TEV_ALPHA_ENV+6:
|
||||
case BPMEM_TEV_ALPHA_ENV+8:
|
||||
case BPMEM_TEV_ALPHA_ENV+10:
|
||||
case BPMEM_TEV_ALPHA_ENV+12:
|
||||
case BPMEM_TEV_ALPHA_ENV+14:
|
||||
case BPMEM_TEV_ALPHA_ENV+16:
|
||||
case BPMEM_TEV_ALPHA_ENV+18:
|
||||
case BPMEM_TEV_ALPHA_ENV+20:
|
||||
case BPMEM_TEV_ALPHA_ENV+22:
|
||||
case BPMEM_TEV_ALPHA_ENV+24:
|
||||
case BPMEM_TEV_ALPHA_ENV+26:
|
||||
case BPMEM_TEV_ALPHA_ENV+28:
|
||||
case BPMEM_TEV_ALPHA_ENV+30:
|
||||
{
|
||||
SetRegName(BPMEM_TEV_ALPHA_ENV);
|
||||
TevStageCombiner::AlphaCombiner ac; ac.hex = cmddata;
|
||||
const char* tevin[] =
|
||||
{
|
||||
"prev", "c0", "c1", "c2",
|
||||
"tex", "ras", "konst", "ZERO",
|
||||
};
|
||||
const char* tevbias[] = { "0", "+0.5", "-0.5", "compare" };
|
||||
const char* tevop[] = { "add", "sub" };
|
||||
const char* tevscale[] = { "1", "2", "4", "0.5" };
|
||||
const char* tevout[] = { "prev", "c0", "c1", "c2" };
|
||||
snprintf(desc, desc_size, "tev stage: %d\n"
|
||||
"a: %s\n"
|
||||
"b: %s\n"
|
||||
"c: %s\n"
|
||||
"d: %s\n"
|
||||
"bias: %s\n"
|
||||
"op: %s\n"
|
||||
"clamp: %s\n"
|
||||
"scale factor: %s\n"
|
||||
"dest: %s\n"
|
||||
"ras sel: %d\n"
|
||||
"tex sel: %d\n",
|
||||
(data[0] - BPMEM_TEV_ALPHA_ENV)/2, tevin[ac.a], tevin[ac.b], tevin[ac.c], tevin[ac.d],
|
||||
tevbias[ac.bias], tevop[ac.op], no_yes[ac.clamp], tevscale[ac.shift], tevout[ac.dest],
|
||||
ac.rswap, ac.tswap);
|
||||
break;
|
||||
}
|
||||
|
||||
case BPMEM_ALPHACOMPARE: // 0xF3
|
||||
{
|
||||
SetRegName(BPMEM_ALPHACOMPARE);
|
||||
AlphaTest test; test.hex = cmddata;
|
||||
const char* functions[] = { "NEVER", "LESS", "EQUAL", "LEQUAL", "GREATER", "NEQUAL", "GEQUAL", "ALWAYS" };
|
||||
const char* logic[] = { "AND", "OR", "XOR", "XNOR" };
|
||||
snprintf(desc, desc_size, "test 1: %s (ref: %#02x)\n"
|
||||
"test 2: %s (ref: %#02x)\n"
|
||||
"logic: %s\n",
|
||||
functions[test.comp0], test.ref0, functions[test.comp1], test.ref1, logic[test.logic]);
|
||||
break;
|
||||
}
|
||||
|
||||
#undef SetRegName
|
||||
}
|
||||
}
|
||||
|
||||
AlphaTest::TEST_RESULT AlphaTest::TestResult()
|
||||
{
|
||||
switch(logic)
|
||||
{
|
||||
case 0: // AND
|
||||
if (comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS)
|
||||
return PASS;
|
||||
if (comp0 == ALPHACMP_NEVER || comp1 == ALPHACMP_NEVER)
|
||||
return FAIL;
|
||||
break;
|
||||
|
||||
case 1: // OR
|
||||
if (comp0 == ALPHACMP_ALWAYS || comp1 == ALPHACMP_ALWAYS)
|
||||
return PASS;
|
||||
if (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER)
|
||||
return FAIL;
|
||||
break;
|
||||
|
||||
case 2: // XOR
|
||||
if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS))
|
||||
return PASS;
|
||||
if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER))
|
||||
return FAIL;
|
||||
break;
|
||||
|
||||
case 3: // XNOR
|
||||
if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS))
|
||||
return FAIL;
|
||||
if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER))
|
||||
return PASS;
|
||||
break;
|
||||
}
|
||||
return UNDETERMINED;
|
||||
}
|
||||
|
||||
@@ -793,7 +793,7 @@ union PE_CONTROL
|
||||
{
|
||||
u32 pixel_format : 3; // PIXELFMT_X
|
||||
u32 zformat : 3; // Z Compression for 16bit Z format
|
||||
u32 zcomploc : 1; // 1: before tex stage
|
||||
u32 early_ztest : 1; // 1: before tex stage
|
||||
u32 unused : 17;
|
||||
u32 rid : 8;
|
||||
};
|
||||
@@ -857,7 +857,7 @@ union TevKSel
|
||||
int getKA(int i) {return i?kasel1:kasel0;}
|
||||
};
|
||||
|
||||
union AlphaFunc
|
||||
union AlphaTest
|
||||
{
|
||||
struct
|
||||
{
|
||||
@@ -868,6 +868,15 @@ union AlphaFunc
|
||||
u32 logic : 2;
|
||||
};
|
||||
u32 hex;
|
||||
|
||||
enum TEST_RESULT
|
||||
{
|
||||
UNDETERMINED = 0,
|
||||
FAIL = 1,
|
||||
PASS = 2,
|
||||
};
|
||||
|
||||
TEST_RESULT TestResult();
|
||||
};
|
||||
|
||||
union UPE_Copy
|
||||
@@ -981,7 +990,7 @@ struct BPMemory
|
||||
TevReg tevregs[4]; //0xE0
|
||||
FogRangeParams fogRange;
|
||||
FogParams fog; //0xEE,0xEF,0xF0,0xF1,0xF2
|
||||
AlphaFunc alphaFunc; //0xF3
|
||||
AlphaTest alpha_test; //0xF3
|
||||
ZTex1 ztex1; //0xf4,0xf5
|
||||
ZTex2 ztex2;
|
||||
TevKSel tevksel[8];//0xf6,0xf7,f8,f9,fa,fb,fc,fd
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
|
||||
using namespace BPFunctions;
|
||||
|
||||
u32 mapTexAddress;
|
||||
bool mapTexFound;
|
||||
int numWrites;
|
||||
static u32 mapTexAddress;
|
||||
static bool mapTexFound;
|
||||
static int numWrites;
|
||||
|
||||
extern volatile bool g_bSkipCurrentFrame;
|
||||
|
||||
@@ -81,6 +81,9 @@ void BPWritten(const BPCmd& bp)
|
||||
just stuff geometry in them and don't put state changes there
|
||||
----------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// check for invalid state, else unneeded configuration are built
|
||||
g_video_backend->CheckInvalidState();
|
||||
|
||||
// Debugging only, this lets you skip a bp update
|
||||
//static int times = 0;
|
||||
@@ -359,9 +362,9 @@ void BPWritten(const BPCmd& bp)
|
||||
PixelShaderManager::SetFogColorChanged();
|
||||
break;
|
||||
case BPMEM_ALPHACOMPARE: // Compare Alpha Values
|
||||
PRIM_LOG("alphacmp: ref0=%d, ref1=%d, comp0=%d, comp1=%d, logic=%d", bpmem.alphaFunc.ref0,
|
||||
bpmem.alphaFunc.ref1, bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1, bpmem.alphaFunc.logic);
|
||||
PixelShaderManager::SetAlpha(bpmem.alphaFunc);
|
||||
PRIM_LOG("alphacmp: ref0=%d, ref1=%d, comp0=%d, comp1=%d, logic=%d", bpmem.alpha_test.ref0,
|
||||
bpmem.alpha_test.ref1, bpmem.alpha_test.comp0, bpmem.alpha_test.comp1, bpmem.alpha_test.logic);
|
||||
PixelShaderManager::SetAlpha(bpmem.alpha_test);
|
||||
break;
|
||||
case BPMEM_BIAS: // BIAS
|
||||
PRIM_LOG("ztex bias=0x%x", bpmem.ztex1.bias);
|
||||
@@ -458,6 +461,7 @@ void BPWritten(const BPCmd& bp)
|
||||
|
||||
case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format
|
||||
g_renderer->SetColorMask(); // alpha writing needs to be disabled if the new pixel format doesn't have an alpha channel
|
||||
g_renderer->SetBlendMode(true);
|
||||
OnPixelFormatChange();
|
||||
break;
|
||||
|
||||
@@ -500,18 +504,39 @@ void BPWritten(const BPCmd& bp)
|
||||
// if this is different from 0, manual TMEM management is used (GX_PreloadEntireTexture).
|
||||
if (bp.newvalue != 0)
|
||||
{
|
||||
// NOTE(neobrain): Apparently tmemodd doesn't affect hardware behavior at all (libogc uses it just as a buffer and switches its contents with tmemeven whenever this is called)
|
||||
// TODO: Not quite sure if this is completely correct (likely not)
|
||||
// NOTE: libogc's implementation of GX_PreloadEntireTexture seems flawed, so it's not necessarily a good reference for RE'ing this feature.
|
||||
|
||||
BPS_TmemConfig& tmem_cfg = bpmem.tmem_config;
|
||||
u8* ram_ptr = Memory::GetPointer(tmem_cfg.preload_addr << 5);
|
||||
u32 tmem_addr = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
|
||||
u32 size = tmem_cfg.preload_tile_info.count * 32;
|
||||
u8* src_ptr = Memory::GetPointer(tmem_cfg.preload_addr << 5); // TODO: Should we add mask here on GC?
|
||||
u32 size = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE;
|
||||
u32 tmem_addr_even = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
|
||||
|
||||
// Check if the game has overflowed TMEM, and copy up to the limit.
|
||||
// Paper Mario does this when entering the Great Boogly Tree (Chap 2)
|
||||
if ((tmem_addr + size) > TMEM_SIZE)
|
||||
size = TMEM_SIZE - tmem_addr;
|
||||
if (tmem_cfg.preload_tile_info.type != 3)
|
||||
{
|
||||
if (tmem_addr_even + size > TMEM_SIZE)
|
||||
size = TMEM_SIZE - tmem_addr_even;
|
||||
|
||||
memcpy(texMem + tmem_addr, ram_ptr, size);
|
||||
memcpy(texMem + tmem_addr_even, src_ptr, size);
|
||||
}
|
||||
else // RGBA8 tiles (and CI14, but that might just be stupid libogc!)
|
||||
{
|
||||
// AR and GB tiles are stored in separate TMEM banks => can't use a single memcpy for everything
|
||||
u32 tmem_addr_odd = tmem_cfg.preload_tmem_odd * TMEM_LINE_SIZE;
|
||||
|
||||
for (u32 i = 0; i < tmem_cfg.preload_tile_info.count; ++i)
|
||||
{
|
||||
if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE ||
|
||||
tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE)
|
||||
break;
|
||||
|
||||
memcpy(texMem + tmem_addr_even, src_ptr, TMEM_LINE_SIZE);
|
||||
memcpy(texMem + tmem_addr_odd, src_ptr + TMEM_LINE_SIZE, TMEM_LINE_SIZE);
|
||||
tmem_addr_even += TMEM_LINE_SIZE;
|
||||
tmem_addr_odd += TMEM_LINE_SIZE;
|
||||
src_ptr += TMEM_LINE_SIZE * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -72,21 +72,9 @@ void GFXDebuggerCheckAndPause(bool update);
|
||||
void GFXDebuggerToPause(bool update);
|
||||
void GFXDebuggerUpdateScreen();
|
||||
|
||||
#undef ENABLE_GFX_DEBUGGER
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#define ENABLE_GFX_DEBUGGER
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_GFX_DEBUGGER
|
||||
#define GFX_DEBUGGER_PAUSE_AT(event,update) {if (((GFXDebuggerToPauseAtNext & event) && --GFXDebuggerEventToPauseCount<=0) || GFXDebuggerPauseFlag) GFXDebuggerToPause(update);}
|
||||
#define GFX_DEBUGGER_PAUSE_LOG_AT(event,update,dumpfunc) {if (((GFXDebuggerToPauseAtNext & event) && --GFXDebuggerEventToPauseCount<=0) || GFXDebuggerPauseFlag) {{dumpfunc};GFXDebuggerToPause(update);}}
|
||||
#define GFX_DEBUGGER_LOG_AT(event,dumpfunc) {if (( GFXDebuggerToPauseAtNext & event ) ) {{dumpfunc};}}
|
||||
#else
|
||||
// Disable debugging calls in Release build
|
||||
#define GFX_DEBUGGER_PAUSE_AT(event,update)
|
||||
#define GFX_DEBUGGER_PAUSE_LOG_AT(event,update,dumpfunc)
|
||||
#define GFX_DEBUGGER_LOG_AT(event,dumpfunc)
|
||||
#endif // ENABLE_GFX_DEBUGGER
|
||||
|
||||
|
||||
#endif // _GFX_DEBUGGER_H_
|
||||
|
||||
@@ -205,10 +205,6 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
|
||||
OnKeyDown(lParam);
|
||||
FreeLookInput((u32)wParam, lParam);
|
||||
}
|
||||
else if (wParam == WIIMOTE_DISCONNECT)
|
||||
{
|
||||
PostMessage(m_hParent, WM_USER, wParam, lParam);
|
||||
}
|
||||
break;
|
||||
|
||||
// Called when a screensaver wants to show up while this window is active
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright (C) 2003 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 "FPSCounter.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Timer.h"
|
||||
#include "VideoConfig.h"
|
||||
|
||||
#define FPS_REFRESH_INTERVAL 1000
|
||||
|
||||
static unsigned int s_counter = 0;
|
||||
static unsigned int s_fps = 0;
|
||||
static unsigned int s_fps_last_counter = 0;
|
||||
static unsigned long s_last_update_time = 0;
|
||||
static File::IOFile s_bench_file;
|
||||
|
||||
void InitFPSCounter()
|
||||
{
|
||||
s_counter = s_fps_last_counter = 0;
|
||||
s_fps = 0;
|
||||
s_last_update_time = Common::Timer::GetTimeMs();
|
||||
|
||||
if (s_bench_file.IsOpen())
|
||||
s_bench_file.Close();
|
||||
}
|
||||
|
||||
static void LogFPSToFile(unsigned long val)
|
||||
{
|
||||
if (!s_bench_file.IsOpen())
|
||||
s_bench_file.Open(File::GetUserPath(D_LOGS_IDX) + "fps.txt", "w");
|
||||
|
||||
char buffer[256];
|
||||
snprintf(buffer, 256, "%ld\n", val);
|
||||
s_bench_file.WriteArray(buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
int UpdateFPSCounter()
|
||||
{
|
||||
if (Common::Timer::GetTimeMs() - s_last_update_time >= FPS_REFRESH_INTERVAL)
|
||||
{
|
||||
s_last_update_time = Common::Timer::GetTimeMs();
|
||||
s_fps = s_counter - s_fps_last_counter;
|
||||
s_fps_last_counter = s_counter;
|
||||
if (g_ActiveConfig.bLogFPSToFile)
|
||||
LogFPSToFile(s_fps);
|
||||
}
|
||||
|
||||
s_counter++;
|
||||
return s_fps;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2003 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 _FPS_COUNTER_H_
|
||||
#define _FPS_COUNTER_H_
|
||||
|
||||
// Initializes the FPS counter.
|
||||
void InitFPSCounter();
|
||||
|
||||
// Called when a frame is rendered. Returns the value to be displayed on
|
||||
// screen as the FPS counter (updated every second).
|
||||
int UpdateFPSCounter();
|
||||
|
||||
#endif // _FPS_COUNTER_H_
|
||||
@@ -16,7 +16,6 @@
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "VideoConfig.h"
|
||||
#include "Setup.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "Thread.h"
|
||||
#include "Atomic.h"
|
||||
@@ -223,11 +222,11 @@ void RunGpu()
|
||||
{
|
||||
u8 *uData = Memory::GetPointer(fifo.CPReadPointer);
|
||||
|
||||
SaveSSEState();
|
||||
LoadDefaultSSEState();
|
||||
FPURoundMode::SaveSIMDState();
|
||||
FPURoundMode::LoadDefaultSIMDState();
|
||||
ReadDataFromFifo(uData, 32);
|
||||
OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
||||
LoadSSEState();
|
||||
FPURoundMode::LoadSIMDState();
|
||||
|
||||
//DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base");
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ XFBSourceBase *FramebufferManagerBase::m_realXFBSource; // Only used in Real XFB
|
||||
FramebufferManagerBase::VirtualXFBListType FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode
|
||||
const XFBSourceBase* FramebufferManagerBase::m_overlappingXFBArray[MAX_VIRTUAL_XFB];
|
||||
|
||||
unsigned int FramebufferManagerBase::s_last_xfb_width = 1;
|
||||
unsigned int FramebufferManagerBase::s_last_xfb_height = 1;
|
||||
|
||||
FramebufferManagerBase::FramebufferManagerBase()
|
||||
{
|
||||
m_realXFBSource = NULL;
|
||||
@@ -226,3 +229,31 @@ void FramebufferManagerBase::ReplaceVirtualXFB()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FramebufferManagerBase::ScaleToVirtualXfbWidth(int x, unsigned int backbuffer_width)
|
||||
{
|
||||
if (g_ActiveConfig.RealXFBEnabled())
|
||||
return x;
|
||||
|
||||
if (g_ActiveConfig.b3DVision)
|
||||
{
|
||||
// This works, yet the version in the else doesn't. No idea why.
|
||||
return x * (int)backbuffer_width / (int)FramebufferManagerBase::LastXfbWidth();
|
||||
}
|
||||
else
|
||||
return x * (int)Renderer::GetTargetRectangle().GetWidth() / (int)FramebufferManagerBase::LastXfbWidth();
|
||||
}
|
||||
|
||||
int FramebufferManagerBase::ScaleToVirtualXfbHeight(int y, unsigned int backbuffer_height)
|
||||
{
|
||||
if (g_ActiveConfig.RealXFBEnabled())
|
||||
return y;
|
||||
|
||||
if (g_ActiveConfig.b3DVision)
|
||||
{
|
||||
// This works, yet the version in the else doesn't. No idea why.
|
||||
return y * (int)backbuffer_height / (int)FramebufferManagerBase::LastXfbHeight();
|
||||
}
|
||||
else
|
||||
return y * (int)Renderer::GetTargetRectangle().GetHeight() / (int)FramebufferManagerBase::LastXfbHeight();
|
||||
}
|
||||
|
||||
@@ -50,6 +50,14 @@ public:
|
||||
static void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma);
|
||||
static const XFBSourceBase* const* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount);
|
||||
|
||||
static void SetLastXfbWidth(unsigned int width) { s_last_xfb_width = width; }
|
||||
static void SetLastXfbHeight(unsigned int height) { s_last_xfb_height = height; }
|
||||
static unsigned int LastXfbWidth() { return s_last_xfb_width; }
|
||||
static unsigned int LastXfbHeight() { return s_last_xfb_height; }
|
||||
|
||||
static int ScaleToVirtualXfbWidth(int x, unsigned int backbuffer_width);
|
||||
static int ScaleToVirtualXfbHeight(int y, unsigned int backbuffer_height);
|
||||
|
||||
protected:
|
||||
struct VirtualXFB
|
||||
{
|
||||
@@ -85,6 +93,9 @@ private:
|
||||
static VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode
|
||||
|
||||
static const XFBSourceBase* m_overlappingXFBArray[MAX_VIRTUAL_XFB];
|
||||
|
||||
static unsigned int s_last_xfb_width;
|
||||
static unsigned int s_last_xfb_height;
|
||||
};
|
||||
|
||||
extern FramebufferManagerBase *g_framebuffer_manager;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (C) 2003-2009 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/
|
||||
|
||||
// TODO: Handle cache-is-full condition :p
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
#include "DLCache.h"
|
||||
|
||||
namespace DLCache
|
||||
{
|
||||
|
||||
void Init()
|
||||
{
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void ProgressiveCleanup()
|
||||
{
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// NOTE - outside the namespace on purpose.
|
||||
bool HandleDisplayList(u32 address, u32 size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void IncrementCheckContextId()
|
||||
{
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
||||
|
||||
int GetLightingShaderId(u32* out)
|
||||
{
|
||||
for (int i = 0; i < xfregs.numChan.numColorChans; ++i)
|
||||
for (u32 i = 0; i < xfregs.numChan.numColorChans; ++i)
|
||||
{
|
||||
out[i] = xfregs.color[i].enablelighting ?
|
||||
(u32)xfregs.color[i].hex :
|
||||
|
||||
@@ -222,11 +222,17 @@ void VideoBackendHardware::InitializeShared()
|
||||
memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs));
|
||||
memset(&s_accessEFBArgs, 0, sizeof(s_accessEFBArgs));
|
||||
s_AccessEFBResult = 0;
|
||||
m_invalid = false;
|
||||
}
|
||||
|
||||
// Run from the CPU thread
|
||||
void VideoBackendHardware::DoState(PointerWrap& p)
|
||||
{
|
||||
bool software = false;
|
||||
p.Do(software);
|
||||
if (p.GetMode() == PointerWrap::MODE_READ && software == true)
|
||||
// change mode to abort load of incompatible save state.
|
||||
p.SetMode(PointerWrap::MODE_VERIFY);
|
||||
VideoCommon_DoState(p);
|
||||
p.DoMarker("VideoCommon");
|
||||
|
||||
@@ -240,16 +246,25 @@ void VideoBackendHardware::DoState(PointerWrap& p)
|
||||
// Refresh state.
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
BPReload();
|
||||
m_invalid = true;
|
||||
RecomputeCachedArraybases();
|
||||
|
||||
// Clear all caches that touch RAM
|
||||
// (? these don't appear to touch any emulation state that gets saved. moved to on load only.)
|
||||
TextureCache::Invalidate();
|
||||
VertexLoaderManager::MarkAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoBackendHardware::CheckInvalidState() {
|
||||
if (m_invalid)
|
||||
{
|
||||
m_invalid = false;
|
||||
|
||||
BPReload();
|
||||
TextureCache::Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoBackendHardware::PauseAndLock(bool doLock, bool unpauseOnUnlock)
|
||||
{
|
||||
Fifo_PauseAndLock(doLock, unpauseOnUnlock);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "ConfigManager.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
#include "RenderBase.h"
|
||||
#include "Timer.h"
|
||||
@@ -47,6 +48,8 @@ void AddMessage(const char* pstr, u32 ms)
|
||||
|
||||
void DrawMessages()
|
||||
{
|
||||
if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bOnScreenDisplayMessages) return;
|
||||
|
||||
if (s_listMsgs.size() > 0)
|
||||
{
|
||||
int left = 25, top = 15;
|
||||
|
||||
@@ -27,9 +27,8 @@
|
||||
#include "VideoConfig.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
|
||||
static int AlphaPreTest();
|
||||
|
||||
static void StageHash(int stage, u32* out)
|
||||
static void StageHash(u32 stage, u32* out)
|
||||
{
|
||||
out[0] |= bpmem.combiners[stage].colorC.hex & 0xFFFFFF; // 24
|
||||
u32 alphaC = bpmem.combiners[stage].alphaC.hex & 0xFFFFF0; // 24, strip out tswap and rswap for now
|
||||
@@ -109,35 +108,19 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 compo
|
||||
uid->values[0] |= bpmem.genMode.numtexgens << 4; // 4
|
||||
uid->values[0] |= dstAlphaMode << 8; // 2
|
||||
|
||||
bool DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth;
|
||||
|
||||
uid->values[0] |= DepthTextureEnable << 10; // 1
|
||||
|
||||
bool enablePL = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting;
|
||||
uid->values[0] |= enablePL << 11; // 1
|
||||
uid->values[0] |= enablePL << 10; // 1
|
||||
|
||||
if (!enablePL) uid->values[0] |= xfregs.numTexGen.numTexGens << 12; // 4
|
||||
u32 alphaPreTest = AlphaPreTest()+1;
|
||||
if (!enablePL) uid->values[0] |= xfregs.numTexGen.numTexGens << 11; // 4
|
||||
|
||||
uid->values[0] |= alphaPreTest << 16; // 2
|
||||
|
||||
if (alphaPreTest == 1 || (alphaPreTest && !DepthTextureEnable && dstAlphaMode == DSTALPHA_ALPHA_PASS))
|
||||
{
|
||||
// Courtesy of PreAlphaTest, we're done already ;)
|
||||
// NOTE: The comment header of generated shaders depends on the value of bpmem.genmode.numindstages.. shouldnt really bother about that though.
|
||||
uid->num_values = 1;
|
||||
return;
|
||||
}
|
||||
AlphaTest::TEST_RESULT alphaPreTest = bpmem.alpha_test.TestResult();
|
||||
uid->values[0] |= alphaPreTest << 15; // 2
|
||||
|
||||
// numtexgens should be <= 8
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i)
|
||||
{
|
||||
if (18+i < 32)
|
||||
uid->values[0] |= xfregs.texMtxInfo[i].projection << (18+i); // 1
|
||||
else
|
||||
uid->values[1] |= xfregs.texMtxInfo[i].projection << (i - 14); // 1
|
||||
}
|
||||
uid->values[0] |= xfregs.texMtxInfo[i].projection << (17+i); // 1
|
||||
|
||||
uid->values[1] = bpmem.genMode.numindstages << 2; // 3
|
||||
uid->values[1] = bpmem.genMode.numindstages; // 3
|
||||
u32 indirectStagesUsed = 0;
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i)
|
||||
if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
|
||||
@@ -145,43 +128,37 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 compo
|
||||
|
||||
assert(indirectStagesUsed == (indirectStagesUsed & 0xF));
|
||||
|
||||
uid->values[1] |= indirectStagesUsed << 5; // 4;
|
||||
uid->values[1] |= indirectStagesUsed << 3; // 4;
|
||||
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i)
|
||||
{
|
||||
if (indirectStagesUsed & (1 << i))
|
||||
{
|
||||
uid->values[1] |= (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) << (9 + 3*i); // 1
|
||||
uid->values[1] |= (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) << (7 + 3*i); // 1
|
||||
if (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens)
|
||||
uid->values[1] |= bpmem.tevindref.getTexCoord(i) << (10 + 3*i); // 2
|
||||
uid->values[1] |= bpmem.tevindref.getTexCoord(i) << (8 + 3*i); // 2
|
||||
}
|
||||
}
|
||||
|
||||
u32* ptr = &uid->values[2];
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtevstages+1; ++i)
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtevstages+1u; ++i)
|
||||
{
|
||||
StageHash(i, ptr);
|
||||
ptr += 4; // max: ptr = &uid->values[66]
|
||||
}
|
||||
|
||||
ptr[0] |= bpmem.alphaFunc.comp0; // 3
|
||||
ptr[0] |= bpmem.alphaFunc.comp1 << 3; // 3
|
||||
ptr[0] |= bpmem.alphaFunc.logic << 6; // 2
|
||||
ptr[0] |= bpmem.alpha_test.comp0; // 3
|
||||
ptr[0] |= bpmem.alpha_test.comp1 << 3; // 3
|
||||
ptr[0] |= bpmem.alpha_test.logic << 6; // 2
|
||||
|
||||
if (alphaPreTest == 0 || alphaPreTest == 2)
|
||||
{
|
||||
ptr[0] |= bpmem.fog.c_proj_fsel.fsel << 8; // 3
|
||||
if (DepthTextureEnable)
|
||||
{
|
||||
ptr[0] |= bpmem.ztex2.op << 11; // 2
|
||||
ptr[0] |= bpmem.zcontrol.zcomploc << 13; // 1
|
||||
ptr[0] |= bpmem.zmode.testenable << 14; // 1
|
||||
ptr[0] |= bpmem.zmode.updateenable << 15; // 1
|
||||
}
|
||||
}
|
||||
ptr[0] |= bpmem.ztex2.op << 8; // 2
|
||||
ptr[0] |= bpmem.zcontrol.early_ztest << 10; // 1
|
||||
ptr[0] |= bpmem.zmode.testenable << 11; // 1
|
||||
ptr[0] |= bpmem.zmode.updateenable << 12; // 1
|
||||
|
||||
if (dstAlphaMode != DSTALPHA_ALPHA_PASS)
|
||||
{
|
||||
ptr[0] |= bpmem.fog.c_proj_fsel.fsel << 13; // 3
|
||||
if (bpmem.fog.c_proj_fsel.fsel != 0)
|
||||
{
|
||||
ptr[0] |= bpmem.fog.c_proj_fsel.proj << 16; // 1
|
||||
@@ -208,9 +185,8 @@ void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode, u
|
||||
*ptr++ = bpmem.ztex2.hex; // 2
|
||||
*ptr++ = bpmem.zcontrol.hex; // 3
|
||||
*ptr++ = bpmem.zmode.hex; // 4
|
||||
*ptr++ = g_ActiveConfig.bEnablePerPixelDepth; // 5
|
||||
*ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; // 6
|
||||
*ptr++ = xfregs.numTexGen.hex; // 7
|
||||
*ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; // 5
|
||||
*ptr++ = xfregs.numTexGen.hex; // 6
|
||||
|
||||
if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting)
|
||||
{
|
||||
@@ -222,28 +198,28 @@ void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode, u
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < 8; ++i)
|
||||
*ptr++ = xfregs.texMtxInfo[i].hex; // 8-15
|
||||
*ptr++ = xfregs.texMtxInfo[i].hex; // 7-14
|
||||
|
||||
for (unsigned int i = 0; i < 16; ++i)
|
||||
*ptr++ = bpmem.tevind[i].hex; // 16-31
|
||||
*ptr++ = bpmem.tevind[i].hex; // 15-30
|
||||
|
||||
*ptr++ = bpmem.tevindref.hex; // 32
|
||||
*ptr++ = bpmem.tevindref.hex; // 31
|
||||
|
||||
for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) // up to 16 times
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtevstages+1u; ++i) // up to 16 times
|
||||
{
|
||||
*ptr++ = bpmem.combiners[i].colorC.hex; // 33+5*i
|
||||
*ptr++ = bpmem.combiners[i].alphaC.hex; // 34+5*i
|
||||
*ptr++ = bpmem.tevind[i].hex; // 35+5*i
|
||||
*ptr++ = bpmem.tevksel[i/2].hex; // 36+5*i
|
||||
*ptr++ = bpmem.tevorders[i/2].hex; // 37+5*i
|
||||
*ptr++ = bpmem.combiners[i].colorC.hex; // 32+5*i
|
||||
*ptr++ = bpmem.combiners[i].alphaC.hex; // 33+5*i
|
||||
*ptr++ = bpmem.tevind[i].hex; // 34+5*i
|
||||
*ptr++ = bpmem.tevksel[i/2].hex; // 35+5*i
|
||||
*ptr++ = bpmem.tevorders[i/2].hex; // 36+5*i
|
||||
}
|
||||
|
||||
ptr = &uid->values[113];
|
||||
ptr = &uid->values[112];
|
||||
|
||||
*ptr++ = bpmem.alphaFunc.hex; // 113
|
||||
*ptr++ = bpmem.alpha_test.hex; // 112
|
||||
|
||||
*ptr++ = bpmem.fog.c_proj_fsel.hex; // 114
|
||||
*ptr++ = bpmem.fogRange.Base.hex; // 115
|
||||
*ptr++ = bpmem.fog.c_proj_fsel.hex; // 113
|
||||
*ptr++ = bpmem.fogRange.Base.hex; // 114
|
||||
|
||||
_assert_((ptr - uid->values) == uid->GetNumValues());
|
||||
}
|
||||
@@ -312,10 +288,10 @@ static const char *tevKSelTableC[] = // KCSEL
|
||||
"0.375f,0.375f,0.375f", // 3_8 = 0x05
|
||||
"0.25f,0.25f,0.25f", // 1_4 = 0x06
|
||||
"0.125f,0.125f,0.125f", // 1_8 = 0x07
|
||||
"ERROR", // 0x08
|
||||
"ERROR", // 0x09
|
||||
"ERROR", // 0x0a
|
||||
"ERROR", // 0x0b
|
||||
"ERROR1", // 0x08
|
||||
"ERROR2", // 0x09
|
||||
"ERROR3", // 0x0a
|
||||
"ERROR4", // 0x0b
|
||||
I_KCOLORS"[0].rgb", // K0 = 0x0C
|
||||
I_KCOLORS"[1].rgb", // K1 = 0x0D
|
||||
I_KCOLORS"[2].rgb", // K2 = 0x0E
|
||||
@@ -348,14 +324,14 @@ static const char *tevKSelTableA[] = // KASEL
|
||||
"0.375f",// 3_8 = 0x05
|
||||
"0.25f", // 1_4 = 0x06
|
||||
"0.125f",// 1_8 = 0x07
|
||||
"ERROR", // 0x08
|
||||
"ERROR", // 0x09
|
||||
"ERROR", // 0x0a
|
||||
"ERROR", // 0x0b
|
||||
"ERROR", // 0x0c
|
||||
"ERROR", // 0x0d
|
||||
"ERROR", // 0x0e
|
||||
"ERROR", // 0x0f
|
||||
"ERROR5", // 0x08
|
||||
"ERROR6", // 0x09
|
||||
"ERROR7", // 0x0a
|
||||
"ERROR8", // 0x0b
|
||||
"ERROR9", // 0x0c
|
||||
"ERROR10", // 0x0d
|
||||
"ERROR11", // 0x0e
|
||||
"ERROR12", // 0x0f
|
||||
I_KCOLORS"[0].r", // K0_R = 0x10
|
||||
I_KCOLORS"[1].r", // K1_R = 0x11
|
||||
I_KCOLORS"[2].r", // K2_R = 0x12
|
||||
@@ -430,7 +406,7 @@ static const char *tevCInputTable[] = // CC
|
||||
"float3(0.5f, 0.5f, 0.5f)", // HALF
|
||||
"(ckonsttemp.rgb)", //"konsttemp.rgb", // KONST
|
||||
"float3(0.0f, 0.0f, 0.0f)", // ZERO
|
||||
"PADERROR", "PADERROR", "PADERROR", "PADERROR"
|
||||
"PADERROR1", "PADERROR2", "PADERROR3", "PADERROR4"
|
||||
};
|
||||
|
||||
static const char *tevAInputTable[] = // CA
|
||||
@@ -452,17 +428,17 @@ static const char *tevAInputTable[] = // CA
|
||||
"crastemp", // RASA,
|
||||
"ckonsttemp", // KONST, (hw1 had quarter)
|
||||
"float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO
|
||||
"PADERROR", "PADERROR", "PADERROR", "PADERROR",
|
||||
"PADERROR", "PADERROR", "PADERROR", "PADERROR",
|
||||
"PADERROR5", "PADERROR6", "PADERROR7", "PADERROR8",
|
||||
"PADERROR9", "PADERROR10", "PADERROR11", "PADERROR12",
|
||||
};
|
||||
|
||||
static const char *tevRasTable[] =
|
||||
{
|
||||
"colors_0",
|
||||
"colors_1",
|
||||
"ERROR", //2
|
||||
"ERROR", //3
|
||||
"ERROR", //4
|
||||
"ERROR13", //2
|
||||
"ERROR14", //3
|
||||
"ERROR15", //4
|
||||
"alphabump", // use bump alpha
|
||||
"(alphabump*(255.0f/248.0f))", //normalized
|
||||
"float4(0.0f, 0.0f, 0.0f, 0.0f)", // zero
|
||||
@@ -485,7 +461,15 @@ static const char *tevIndFmtScale[] = {"255.0f", "31.0f", "15.0f", "7.0f" };
|
||||
static char swapModeTable[4][5];
|
||||
|
||||
static char text[16384];
|
||||
static bool DepthTextureEnable;
|
||||
|
||||
struct RegisterState
|
||||
{
|
||||
bool ColorNeedOverflowControl;
|
||||
bool AlphaNeedOverflowControl;
|
||||
bool AuxStored;
|
||||
};
|
||||
|
||||
static RegisterState RegisterStates[4];
|
||||
|
||||
static void BuildSwapModeTable()
|
||||
{
|
||||
@@ -523,7 +507,6 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
|
||||
nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt;
|
||||
}
|
||||
}
|
||||
DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth ;
|
||||
// Declare samplers
|
||||
|
||||
if(ApiType != API_D3D11)
|
||||
@@ -579,14 +562,14 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
|
||||
{
|
||||
WRITE(p, " out float4 ocol0 : COLOR0,%s%s\n in float4 rawpos : %s,\n",
|
||||
dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : COLOR1," : "",
|
||||
DepthTextureEnable ? "\n out float depth : DEPTH," : "",
|
||||
"\n out float depth : DEPTH,",
|
||||
ApiType & API_OPENGL ? "WPOS" : ApiType & API_D3D9_SM20 ? "POSITION" : "VPOS");
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE(p, " out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n",
|
||||
dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "",
|
||||
DepthTextureEnable ? "\n out float depth : SV_Depth," : "");
|
||||
"\n out float depth : SV_Depth,");
|
||||
}
|
||||
|
||||
WRITE(p, " in float4 colors_0 : COLOR0,\n");
|
||||
@@ -617,33 +600,6 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
|
||||
}
|
||||
WRITE(p, " ) {\n");
|
||||
|
||||
char* pmainstart = p;
|
||||
int Pretest = AlphaPreTest();
|
||||
if(Pretest >= 0 && !DepthTextureEnable)
|
||||
{
|
||||
if (!Pretest)
|
||||
{
|
||||
// alpha test will always fail, so restart the shader and just make it an empty function
|
||||
WRITE(p, "ocol0 = 0;\n");
|
||||
if(DepthTextureEnable)
|
||||
WRITE(p, "depth = 1.f;\n");
|
||||
if(dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND)
|
||||
WRITE(p, "ocol1 = 0;\n");
|
||||
WRITE(p, "discard;\n");
|
||||
if(ApiType != API_D3D11)
|
||||
WRITE(p, "return;\n");
|
||||
}
|
||||
else if (dstAlphaMode == DSTALPHA_ALPHA_PASS)
|
||||
{
|
||||
WRITE(p, " ocol0 = " I_ALPHA"[0].aaaa;\n");
|
||||
}
|
||||
if(!Pretest || dstAlphaMode == DSTALPHA_ALPHA_PASS)
|
||||
{
|
||||
WRITE(p, "}\n");
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
WRITE(p, " float4 c0 = " I_COLORS"[1], c1 = " I_COLORS"[2], c2 = " I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n"
|
||||
" float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f);\n"
|
||||
" float4 alphabump=float4(0.0f,0.0f,0.0f,0.0f);\n"
|
||||
@@ -717,6 +673,16 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
|
||||
}
|
||||
}
|
||||
|
||||
RegisterStates[0].AlphaNeedOverflowControl = false;
|
||||
RegisterStates[0].ColorNeedOverflowControl = false;
|
||||
RegisterStates[0].AuxStored = false;
|
||||
for(int i = 1; i < 4; i++)
|
||||
{
|
||||
RegisterStates[i].AlphaNeedOverflowControl = true;
|
||||
RegisterStates[i].ColorNeedOverflowControl = true;
|
||||
RegisterStates[i].AuxStored = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numStages; i++)
|
||||
WriteStage(p, i, ApiType); //build the equation for this stage
|
||||
|
||||
@@ -724,40 +690,43 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
|
||||
{
|
||||
// The results of the last texenv stage are put onto the screen,
|
||||
// regardless of the used destination register
|
||||
WRITE(p, "prev.rgb = %s;\n",tevCOutputTable[bpmem.combiners[numStages-1].colorC.dest]);
|
||||
WRITE(p, "prev.a = %s;\n",tevAOutputTable[bpmem.combiners[numStages-1].alphaC.dest]);
|
||||
if(bpmem.combiners[numStages - 1].colorC.dest != 0)
|
||||
{
|
||||
bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].AuxStored;
|
||||
WRITE(p, "prev.rgb = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]);
|
||||
RegisterStates[0].ColorNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl;
|
||||
}
|
||||
if(bpmem.combiners[numStages - 1].alphaC.dest != 0)
|
||||
{
|
||||
bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AuxStored;
|
||||
WRITE(p, "prev.a = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]);
|
||||
RegisterStates[0].AlphaNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl;
|
||||
}
|
||||
}
|
||||
// emulation of unsigned 8 overflow when casting
|
||||
WRITE(p, "prev = frac(4.0f + prev * (255.0f/256.0f)) * (256.0f/255.0f);\n");
|
||||
// emulation of unsigned 8 overflow when casting if needed
|
||||
if(RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl)
|
||||
WRITE(p, "prev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n");
|
||||
|
||||
if(Pretest == -1)
|
||||
{
|
||||
AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult();
|
||||
if (Pretest == AlphaTest::UNDETERMINED)
|
||||
WriteAlphaTest(p, ApiType, dstAlphaMode);
|
||||
}
|
||||
|
||||
if((bpmem.fog.c_proj_fsel.fsel != 0) || DepthTextureEnable)
|
||||
{
|
||||
// the screen space depth value = far z + (clip z / clip w) * z range
|
||||
WRITE(p, "float zCoord = " I_ZBIAS"[1].x + (clipPos.z / clipPos.w) * " I_ZBIAS"[1].y;\n");
|
||||
}
|
||||
// the screen space depth value = far z + (clip z / clip w) * z range
|
||||
WRITE(p, "float zCoord = " I_ZBIAS"[1].x + (clipPos.z / clipPos.w) * " I_ZBIAS"[1].y;\n");
|
||||
|
||||
if (DepthTextureEnable)
|
||||
// Note: depth textures are disabled if early depth test is enabled
|
||||
if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest && bpmem.zmode.testenable)
|
||||
{
|
||||
// use the texture input of the last texture stage (textemp), hopefully this has been read and is in correct format...
|
||||
if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable)
|
||||
{
|
||||
if (bpmem.ztex2.op == ZTEXTURE_ADD)
|
||||
WRITE(p, "zCoord = dot(" I_ZBIAS"[0].xyzw, textemp.xyzw) + " I_ZBIAS"[1].w + zCoord;\n");
|
||||
else
|
||||
WRITE(p, "zCoord = dot(" I_ZBIAS"[0].xyzw, textemp.xyzw) + " I_ZBIAS"[1].w;\n");
|
||||
WRITE(p, "zCoord = dot(" I_ZBIAS"[0].xyzw, textemp.xyzw) + " I_ZBIAS"[1].w %s;\n",
|
||||
(bpmem.ztex2.op == ZTEXTURE_ADD) ? "+ zCoord" : "");
|
||||
|
||||
// scale to make result from frac correct
|
||||
WRITE(p, "zCoord = zCoord * (16777215.0f/16777216.0f);\n");
|
||||
WRITE(p, "zCoord = frac(zCoord);\n");
|
||||
WRITE(p, "zCoord = zCoord * (16777216.0f/16777215.0f);\n");
|
||||
}
|
||||
WRITE(p, "depth = zCoord;\n");
|
||||
// scale to make result from frac correct
|
||||
WRITE(p, "zCoord = zCoord * (16777215.0f/16777216.0f);\n");
|
||||
WRITE(p, "zCoord = frac(zCoord);\n");
|
||||
WRITE(p, "zCoord = zCoord * (16777216.0f/16777215.0f);\n");
|
||||
}
|
||||
WRITE(p, "depth = zCoord;\n");
|
||||
|
||||
if (dstAlphaMode == DSTALPHA_ALPHA_PASS)
|
||||
WRITE(p, " ocol0 = float4(prev.rgb, " I_ALPHA"[0].a);\n");
|
||||
@@ -917,7 +886,6 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
|
||||
TevStageCombiner::ColorCombiner &cc = bpmem.combiners[n].colorC;
|
||||
TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[n].alphaC;
|
||||
|
||||
// blah1
|
||||
if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC
|
||||
|| cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC
|
||||
|| cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC
|
||||
@@ -950,7 +918,6 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
|
||||
WRITE(p, "textemp = float4(1.0f, 1.0f, 1.0f, 1.0f);\n");
|
||||
|
||||
|
||||
// blah2
|
||||
if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST
|
||||
|| ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST)
|
||||
{
|
||||
@@ -971,30 +938,78 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
|
||||
|| cc.b == TEVCOLORARG_CPREV || cc.b == TEVCOLORARG_APREV
|
||||
|| cc.c == TEVCOLORARG_CPREV || cc.c == TEVCOLORARG_APREV
|
||||
|| ac.a == TEVALPHAARG_APREV || ac.b == TEVALPHAARG_APREV || ac.c == TEVALPHAARG_APREV)
|
||||
WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n");
|
||||
|
||||
{
|
||||
if(RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl)
|
||||
{
|
||||
WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n");
|
||||
RegisterStates[0].AlphaNeedOverflowControl = false;
|
||||
RegisterStates[0].ColorNeedOverflowControl = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE(p, "cprev = prev;\n");
|
||||
}
|
||||
RegisterStates[0].AuxStored = true;
|
||||
}
|
||||
|
||||
if(cc.a == TEVCOLORARG_C0 || cc.a == TEVCOLORARG_A0
|
||||
|| cc.b == TEVCOLORARG_C0 || cc.b == TEVCOLORARG_A0
|
||||
|| cc.c == TEVCOLORARG_C0 || cc.c == TEVCOLORARG_A0
|
||||
|| ac.a == TEVALPHAARG_A0 || ac.b == TEVALPHAARG_A0 || ac.c == TEVALPHAARG_A0)
|
||||
WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
|
||||
|
||||
{
|
||||
if(RegisterStates[1].AlphaNeedOverflowControl || RegisterStates[1].ColorNeedOverflowControl)
|
||||
{
|
||||
WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
|
||||
RegisterStates[1].AlphaNeedOverflowControl = false;
|
||||
RegisterStates[1].ColorNeedOverflowControl = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE(p, "cc0 = c0;\n");
|
||||
}
|
||||
RegisterStates[1].AuxStored = true;
|
||||
}
|
||||
|
||||
if(cc.a == TEVCOLORARG_C1 || cc.a == TEVCOLORARG_A1
|
||||
|| cc.b == TEVCOLORARG_C1 || cc.b == TEVCOLORARG_A1
|
||||
|| cc.c == TEVCOLORARG_C1 || cc.c == TEVCOLORARG_A1
|
||||
|| ac.a == TEVALPHAARG_A1 || ac.b == TEVALPHAARG_A1 || ac.c == TEVALPHAARG_A1)
|
||||
WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
|
||||
|
||||
{
|
||||
if(RegisterStates[2].AlphaNeedOverflowControl || RegisterStates[2].ColorNeedOverflowControl)
|
||||
{
|
||||
WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
|
||||
RegisterStates[2].AlphaNeedOverflowControl = false;
|
||||
RegisterStates[2].ColorNeedOverflowControl = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE(p, "cc1 = c1;\n");
|
||||
}
|
||||
RegisterStates[2].AuxStored = true;
|
||||
}
|
||||
|
||||
if(cc.a == TEVCOLORARG_C2 || cc.a == TEVCOLORARG_A2
|
||||
|| cc.b == TEVCOLORARG_C2 || cc.b == TEVCOLORARG_A2
|
||||
|| cc.c == TEVCOLORARG_C2 || cc.c == TEVCOLORARG_A2
|
||||
|| ac.a == TEVALPHAARG_A2 || ac.b == TEVALPHAARG_A2 || ac.c == TEVALPHAARG_A2)
|
||||
{
|
||||
if(RegisterStates[3].AlphaNeedOverflowControl || RegisterStates[3].ColorNeedOverflowControl)
|
||||
{
|
||||
WRITE(p, "cc2 = frac(c2 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
|
||||
RegisterStates[3].AlphaNeedOverflowControl = false;
|
||||
RegisterStates[3].ColorNeedOverflowControl = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE(p, "cc2 = c2;\n");
|
||||
}
|
||||
RegisterStates[3].AuxStored = true;
|
||||
}
|
||||
|
||||
RegisterStates[cc.dest].ColorNeedOverflowControl = (cc.clamp == 0);
|
||||
RegisterStates[cc.dest].AuxStored = false;
|
||||
|
||||
// combine the color channel
|
||||
WRITE(p, "// color combine\n");
|
||||
if (cc.clamp)
|
||||
WRITE(p, "%s = saturate(", tevCOutputTable[cc.dest]);
|
||||
@@ -1042,8 +1057,11 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
|
||||
WRITE(p, ")");
|
||||
WRITE(p,";\n");
|
||||
|
||||
WRITE(p, "// alpha combine\n");
|
||||
RegisterStates[ac.dest].AlphaNeedOverflowControl = (ac.clamp == 0);
|
||||
RegisterStates[ac.dest].AuxStored = false;
|
||||
|
||||
// combine the alpha channel
|
||||
WRITE(p, "// alpha combine\n");
|
||||
if (ac.clamp)
|
||||
WRITE(p, "%s = saturate(", tevAOutputTable[ac.dest]);
|
||||
else
|
||||
@@ -1118,39 +1136,6 @@ static const char *tevAlphaFunclogicTable[] =
|
||||
" != ", // xor
|
||||
" == " // xnor
|
||||
};
|
||||
static int AlphaPreTest()
|
||||
{
|
||||
u32 op = bpmem.alphaFunc.logic;
|
||||
u32 comp[2] = {bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1};
|
||||
|
||||
// First kill all the simple cases
|
||||
switch(op)
|
||||
{
|
||||
case 0: // AND
|
||||
if (comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) return true;
|
||||
if (comp[0] == ALPHACMP_NEVER || comp[1] == ALPHACMP_NEVER) return false;
|
||||
break;
|
||||
case 1: // OR
|
||||
if (comp[0] == ALPHACMP_ALWAYS || comp[1] == ALPHACMP_ALWAYS) return true;
|
||||
if (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)return false;
|
||||
break;
|
||||
case 2: // XOR
|
||||
if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS))
|
||||
return true;
|
||||
if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER))
|
||||
return false;
|
||||
break;
|
||||
case 3: // XNOR
|
||||
if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS))
|
||||
return false;
|
||||
if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER))
|
||||
return true;
|
||||
break;
|
||||
default: PanicAlert("bad logic for alpha test? %08x", op);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode)
|
||||
{
|
||||
@@ -1163,34 +1148,31 @@ static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode
|
||||
// using discard then return works the same in cg and dx9 but not in dx11
|
||||
WRITE(p, "if(!( ");
|
||||
|
||||
int compindex = bpmem.alphaFunc.comp0 % 8;
|
||||
int compindex = bpmem.alpha_test.comp0;
|
||||
WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[0]);//lookup the first component from the alpha function table
|
||||
|
||||
WRITE(p, "%s", tevAlphaFunclogicTable[bpmem.alphaFunc.logic % 4]);//lookup the logic op
|
||||
WRITE(p, "%s", tevAlphaFunclogicTable[bpmem.alpha_test.logic]);//lookup the logic op
|
||||
|
||||
compindex = bpmem.alphaFunc.comp1 % 8;
|
||||
compindex = bpmem.alpha_test.comp1;
|
||||
WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[1]);//lookup the second component from the alpha function table
|
||||
WRITE(p, ")) {\n");
|
||||
|
||||
WRITE(p, "ocol0 = 0;\n");
|
||||
if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND)
|
||||
WRITE(p, "ocol1 = 0;\n");
|
||||
if (DepthTextureEnable)
|
||||
WRITE(p, "depth = 1.f;\n");
|
||||
WRITE(p, "depth = 1.f;\n");
|
||||
|
||||
// HAXX: zcomploc is a way to control whether depth test is done before
|
||||
// or after texturing and alpha test. PC GPU does depth test before texturing ONLY if depth value is
|
||||
// not updated during shader execution.
|
||||
// HAXX: zcomploc (aka early_ztest) is a way to control whether depth test is done before
|
||||
// or after texturing and alpha test. PC GPUs have no way to support this
|
||||
// feature properly as of 2012: depth buffer and depth test are not
|
||||
// programmable and the depth test is always done after texturing.
|
||||
// Most importantly, PC GPUs do not allow writing to the z buffer without
|
||||
// writing a color value (unless color writing is disabled altogether).
|
||||
// We implement "depth test before texturing" by discarding the fragment
|
||||
// when the alpha test fail. This is not a correct implementation because
|
||||
// even if the depth test fails the fragment could be alpha blended.
|
||||
// this implemnetation is a trick to keep speed.
|
||||
// the correct, but slow, way to implement a correct zComploc is :
|
||||
// 1 - if zcomplock is enebled make a first pass, with color channel write disabled updating only
|
||||
// depth channel.
|
||||
// 2 - in the next pass disable depth chanel update, but proccess the color data normally
|
||||
// this way is the only CORRECT way to emulate perfectly the zcomplock behaviour
|
||||
if (!(bpmem.zcontrol.zcomploc && bpmem.zmode.updateenable))
|
||||
// even if the depth test fails the fragment could be alpha blended, but
|
||||
// we don't have a choice.
|
||||
if (!(bpmem.zcontrol.early_ztest && bpmem.zmode.updateenable))
|
||||
{
|
||||
WRITE(p, "discard;\n");
|
||||
if (ApiType != API_D3D11)
|
||||
@@ -1198,7 +1180,6 @@ static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode
|
||||
}
|
||||
|
||||
WRITE(p, "}\n");
|
||||
|
||||
}
|
||||
|
||||
static const char *tevFogFuncsTable[] =
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#define C_PMATERIALS (C_PLIGHTS + 40)
|
||||
#define C_PENVCONST_END (C_PMATERIALS + 4)
|
||||
#define PIXELSHADERUID_MAX_VALUES 70
|
||||
#define PIXELSHADERUID_MAX_VALUES_SAFE 120
|
||||
#define PIXELSHADERUID_MAX_VALUES_SAFE 115
|
||||
|
||||
// DO NOT make anything in this class virtual.
|
||||
template<bool safe>
|
||||
|
||||
@@ -302,7 +302,7 @@ void PixelShaderManager::SetConstants()
|
||||
float GC_ALIGNED16(material[4]);
|
||||
float NormalizationCoef = 1 / 255.0f;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (nMaterialsChanged & (1 << i))
|
||||
{
|
||||
@@ -316,6 +316,21 @@ void PixelShaderManager::SetConstants()
|
||||
SetPSConstant4fv(C_PMATERIALS + i, material);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (nMaterialsChanged & (1 << (i + 2)))
|
||||
{
|
||||
u32 data = *(xfregs.matColor + i);
|
||||
|
||||
material[0] = ((data >> 24) & 0xFF) * NormalizationCoef;
|
||||
material[1] = ((data >> 16) & 0xFF) * NormalizationCoef;
|
||||
material[2] = ((data >> 8) & 0xFF) * NormalizationCoef;
|
||||
material[3] = ( data & 0xFF) * NormalizationCoef;
|
||||
|
||||
SetPSConstant4fv(C_PMATERIALS + i + 2, material);
|
||||
}
|
||||
}
|
||||
|
||||
nMaterialsChanged = 0;
|
||||
}
|
||||
@@ -358,7 +373,7 @@ void PixelShaderManager::SetColorChanged(int type, int num, bool high)
|
||||
PRIM_LOG("pixel %scolor%d: %f %f %f %f\n", type?"k":"", num, pf[0], pf[1], pf[2], pf[3]);
|
||||
}
|
||||
|
||||
void PixelShaderManager::SetAlpha(const AlphaFunc& alpha)
|
||||
void PixelShaderManager::SetAlpha(const AlphaTest& alpha)
|
||||
{
|
||||
if ((alpha.hex & 0xffff) != lastAlpha)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
|
||||
// constant management, should be called after memory is committed
|
||||
static void SetColorChanged(int type, int index, bool high);
|
||||
static void SetAlpha(const AlphaFunc& alpha);
|
||||
static void SetAlpha(const AlphaTest& alpha);
|
||||
static void SetDestAlpha(const ConstantAlpha& alpha);
|
||||
static void SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt);
|
||||
static void SetZTextureBias(u32 bias);
|
||||
|
||||
@@ -67,12 +67,7 @@ int Renderer::s_target_height;
|
||||
int Renderer::s_backbuffer_width;
|
||||
int Renderer::s_backbuffer_height;
|
||||
|
||||
// ratio of backbuffer size and render area size
|
||||
float Renderer::xScale;
|
||||
float Renderer::yScale;
|
||||
|
||||
unsigned int Renderer::s_XFB_width;
|
||||
unsigned int Renderer::s_XFB_height;
|
||||
TargetRectangle Renderer::target_rc;
|
||||
|
||||
int Renderer::s_LastEFBScale;
|
||||
|
||||
@@ -81,9 +76,16 @@ bool Renderer::XFBWrited;
|
||||
bool Renderer::s_EnableDLCachingAfterRecording;
|
||||
|
||||
unsigned int Renderer::prev_efb_format = (unsigned int)-1;
|
||||
unsigned int Renderer::efb_scale_numeratorX = 1;
|
||||
unsigned int Renderer::efb_scale_numeratorY = 1;
|
||||
unsigned int Renderer::efb_scale_denominatorX = 1;
|
||||
unsigned int Renderer::efb_scale_denominatorY = 1;
|
||||
unsigned int Renderer::ssaa_multiplier = 1;
|
||||
|
||||
|
||||
Renderer::Renderer() : frame_data(NULL), bLastFrameDumped(false)
|
||||
Renderer::Renderer()
|
||||
: frame_data()
|
||||
, bLastFrameDumped(false)
|
||||
{
|
||||
UpdateActiveConfig();
|
||||
TextureCache::OnConfigChanged(g_ActiveConfig);
|
||||
@@ -91,6 +93,9 @@ Renderer::Renderer() : frame_data(NULL), bLastFrameDumped(false)
|
||||
#if defined _WIN32 || defined HAVE_LIBAV
|
||||
bAVIDumping = false;
|
||||
#endif
|
||||
|
||||
OSDChoice = 0;
|
||||
OSDTime = 0;
|
||||
}
|
||||
|
||||
Renderer::~Renderer()
|
||||
@@ -98,6 +103,8 @@ Renderer::~Renderer()
|
||||
// invalidate previous efb format
|
||||
prev_efb_format = (unsigned int)-1;
|
||||
|
||||
efb_scale_numeratorX = efb_scale_numeratorY = efb_scale_denominatorX = efb_scale_denominatorY = ssaa_multiplier = 1;
|
||||
|
||||
#if defined _WIN32 || defined HAVE_LIBAV
|
||||
if (g_ActiveConfig.bDumpFrames && bLastFrameDumped && bAVIDumping)
|
||||
AVIDump::Stop();
|
||||
@@ -105,7 +112,6 @@ Renderer::~Renderer()
|
||||
if (pFrameDump.IsOpen())
|
||||
pFrameDump.Close();
|
||||
#endif
|
||||
delete[] frame_data;
|
||||
}
|
||||
|
||||
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma)
|
||||
@@ -121,64 +127,117 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect
|
||||
VideoFifo_CheckSwapRequestAt(xfbAddr, fbWidth, fbHeight);
|
||||
XFBWrited = true;
|
||||
|
||||
// XXX: Without the VI, how would we know what kind of field this is? So
|
||||
// just use progressive.
|
||||
if (g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
FramebufferManagerBase::CopyToXFB(xfbAddr, fbWidth, fbHeight, sourceRc,Gamma);
|
||||
}
|
||||
else
|
||||
{
|
||||
// XXX: Without the VI, how would we know what kind of field this is? So
|
||||
// just use progressive.
|
||||
g_renderer->Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight,sourceRc,Gamma);
|
||||
Common::AtomicStoreRelease(s_swapRequested, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::CalculateTargetScale(int x, int y, int &scaledX, int &scaledY)
|
||||
int Renderer::EFBToScaledX(int x)
|
||||
{
|
||||
switch (g_ActiveConfig.iEFBScale)
|
||||
{
|
||||
case 3: // 1.5x
|
||||
scaledX = (x / 2) * 3;
|
||||
scaledY = (y / 2) * 3;
|
||||
break;
|
||||
case 4: // 2x
|
||||
scaledX = x * 2;
|
||||
scaledY = y * 2;
|
||||
break;
|
||||
case 5: // 2.5x
|
||||
scaledX = (x / 2) * 5;
|
||||
scaledY = (y / 2) * 5;
|
||||
break;
|
||||
case 6: // 3x
|
||||
scaledX = x * 3;
|
||||
scaledY = y * 3;
|
||||
break;
|
||||
case 7: // 4x
|
||||
scaledX = x * 4;
|
||||
scaledY = y * 4;
|
||||
break;
|
||||
case 0: // fractional
|
||||
return (int)ssaa_multiplier * FramebufferManagerBase::ScaleToVirtualXfbWidth(x, s_backbuffer_width);
|
||||
|
||||
default:
|
||||
scaledX = x;
|
||||
scaledY = y;
|
||||
break;
|
||||
return x * (int)ssaa_multiplier * (int)efb_scale_numeratorX / (int)efb_scale_denominatorX;
|
||||
};
|
||||
}
|
||||
|
||||
int Renderer::EFBToScaledY(int y)
|
||||
{
|
||||
switch (g_ActiveConfig.iEFBScale)
|
||||
{
|
||||
case 0: // fractional
|
||||
return (int)ssaa_multiplier * FramebufferManagerBase::ScaleToVirtualXfbHeight(y, s_backbuffer_height);
|
||||
|
||||
default:
|
||||
return y * (int)ssaa_multiplier * (int)efb_scale_numeratorY / (int)efb_scale_denominatorY;
|
||||
};
|
||||
}
|
||||
|
||||
void Renderer::CalculateTargetScale(int x, int y, int &scaledX, int &scaledY)
|
||||
{
|
||||
if (g_ActiveConfig.iEFBScale == 0 || g_ActiveConfig.iEFBScale == 1)
|
||||
{
|
||||
scaledX = x;
|
||||
scaledY = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
scaledX = x * (int)efb_scale_numeratorX / (int)efb_scale_denominatorX;
|
||||
scaledY = y * (int)efb_scale_numeratorY / (int)efb_scale_denominatorY;
|
||||
}
|
||||
}
|
||||
|
||||
// return true if target size changed
|
||||
bool Renderer::CalculateTargetSize(int multiplier)
|
||||
bool Renderer::CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height, int multiplier)
|
||||
{
|
||||
int newEFBWidth, newEFBHeight;
|
||||
|
||||
// TODO: Ugly. Clean up
|
||||
switch (s_LastEFBScale)
|
||||
{
|
||||
case 2: // 1x
|
||||
efb_scale_numeratorX = efb_scale_numeratorY = 1;
|
||||
efb_scale_denominatorX = efb_scale_denominatorY = 1;
|
||||
break;
|
||||
|
||||
case 3: // 1.5x
|
||||
efb_scale_numeratorX = efb_scale_numeratorY = 3;
|
||||
efb_scale_denominatorX = efb_scale_denominatorY = 2;
|
||||
break;
|
||||
|
||||
case 4: // 2x
|
||||
efb_scale_numeratorX = efb_scale_numeratorY = 2;
|
||||
efb_scale_denominatorX = efb_scale_denominatorY = 1;
|
||||
break;
|
||||
|
||||
case 5: // 2.5x
|
||||
efb_scale_numeratorX = efb_scale_numeratorY = 5;
|
||||
efb_scale_denominatorX = efb_scale_denominatorY = 2;
|
||||
break;
|
||||
|
||||
case 6: // 3x
|
||||
efb_scale_numeratorX = efb_scale_numeratorY = 3;
|
||||
efb_scale_denominatorX = efb_scale_denominatorY = 1;
|
||||
break;
|
||||
|
||||
case 7: // 4x
|
||||
efb_scale_numeratorX = efb_scale_numeratorY = 4;
|
||||
efb_scale_denominatorX = efb_scale_denominatorY = 1;
|
||||
break;
|
||||
|
||||
default: // fractional & integral handled later
|
||||
break;
|
||||
}
|
||||
|
||||
switch (s_LastEFBScale)
|
||||
{
|
||||
case 0: // fractional
|
||||
newEFBWidth = (int)(EFB_WIDTH * xScale);
|
||||
newEFBHeight = (int)(EFB_HEIGHT * yScale);
|
||||
break;
|
||||
case 1: // integral
|
||||
newEFBWidth = EFB_WIDTH * (int)ceilf(xScale);
|
||||
newEFBHeight = EFB_HEIGHT * (int)ceilf(yScale);
|
||||
newEFBWidth = FramebufferManagerBase::ScaleToVirtualXfbWidth(EFB_WIDTH, framebuffer_width);
|
||||
newEFBHeight = FramebufferManagerBase::ScaleToVirtualXfbHeight(EFB_HEIGHT, framebuffer_height);
|
||||
|
||||
if (s_LastEFBScale == 1)
|
||||
{
|
||||
newEFBWidth = ((newEFBWidth-1) / EFB_WIDTH + 1) * EFB_WIDTH;
|
||||
newEFBHeight = ((newEFBHeight-1) / EFB_HEIGHT + 1) * EFB_HEIGHT;
|
||||
}
|
||||
efb_scale_numeratorX = newEFBWidth;
|
||||
efb_scale_denominatorX = EFB_WIDTH;
|
||||
efb_scale_numeratorY = newEFBHeight;
|
||||
efb_scale_denominatorY = EFB_HEIGHT;
|
||||
break;
|
||||
|
||||
default:
|
||||
CalculateTargetScale(EFB_WIDTH, EFB_HEIGHT, newEFBWidth, newEFBHeight);
|
||||
break;
|
||||
@@ -186,6 +245,7 @@ bool Renderer::CalculateTargetSize(int multiplier)
|
||||
|
||||
newEFBWidth *= multiplier;
|
||||
newEFBHeight *= multiplier;
|
||||
ssaa_multiplier = multiplier;
|
||||
|
||||
if (newEFBWidth != s_target_width || newEFBHeight != s_target_height)
|
||||
{
|
||||
@@ -207,131 +267,230 @@ void Renderer::SetScreenshot(const char *filename)
|
||||
// Create On-Screen-Messages
|
||||
void Renderer::DrawDebugText()
|
||||
{
|
||||
if (!g_Config.bOSDHotKey)
|
||||
return;
|
||||
|
||||
// OSD Menu messages
|
||||
if (g_ActiveConfig.bOSDHotKey)
|
||||
if (OSDChoice > 0)
|
||||
{
|
||||
if (OSDChoice > 0)
|
||||
{
|
||||
OSDTime = Common::Timer::GetTimeMs() + 3000;
|
||||
OSDChoice = -OSDChoice;
|
||||
}
|
||||
if ((u32)OSDTime > Common::Timer::GetTimeMs())
|
||||
{
|
||||
const char* res_text = "";
|
||||
switch (g_ActiveConfig.iEFBScale)
|
||||
{
|
||||
case 0:
|
||||
res_text = "Auto (fractional)";
|
||||
break;
|
||||
case 1:
|
||||
res_text = "Auto (integral)";
|
||||
break;
|
||||
case 2:
|
||||
res_text = "Native";
|
||||
break;
|
||||
case 3:
|
||||
res_text = "1.5x";
|
||||
break;
|
||||
case 4:
|
||||
res_text = "2x";
|
||||
break;
|
||||
case 5:
|
||||
res_text = "2.5x";
|
||||
break;
|
||||
case 6:
|
||||
res_text = "3x";
|
||||
break;
|
||||
case 7:
|
||||
res_text = "4x";
|
||||
break;
|
||||
}
|
||||
|
||||
const char* ar_text = "";
|
||||
switch(g_ActiveConfig.iAspectRatio)
|
||||
{
|
||||
case ASPECT_AUTO:
|
||||
ar_text = "Auto";
|
||||
break;
|
||||
case ASPECT_FORCE_16_9:
|
||||
ar_text = "16:9";
|
||||
break;
|
||||
case ASPECT_FORCE_4_3:
|
||||
ar_text = "4:3";
|
||||
break;
|
||||
case ASPECT_STRETCH:
|
||||
ar_text = "Stretch";
|
||||
break;
|
||||
}
|
||||
|
||||
const char* const efbcopy_text = g_ActiveConfig.bEFBCopyEnable ?
|
||||
(g_ActiveConfig.bCopyEFBToTexture ? "to Texture" : "to RAM") : "Disabled";
|
||||
|
||||
// The rows
|
||||
const std::string lines[] =
|
||||
{
|
||||
std::string("3: Internal Resolution: ") + res_text,
|
||||
std::string("4: Aspect Ratio: ") + ar_text + (g_ActiveConfig.bCrop ? " (crop)" : ""),
|
||||
std::string("5: Copy EFB: ") + efbcopy_text,
|
||||
std::string("6: Fog: ") + (g_ActiveConfig.bDisableFog ? "Disabled" : "Enabled"),
|
||||
};
|
||||
|
||||
enum { lines_count = sizeof(lines)/sizeof(*lines) };
|
||||
|
||||
std::string final_yellow, final_cyan;
|
||||
|
||||
// If there is more text than this we will have a collision
|
||||
if (g_ActiveConfig.bShowFPS)
|
||||
{
|
||||
final_yellow = final_cyan = "\n\n";
|
||||
}
|
||||
|
||||
// The latest changed setting in yellow
|
||||
for (int i = 0; i != lines_count; ++i)
|
||||
{
|
||||
if (OSDChoice == -i - 1)
|
||||
final_yellow += lines[i];
|
||||
final_yellow += '\n';
|
||||
}
|
||||
|
||||
// The other settings in cyan
|
||||
for (int i = 0; i != lines_count; ++i)
|
||||
{
|
||||
if (OSDChoice != -i - 1)
|
||||
final_cyan += lines[i];
|
||||
final_cyan += '\n';
|
||||
}
|
||||
|
||||
// Render a shadow
|
||||
g_renderer->RenderText(final_cyan.c_str(), 21, 21, 0xDD000000);
|
||||
g_renderer->RenderText(final_yellow.c_str(), 21, 21, 0xDD000000);
|
||||
//and then the text
|
||||
g_renderer->RenderText(final_cyan.c_str(), 20, 20, 0xFF00FFFF);
|
||||
g_renderer->RenderText(final_yellow.c_str(), 20, 20, 0xFFFFFF00);
|
||||
}
|
||||
OSDTime = Common::Timer::GetTimeMs() + 3000;
|
||||
OSDChoice = -OSDChoice;
|
||||
}
|
||||
|
||||
if ((u32)OSDTime <= Common::Timer::GetTimeMs())
|
||||
return;
|
||||
|
||||
const char* res_text = "";
|
||||
switch (g_ActiveConfig.iEFBScale)
|
||||
{
|
||||
case 0:
|
||||
res_text = "Auto (fractional)";
|
||||
break;
|
||||
case 1:
|
||||
res_text = "Auto (integral)";
|
||||
break;
|
||||
case 2:
|
||||
res_text = "Native";
|
||||
break;
|
||||
case 3:
|
||||
res_text = "1.5x";
|
||||
break;
|
||||
case 4:
|
||||
res_text = "2x";
|
||||
break;
|
||||
case 5:
|
||||
res_text = "2.5x";
|
||||
break;
|
||||
case 6:
|
||||
res_text = "3x";
|
||||
break;
|
||||
case 7:
|
||||
res_text = "4x";
|
||||
break;
|
||||
}
|
||||
|
||||
const char* ar_text = "";
|
||||
switch(g_ActiveConfig.iAspectRatio)
|
||||
{
|
||||
case ASPECT_AUTO:
|
||||
ar_text = "Auto";
|
||||
break;
|
||||
case ASPECT_FORCE_16_9:
|
||||
ar_text = "16:9";
|
||||
break;
|
||||
case ASPECT_FORCE_4_3:
|
||||
ar_text = "4:3";
|
||||
break;
|
||||
case ASPECT_STRETCH:
|
||||
ar_text = "Stretch";
|
||||
break;
|
||||
}
|
||||
|
||||
const char* const efbcopy_text = g_ActiveConfig.bEFBCopyEnable ?
|
||||
(g_ActiveConfig.bCopyEFBToTexture ? "to Texture" : "to RAM") : "Disabled";
|
||||
|
||||
// The rows
|
||||
const std::string lines[] =
|
||||
{
|
||||
std::string("3: Internal Resolution: ") + res_text,
|
||||
std::string("4: Aspect Ratio: ") + ar_text + (g_ActiveConfig.bCrop ? " (crop)" : ""),
|
||||
std::string("5: Copy EFB: ") + efbcopy_text,
|
||||
std::string("6: Fog: ") + (g_ActiveConfig.bDisableFog ? "Disabled" : "Enabled"),
|
||||
};
|
||||
|
||||
enum { lines_count = sizeof(lines)/sizeof(*lines) };
|
||||
|
||||
std::string final_yellow, final_cyan;
|
||||
|
||||
// If there is more text than this we will have a collision
|
||||
if (g_ActiveConfig.bShowFPS)
|
||||
{
|
||||
final_yellow = final_cyan = "\n\n";
|
||||
}
|
||||
|
||||
// The latest changed setting in yellow
|
||||
for (int i = 0; i != lines_count; ++i)
|
||||
{
|
||||
if (OSDChoice == -i - 1)
|
||||
final_yellow += lines[i];
|
||||
final_yellow += '\n';
|
||||
}
|
||||
|
||||
// The other settings in cyan
|
||||
for (int i = 0; i != lines_count; ++i)
|
||||
{
|
||||
if (OSDChoice != -i - 1)
|
||||
final_cyan += lines[i];
|
||||
final_cyan += '\n';
|
||||
}
|
||||
|
||||
// Render a shadow
|
||||
g_renderer->RenderText(final_cyan.c_str(), 21, 21, 0xDD000000);
|
||||
g_renderer->RenderText(final_yellow.c_str(), 21, 21, 0xDD000000);
|
||||
//and then the text
|
||||
g_renderer->RenderText(final_cyan.c_str(), 20, 20, 0xFF00FFFF);
|
||||
g_renderer->RenderText(final_yellow.c_str(), 20, 20, 0xFFFFFF00);
|
||||
}
|
||||
|
||||
void Renderer::CalculateXYScale(const TargetRectangle& dst_rect)
|
||||
// TODO: remove
|
||||
extern bool g_aspect_wide;
|
||||
|
||||
void Renderer::UpdateDrawRectangle(int backbuffer_width, int backbuffer_height)
|
||||
{
|
||||
if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB)
|
||||
float FloatGLWidth = (float)backbuffer_width;
|
||||
float FloatGLHeight = (float)backbuffer_height;
|
||||
float FloatXOffset = 0;
|
||||
float FloatYOffset = 0;
|
||||
|
||||
// The rendering window size
|
||||
const float WinWidth = FloatGLWidth;
|
||||
const float WinHeight = FloatGLHeight;
|
||||
|
||||
// Handle aspect ratio.
|
||||
// Default to auto.
|
||||
bool use16_9 = g_aspect_wide;
|
||||
|
||||
// Update aspect ratio hack values
|
||||
// Won't take effect until next frame
|
||||
// Don't know if there is a better place for this code so there isn't a 1 frame delay
|
||||
if ( g_ActiveConfig.bWidescreenHack )
|
||||
{
|
||||
xScale = 1.0f;
|
||||
yScale = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_ActiveConfig.b3DVision)
|
||||
float source_aspect = use16_9 ? (16.0f / 9.0f) : (4.0f / 3.0f);
|
||||
float target_aspect;
|
||||
|
||||
switch ( g_ActiveConfig.iAspectRatio )
|
||||
{
|
||||
// This works, yet the version in the else doesn't. No idea why.
|
||||
xScale = (float)(s_backbuffer_width-1) / (float)(s_XFB_width-1);
|
||||
yScale = (float)(s_backbuffer_height-1) / (float)(s_XFB_height-1);
|
||||
case ASPECT_FORCE_16_9 :
|
||||
target_aspect = 16.0f / 9.0f;
|
||||
break;
|
||||
case ASPECT_FORCE_4_3 :
|
||||
target_aspect = 4.0f / 3.0f;
|
||||
break;
|
||||
case ASPECT_STRETCH :
|
||||
target_aspect = WinWidth / WinHeight;
|
||||
break;
|
||||
default :
|
||||
// ASPECT_AUTO == no hacking
|
||||
target_aspect = source_aspect;
|
||||
break;
|
||||
}
|
||||
|
||||
float adjust = source_aspect / target_aspect;
|
||||
if ( adjust > 1 )
|
||||
{
|
||||
// Vert+
|
||||
g_Config.fAspectRatioHackW = 1;
|
||||
g_Config.fAspectRatioHackH = 1/adjust;
|
||||
}
|
||||
else
|
||||
{
|
||||
xScale = (float)(dst_rect.right - dst_rect.left - 1) / (float)(s_XFB_width-1);
|
||||
yScale = (float)(dst_rect.bottom - dst_rect.top - 1) / (float)(s_XFB_height-1);
|
||||
// Hor+
|
||||
g_Config.fAspectRatioHackW = adjust;
|
||||
g_Config.fAspectRatioHackH = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hack is disabled
|
||||
g_Config.fAspectRatioHackW = 1;
|
||||
g_Config.fAspectRatioHackH = 1;
|
||||
}
|
||||
|
||||
// Check for force-settings and override.
|
||||
if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9)
|
||||
use16_9 = true;
|
||||
else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3)
|
||||
use16_9 = false;
|
||||
|
||||
if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH)
|
||||
{
|
||||
// The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio
|
||||
float Ratio = (WinWidth / WinHeight) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f));
|
||||
// Check if height or width is the limiting factor. If ratio > 1 the picture is too wide and have to limit the width.
|
||||
if (Ratio > 1.0f)
|
||||
{
|
||||
// Scale down and center in the X direction.
|
||||
FloatGLWidth /= Ratio;
|
||||
FloatXOffset = (WinWidth - FloatGLWidth) / 2.0f;
|
||||
}
|
||||
// The window is too high, we have to limit the height
|
||||
else
|
||||
{
|
||||
// Scale down and center in the Y direction.
|
||||
FloatGLHeight *= Ratio;
|
||||
FloatYOffset = FloatYOffset + (WinHeight - FloatGLHeight) / 2.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Crop the picture from 4:3 to 5:4 or from 16:9 to 16:10.
|
||||
// Output: FloatGLWidth, FloatGLHeight, FloatXOffset, FloatYOffset
|
||||
// ------------------
|
||||
if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH && g_ActiveConfig.bCrop)
|
||||
{
|
||||
float Ratio = !use16_9 ? ((4.0f / 3.0f) / (5.0f / 4.0f)) : (((16.0f / 9.0f) / (16.0f / 10.0f)));
|
||||
// The width and height we will add (calculate this before FloatGLWidth and FloatGLHeight is adjusted)
|
||||
float IncreasedWidth = (Ratio - 1.0f) * FloatGLWidth;
|
||||
float IncreasedHeight = (Ratio - 1.0f) * FloatGLHeight;
|
||||
// The new width and height
|
||||
FloatGLWidth = FloatGLWidth * Ratio;
|
||||
FloatGLHeight = FloatGLHeight * Ratio;
|
||||
// Adjust the X and Y offset
|
||||
FloatXOffset = FloatXOffset - (IncreasedWidth * 0.5f);
|
||||
FloatYOffset = FloatYOffset - (IncreasedHeight * 0.5f);
|
||||
}
|
||||
|
||||
int XOffset = (int)(FloatXOffset + 0.5f);
|
||||
int YOffset = (int)(FloatYOffset + 0.5f);
|
||||
int iWhidth = (int)ceil(FloatGLWidth);
|
||||
int iHeight = (int)ceil(FloatGLHeight);
|
||||
iWhidth -= iWhidth % 4; // ensure divisibility by 4 to make it compatible with all the video encoders
|
||||
iHeight -= iHeight % 4;
|
||||
|
||||
target_rc.left = XOffset;
|
||||
target_rc.top = YOffset;
|
||||
target_rc.right = XOffset + iWhidth;
|
||||
target_rc.bottom = YOffset + iHeight;
|
||||
}
|
||||
|
||||
void Renderer::SetWindowSize(int width, int height)
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
// TODO: Move these out of here.
|
||||
extern int frameCount;
|
||||
extern int OSDChoice, OSDTime;
|
||||
extern int OSDChoice;
|
||||
|
||||
extern bool bLastFrameDumped;
|
||||
|
||||
@@ -83,10 +83,6 @@ public:
|
||||
static int GetBackbufferWidth() { return s_backbuffer_width; }
|
||||
static int GetBackbufferHeight() { return s_backbuffer_height; }
|
||||
|
||||
// XFB scale - TODO: Remove this and add two XFBToScaled functions instead
|
||||
static float GetXFBScaleX() { return xScale; }
|
||||
static float GetXFBScaleY() { return yScale; }
|
||||
|
||||
static void SetWindowSize(int width, int height);
|
||||
|
||||
// EFB coordinate conversion functions
|
||||
@@ -94,9 +90,13 @@ public:
|
||||
// Use this to convert a whole native EFB rect to backbuffer coordinates
|
||||
virtual TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) = 0;
|
||||
|
||||
static const TargetRectangle& GetTargetRectangle() { return target_rc; }
|
||||
static void UpdateDrawRectangle(int backbuffer_width, int backbuffer_height);
|
||||
|
||||
|
||||
// Use this to upscale native EFB coordinates to IDEAL internal resolution
|
||||
static unsigned int EFBToScaledX(int x) { return x * GetTargetWidth() / EFB_WIDTH; }
|
||||
static unsigned int EFBToScaledY(int y) { return y * GetTargetHeight() / EFB_HEIGHT; }
|
||||
static int EFBToScaledX(int x);
|
||||
static int EFBToScaledY(int y);
|
||||
|
||||
// Floating point versions of the above - only use them if really necessary
|
||||
static float EFBToScaledXf(float x) { return x * ((float)GetTargetWidth() / (float)EFB_WIDTH); }
|
||||
@@ -147,8 +147,7 @@ public:
|
||||
protected:
|
||||
|
||||
static void CalculateTargetScale(int x, int y, int &scaledX, int &scaledY);
|
||||
static bool CalculateTargetSize(int multiplier = 1);
|
||||
static void CalculateXYScale(const TargetRectangle& dst_rect);
|
||||
static bool CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height, int multiplier = 1);
|
||||
|
||||
static void CheckFifoRecording();
|
||||
static void RecordVideoMemory();
|
||||
@@ -162,7 +161,7 @@ protected:
|
||||
#else
|
||||
File::IOFile pFrameDump;
|
||||
#endif
|
||||
char* frame_data;
|
||||
std::vector<u8> frame_data;
|
||||
bool bLastFrameDumped;
|
||||
|
||||
// The framebuffer size
|
||||
@@ -173,12 +172,7 @@ protected:
|
||||
static int s_backbuffer_width;
|
||||
static int s_backbuffer_height;
|
||||
|
||||
// ratio of backbuffer size and render area size - TODO: Remove these!
|
||||
static float xScale;
|
||||
static float yScale;
|
||||
|
||||
static unsigned int s_XFB_width;
|
||||
static unsigned int s_XFB_height;
|
||||
static TargetRectangle target_rc;
|
||||
|
||||
// can probably eliminate this static var
|
||||
static int s_LastEFBScale;
|
||||
@@ -190,6 +184,11 @@ protected:
|
||||
|
||||
private:
|
||||
static unsigned int prev_efb_format;
|
||||
static unsigned int efb_scale_numeratorX;
|
||||
static unsigned int efb_scale_numeratorY;
|
||||
static unsigned int efb_scale_denominatorX;
|
||||
static unsigned int efb_scale_denominatorY;
|
||||
static unsigned int ssaa_multiplier;
|
||||
};
|
||||
|
||||
extern Renderer *g_renderer;
|
||||
|
||||
@@ -43,7 +43,7 @@ struct Statistics
|
||||
|
||||
int numUniquePixelShaders;
|
||||
|
||||
float proj_0, proj_1, proj_2, proj_3, proj_4, proj_5, proj_6;
|
||||
float proj_0, proj_1, proj_2, proj_3, proj_4, proj_5;
|
||||
float gproj_0, gproj_1, gproj_2, gproj_3, gproj_4, gproj_5;
|
||||
float gproj_6, gproj_7, gproj_8, gproj_9, gproj_10, gproj_11, gproj_12, gproj_13, gproj_14, gproj_15;
|
||||
|
||||
|
||||
@@ -84,35 +84,34 @@ TextureCache::~TextureCache()
|
||||
|
||||
void TextureCache::OnConfigChanged(VideoConfig& config)
|
||||
{
|
||||
if (!g_texture_cache)
|
||||
goto skip_checks;
|
||||
|
||||
// TODO: Invalidating texcache is really stupid in some of these cases
|
||||
if (config.iSafeTextureCache_ColorSamples != backup_config.s_colorsamples ||
|
||||
config.bTexFmtOverlayEnable != backup_config.s_texfmt_overlay ||
|
||||
config.bTexFmtOverlayCenter != backup_config.s_texfmt_overlay_center ||
|
||||
config.bHiresTextures != backup_config.s_hires_textures)
|
||||
if (g_texture_cache)
|
||||
{
|
||||
g_texture_cache->Invalidate();
|
||||
// TODO: Invalidating texcache is really stupid in some of these cases
|
||||
if (config.iSafeTextureCache_ColorSamples != backup_config.s_colorsamples ||
|
||||
config.bTexFmtOverlayEnable != backup_config.s_texfmt_overlay ||
|
||||
config.bTexFmtOverlayCenter != backup_config.s_texfmt_overlay_center ||
|
||||
config.bHiresTextures != backup_config.s_hires_textures)
|
||||
{
|
||||
g_texture_cache->Invalidate();
|
||||
|
||||
if(g_ActiveConfig.bHiresTextures)
|
||||
HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
|
||||
if(g_ActiveConfig.bHiresTextures)
|
||||
HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
|
||||
|
||||
SetHash64Function(g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures);
|
||||
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
|
||||
SetHash64Function(g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures);
|
||||
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
|
||||
}
|
||||
|
||||
// TODO: Probably shouldn't clear all render targets here, just mark them dirty or something.
|
||||
if (config.bEFBCopyCacheEnable != backup_config.s_copy_cache_enable || // TODO: not sure if this is needed?
|
||||
config.bCopyEFBToTexture != backup_config.s_copy_efb_to_texture ||
|
||||
config.bCopyEFBScaled != backup_config.s_copy_efb_scaled ||
|
||||
config.bEFBCopyEnable != backup_config.s_copy_efb ||
|
||||
config.iEFBScale != backup_config.s_efb_scale)
|
||||
{
|
||||
g_texture_cache->ClearRenderTargets();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Probably shouldn't clear all render targets here, just mark them dirty or something.
|
||||
if (config.bEFBCopyCacheEnable != backup_config.s_copy_cache_enable || // TODO: not sure if this is needed?
|
||||
config.bCopyEFBToTexture != backup_config.s_copy_efb_to_texture ||
|
||||
config.bCopyEFBScaled != backup_config.s_copy_efb_scaled ||
|
||||
config.bEFBCopyEnable != backup_config.s_copy_efb ||
|
||||
config.iEFBScale != backup_config.s_efb_scale)
|
||||
{
|
||||
g_texture_cache->ClearRenderTargets();
|
||||
}
|
||||
|
||||
skip_checks:
|
||||
|
||||
backup_config.s_colorsamples = config.iSafeTextureCache_ColorSamples;
|
||||
backup_config.s_copy_efb_to_texture = config.bCopyEFBToTexture;
|
||||
backup_config.s_copy_efb_scaled = config.bCopyEFBScaled;
|
||||
@@ -130,7 +129,11 @@ void TextureCache::Cleanup()
|
||||
TexCache::iterator tcend = textures.end();
|
||||
while (iter != tcend)
|
||||
{
|
||||
if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) // TODO: Deleting EFB copies might not be a good idea here...
|
||||
if ( frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount
|
||||
|
||||
// EFB copies living on the host GPU are unrecoverable and thus shouldn't be deleted
|
||||
// TODO: encoding the texture back to RAM here might be a good idea
|
||||
&& ! (g_ActiveConfig.bCopyEFBToTexture && iter->second->IsEfbCopy()) )
|
||||
{
|
||||
delete iter->second;
|
||||
textures.erase(iter++);
|
||||
@@ -204,13 +207,23 @@ void TextureCache::ClearRenderTargets()
|
||||
iter = textures.begin(),
|
||||
tcend = textures.end();
|
||||
|
||||
for (; iter!=tcend; ++iter)
|
||||
if (iter->second->type != TCET_EC_DYNAMIC)
|
||||
iter->second->type = TCET_NORMAL;
|
||||
while (iter != tcend)
|
||||
{
|
||||
if (iter->second->type == TCET_EC_VRAM)
|
||||
{
|
||||
delete iter->second;
|
||||
textures.erase(iter++);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureCache::CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsigned int levels)
|
||||
{
|
||||
if (levels == 1)
|
||||
return false;
|
||||
|
||||
// Just checking if the necessary files exist, if they can't be loaded or have incorrect dimensions LODs will be black
|
||||
char texBasePathTemp[MAX_PATH];
|
||||
char texPathTemp[MAX_PATH];
|
||||
@@ -291,14 +304,30 @@ void TextureCache::DumpTexture(TCacheEntryBase* entry, unsigned int level)
|
||||
entry->Save(szTemp, level);
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
u32 address, unsigned int width, unsigned int height, int texformat,
|
||||
unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem)
|
||||
static u32 CalculateLevelSize(u32 level_0_size, u32 level)
|
||||
{
|
||||
return (level_0_size + ((1 << level) - 1)) >> level;
|
||||
}
|
||||
|
||||
// Used by TextureCache::Load
|
||||
static TextureCache::TCacheEntryBase* ReturnEntry(unsigned int stage, TextureCache::TCacheEntryBase* entry)
|
||||
{
|
||||
entry->frameCount = frameCount;
|
||||
entry->Bind(stage);
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_TEXTURE_CHANGE, true);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
|
||||
u32 const address, unsigned int width, unsigned int height, int const texformat,
|
||||
unsigned int const tlutaddr, int const tlutfmt, bool const use_mipmaps, unsigned int maxlevel, bool const from_tmem)
|
||||
{
|
||||
if (0 == address)
|
||||
return NULL;
|
||||
|
||||
// TexelSizeInNibbles(format)*width*height/16;
|
||||
// TexelSizeInNibbles(format) * width * height / 16;
|
||||
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1;
|
||||
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1;
|
||||
|
||||
@@ -307,11 +336,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
const unsigned int nativeW = width;
|
||||
const unsigned int nativeH = height;
|
||||
|
||||
bool using_custom_texture = false;
|
||||
bool using_custom_lods = false;
|
||||
|
||||
u32 texID = address;
|
||||
u64 tex_hash = TEXHASH_INVALID; // Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup)
|
||||
// Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup)
|
||||
u64 tex_hash = TEXHASH_INVALID;
|
||||
u64 tlut_hash = TEXHASH_INVALID;
|
||||
|
||||
u32 full_format = texformat;
|
||||
@@ -322,10 +349,14 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
full_format = texformat | (tlutfmt << 16);
|
||||
|
||||
const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
|
||||
u8* src_data;
|
||||
if (from_tmem) src_data = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE];
|
||||
else src_data = Memory::GetPointer(address);
|
||||
|
||||
const u8* src_data;
|
||||
if (from_tmem)
|
||||
src_data = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE];
|
||||
else
|
||||
src_data = Memory::GetPointer(address);
|
||||
|
||||
// TODO: This doesn't hash GB tiles for preloaded RGBA8 textures (instead, it's hashing more data from the low tmem bank than it should)
|
||||
tex_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
if (isPaletteTexture)
|
||||
{
|
||||
@@ -345,6 +376,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
tex_hash ^= tlut_hash;
|
||||
}
|
||||
|
||||
// D3D doesn't like when the specified mipmap count would require more than one 1x1-sized LOD in the mipmap chain
|
||||
// e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,1x1, so we limit the mipmap count to 6 there
|
||||
while (g_ActiveConfig.backend_info.bUseMinimalMipCount && max(expandedWidth, expandedHeight) >> maxlevel == 0)
|
||||
--maxlevel;
|
||||
|
||||
TCacheEntryBase *entry = textures[texID];
|
||||
if (entry)
|
||||
{
|
||||
@@ -358,15 +394,17 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
{
|
||||
entry->type = TCET_EC_VRAM;
|
||||
|
||||
// TODO: Print a warning if the format changes! In this case, we could reinterpret the internal texture object data to the new pixel format (similiar to what is already being done in Renderer::ReinterpretPixelFormat())
|
||||
goto return_entry;
|
||||
// TODO: Print a warning if the format changes! In this case,
|
||||
// we could reinterpret the internal texture object data to the new pixel format
|
||||
// (similiar to what is already being done in Renderer::ReinterpretPixelFormat())
|
||||
return ReturnEntry(stage, entry);
|
||||
}
|
||||
|
||||
// 2. b) For normal textures, all texture parameters need to match
|
||||
if (address == entry->addr && tex_hash == entry->hash && full_format == entry->format &&
|
||||
entry->num_mipmaps == maxlevel && entry->native_width == nativeW && entry->native_height == nativeH)
|
||||
entry->num_mipmaps > maxlevel && entry->native_width == nativeW && entry->native_height == nativeH)
|
||||
{
|
||||
goto return_entry;
|
||||
return ReturnEntry(stage, entry);
|
||||
}
|
||||
|
||||
// 3. If we reach this line, we'll have to upload the new texture data to VRAM.
|
||||
@@ -374,7 +412,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
//
|
||||
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
|
||||
// TODO: Actually, it should be enough if the internal texture format matches...
|
||||
if ((entry->type == TCET_NORMAL && width == entry->native_width && height == entry->native_height && full_format == entry->format && entry->num_mipmaps == maxlevel)
|
||||
if ((entry->type == TCET_NORMAL && width == entry->virtual_width && height == entry->virtual_height
|
||||
&& full_format == entry->format && entry->num_mipmaps > maxlevel)
|
||||
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height))
|
||||
{
|
||||
// reuse the texture
|
||||
@@ -387,132 +426,135 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
||||
}
|
||||
}
|
||||
|
||||
bool using_custom_texture = false;
|
||||
|
||||
if (g_ActiveConfig.bHiresTextures)
|
||||
{
|
||||
// This function may modify width/height.
|
||||
pcfmt = LoadCustomTexture(tex_hash, texformat, 0, width, height);
|
||||
if (pcfmt != PC_TEX_FMT_NONE)
|
||||
{
|
||||
expandedWidth = width;
|
||||
expandedHeight = height;
|
||||
if (expandedWidth != width || expandedHeight != height)
|
||||
{
|
||||
expandedWidth = width;
|
||||
expandedHeight = height;
|
||||
|
||||
// If we thought we could reuse the texture before, make sure to delete it now!
|
||||
delete entry;
|
||||
entry = NULL;
|
||||
}
|
||||
using_custom_texture = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: RGBA8 textures are stored non-continuously in tmem, that might cause problems when preloading is enabled
|
||||
if (pcfmt == PC_TEX_FMT_NONE)
|
||||
pcfmt = TexDecoder_Decode(temp, src_data, expandedWidth,
|
||||
expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||
if (!using_custom_texture)
|
||||
{
|
||||
if (!(texformat == GX_TF_RGBA8 && from_tmem))
|
||||
{
|
||||
pcfmt = TexDecoder_Decode(temp, src_data, expandedWidth,
|
||||
expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||
}
|
||||
else
|
||||
{
|
||||
u8* src_data_gb = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
|
||||
pcfmt = TexDecoder_DecodeRGBA8FromTmem(temp, src_data, src_data_gb, expandedWidth, expandedHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Cleanup. Plus, we still autogenerate mipmaps in certain cases (we shouldn't do that)
|
||||
bool isPow2;
|
||||
unsigned int texLevels;
|
||||
isPow2 = !((width & (width - 1)) || (height & (height - 1)));
|
||||
texLevels = (isPow2 && maxlevel) ? GetPow2(std::max(width, height)) : !isPow2;
|
||||
texLevels = maxlevel ? std::min(texLevels, maxlevel + 1) : texLevels;
|
||||
using_custom_lods = using_custom_texture && CheckForCustomTextureLODs(tex_hash, texformat, texLevels);
|
||||
UseNativeMips = UseNativeMips && !using_custom_lods && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions
|
||||
texLevels = (UseNativeMips || using_custom_lods) ? texLevels : !isPow2;
|
||||
u32 texLevels = use_mipmaps ? (maxlevel + 1) : 1;
|
||||
const bool using_custom_lods = using_custom_texture && CheckForCustomTextureLODs(tex_hash, texformat, texLevels);
|
||||
// Only load native mips if their dimensions fit to our virtual texture dimensions
|
||||
const bool use_native_mips = use_mipmaps && !using_custom_lods && (width == nativeW && height == nativeH);
|
||||
texLevels = (use_native_mips || using_custom_lods) ? texLevels : 1; // TODO: Should be forced to 1 for non-pow2 textures (e.g. efb copies with automatically adjusted IR)
|
||||
|
||||
// create the entry/texture
|
||||
if (NULL == entry) {
|
||||
if (NULL == entry)
|
||||
{
|
||||
textures[texID] = entry = g_texture_cache->CreateTexture(width, height, expandedWidth, texLevels, pcfmt);
|
||||
|
||||
// Sometimes, we can get around recreating a texture if only the number of mip levels changes
|
||||
// e.g. if our texture cache entry got too many mipmap levels we can limit the number of used levels by setting the appropriate render states
|
||||
// Thus, we don't update this member for every Load, but just whenever the texture gets recreated
|
||||
//
|
||||
// TODO: Won't we end up recreating textures all the time because maxlevel doesn't necessarily equal texLevels?
|
||||
entry->num_mipmaps = maxlevel; // TODO: Does this actually work? We can't really adjust mipmap settings per-stage...
|
||||
// TODO: D3D9 doesn't support min_lod. We should add a workaround for that here!
|
||||
|
||||
// TODO: This is the wrong value. We should be storing the number of levels our actual texture has.
|
||||
// But that will currently make the above "existing entry" tests fail as "texLevels" is not calculated until after.
|
||||
// Currently, we might try to reuse a texture which appears to have more levels than actual, maybe..
|
||||
entry->num_mipmaps = maxlevel + 1;
|
||||
entry->type = TCET_NORMAL;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// load texture (CreateTexture also loads level 0)
|
||||
entry->Load(width, height, expandedWidth, 0);
|
||||
}
|
||||
|
||||
entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
|
||||
entry->SetDimensions(nativeW, nativeH, width, height);
|
||||
entry->hash = tex_hash;
|
||||
if (entry->IsEfbCopy() && !g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_EC_DYNAMIC;
|
||||
else entry->type = TCET_NORMAL;
|
||||
|
||||
// load texture
|
||||
entry->Load(width, height, expandedWidth, 0, (texLevels == 0));
|
||||
|
||||
if (entry->IsEfbCopy() && !g_ActiveConfig.bCopyEFBToTexture)
|
||||
entry->type = TCET_EC_DYNAMIC;
|
||||
else
|
||||
entry->type = TCET_NORMAL;
|
||||
|
||||
if (g_ActiveConfig.bDumpTextures && !using_custom_texture)
|
||||
DumpTexture(entry, 0);
|
||||
|
||||
u32 level = 1;
|
||||
// load mips - TODO: Loading mipmaps from tmem is untested!
|
||||
if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE && UseNativeMips)
|
||||
if (pcfmt != PC_TEX_FMT_NONE)
|
||||
{
|
||||
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
|
||||
|
||||
unsigned int level = 1;
|
||||
unsigned int mipWidth = (width + 1) >> 1;
|
||||
unsigned int mipHeight = (height + 1) >> 1;
|
||||
|
||||
u8* ptr_even = NULL, *ptr_odd = NULL;
|
||||
if (from_tmem)
|
||||
if (use_native_mips)
|
||||
{
|
||||
ptr_even = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE + texture_size];
|
||||
ptr_odd = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
|
||||
src_data += texture_size;
|
||||
|
||||
const u8* ptr_even = NULL;
|
||||
const u8* ptr_odd = NULL;
|
||||
if (from_tmem)
|
||||
{
|
||||
ptr_even = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE + texture_size];
|
||||
ptr_odd = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
|
||||
}
|
||||
|
||||
for (; level != texLevels; ++level)
|
||||
{
|
||||
const u32 mip_width = CalculateLevelSize(width, level);
|
||||
const u32 mip_height = CalculateLevelSize(height, level);
|
||||
const u32 expanded_mip_width = (mip_width + bsw) & (~bsw);
|
||||
const u32 expanded_mip_height = (mip_height + bsh) & (~bsh);
|
||||
|
||||
const u8*& mip_src_data = from_tmem
|
||||
? ((level % 2) ? ptr_odd : ptr_even)
|
||||
: src_data;
|
||||
TexDecoder_Decode(temp, mip_src_data, expanded_mip_width, expanded_mip_height, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||
mip_src_data += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat);
|
||||
|
||||
entry->Load(mip_width, mip_height, expanded_mip_width, level);
|
||||
|
||||
if (g_ActiveConfig.bDumpTextures)
|
||||
DumpTexture(entry, level);
|
||||
}
|
||||
}
|
||||
src_data += texture_size;
|
||||
|
||||
while ((mipHeight || mipWidth) && (level < texLevels))
|
||||
else if (using_custom_lods)
|
||||
{
|
||||
u8** ptr;
|
||||
if (from_tmem) ptr = (level % 2) ? &ptr_odd : &ptr_even;
|
||||
else ptr = &src_data;
|
||||
for (; level != texLevels; ++level)
|
||||
{
|
||||
unsigned int mip_width = CalculateLevelSize(width, level);
|
||||
unsigned int mip_height = CalculateLevelSize(height, level);
|
||||
|
||||
const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
|
||||
const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
|
||||
|
||||
expandedWidth = (currentWidth + bsw) & (~bsw);
|
||||
expandedHeight = (currentHeight + bsh) & (~bsh);
|
||||
|
||||
TexDecoder_Decode(temp, *ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||
entry->Load(currentWidth, currentHeight, expandedWidth, level, false);
|
||||
|
||||
if (g_ActiveConfig.bDumpTextures)
|
||||
DumpTexture(entry, level);
|
||||
|
||||
*ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
|
||||
mipWidth >>= 1;
|
||||
mipHeight >>= 1;
|
||||
++level;
|
||||
}
|
||||
}
|
||||
else if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE && using_custom_lods)
|
||||
{
|
||||
unsigned int level = 1;
|
||||
unsigned int mipWidth = (width + 1) >> 1;
|
||||
unsigned int mipHeight = (height + 1) >> 1;
|
||||
|
||||
while ((mipHeight || mipWidth) && (level < texLevels))
|
||||
{
|
||||
unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
|
||||
unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
|
||||
|
||||
LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight);
|
||||
entry->Load(currentWidth, currentHeight, currentWidth, level, false);
|
||||
|
||||
mipWidth >>= 1;
|
||||
mipHeight >>= 1;
|
||||
++level;
|
||||
LoadCustomTexture(tex_hash, texformat, level, mip_width, mip_height);
|
||||
entry->Load(mip_width, mip_height, mip_width, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INCSTAT(stats.numTexturesCreated);
|
||||
SETSTAT(stats.numTexturesAlive, textures.size());
|
||||
|
||||
return_entry:
|
||||
|
||||
entry->frameCount = frameCount;
|
||||
entry->Bind(stage);
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_TEXTURE_CHANGE, true);
|
||||
|
||||
return entry;
|
||||
return ReturnEntry(stage, entry);
|
||||
}
|
||||
|
||||
void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
|
||||
@@ -782,7 +824,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
|
||||
textures[dstAddr] = entry = g_texture_cache->CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h);
|
||||
|
||||
// TODO: Using the wrong dstFormat, dumb...
|
||||
entry->SetGeneralParameters(dstAddr, 0, dstFormat, 0);
|
||||
entry->SetGeneralParameters(dstAddr, 0, dstFormat, 1);
|
||||
entry->SetDimensions(tex_w, tex_h, scaled_tex_w, scaled_tex_h);
|
||||
entry->SetHashes(TEXHASH_INVALID);
|
||||
entry->type = TCET_EC_VRAM;
|
||||
|
||||
@@ -60,26 +60,26 @@ public:
|
||||
int frameCount;
|
||||
|
||||
|
||||
void SetGeneralParameters(u32 addr, u32 size, u32 format, unsigned int num_mipmaps)
|
||||
void SetGeneralParameters(u32 _addr, u32 _size, u32 _format, unsigned int _num_mipmaps)
|
||||
{
|
||||
this->addr = addr;
|
||||
this->size_in_bytes = size;
|
||||
this->format = format;
|
||||
this->num_mipmaps = num_mipmaps;
|
||||
addr = _addr;
|
||||
size_in_bytes = _size;
|
||||
format = _format;
|
||||
num_mipmaps = _num_mipmaps;
|
||||
}
|
||||
|
||||
void SetDimensions(unsigned int native_width, unsigned int native_height, unsigned int virtual_width, unsigned int virtual_height)
|
||||
void SetDimensions(unsigned int _native_width, unsigned int _native_height, unsigned int _virtual_width, unsigned int _virtual_height)
|
||||
{
|
||||
this->native_width = native_width;
|
||||
this->native_height = native_height;
|
||||
this->virtual_width = virtual_width;
|
||||
this->virtual_height = virtual_height;
|
||||
native_width = _native_width;
|
||||
native_height = _native_height;
|
||||
virtual_width = _virtual_width;
|
||||
virtual_height = _virtual_height;
|
||||
}
|
||||
|
||||
void SetHashes(u64 hash/*, u32 pal_hash*/)
|
||||
void SetHashes(u64 _hash/*, u32 _pal_hash*/)
|
||||
{
|
||||
this->hash = hash;
|
||||
//this->pal_hash = pal_hash;
|
||||
hash = _hash;
|
||||
//pal_hash = _pal_hash;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
virtual bool Save(const char filename[], unsigned int level) = 0;
|
||||
|
||||
virtual void Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level, bool autogen_mips) = 0;
|
||||
unsigned int expanded_width, unsigned int level) = 0;
|
||||
virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
|
||||
unsigned int srcFormat, const EFBRectangle& srcRect,
|
||||
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
|
||||
@@ -116,7 +116,7 @@ public:
|
||||
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 0;
|
||||
|
||||
static TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, unsigned int height,
|
||||
int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem);
|
||||
int format, unsigned int tlutaddr, int tlutfmt, bool use_mipmaps, unsigned int maxlevel, bool from_tmem);
|
||||
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
|
||||
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);
|
||||
|
||||
|
||||
@@ -86,6 +86,8 @@ enum PC_TexFormat
|
||||
PC_TexFormat TexDecoder_Decode(u8 *dst, const u8 *src, int width, int height, int texformat, int tlutaddr, int tlutfmt,bool rgbaOnly = false);
|
||||
PC_TexFormat GetPC_TexFormat(int texformat, int tlutfmt);
|
||||
void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth, int texformat, int tlutaddr, int tlutfmt);
|
||||
void TexDecoder_DecodeTexelRGBA8FromTmem(u8 *dst, const u8 *src_ar, const u8* src_gb, int s, int t, int imageWidth);
|
||||
PC_TexFormat TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8 *src_ar, const u8 *src_gb, int width, int height);
|
||||
void TexDecoder_SetTexFmtOverlayOptions(bool enable, bool center);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "MemoryUtil.h"
|
||||
#include "StringUtil.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "ABI.h"
|
||||
#include "x64ABI.h"
|
||||
#include "PixelEngine.h"
|
||||
#include "Host.h"
|
||||
|
||||
@@ -43,8 +43,9 @@
|
||||
//BBox
|
||||
#include "XFMemory.h"
|
||||
extern float GC_ALIGNED16(g_fProjectionMatrix[16]);
|
||||
|
||||
#ifndef _M_GENERIC
|
||||
#define USE_JIT
|
||||
#endif
|
||||
|
||||
#define COMPILED_CODE_SIZE 4096
|
||||
|
||||
@@ -82,8 +83,9 @@ static const float fractionTable[32] = {
|
||||
1.0f / (1U << 24), 1.0f / (1U << 25), 1.0f / (1U << 26), 1.0f / (1U << 27),
|
||||
1.0f / (1U << 28), 1.0f / (1U << 29), 1.0f / (1U << 30), 1.0f / (1U << 31),
|
||||
};
|
||||
|
||||
#ifdef USE_JIT
|
||||
using namespace Gen;
|
||||
#endif
|
||||
|
||||
void LOADERDECL PosMtx_ReadDirect_UByte()
|
||||
{
|
||||
@@ -182,14 +184,19 @@ VertexLoader::VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr)
|
||||
m_VtxDesc = vtx_desc;
|
||||
SetVAT(vtx_attr.g0.Hex, vtx_attr.g1.Hex, vtx_attr.g2.Hex);
|
||||
|
||||
#ifdef USE_JIT
|
||||
AllocCodeSpace(COMPILED_CODE_SIZE);
|
||||
CompileVertexTranslator();
|
||||
WriteProtect();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
VertexLoader::~VertexLoader()
|
||||
{
|
||||
#ifdef USE_JIT
|
||||
FreeCodeSpace();
|
||||
#endif
|
||||
delete m_NativeFmt;
|
||||
}
|
||||
|
||||
@@ -224,14 +231,14 @@ void VertexLoader::CompileVertexTranslator()
|
||||
#endif
|
||||
|
||||
// Colors
|
||||
const int col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
|
||||
const u32 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
|
||||
// TextureCoord
|
||||
// Since m_VtxDesc.Text7Coord is broken across a 32 bit word boundary, retrieve its value manually.
|
||||
// If we didn't do this, the vertex format would be read as one bit offset from where it should be, making
|
||||
// 01 become 00, and 10/11 become 01
|
||||
const int tc[8] = {
|
||||
const u32 tc[8] = {
|
||||
m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord,
|
||||
m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, (const int)((m_VtxDesc.Hex >> 31) & 3)
|
||||
m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, (const u32)((m_VtxDesc.Hex >> 31) & 3)
|
||||
};
|
||||
|
||||
// Reset pipeline
|
||||
@@ -474,7 +481,8 @@ void VertexLoader::WriteCall(TPipelineFunction func)
|
||||
m_PipelineStages[m_numPipelineStages++] = func;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ARMTODO: This should be done in a better way
|
||||
#ifndef _M_GENERIC
|
||||
void VertexLoader::WriteGetVariable(int bits, OpArg dest, void *address)
|
||||
{
|
||||
#ifdef USE_JIT
|
||||
@@ -498,7 +506,7 @@ void VertexLoader::WriteSetVariable(int bits, void *address, OpArg value)
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
void VertexLoader::RunVertices(int vtx_attr_group, int primitive, int count)
|
||||
{
|
||||
m_numLoadedVertices += count;
|
||||
@@ -770,7 +778,7 @@ void VertexLoader::AppendToString(std::string *dest) const
|
||||
dest->append(StringFromFormat("Nrm: %i %s-%s ",
|
||||
m_VtxAttr.NormalElements, posMode[m_VtxDesc.Normal], posFormats[m_VtxAttr.NormalFormat]));
|
||||
}
|
||||
int color_mode[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
|
||||
u32 color_mode[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (color_mode[i])
|
||||
@@ -778,7 +786,7 @@ void VertexLoader::AppendToString(std::string *dest) const
|
||||
dest->append(StringFromFormat("C%i: %i %s-%s ", i, m_VtxAttr.color[i].Elements, posMode[color_mode[i]], colorFormat[m_VtxAttr.color[i].Comp]));
|
||||
}
|
||||
}
|
||||
int tex_mode[8] = {
|
||||
u32 tex_mode[8] = {
|
||||
m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord,
|
||||
m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord
|
||||
};
|
||||
|
||||
@@ -76,7 +76,12 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
// ARMTODO: This should be done in a better way
|
||||
#ifndef _M_GENERIC
|
||||
class VertexLoader : public Gen::XCodeBlock, NonCopyable
|
||||
#else
|
||||
class VertexLoader
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr);
|
||||
@@ -122,8 +127,10 @@ private:
|
||||
|
||||
void WriteCall(TPipelineFunction);
|
||||
|
||||
#ifndef _M_GENERIC
|
||||
void WriteGetVariable(int bits, Gen::OpArg dest, void *address);
|
||||
void WriteSetVariable(int bits, void *address, Gen::OpArg dest);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,9 +19,12 @@
|
||||
#ifdef _MSC_VER
|
||||
#include <hash_map>
|
||||
using stdext::hash_map;
|
||||
#else
|
||||
#elif defined __APPLE__
|
||||
#include <ext/hash_map>
|
||||
using __gnu_cxx::hash_map;
|
||||
#else
|
||||
#include <unordered_map>
|
||||
using std::unordered_map;
|
||||
#endif
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@@ -45,7 +48,12 @@ namespace stdext {
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace __gnu_cxx {
|
||||
#ifdef __APPLE__
|
||||
namespace __gnu_cxx
|
||||
#else
|
||||
namespace std
|
||||
#endif
|
||||
{
|
||||
template<> struct hash<VertexLoaderUID> {
|
||||
size_t operator()(const VertexLoaderUID& uid) const {
|
||||
return uid.GetHash();
|
||||
@@ -54,10 +62,15 @@ namespace __gnu_cxx {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined _MSC_VER || defined __APPLE__
|
||||
typedef hash_map<VertexLoaderUID, VertexLoader*> VertexLoaderMap;
|
||||
#else
|
||||
typedef unordered_map<VertexLoaderUID, VertexLoader*> VertexLoaderMap;
|
||||
#endif
|
||||
|
||||
namespace VertexLoaderManager
|
||||
{
|
||||
|
||||
typedef hash_map<VertexLoaderUID, VertexLoader*> VertexLoaderMap;
|
||||
static VertexLoaderMap g_VertexLoaderMap;
|
||||
// TODO - change into array of pointers. Keep a map of all seen so far.
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "TextureCacheBase.h"
|
||||
#include "RenderBase.h"
|
||||
#include "BPStructs.h"
|
||||
|
||||
#include "VertexManagerBase.h"
|
||||
#include "VideoConfig.h"
|
||||
@@ -159,6 +160,9 @@ void VertexManager::AddVertices(int primitive, int numVertices)
|
||||
|
||||
void VertexManager::Flush()
|
||||
{
|
||||
// loading a state will invalidate BP, so check for it
|
||||
g_video_backend->CheckInvalidState();
|
||||
|
||||
g_vertex_manager->vFlush();
|
||||
}
|
||||
|
||||
@@ -198,7 +202,7 @@ void VertexManager::Flush()
|
||||
}
|
||||
|
||||
PRIM_LOG("pixel: tev=%d, ind=%d, texgen=%d, dstalpha=%d, alphafunc=0x%x", bpmem.genMode.numtevstages+1, bpmem.genMode.numindstages,
|
||||
bpmem.genMode.numtexgens, (u32)bpmem.dstalpha.enable, (bpmem.alphaFunc.hex>>16)&0xff);
|
||||
bpmem.genMode.numtexgens, (u32)bpmem.dstalpha.enable, (bpmem.alpha_test.hex>>16)&0xff);
|
||||
#endif
|
||||
|
||||
u32 usedtextures = 0;
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
|
||||
// values from DX11 backend
|
||||
MAXVBUFFERSIZE = 0x50000,
|
||||
MAXIBUFFERSIZE = 0x10000,
|
||||
MAXIBUFFERSIZE = 0xFFFF,
|
||||
};
|
||||
|
||||
VertexManager();
|
||||
@@ -46,7 +46,8 @@ public:
|
||||
static u8* GetVertexBuffer() { return LocalVBuffer; }
|
||||
|
||||
static void DoState(PointerWrap& p);
|
||||
|
||||
virtual void CreateDeviceObjects(){};
|
||||
virtual void DestroyDeviceObjects(){};
|
||||
protected:
|
||||
// TODO: make private after Flush() is merged
|
||||
static void ResetBuffer();
|
||||
|
||||
@@ -465,6 +465,7 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type)
|
||||
|
||||
//write the true depth value, if the game uses depth textures pixel shaders will override with the correct values
|
||||
//if not early z culling will improve speed
|
||||
// TODO: Can probably be dropped?
|
||||
if (is_d3d)
|
||||
{
|
||||
WRITE(p, "o.pos.z = " I_DEPTHPARAMS".x * o.pos.w + o.pos.z * " I_DEPTHPARAMS".y;\n");
|
||||
|
||||
@@ -169,14 +169,24 @@ void VertexShaderManager::Shutdown()
|
||||
|
||||
void VertexShaderManager::Dirty()
|
||||
{
|
||||
nTransformMatricesChanged[0] = 0; nTransformMatricesChanged[1] = 256;
|
||||
nNormalMatricesChanged[0] = 0; nNormalMatricesChanged[1] = 96;
|
||||
nPostTransformMatricesChanged[0] = 0; nPostTransformMatricesChanged[1] = 256;
|
||||
nLightsChanged[0] = 0; nLightsChanged[1] = 0x80;
|
||||
nTransformMatricesChanged[0] = 0;
|
||||
nTransformMatricesChanged[1] = 256;
|
||||
|
||||
nNormalMatricesChanged[0] = 0;
|
||||
nNormalMatricesChanged[1] = 96;
|
||||
|
||||
nPostTransformMatricesChanged[0] = 0;
|
||||
nPostTransformMatricesChanged[1] = 256;
|
||||
|
||||
nLightsChanged[0] = 0;
|
||||
nLightsChanged[1] = 0x80;
|
||||
|
||||
bPosNormalMatrixChanged = true;
|
||||
bTexMatricesChanged[0] = bTexMatricesChanged[1] = true;
|
||||
bTexMatricesChanged[0] = true;
|
||||
bTexMatricesChanged[1] = true;
|
||||
|
||||
bProjectionChanged = true;
|
||||
bPosNormalMatrixChanged = bTexMatricesChanged[0] = bTexMatricesChanged[1] = true;
|
||||
|
||||
nMaterialsChanged = 15;
|
||||
}
|
||||
|
||||
@@ -207,6 +217,7 @@ void VertexShaderManager::SetConstants()
|
||||
int endn = (nPostTransformMatricesChanged[1] + 3 ) / 4;
|
||||
const float* pstart = (const float*)&xfmem[XFMEM_POSTMATRICES + startn * 4];
|
||||
SetMultiVSConstant4fv(C_POSTTRANSFORMMATRICES + startn, endn - startn, pstart);
|
||||
nPostTransformMatricesChanged[0] = nPostTransformMatricesChanged[1] = -1;
|
||||
}
|
||||
|
||||
if (nLightsChanged[0] >= 0)
|
||||
@@ -250,7 +261,7 @@ void VertexShaderManager::SetConstants()
|
||||
float GC_ALIGNED16(material[4]);
|
||||
float NormalizationCoef = 1 / 255.0f;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (nMaterialsChanged & (1 << i))
|
||||
{
|
||||
@@ -264,6 +275,21 @@ void VertexShaderManager::SetConstants()
|
||||
SetVSConstant4fv(C_MATERIALS + i, material);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (nMaterialsChanged & (1 << (i + 2)))
|
||||
{
|
||||
u32 data = *(xfregs.matColor + i);
|
||||
|
||||
material[0] = ((data >> 24) & 0xFF) * NormalizationCoef;
|
||||
material[1] = ((data >> 16) & 0xFF) * NormalizationCoef;
|
||||
material[2] = ((data >> 8) & 0xFF) * NormalizationCoef;
|
||||
material[3] = ( data & 0xFF) * NormalizationCoef;
|
||||
|
||||
SetVSConstant4fv(C_MATERIALS + i + 2, material);
|
||||
}
|
||||
}
|
||||
|
||||
nMaterialsChanged = 0;
|
||||
}
|
||||
@@ -324,26 +350,28 @@ void VertexShaderManager::SetConstants()
|
||||
if (bProjectionChanged)
|
||||
{
|
||||
bProjectionChanged = false;
|
||||
|
||||
float *rawProjection = xfregs.projection.rawProjection;
|
||||
|
||||
if (xfregs.rawProjection[6] == 0)
|
||||
switch(xfregs.projection.type)
|
||||
{
|
||||
// Perspective
|
||||
case GX_PERSPECTIVE:
|
||||
|
||||
g_fProjectionMatrix[0] = xfregs.rawProjection[0] * g_ActiveConfig.fAspectRatioHackW;
|
||||
g_fProjectionMatrix[0] = rawProjection[0] * g_ActiveConfig.fAspectRatioHackW;
|
||||
g_fProjectionMatrix[1] = 0.0f;
|
||||
g_fProjectionMatrix[2] = xfregs.rawProjection[1];
|
||||
g_fProjectionMatrix[2] = rawProjection[1];
|
||||
g_fProjectionMatrix[3] = 0.0f;
|
||||
|
||||
g_fProjectionMatrix[4] = 0.0f;
|
||||
g_fProjectionMatrix[5] = xfregs.rawProjection[2] * g_ActiveConfig.fAspectRatioHackH;
|
||||
g_fProjectionMatrix[6] = xfregs.rawProjection[3];
|
||||
g_fProjectionMatrix[5] = rawProjection[2] * g_ActiveConfig.fAspectRatioHackH;
|
||||
g_fProjectionMatrix[6] = rawProjection[3];
|
||||
g_fProjectionMatrix[7] = 0.0f;
|
||||
|
||||
g_fProjectionMatrix[8] = 0.0f;
|
||||
g_fProjectionMatrix[9] = 0.0f;
|
||||
g_fProjectionMatrix[10] = xfregs.rawProjection[4];
|
||||
g_fProjectionMatrix[10] = rawProjection[4];
|
||||
|
||||
g_fProjectionMatrix[11] = xfregs.rawProjection[5];
|
||||
g_fProjectionMatrix[11] = rawProjection[5];
|
||||
|
||||
g_fProjectionMatrix[12] = 0.0f;
|
||||
g_fProjectionMatrix[13] = 0.0f;
|
||||
@@ -368,24 +396,24 @@ void VertexShaderManager::SetConstants()
|
||||
SETSTAT_FT(stats.gproj_13, g_fProjectionMatrix[13]);
|
||||
SETSTAT_FT(stats.gproj_14, g_fProjectionMatrix[14]);
|
||||
SETSTAT_FT(stats.gproj_15, g_fProjectionMatrix[15]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Orthographic Projection
|
||||
g_fProjectionMatrix[0] = xfregs.rawProjection[0];
|
||||
break;
|
||||
|
||||
case GX_ORTHOGRAPHIC:
|
||||
|
||||
g_fProjectionMatrix[0] = rawProjection[0];
|
||||
g_fProjectionMatrix[1] = 0.0f;
|
||||
g_fProjectionMatrix[2] = 0.0f;
|
||||
g_fProjectionMatrix[3] = xfregs.rawProjection[1];
|
||||
g_fProjectionMatrix[3] = rawProjection[1];
|
||||
|
||||
g_fProjectionMatrix[4] = 0.0f;
|
||||
g_fProjectionMatrix[5] = xfregs.rawProjection[2];
|
||||
g_fProjectionMatrix[5] = rawProjection[2];
|
||||
g_fProjectionMatrix[6] = 0.0f;
|
||||
g_fProjectionMatrix[7] = xfregs.rawProjection[3];
|
||||
g_fProjectionMatrix[7] = rawProjection[3];
|
||||
|
||||
g_fProjectionMatrix[8] = 0.0f;
|
||||
g_fProjectionMatrix[9] = 0.0f;
|
||||
g_fProjectionMatrix[10] = (g_ProjHack1.value + xfregs.rawProjection[4]) * ((g_ProjHack1.sign == 0) ? 1.0f : g_ProjHack1.sign);
|
||||
g_fProjectionMatrix[11] = (g_ProjHack2.value + xfregs.rawProjection[5]) * ((g_ProjHack2.sign == 0) ? 1.0f : g_ProjHack2.sign);
|
||||
g_fProjectionMatrix[10] = (g_ProjHack1.value + rawProjection[4]) * ((g_ProjHack1.sign == 0) ? 1.0f : g_ProjHack1.sign);
|
||||
g_fProjectionMatrix[11] = (g_ProjHack2.value + rawProjection[5]) * ((g_ProjHack2.sign == 0) ? 1.0f : g_ProjHack2.sign);
|
||||
|
||||
g_fProjectionMatrix[12] = 0.0f;
|
||||
g_fProjectionMatrix[13] = 0.0f;
|
||||
@@ -398,7 +426,7 @@ void VertexShaderManager::SetConstants()
|
||||
*/
|
||||
|
||||
g_fProjectionMatrix[14] = 0.0f;
|
||||
g_fProjectionMatrix[15] = (g_ProjHack3 && xfregs.rawProjection[0] == 2.0f ? 0.0f : 1.0f); //causes either the efb copy or bloom layer not to show if proj hack enabled
|
||||
g_fProjectionMatrix[15] = (g_ProjHack3 && rawProjection[0] == 2.0f ? 0.0f : 1.0f); //causes either the efb copy or bloom layer not to show if proj hack enabled
|
||||
|
||||
SETSTAT_FT(stats.g2proj_0, g_fProjectionMatrix[0]);
|
||||
SETSTAT_FT(stats.g2proj_1, g_fProjectionMatrix[1]);
|
||||
@@ -416,18 +444,21 @@ void VertexShaderManager::SetConstants()
|
||||
SETSTAT_FT(stats.g2proj_13, g_fProjectionMatrix[13]);
|
||||
SETSTAT_FT(stats.g2proj_14, g_fProjectionMatrix[14]);
|
||||
SETSTAT_FT(stats.g2proj_15, g_fProjectionMatrix[15]);
|
||||
SETSTAT_FT(stats.proj_0, xfregs.rawProjection[0]);
|
||||
SETSTAT_FT(stats.proj_1, xfregs.rawProjection[1]);
|
||||
SETSTAT_FT(stats.proj_2, xfregs.rawProjection[2]);
|
||||
SETSTAT_FT(stats.proj_3, xfregs.rawProjection[3]);
|
||||
SETSTAT_FT(stats.proj_4, xfregs.rawProjection[4]);
|
||||
SETSTAT_FT(stats.proj_5, xfregs.rawProjection[5]);
|
||||
SETSTAT_FT(stats.proj_6, xfregs.rawProjection[6]);
|
||||
SETSTAT_FT(stats.proj_0, rawProjection[0]);
|
||||
SETSTAT_FT(stats.proj_1, rawProjection[1]);
|
||||
SETSTAT_FT(stats.proj_2, rawProjection[2]);
|
||||
SETSTAT_FT(stats.proj_3, rawProjection[3]);
|
||||
SETSTAT_FT(stats.proj_4, rawProjection[4]);
|
||||
SETSTAT_FT(stats.proj_5, rawProjection[5]);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "unknown projection type: %d", xfregs.projection.type);
|
||||
}
|
||||
|
||||
PRIM_LOG("Projection: %f %f %f %f %f %f\n", xfregs.rawProjection[0], xfregs.rawProjection[1], xfregs.rawProjection[2], xfregs.rawProjection[3], xfregs.rawProjection[4], xfregs.rawProjection[5]);
|
||||
PRIM_LOG("Projection: %f %f %f %f %f %f\n", rawProjection[0], rawProjection[1], rawProjection[2], rawProjection[3], rawProjection[4], rawProjection[5]);
|
||||
|
||||
if ((g_ActiveConfig.bFreeLook || g_ActiveConfig.bAnaglyphStereo ) && xfregs.rawProjection[6] == 0)
|
||||
if ((g_ActiveConfig.bFreeLook || g_ActiveConfig.bAnaglyphStereo ) && xfregs.projection.type == GX_PERSPECTIVE)
|
||||
{
|
||||
Matrix44 mtxA;
|
||||
Matrix44 mtxB;
|
||||
|
||||
@@ -44,17 +44,14 @@ enum
|
||||
EFB_HEIGHT = 528,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
// XFB width is decided by EFB copy operation. The VI can do horizontal
|
||||
// scaling (TODO: emulate).
|
||||
MAX_XFB_WIDTH = EFB_WIDTH,
|
||||
// XFB width is decided by EFB copy operation. The VI can do horizontal
|
||||
// scaling (TODO: emulate).
|
||||
const u32 MAX_XFB_WIDTH = EFB_WIDTH;
|
||||
|
||||
// Although EFB height is 528, 574-line XFB's can be created either with
|
||||
// vertical scaling by the EFB copy operation or copying to multiple XFB's
|
||||
// that are next to each other in memory (TODO: handle that situation).
|
||||
MAX_XFB_HEIGHT = 574
|
||||
};
|
||||
// Although EFB height is 528, 574-line XFB's can be created either with
|
||||
// vertical scaling by the EFB copy operation or copying to multiple XFB's
|
||||
// that are next to each other in memory (TODO: handle that situation).
|
||||
const u32 MAX_XFB_HEIGHT = 574;
|
||||
|
||||
// Logging
|
||||
// ----------
|
||||
|
||||
@@ -42,6 +42,7 @@ VideoConfig::VideoConfig()
|
||||
// disable all features by default
|
||||
backend_info.APIType = API_NONE;
|
||||
backend_info.bUseRGBATextures = false;
|
||||
backend_info.bUseMinimalMipCount = false;
|
||||
backend_info.bSupports3DVision = false;
|
||||
}
|
||||
|
||||
@@ -59,6 +60,7 @@ void VideoConfig::Load(const char *ini_file)
|
||||
iniFile.Get("Settings", "UseRealXFB", &bUseRealXFB, 0);
|
||||
iniFile.Get("Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples,128);
|
||||
iniFile.Get("Settings", "ShowFPS", &bShowFPS, false); // Settings
|
||||
iniFile.Get("Settings", "LogFPSToFile", &bLogFPSToFile, false);
|
||||
iniFile.Get("Settings", "ShowInputDisplay", &bShowInputDisplay, false);
|
||||
iniFile.Get("Settings", "OverlayStats", &bOverlayStats, false);
|
||||
iniFile.Get("Settings", "OverlayProjStats", &bOverlayProjStats, false);
|
||||
@@ -74,7 +76,6 @@ void VideoConfig::Load(const char *ini_file)
|
||||
iniFile.Get("Settings", "AnaglyphStereoSeparation", &iAnaglyphStereoSeparation, 200);
|
||||
iniFile.Get("Settings", "AnaglyphFocalAngle", &iAnaglyphFocalAngle, 0);
|
||||
iniFile.Get("Settings", "EnablePixelLighting", &bEnablePixelLighting, 0);
|
||||
iniFile.Get("Settings", "EnablePerPixelDepth", &bEnablePerPixelDepth, 0);
|
||||
|
||||
iniFile.Get("Settings", "MSAA", &iMultisampleMode, 0);
|
||||
iniFile.Get("Settings", "EFBScale", &iEFBScale, 2); // native
|
||||
@@ -134,7 +135,6 @@ void VideoConfig::GameIniLoad(const char *ini_file)
|
||||
iniFile.GetIfExists("Video_Settings", "AnaglyphStereoSeparation", &iAnaglyphStereoSeparation);
|
||||
iniFile.GetIfExists("Video_Settings", "AnaglyphFocalAngle", &iAnaglyphFocalAngle);
|
||||
iniFile.GetIfExists("Video_Settings", "EnablePixelLighting", &bEnablePixelLighting);
|
||||
iniFile.GetIfExists("Video_Settings", "EnablePerPixelDepth", &bEnablePerPixelDepth);
|
||||
iniFile.GetIfExists("Video_Settings", "MSAA", &iMultisampleMode);
|
||||
iniFile.GetIfExists("Video_Settings", "EFBScale", &iEFBScale); // integral
|
||||
iniFile.GetIfExists("Video_Settings", "DstAlphaPass", &bDstAlphaPass);
|
||||
@@ -189,6 +189,7 @@ void VideoConfig::Save(const char *ini_file)
|
||||
iniFile.Set("Settings", "UseRealXFB", bUseRealXFB);
|
||||
iniFile.Set("Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
|
||||
iniFile.Set("Settings", "ShowFPS", bShowFPS);
|
||||
iniFile.Set("Settings", "LogFPSToFile", bLogFPSToFile);
|
||||
iniFile.Set("Settings", "ShowInputDisplay", bShowInputDisplay);
|
||||
iniFile.Set("Settings", "OverlayStats", bOverlayStats);
|
||||
iniFile.Set("Settings", "OverlayProjStats", bOverlayProjStats);
|
||||
@@ -204,7 +205,6 @@ void VideoConfig::Save(const char *ini_file)
|
||||
iniFile.Set("Settings", "AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
|
||||
iniFile.Set("Settings", "AnaglyphFocalAngle", iAnaglyphFocalAngle);
|
||||
iniFile.Set("Settings", "EnablePixelLighting", bEnablePixelLighting);
|
||||
iniFile.Set("Settings", "EnablePerPixelDepth", bEnablePerPixelDepth);
|
||||
|
||||
|
||||
iniFile.Set("Settings", "ShowEFBCopyRegions", bShowEFBCopyRegions);
|
||||
@@ -271,7 +271,6 @@ void VideoConfig::GameIniSave(const char* default_ini, const char* game_ini)
|
||||
SET_IF_DIFFERS("Video_Settings", "AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
|
||||
SET_IF_DIFFERS("Video_Settings", "AnaglyphFocalAngle", iAnaglyphFocalAngle);
|
||||
SET_IF_DIFFERS("Video_Settings", "EnablePixelLighting", bEnablePixelLighting);
|
||||
SET_IF_DIFFERS("Video_Settings", "EnablePerPixelDepth", bEnablePerPixelDepth);
|
||||
SET_IF_DIFFERS("Video_Settings", "MSAA", iMultisampleMode);
|
||||
SET_IF_DIFFERS("Video_Settings", "EFBScale", iEFBScale); // integral
|
||||
SET_IF_DIFFERS("Video_Settings", "DstAlphaPass", bDstAlphaPass);
|
||||
@@ -295,125 +294,3 @@ void VideoConfig::GameIniSave(const char* default_ini, const char* game_ini)
|
||||
|
||||
iniFile.Save(game_ini);
|
||||
}
|
||||
|
||||
|
||||
// TODO: remove
|
||||
extern bool g_aspect_wide;
|
||||
|
||||
// TODO: Figure out a better place for this function.
|
||||
void ComputeDrawRectangle(int backbuffer_width, int backbuffer_height, bool flip, TargetRectangle *rc)
|
||||
{
|
||||
float FloatGLWidth = (float)backbuffer_width;
|
||||
float FloatGLHeight = (float)backbuffer_height;
|
||||
float FloatXOffset = 0;
|
||||
float FloatYOffset = 0;
|
||||
|
||||
// The rendering window size
|
||||
const float WinWidth = FloatGLWidth;
|
||||
const float WinHeight = FloatGLHeight;
|
||||
|
||||
// Handle aspect ratio.
|
||||
// Default to auto.
|
||||
bool use16_9 = g_aspect_wide;
|
||||
|
||||
// Update aspect ratio hack values
|
||||
// Won't take effect until next frame
|
||||
// Don't know if there is a better place for this code so there isn't a 1 frame delay
|
||||
if ( g_ActiveConfig.bWidescreenHack )
|
||||
{
|
||||
float source_aspect = use16_9 ? (16.0f / 9.0f) : (4.0f / 3.0f);
|
||||
float target_aspect;
|
||||
|
||||
switch ( g_ActiveConfig.iAspectRatio )
|
||||
{
|
||||
case ASPECT_FORCE_16_9 :
|
||||
target_aspect = 16.0f / 9.0f;
|
||||
break;
|
||||
case ASPECT_FORCE_4_3 :
|
||||
target_aspect = 4.0f / 3.0f;
|
||||
break;
|
||||
case ASPECT_STRETCH :
|
||||
target_aspect = WinWidth / WinHeight;
|
||||
break;
|
||||
default :
|
||||
// ASPECT_AUTO == no hacking
|
||||
target_aspect = source_aspect;
|
||||
break;
|
||||
}
|
||||
|
||||
float adjust = source_aspect / target_aspect;
|
||||
if ( adjust > 1 )
|
||||
{
|
||||
// Vert+
|
||||
g_Config.fAspectRatioHackW = 1;
|
||||
g_Config.fAspectRatioHackH = 1/adjust;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hor+
|
||||
g_Config.fAspectRatioHackW = adjust;
|
||||
g_Config.fAspectRatioHackH = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hack is disabled
|
||||
g_Config.fAspectRatioHackW = 1;
|
||||
g_Config.fAspectRatioHackH = 1;
|
||||
}
|
||||
|
||||
// Check for force-settings and override.
|
||||
if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9)
|
||||
use16_9 = true;
|
||||
else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3)
|
||||
use16_9 = false;
|
||||
|
||||
if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH)
|
||||
{
|
||||
// The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio
|
||||
float Ratio = (WinWidth / WinHeight) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f));
|
||||
// Check if height or width is the limiting factor. If ratio > 1 the picture is too wide and have to limit the width.
|
||||
if (Ratio > 1.0f)
|
||||
{
|
||||
// Scale down and center in the X direction.
|
||||
FloatGLWidth /= Ratio;
|
||||
FloatXOffset = (WinWidth - FloatGLWidth) / 2.0f;
|
||||
}
|
||||
// The window is too high, we have to limit the height
|
||||
else
|
||||
{
|
||||
// Scale down and center in the Y direction.
|
||||
FloatGLHeight *= Ratio;
|
||||
FloatYOffset = FloatYOffset + (WinHeight - FloatGLHeight) / 2.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Crop the picture from 4:3 to 5:4 or from 16:9 to 16:10.
|
||||
// Output: FloatGLWidth, FloatGLHeight, FloatXOffset, FloatYOffset
|
||||
// ------------------
|
||||
if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH && g_ActiveConfig.bCrop)
|
||||
{
|
||||
float Ratio = !use16_9 ? ((4.0f / 3.0f) / (5.0f / 4.0f)) : (((16.0f / 9.0f) / (16.0f / 10.0f)));
|
||||
// The width and height we will add (calculate this before FloatGLWidth and FloatGLHeight is adjusted)
|
||||
float IncreasedWidth = (Ratio - 1.0f) * FloatGLWidth;
|
||||
float IncreasedHeight = (Ratio - 1.0f) * FloatGLHeight;
|
||||
// The new width and height
|
||||
FloatGLWidth = FloatGLWidth * Ratio;
|
||||
FloatGLHeight = FloatGLHeight * Ratio;
|
||||
// Adjust the X and Y offset
|
||||
FloatXOffset = FloatXOffset - (IncreasedWidth * 0.5f);
|
||||
FloatYOffset = FloatYOffset - (IncreasedHeight * 0.5f);
|
||||
}
|
||||
|
||||
int XOffset = (int)(FloatXOffset + 0.5f);
|
||||
int YOffset = (int)(FloatYOffset + 0.5f);
|
||||
int iWhidth = (int)ceil(FloatGLWidth);
|
||||
int iHeight = (int)ceil(FloatGLHeight);
|
||||
iWhidth -= iWhidth % 4; // ensure divisibility by 4 to make it compatible with all the video encoders
|
||||
iHeight -= iHeight % 4;
|
||||
rc->left = XOffset;
|
||||
rc->top = flip ? (int)(YOffset + iHeight) : YOffset;
|
||||
rc->right = XOffset + iWhidth;
|
||||
rc->bottom = flip ? YOffset : (int)(YOffset + iHeight);
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ struct VideoConfig
|
||||
bool bTexFmtOverlayEnable;
|
||||
bool bTexFmtOverlayCenter;
|
||||
bool bShowEFBCopyRegions;
|
||||
bool bLogFPSToFile;
|
||||
|
||||
// Render
|
||||
bool bWireFrame;
|
||||
@@ -132,7 +133,6 @@ struct VideoConfig
|
||||
bool bZTPSpeedHack; // The Legend of Zelda: Twilight Princess
|
||||
bool bUseBBox;
|
||||
bool bEnablePixelLighting;
|
||||
bool bEnablePerPixelDepth;
|
||||
bool bDisablePixelPerf;
|
||||
|
||||
int iLog; // CONF_ bits
|
||||
@@ -158,12 +158,19 @@ struct VideoConfig
|
||||
std::vector<std::string> PPShaders; // post-processing shaders
|
||||
|
||||
bool bUseRGBATextures; // used for D3D11 in TextureCache
|
||||
bool bUseMinimalMipCount;
|
||||
bool bSupports3DVision;
|
||||
bool bSupportsDualSourceBlend; // only supported by D3D11 and OpenGL
|
||||
bool bSupportsFormatReinterpretation;
|
||||
bool bSupportsPixelLighting;
|
||||
bool bSupportsPixelPerfQuery;
|
||||
} backend_info;
|
||||
|
||||
// Utility
|
||||
bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; }
|
||||
bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; }
|
||||
bool EFBCopiesToTextureEnabled() const { return bEFBCopyEnable && bCopyEFBToTexture; }
|
||||
bool EFBCopiesToRamEnabled() const { return bEFBCopyEnable && !bCopyEFBToTexture; }
|
||||
};
|
||||
|
||||
extern VideoConfig g_Config;
|
||||
@@ -172,6 +179,4 @@ extern VideoConfig g_ActiveConfig;
|
||||
// Called every frame.
|
||||
void UpdateActiveConfig();
|
||||
|
||||
void ComputeDrawRectangle(int backbuffer_width, int backbuffer_height, bool flip, TargetRectangle *rc);
|
||||
|
||||
#endif // _VIDEO_CONFIG_H_
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
#define LIGHTATTN_NONE 2
|
||||
#define LIGHTATTN_DIR 3
|
||||
|
||||
#define GX_PERSPECTIVE 0
|
||||
#define GX_ORTHOGRAPHIC 1
|
||||
|
||||
#define XFMEM_SIZE 0x8000
|
||||
#define XFMEM_POSMATRICES 0x000
|
||||
#define XFMEM_POSMATRICES_END 0x100
|
||||
@@ -235,6 +238,12 @@ struct Viewport
|
||||
float farZ;
|
||||
};
|
||||
|
||||
struct Projection
|
||||
{
|
||||
float rawProjection[6];
|
||||
u32 type; // only GX_PERSPECTIVE or GX_ORTHOGRAPHIC are allowed
|
||||
};
|
||||
|
||||
struct XFRegisters
|
||||
{
|
||||
u32 error; // 0x1000
|
||||
@@ -257,10 +266,10 @@ struct XFRegisters
|
||||
u32 unk5; // 0x1015
|
||||
u32 unk6; // 0x1016
|
||||
u32 unk7; // 0x1017
|
||||
u32 MatrixIndexA; // 0x1018
|
||||
u32 MatrixIndexB; // 0x1019
|
||||
u32 MatrixIndexA; // 0x1018
|
||||
u32 MatrixIndexB; // 0x1019
|
||||
Viewport viewport; // 0x101a - 0x101f
|
||||
float rawProjection[7]; // 0x1020 - 0x1026
|
||||
Projection projection; // 0x1020 - 0x1026
|
||||
u32 unk8[24]; // 0x1027 - 0x103e
|
||||
NumTexGen numTexGen; // 0x103f
|
||||
TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047
|
||||
|
||||
@@ -121,18 +121,12 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData)
|
||||
case XFMEM_SETVIEWPORT+3:
|
||||
case XFMEM_SETVIEWPORT+4:
|
||||
case XFMEM_SETVIEWPORT+5:
|
||||
{
|
||||
u8 size = std::min(transferSize * 4, 6 * 4);
|
||||
if (memcmp((u32*)&xfregs + (address - 0x1000), pData + dataIndex, size))
|
||||
{
|
||||
VertexManager::Flush();
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
PixelShaderManager::SetViewportChanged();
|
||||
}
|
||||
VertexManager::Flush();
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
PixelShaderManager::SetViewportChanged();
|
||||
|
||||
nextAddress = XFMEM_SETVIEWPORT + 6;
|
||||
break;
|
||||
}
|
||||
nextAddress = XFMEM_SETVIEWPORT + 6;
|
||||
break;
|
||||
|
||||
case XFMEM_SETPROJECTION:
|
||||
case XFMEM_SETPROJECTION+1:
|
||||
@@ -141,21 +135,15 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData)
|
||||
case XFMEM_SETPROJECTION+4:
|
||||
case XFMEM_SETPROJECTION+5:
|
||||
case XFMEM_SETPROJECTION+6:
|
||||
{
|
||||
u8 size = std::min(transferSize * 4, 7 * 4);
|
||||
if (memcmp((u32*)&xfregs + (address - 0x1000), pData + dataIndex, size))
|
||||
{
|
||||
VertexManager::Flush();
|
||||
VertexShaderManager::SetProjectionChanged();
|
||||
}
|
||||
VertexManager::Flush();
|
||||
VertexShaderManager::SetProjectionChanged();
|
||||
|
||||
nextAddress = XFMEM_SETPROJECTION + 7;
|
||||
break;
|
||||
}
|
||||
nextAddress = XFMEM_SETPROJECTION + 7;
|
||||
break;
|
||||
|
||||
case XFMEM_SETNUMTEXGENS: // GXSetNumTexGens
|
||||
if (xfregs.numTexGen.numTexGens != (newValue & 15))
|
||||
VertexManager::Flush();
|
||||
VertexManager::Flush();
|
||||
break;
|
||||
|
||||
case XFMEM_SETTEXMTXINFO:
|
||||
@@ -166,16 +154,10 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData)
|
||||
case XFMEM_SETTEXMTXINFO+5:
|
||||
case XFMEM_SETTEXMTXINFO+6:
|
||||
case XFMEM_SETTEXMTXINFO+7:
|
||||
{
|
||||
u8 size = std::min(transferSize * 4, 8 * 4);
|
||||
if (memcmp((u32*)&xfregs + (address - 0x1000), pData + dataIndex, size))
|
||||
{
|
||||
VertexManager::Flush();
|
||||
}
|
||||
VertexManager::Flush();
|
||||
|
||||
nextAddress = XFMEM_SETTEXMTXINFO + 8;
|
||||
break;
|
||||
}
|
||||
nextAddress = XFMEM_SETTEXMTXINFO + 8;
|
||||
break;
|
||||
|
||||
case XFMEM_SETPOSMTXINFO:
|
||||
case XFMEM_SETPOSMTXINFO+1:
|
||||
@@ -185,16 +167,10 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData)
|
||||
case XFMEM_SETPOSMTXINFO+5:
|
||||
case XFMEM_SETPOSMTXINFO+6:
|
||||
case XFMEM_SETPOSMTXINFO+7:
|
||||
{
|
||||
u8 size = std::min(transferSize * 4, 8 * 4);
|
||||
if (memcmp((u32*)&xfregs + (address - 0x1000), pData + dataIndex, size))
|
||||
{
|
||||
VertexManager::Flush();
|
||||
}
|
||||
VertexManager::Flush();
|
||||
|
||||
nextAddress = XFMEM_SETPOSMTXINFO + 8;
|
||||
break;
|
||||
}
|
||||
nextAddress = XFMEM_SETPOSMTXINFO + 8;
|
||||
break;
|
||||
|
||||
// --------------
|
||||
// Unknown Regs
|
||||
@@ -264,15 +240,8 @@ void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData)
|
||||
transferSize = 0;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < xfMemTransferSize; ++i)
|
||||
{
|
||||
if (((u32*)&xfmem[xfMemBase])[i] != pData[i])
|
||||
{
|
||||
XFMemWritten(xfMemTransferSize, xfMemBase);
|
||||
memcpy_gc(&xfmem[xfMemBase], pData, xfMemTransferSize * 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFMemWritten(xfMemTransferSize, xfMemBase);
|
||||
memcpy_gc(&xfmem[xfMemBase], pData, xfMemTransferSize * 4);
|
||||
|
||||
pData += xfMemTransferSize;
|
||||
}
|
||||
|
||||
+5
-5
@@ -35,7 +35,7 @@
|
||||
#include "VertexLoaderManager.h"
|
||||
#include "VertexManagerBase.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "ABI.h"
|
||||
#include "x64ABI.h"
|
||||
|
||||
#include "DLCache.h"
|
||||
#include "VideoConfig.h"
|
||||
@@ -361,9 +361,9 @@ u32 AnalyzeAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl)
|
||||
(cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT,
|
||||
numVertices);
|
||||
num_draw_call++;
|
||||
const int tc[12] = {
|
||||
const u32 tc[12] = {
|
||||
g_VtxDesc.Position, g_VtxDesc.Normal, g_VtxDesc.Color0, g_VtxDesc.Color1, g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord,
|
||||
g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const int)((g_VtxDesc.Hex >> 31) & 3)
|
||||
g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const u32)((g_VtxDesc.Hex >> 31) & 3)
|
||||
};
|
||||
for(int i = 0; i < 12; i++)
|
||||
{
|
||||
@@ -563,9 +563,9 @@ void CompileAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl)
|
||||
dl->InsertRegion(NewRegion);
|
||||
memcpy(NewRegion->start_address, StartAddress, Vdatasize);
|
||||
emitter.ABI_CallFunctionCCCP((void *)&VertexLoaderManager::RunCompiledVertices, cmd_byte & GX_VAT_MASK, (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices, NewRegion->start_address);
|
||||
const int tc[12] = {
|
||||
const u32 tc[12] = {
|
||||
g_VtxDesc.Position, g_VtxDesc.Normal, g_VtxDesc.Color0, g_VtxDesc.Color1, g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord,
|
||||
g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const int)((g_VtxDesc.Hex >> 31) & 3)
|
||||
g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const u32)((g_VtxDesc.Hex >> 31) & 3)
|
||||
};
|
||||
for(int i = 0; i < 12; i++)
|
||||
{
|
||||
+35
-94
@@ -692,7 +692,7 @@ inline void SetOpenMPThreadCount(int width, int height)
|
||||
if (g_ActiveConfig.bOMPDecoder && width > 127 && height > 127)
|
||||
{
|
||||
// don't span to many threads they will kill the rest of the emu :)
|
||||
omp_set_num_threads((cpu_info.num_cores + 2) / 3);
|
||||
omp_set_num_threads((omp_get_num_procs() + 2) / 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1119,20 +1119,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he
|
||||
_mm_storeu_si128( (__m128i*)( dst+(y + iy+1) * width + x + 4 ), o4 );
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Reference C implementation:
|
||||
for (int y = 0; y < height; y += 8)
|
||||
for (int x = 0; x < width; x += 8)
|
||||
for (int iy = 0; iy < 8; iy++, src += 4)
|
||||
for (int ix = 0; ix < 4; ix++)
|
||||
{
|
||||
int val = src[ix];
|
||||
u8 i1 = Convert4To8(val >> 4);
|
||||
u8 i2 = Convert4To8(val & 0xF);
|
||||
memset(dst+(y + iy) * width + x + ix * 2 , i1,4);
|
||||
memset(dst+(y + iy) * width + x + ix * 2 + 1 , i2,4);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case GX_TF_I8: // speed critical
|
||||
@@ -1248,26 +1234,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he
|
||||
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Reference C implementation
|
||||
for (int y = 0; y < height; y += 4)
|
||||
for (int x = 0; x < width; x += 8)
|
||||
for (int iy = 0; iy < 4; ++iy, src += 8)
|
||||
{
|
||||
u32 * newdst = dst + (y + iy)*width+x;
|
||||
const u8 * newsrc = src;
|
||||
u8 srcval;
|
||||
|
||||
srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24);
|
||||
srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24);
|
||||
srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24);
|
||||
srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24);
|
||||
srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24);
|
||||
srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24);
|
||||
srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24);
|
||||
srcval = newsrc[0]; newdst[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case GX_TF_C8:
|
||||
@@ -1380,20 +1346,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he
|
||||
_mm_storeu_si128( (__m128i*)(dst + (y + iy) * width + x), r1 );
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Reference C implementation:
|
||||
for (int y = 0; y < height; y += 4)
|
||||
for (int x = 0; x < width; x += 4)
|
||||
for (int iy = 0; iy < 4; iy++, src += 8)
|
||||
{
|
||||
u32 *ptr = dst + (y + iy) * width + x;
|
||||
u16 *s = (u16 *)src;
|
||||
ptr[0] = decodeIA8Swapped(s[0]);
|
||||
ptr[1] = decodeIA8Swapped(s[1]);
|
||||
ptr[2] = decodeIA8Swapped(s[2]);
|
||||
ptr[3] = decodeIA8Swapped(s[3]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case GX_TF_C14X2:
|
||||
@@ -1493,18 +1445,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he
|
||||
__m128i *ptr = (__m128i *)(dst + (y + iy) * width + x);
|
||||
_mm_storeu_si128(ptr, abgr888x4);
|
||||
}
|
||||
#if 0
|
||||
// Reference C implementation.
|
||||
for (int y = 0; y < height; y += 4)
|
||||
for (int x = 0; x < width; x += 4)
|
||||
for (int iy = 0; iy < 4; iy++, src += 8)
|
||||
{
|
||||
u32 *ptr = dst + (y + iy) * width + x;
|
||||
u16 *s = (u16 *)src;
|
||||
for(int j = 0; j < 4; j++)
|
||||
*ptr++ = decode565RGBA(Common::swap16(*s++));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case GX_TF_RGB5A3:
|
||||
@@ -1718,13 +1658,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he
|
||||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Reference C implementation:
|
||||
for (int y = 0; y < height; y += 4)
|
||||
for (int x = 0; x < width; x += 4)
|
||||
for (int iy = 0; iy < 4; iy++, src += 8)
|
||||
decodebytesRGB5A3rgba(dst+(y+iy)*width+x, (u16*)src);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case GX_TF_RGBA8: // speed critical
|
||||
@@ -1860,16 +1793,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he
|
||||
_mm_storeu_si128(dst128, rgba11);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Reference C implementation.
|
||||
for (int y = 0; y < height; y += 4)
|
||||
for (int x = 0; x < width; x += 4)
|
||||
{
|
||||
for (int iy = 0; iy < 4; iy++)
|
||||
decodebytesARGB8_4ToRgba(dst + (y+iy)*width + x, (u16*)src + 4 * iy, (u16*)src + 4 * iy + 16);
|
||||
src += 64;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case GX_TF_CMPR: // speed critical
|
||||
@@ -2104,22 +2027,6 @@ PC_TexFormat TexDecoder_Decode_RGBA(u32 * dst, const u8 * src, int width, int he
|
||||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
for (int y = 0; y < height; y += 8)
|
||||
{
|
||||
for (int x = 0; x < width; x += 8)
|
||||
{
|
||||
decodeDXTBlockRGBA((u32*)dst + y * width + x, (DXTBlock*)src, width);
|
||||
src += sizeof(DXTBlock);
|
||||
decodeDXTBlockRGBA((u32*)dst + y * width + x + 4, (DXTBlock*)src, width);
|
||||
src += sizeof(DXTBlock);
|
||||
decodeDXTBlockRGBA((u32*)dst + (y + 4) * width + x, (DXTBlock*)src, width);
|
||||
src += sizeof(DXTBlock);
|
||||
decodeDXTBlockRGBA((u32*)dst + (y + 4) * width + x + 4, (DXTBlock*)src, width);
|
||||
src += sizeof(DXTBlock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2515,6 +2422,40 @@ void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth
|
||||
}
|
||||
}
|
||||
|
||||
void TexDecoder_DecodeTexelRGBA8FromTmem(u8 *dst, const u8 *src_ar, const u8* src_gb, int s, int t, int imageWidth)
|
||||
{
|
||||
u16 sBlk = s >> 2;
|
||||
u16 tBlk = t >> 2;
|
||||
u16 widthBlks = (imageWidth >> 2) + 1; // TODO: Looks wrong. Shouldn't this be ((imageWidth-1)>>2)+1 ?
|
||||
u32 base_ar = (tBlk * widthBlks + sBlk) << 4;
|
||||
u32 base_gb = (tBlk * widthBlks + sBlk) << 4;
|
||||
u16 blkS = s & 3;
|
||||
u16 blkT = t & 3;
|
||||
u32 blk_off = (blkT << 2) + blkS;
|
||||
|
||||
u32 offset_ar = (base_ar + blk_off) << 1;
|
||||
u32 offset_gb = (base_gb + blk_off) << 1;
|
||||
const u8* val_addr_ar = src_ar + offset_ar;
|
||||
const u8* val_addr_gb = src_gb + offset_gb;
|
||||
|
||||
dst[3] = val_addr_ar[0]; // A
|
||||
dst[0] = val_addr_ar[1]; // R
|
||||
dst[1] = val_addr_gb[0]; // G
|
||||
dst[2] = val_addr_gb[1]; // B
|
||||
}
|
||||
|
||||
PC_TexFormat TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8 *src_ar, const u8 *src_gb, int width, int height)
|
||||
{
|
||||
// TODO for someone who cares: Make this less slow!
|
||||
for (int y = 0; y < height; ++y)
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(dst, src_ar, src_gb, x, y, width-1);
|
||||
dst += 4;
|
||||
}
|
||||
|
||||
return PC_TEX_FMT_RGBA32;
|
||||
}
|
||||
|
||||
const char* texfmt[] = {
|
||||
// pixel
|
||||
Reference in New Issue
Block a user