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:
NeoBrainX
2013-03-01 01:07:34 +01:00
886 changed files with 69167 additions and 56567 deletions
+18 -6
View File
@@ -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
+4 -2
View File
@@ -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();
};
+169 -1
View File
@@ -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;
}
+12 -3
View File
@@ -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
+40 -15
View File
@@ -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;
-12
View File
@@ -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;
}
+28
View File
@@ -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_
+3 -4
View File
@@ -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 :
+17 -2
View File
@@ -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;
+173 -192
View File
@@ -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[] =
+1 -1
View File
@@ -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);
+311 -152
View File
@@ -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)
+15 -16
View File
@@ -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;
+1 -1
View File
@@ -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;
+172 -130
View File
@@ -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;
+15 -15
View File
@@ -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
+18 -10
View File
@@ -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;
+7 -10
View File
@@ -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
// ----------
+3 -126
View File
@@ -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);
}
+8 -3
View File
@@ -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_
+12 -3
View File
@@ -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
+18 -49
View File
@@ -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;
}
@@ -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++)
{
@@ -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