mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Rebase immediate-removal on master
This commit is contained in:
@ -73,8 +73,9 @@ void OpenGL_SetWindowText(const char *text)
|
||||
#elif defined(__APPLE__)
|
||||
[GLWin.cocoaWin setTitle: [NSString stringWithUTF8String: text]];
|
||||
#elif defined(_WIN32)
|
||||
// TODO convert text to unicode and change SetWindowTextA to SetWindowText
|
||||
SetWindowTextA(EmuWindow::GetWnd(), text);
|
||||
TCHAR temp[512];
|
||||
swprintf_s(temp, sizeof(temp)/sizeof(TCHAR), _T("%hs"), text);
|
||||
EmuWindow::SetWindowText(temp);
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
// Tell X to ask the window manager to set the window title.
|
||||
// (X itself doesn't provide window title functionality.)
|
||||
@ -173,7 +174,7 @@ void XEventThread()
|
||||
OSDChoice = 1;
|
||||
// Toggle native resolution
|
||||
g_Config.iEFBScale = g_Config.iEFBScale + 1;
|
||||
if (g_Config.iEFBScale > 4) g_Config.iEFBScale = 0;
|
||||
if (g_Config.iEFBScale > 7) g_Config.iEFBScale = 0;
|
||||
break;
|
||||
case XK_4:
|
||||
OSDChoice = 2;
|
||||
@ -197,10 +198,6 @@ void XEventThread()
|
||||
OSDChoice = 4;
|
||||
g_Config.bDisableFog = !g_Config.bDisableFog;
|
||||
break;
|
||||
case XK_7:
|
||||
OSDChoice = 5;
|
||||
g_Config.bDisableLighting = !g_Config.bDisableLighting;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -271,21 +271,13 @@ void GLVertexFormat::EnableComponents(u32 components)
|
||||
// tex
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (!g_ActiveConfig.bDisableTexturing)
|
||||
{
|
||||
if ((components & (VB_HAS_UV0 << i)) != (s_prevcomponents & (VB_HAS_UV0 << i)))
|
||||
{
|
||||
glClientActiveTexture(GL_TEXTURE0 + i);
|
||||
if (components & (VB_HAS_UV0 << i))
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
}
|
||||
else
|
||||
if ((components & (VB_HAS_UV0 << i)) != (s_prevcomponents & (VB_HAS_UV0 << i)))
|
||||
{
|
||||
glClientActiveTexture(GL_TEXTURE0 + i);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
if (components & (VB_HAS_UV0 << i))
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,8 @@ bool PixelShaderCache::s_displayCompileAlert;
|
||||
GLuint PixelShaderCache::CurrentShader;
|
||||
bool PixelShaderCache::ShaderEnabled;
|
||||
|
||||
static FRAGMENTSHADER* pShaderLast = NULL;
|
||||
PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry = NULL;
|
||||
PIXELSHADERUID PixelShaderCache::last_uid;
|
||||
|
||||
GLuint PixelShaderCache::GetDepthMatrixProgram()
|
||||
{
|
||||
@ -61,10 +62,9 @@ void PixelShaderCache::Init()
|
||||
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
ShaderEnabled = true;
|
||||
CurrentShader = 0;
|
||||
last_entry = NULL;
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid));
|
||||
|
||||
s_displayCompileAlert = true;
|
||||
|
||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions);
|
||||
@ -184,38 +184,43 @@ void PixelShaderCache::Shutdown()
|
||||
FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components)
|
||||
{
|
||||
PIXELSHADERUID uid;
|
||||
GetPixelShaderId(&uid, dstAlphaMode);
|
||||
|
||||
GetPixelShaderId(&uid, dstAlphaMode, components);
|
||||
|
||||
// Check if the shader is already set
|
||||
if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount)
|
||||
if (last_entry)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return pShaderLast;
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
ValidatePixelShaderIDs(API_OPENGL, last_entry->safe_uid, last_entry->shader.strprog, dstAlphaMode, components);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID));
|
||||
last_uid = uid;
|
||||
|
||||
PSCache::iterator iter = PixelShaders.find(uid);
|
||||
|
||||
if (iter != PixelShaders.end())
|
||||
{
|
||||
iter->second.frameCount = frameCount;
|
||||
PSCacheEntry &entry = iter->second;
|
||||
if (&entry.shader != pShaderLast)
|
||||
{
|
||||
pShaderLast = &entry.shader;
|
||||
}
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return pShaderLast;
|
||||
ValidatePixelShaderIDs(API_OPENGL, entry.safe_uid, entry.shader.strprog, dstAlphaMode, components);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
// Make an entry in the table
|
||||
PSCacheEntry& newentry = PixelShaders[uid];
|
||||
newentry.frameCount = frameCount;
|
||||
pShaderLast = &newentry.shader;
|
||||
last_entry = &newentry;
|
||||
const char *code = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components);
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging && code)
|
||||
{
|
||||
GetSafePixelShaderId(&newentry.safe_uid, dstAlphaMode, components);
|
||||
newentry.shader.strprog = code;
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) {
|
||||
static int counter = 0;
|
||||
@ -234,7 +239,7 @@ FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 comp
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, PixelShaders.size());
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return pShaderLast;
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram)
|
||||
@ -247,7 +252,7 @@ bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrpr
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
char stropt[128];
|
||||
sprintf(stropt, "MaxLocalParams=32,NumInstructionSlots=%d", s_nMaxPixelInstructions);
|
||||
sprintf(stropt, "MaxLocalParams=224,NumInstructionSlots=%d", s_nMaxPixelInstructions);
|
||||
const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL};
|
||||
CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts);
|
||||
|
||||
@ -318,9 +323,6 @@ bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrpr
|
||||
cgDestroyProgram(tempprog);
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
ps.strprog = pstrprogram;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -39,9 +39,7 @@ struct FRAGMENTSHADER
|
||||
}
|
||||
}
|
||||
GLuint glprogid; // opengl program id
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
std::string strprog;
|
||||
#endif
|
||||
};
|
||||
|
||||
class PixelShaderCache
|
||||
@ -49,13 +47,13 @@ class PixelShaderCache
|
||||
struct PSCacheEntry
|
||||
{
|
||||
FRAGMENTSHADER shader;
|
||||
int frameCount;
|
||||
PSCacheEntry() : frameCount(0) {}
|
||||
PSCacheEntry() {}
|
||||
~PSCacheEntry() {}
|
||||
void Destroy()
|
||||
{
|
||||
shader.Destroy();
|
||||
}
|
||||
PIXELSHADERUIDSAFE safe_uid;
|
||||
};
|
||||
|
||||
typedef std::map<PIXELSHADERUID, PSCacheEntry> PSCache;
|
||||
@ -67,6 +65,8 @@ class PixelShaderCache
|
||||
static bool s_displayCompileAlert;
|
||||
|
||||
static GLuint CurrentShader;
|
||||
static PSCacheEntry* last_entry;
|
||||
static PIXELSHADERUID last_uid;
|
||||
|
||||
static bool ShaderEnabled;
|
||||
|
||||
|
@ -60,6 +60,8 @@
|
||||
#include "Core.h"
|
||||
#include "Movie.h"
|
||||
#include "Host.h"
|
||||
#include "BPFunctions.h"
|
||||
#include "FPSCounter.h"
|
||||
|
||||
#include "main.h" // Local
|
||||
#ifdef _WIN32
|
||||
@ -109,12 +111,6 @@ int s_fps=0;
|
||||
|
||||
RasterFont* s_pfont = NULL;
|
||||
|
||||
#if defined _WIN32 || defined HAVE_LIBAV
|
||||
static bool s_bAVIDumping = false;
|
||||
#else
|
||||
static File::IOFile f_pFrameDump;
|
||||
#endif
|
||||
|
||||
// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
|
||||
static int s_MSAASamples = 1;
|
||||
static int s_MSAACoverageSamples = 0;
|
||||
@ -128,6 +124,12 @@ static u32 s_blendMode;
|
||||
static std::thread scrshotThread;
|
||||
#endif
|
||||
|
||||
// EFB cache related
|
||||
const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks.
|
||||
const u32 EFB_CACHE_WIDTH = (EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; // round up
|
||||
const u32 EFB_CACHE_HEIGHT = (EFB_HEIGHT + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE;
|
||||
static bool s_efbCacheValid[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT];
|
||||
static std::vector<u32> s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2 for PEEK_Z and PEEK_COLOR
|
||||
|
||||
static const GLenum glSrcFactors[8] =
|
||||
{
|
||||
@ -249,9 +251,8 @@ Renderer::Renderer()
|
||||
|
||||
s_fps=0;
|
||||
s_blendMode = 0;
|
||||
#if defined _WIN32 || defined HAVE_LIBAV
|
||||
s_bAVIDumping = false;
|
||||
#endif
|
||||
|
||||
InitFPSCounter();
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
g_cgcontext = cgCreateContext();
|
||||
@ -515,19 +516,6 @@ Renderer::~Renderer()
|
||||
#endif
|
||||
|
||||
delete g_framebuffer_manager;
|
||||
|
||||
#if defined _WIN32 || defined HAVE_LIBAV
|
||||
if(s_bAVIDumping)
|
||||
{
|
||||
AVIDump::Stop();
|
||||
s_bLastFrameDumped = false;
|
||||
s_bAVIDumping = false;
|
||||
}
|
||||
#else
|
||||
if (f_pFrameDump.IsOpen())
|
||||
f_pFrameDump.Close();
|
||||
s_bLastFrameDumped = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create On-Screen-Messages
|
||||
@ -610,7 +598,7 @@ void Renderer::RenderText(const char *text, int left, int top, u32 color)
|
||||
{
|
||||
const int nBackbufferWidth = (int)OpenGL_GetBackbufferWidth();
|
||||
const int nBackbufferHeight = (int)OpenGL_GetBackbufferHeight();
|
||||
|
||||
|
||||
glColor4f(((color>>16) & 0xff)/255.0f, ((color>> 8) & 0xff)/255.0f,
|
||||
((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f);
|
||||
|
||||
@ -642,49 +630,9 @@ TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||
// Renderer::GetTargetHeight() = the fixed ini file setting
|
||||
// donkopunchstania - it appears scissorBR is the bottom right pixel inside the scissor box
|
||||
// therefore the width and height are (scissorBR + 1) - scissorTL
|
||||
bool Renderer::SetScissorRect()
|
||||
void Renderer::SetScissorRect(const TargetRectangle& rc)
|
||||
{
|
||||
MathUtil::Rectangle<float> rc;
|
||||
GetScissorRect(rc);
|
||||
|
||||
if (rc.left < 0) rc.left = 0;
|
||||
if (rc.top < 0) rc.top = 0;
|
||||
if (rc.right > EFB_WIDTH) rc.right = EFB_WIDTH;
|
||||
if (rc.bottom > EFB_HEIGHT) rc.bottom = EFB_HEIGHT;
|
||||
|
||||
if (rc.left > rc.right)
|
||||
{
|
||||
int temp = rc.right;
|
||||
rc.right = rc.left;
|
||||
rc.left = temp;
|
||||
}
|
||||
if (rc.top > rc.bottom)
|
||||
{
|
||||
int temp = rc.bottom;
|
||||
rc.bottom = rc.top;
|
||||
rc.top = temp;
|
||||
}
|
||||
|
||||
// Check that the coordinates are good
|
||||
if (rc.right != rc.left && rc.bottom != rc.top)
|
||||
{
|
||||
glScissor(
|
||||
EFBToScaledX(rc.left), // x = 0 for example
|
||||
EFBToScaledY(EFB_HEIGHT - rc.bottom), // y = 0 for example
|
||||
EFBToScaledX(rc.right - rc.left), // width = 640 for example
|
||||
EFBToScaledY(rc.bottom - rc.top)); // height = 480 for example
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
glScissor(
|
||||
0,
|
||||
0,
|
||||
Renderer::GetTargetWidth(),
|
||||
Renderer::GetTargetHeight()
|
||||
);
|
||||
}
|
||||
return false;
|
||||
glScissor(rc.left, rc.bottom, rc.GetWidth(), rc.GetHeight());
|
||||
}
|
||||
|
||||
void Renderer::SetColorMask()
|
||||
@ -698,6 +646,44 @@ void Renderer::SetColorMask()
|
||||
glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask);
|
||||
}
|
||||
|
||||
void ClearEFBCache()
|
||||
{
|
||||
for (u32 i = 0; i < EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT; ++i)
|
||||
s_efbCacheValid[0][i] = false;
|
||||
|
||||
for (u32 i = 0; i < EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT; ++i)
|
||||
s_efbCacheValid[1][i] = false;
|
||||
}
|
||||
|
||||
void Renderer::UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const u32* data)
|
||||
{
|
||||
u32 cacheType = (type == PEEK_Z ? 0 : 1);
|
||||
|
||||
if (!s_efbCache[cacheType][cacheRectIdx].size())
|
||||
s_efbCache[cacheType][cacheRectIdx].resize(EFB_CACHE_RECT_SIZE * EFB_CACHE_RECT_SIZE);
|
||||
|
||||
u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left;
|
||||
u32 efbPixelRcHeight = efbPixelRc.bottom - efbPixelRc.top;
|
||||
u32 efbPixelRcWidth = efbPixelRc.right - efbPixelRc.left;
|
||||
|
||||
for (u32 yCache = 0; yCache < efbPixelRcHeight; ++yCache)
|
||||
{
|
||||
u32 yEFB = efbPixelRc.top + yCache;
|
||||
u32 yPixel = (EFBToScaledY(EFB_HEIGHT - yEFB) + EFBToScaledY(EFB_HEIGHT - yEFB - 1)) / 2;
|
||||
u32 yData = yPixel - targetPixelRc.bottom;
|
||||
|
||||
for (u32 xCache = 0; xCache < efbPixelRcWidth; ++xCache)
|
||||
{
|
||||
u32 xEFB = efbPixelRc.left + xCache;
|
||||
u32 xPixel = (EFBToScaledX(xEFB) + EFBToScaledX(xEFB + 1)) / 2;
|
||||
u32 xData = xPixel - targetPixelRc.left;
|
||||
s_efbCache[cacheType][cacheRectIdx][yCache * EFB_CACHE_RECT_SIZE + xCache] = data[yData * targetPixelRcWidth + xData];
|
||||
}
|
||||
}
|
||||
|
||||
s_efbCacheValid[cacheType][cacheRectIdx] = true;
|
||||
}
|
||||
|
||||
// This function allows the CPU to directly access the EFB.
|
||||
// There are EFB peeks (which will read the color or depth of a pixel)
|
||||
// and EFB pokes (which will change the color or depth of a pixel).
|
||||
@ -717,34 +703,50 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
|
||||
if (!g_ActiveConfig.bEFBAccessEnable)
|
||||
return 0;
|
||||
|
||||
// Get the rectangular target region covered by the EFB pixel
|
||||
u32 cacheRectIdx = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_WIDTH
|
||||
+ (x / EFB_CACHE_RECT_SIZE);
|
||||
|
||||
// Get the rectangular target region containing the EFB pixel
|
||||
EFBRectangle efbPixelRc;
|
||||
efbPixelRc.left = x;
|
||||
efbPixelRc.top = y;
|
||||
efbPixelRc.right = x + 1;
|
||||
efbPixelRc.bottom = y + 1;
|
||||
efbPixelRc.left = (x / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE;
|
||||
efbPixelRc.top = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE;
|
||||
efbPixelRc.right = std::min(efbPixelRc.left + EFB_CACHE_RECT_SIZE, (u32)EFB_WIDTH);
|
||||
efbPixelRc.bottom = std::min(efbPixelRc.top + EFB_CACHE_RECT_SIZE, (u32)EFB_HEIGHT);
|
||||
|
||||
TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc);
|
||||
u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left;
|
||||
u32 targetPixelRcHeight = targetPixelRc.top - targetPixelRc.bottom;
|
||||
|
||||
// TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
|
||||
switch (type)
|
||||
{
|
||||
case PEEK_Z:
|
||||
{
|
||||
if (s_MSAASamples > 1)
|
||||
u32 z;
|
||||
|
||||
if (!s_efbCacheValid[0][cacheRectIdx])
|
||||
{
|
||||
// Resolve our rectangle.
|
||||
FramebufferManager::GetEFBDepthTexture(efbPixelRc);
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer());
|
||||
if (s_MSAASamples > 1)
|
||||
{
|
||||
// Resolve our rectangle.
|
||||
FramebufferManager::GetEFBDepthTexture(efbPixelRc);
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer());
|
||||
}
|
||||
|
||||
u32* depthMap = new u32[targetPixelRcWidth * targetPixelRcHeight];
|
||||
|
||||
glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
|
||||
GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, depthMap);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, depthMap);
|
||||
|
||||
delete[] depthMap;
|
||||
}
|
||||
|
||||
// Sample from the center of the target region.
|
||||
int srcX = (targetPixelRc.left + targetPixelRc.right) / 2;
|
||||
int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
||||
|
||||
u32 z = 0;
|
||||
glReadPixels(srcX, srcY, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &z);
|
||||
GL_REPORT_ERRORD();
|
||||
u32 xRect = x % EFB_CACHE_RECT_SIZE;
|
||||
u32 yRect = y % EFB_CACHE_RECT_SIZE;
|
||||
z = s_efbCache[0][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
|
||||
|
||||
// Scale the 32-bit value returned by glReadPixels to a 24-bit
|
||||
// value (GC uses a 24-bit Z-buffer).
|
||||
@ -769,21 +771,31 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
|
||||
// determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
|
||||
// Wind Waker is also using it for the pictograph to determine the color of each pixel
|
||||
|
||||
if (s_MSAASamples > 1)
|
||||
u32 color;
|
||||
|
||||
if (!s_efbCacheValid[1][cacheRectIdx])
|
||||
{
|
||||
// Resolve our rectangle.
|
||||
FramebufferManager::GetEFBColorTexture(efbPixelRc);
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer());
|
||||
if (s_MSAASamples > 1)
|
||||
{
|
||||
// Resolve our rectangle.
|
||||
FramebufferManager::GetEFBColorTexture(efbPixelRc);
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer());
|
||||
}
|
||||
|
||||
u32* colorMap = new u32[targetPixelRcWidth * targetPixelRcHeight];
|
||||
|
||||
glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
|
||||
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, colorMap);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, colorMap);
|
||||
|
||||
delete[] colorMap;
|
||||
}
|
||||
|
||||
// Sample from the center of the target region.
|
||||
int srcX = (targetPixelRc.left + targetPixelRc.right) / 2;
|
||||
int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
||||
|
||||
// Read back pixel in BGRA format, then byteswap to get GameCube's ARGB Format.
|
||||
u32 color = 0;
|
||||
glReadPixels(srcX, srcY, 1, 1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &color);
|
||||
GL_REPORT_ERRORD();
|
||||
u32 xRect = x % EFB_CACHE_RECT_SIZE;
|
||||
u32 yRect = y % EFB_CACHE_RECT_SIZE;
|
||||
color = s_efbCache[1][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
|
||||
|
||||
// check what to do with the alpha channel (GX_PokeAlphaRead)
|
||||
PixelEngine::UPEAlphaReadReg alpha_read_mode;
|
||||
@ -865,64 +877,35 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE
|
||||
{
|
||||
ResetAPIState();
|
||||
|
||||
GLenum ColorMask = GL_FALSE, AlphaMask = GL_FALSE;
|
||||
if (colorEnable) ColorMask = GL_TRUE;
|
||||
if (alphaEnable) AlphaMask = GL_TRUE;
|
||||
glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask);
|
||||
// color
|
||||
GLboolean const
|
||||
color_mask = colorEnable ? GL_TRUE : GL_FALSE,
|
||||
alpha_mask = alphaEnable ? GL_TRUE : GL_FALSE;
|
||||
glColorMask(color_mask, color_mask, color_mask, alpha_mask);
|
||||
|
||||
if (zEnable)
|
||||
{
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
glDepthFunc(GL_NEVER);
|
||||
}
|
||||
glClearColor(
|
||||
float((color >> 16) & 0xFF) / 255.0f,
|
||||
float((color >> 8) & 0xFF) / 255.0f,
|
||||
float((color >> 0) & 0xFF) / 255.0f,
|
||||
float((color >> 24) & 0xFF) / 255.0f);
|
||||
|
||||
// Update viewport for clearing the picture
|
||||
TargetRectangle targetRc = ConvertEFBRectangle(rc);
|
||||
glViewport(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
|
||||
glDepthRange(0.0, (float)(z & 0xFFFFFF) / float(0xFFFFFF));
|
||||
// depth
|
||||
glDepthMask(zEnable ? GL_TRUE : GL_FALSE);
|
||||
|
||||
GLfloat vtx1[] = {
|
||||
-1, -1, 1,
|
||||
-1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, -1, 1
|
||||
};
|
||||
GLfloat col1[] = { // This looks terrible
|
||||
(float)((color >> 16) & 0xFF) / 255.0f,
|
||||
(float)((color >> 8) & 0xFF) / 255.0f,
|
||||
(float)(color & 0xFF) / 255.0f,
|
||||
(float)((color >> 24) & 0xFF) / 255.0f,
|
||||
glClearDepth(float(z & 0xFFFFFF) / float(0xFFFFFF));
|
||||
|
||||
(float)((color >> 16) & 0xFF) / 255.0f,
|
||||
(float)((color >> 8) & 0xFF) / 255.0f,
|
||||
(float)(color & 0xFF) / 255.0f,
|
||||
(float)((color >> 24) & 0xFF) / 255.0f,
|
||||
// Update rect for clearing the picture
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
(float)((color >> 16) & 0xFF) / 255.0f,
|
||||
(float)((color >> 8) & 0xFF) / 255.0f,
|
||||
(float)(color & 0xFF) / 255.0f,
|
||||
(float)((color >> 24) & 0xFF) / 255.0f,
|
||||
TargetRectangle const targetRc = ConvertEFBRectangle(rc);
|
||||
glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
|
||||
|
||||
(float)((color >> 16) & 0xFF) / 255.0f,
|
||||
(float)((color >> 8) & 0xFF) / 255.0f,
|
||||
(float)(color & 0xFF) / 255.0f,
|
||||
(float)((color >> 24) & 0xFF) / 255.0f
|
||||
};
|
||||
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); // Only need this to not overwrite the GL_COLOR_ARRAY state
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glColorPointer(4, GL_FLOAT, 0 ,col1);
|
||||
glVertexPointer(3, GL_FLOAT, 0, vtx1);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glPopClientAttrib();
|
||||
// glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
RestoreAPIState();
|
||||
|
||||
ClearEFBCache();
|
||||
}
|
||||
|
||||
void Renderer::ReinterpretPixelData(unsigned int convtype)
|
||||
@ -1009,16 +992,17 @@ void Renderer::SetBlendMode(bool forceUpdate)
|
||||
// This function has the final picture. We adjust the aspect ratio here.
|
||||
void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma)
|
||||
{
|
||||
static u8 *data = NULL;
|
||||
static int w = 0, h = 0;
|
||||
if (g_bSkipCurrentFrame || (!XFBWrited && (!g_ActiveConfig.bUseXFB || !g_ActiveConfig.bUseRealXFB)) || !fbWidth || !fbHeight)
|
||||
{
|
||||
if (g_ActiveConfig.bDumpFrames && data)
|
||||
#ifdef _WIN32
|
||||
AVIDump::AddFrame((char *) data);
|
||||
#elif defined HAVE_LIBAV
|
||||
AVIDump::AddFrame(data, w, h);
|
||||
#endif
|
||||
if (g_ActiveConfig.bDumpFrames && frame_data)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
AVIDump::AddFrame(frame_data);
|
||||
#elif defined HAVE_LIBAV
|
||||
AVIDump::AddFrame((u8*)frame_data, w, h);
|
||||
#endif
|
||||
}
|
||||
Core::Callback_VideoCopiedToXFB(false);
|
||||
return;
|
||||
}
|
||||
@ -1031,12 +1015,14 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
|
||||
if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
|
||||
{
|
||||
if (g_ActiveConfig.bDumpFrames && data)
|
||||
#ifdef _WIN32
|
||||
AVIDump::AddFrame((char *) data);
|
||||
#elif defined HAVE_LIBAV
|
||||
AVIDump::AddFrame(data, w, h);
|
||||
#endif
|
||||
if (g_ActiveConfig.bDumpFrames && frame_data)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
AVIDump::AddFrame(frame_data);
|
||||
#elif defined HAVE_LIBAV
|
||||
AVIDump::AddFrame((u8*)frame_data, w, h);
|
||||
#endif
|
||||
}
|
||||
Core::Callback_VideoCopiedToXFB(false);
|
||||
return;
|
||||
}
|
||||
@ -1145,11 +1131,16 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
1, 1, 1,
|
||||
1, -1, 1
|
||||
};
|
||||
GLfloat top = (GLfloat)targetRc.top;
|
||||
GLfloat right = (GLfloat)targetRc.right;
|
||||
GLfloat bottom = (GLfloat)targetRc.bottom;
|
||||
GLfloat left = (GLfloat)targetRc.left;
|
||||
|
||||
GLfloat tex1[] = { // For TEXTURE0
|
||||
targetRc.left, targetRc.bottom,
|
||||
targetRc.left, targetRc.top,
|
||||
targetRc.right, targetRc.top,
|
||||
targetRc.right, targetRc.bottom
|
||||
left, bottom,
|
||||
left, top,
|
||||
right, top,
|
||||
right, bottom
|
||||
};
|
||||
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
@ -1187,26 +1178,26 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
if (g_ActiveConfig.bDumpFrames)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
|
||||
if (!data || w != dst_rect.GetWidth() ||
|
||||
if (!frame_data || w != dst_rect.GetWidth() ||
|
||||
h != dst_rect.GetHeight())
|
||||
{
|
||||
if (data) delete[] data;
|
||||
if (frame_data) delete[] frame_data;
|
||||
w = dst_rect.GetWidth();
|
||||
h = dst_rect.GetHeight();
|
||||
data = new u8[3 * w * h];
|
||||
frame_data = new char[3 * w * h];
|
||||
}
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data);
|
||||
glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, frame_data);
|
||||
if (GL_REPORT_ERROR() == GL_NO_ERROR && w > 0 && h > 0)
|
||||
{
|
||||
if (!s_bLastFrameDumped)
|
||||
if (!bLastFrameDumped)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
s_bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), w, h);
|
||||
bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), w, h);
|
||||
#else
|
||||
s_bAVIDumping = AVIDump::Start(w, h);
|
||||
bAVIDumping = AVIDump::Start(w, h);
|
||||
#endif
|
||||
if (!s_bAVIDumping)
|
||||
if (!bAVIDumping)
|
||||
OSD::AddMessage("AVIDump Start failed", 2000);
|
||||
else
|
||||
{
|
||||
@ -1215,36 +1206,36 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), w, h).c_str(), 2000);
|
||||
}
|
||||
}
|
||||
if (s_bAVIDumping)
|
||||
if (bAVIDumping)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
AVIDump::AddFrame((char *) data);
|
||||
AVIDump::AddFrame(frame_data);
|
||||
#else
|
||||
FlipImageData(data, w, h);
|
||||
AVIDump::AddFrame(data, w, h);
|
||||
FlipImageData((u8*)frame_data, w, h);
|
||||
AVIDump::AddFrame((u8*)frame_data, w, h);
|
||||
#endif
|
||||
}
|
||||
|
||||
s_bLastFrameDumped = true;
|
||||
bLastFrameDumped = true;
|
||||
}
|
||||
else
|
||||
NOTICE_LOG(VIDEO, "Error reading framebuffer");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_bLastFrameDumped && s_bAVIDumping)
|
||||
if (bLastFrameDumped && bAVIDumping)
|
||||
{
|
||||
if (data)
|
||||
if (frame_data)
|
||||
{
|
||||
delete[] data;
|
||||
data = NULL;
|
||||
delete[] frame_data;
|
||||
frame_data = NULL;
|
||||
w = h = 0;
|
||||
}
|
||||
AVIDump::Stop();
|
||||
s_bAVIDumping = false;
|
||||
bAVIDumping = false;
|
||||
OSD::AddMessage("Stop dumping frames", 2000);
|
||||
}
|
||||
s_bLastFrameDumped = false;
|
||||
bLastFrameDumped = false;
|
||||
}
|
||||
#else
|
||||
if (g_ActiveConfig.bDumpFrames)
|
||||
@ -1253,16 +1244,16 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
std::string movie_file_name;
|
||||
w = dst_rect.GetWidth();
|
||||
h = dst_rect.GetHeight();
|
||||
data = new u8[3 * w * h];
|
||||
frame_data = new char[3 * w * h];
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data);
|
||||
glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, frame_data);
|
||||
if (GL_REPORT_ERROR() == GL_NO_ERROR)
|
||||
{
|
||||
if (!s_bLastFrameDumped)
|
||||
if (!bLastFrameDumped)
|
||||
{
|
||||
movie_file_name = File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump.raw";
|
||||
f_pFrameDump.Open(movie_file_name, "wb");
|
||||
if (!f_pFrameDump)
|
||||
pFrameDump.Open(movie_file_name, "wb");
|
||||
if (!pFrameDump)
|
||||
OSD::AddMessage("Error opening framedump.raw for writing.", 2000);
|
||||
else
|
||||
{
|
||||
@ -1271,22 +1262,22 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
OSD::AddMessage(msg, 2000);
|
||||
}
|
||||
}
|
||||
if (f_pFrameDump)
|
||||
if (pFrameDump)
|
||||
{
|
||||
FlipImageData(data, w, h);
|
||||
f_pFrameDump.WriteBytes(data, w * 3 * h);
|
||||
f_pFrameDump.Flush();
|
||||
FlipImageData((u8*)frame_data, w, h);
|
||||
pFrameDump.WriteBytes(frame_data, w * 3 * h);
|
||||
pFrameDump.Flush();
|
||||
}
|
||||
s_bLastFrameDumped = true;
|
||||
bLastFrameDumped = true;
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
delete[] frame_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_bLastFrameDumped)
|
||||
f_pFrameDump.Close();
|
||||
s_bLastFrameDumped = false;
|
||||
if (bLastFrameDumped)
|
||||
pFrameDump.Close();
|
||||
bLastFrameDumped = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1339,20 +1330,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
}
|
||||
}
|
||||
|
||||
// Place messages on the picture, then copy it to the screen
|
||||
// ---------------------------------------------------------------------
|
||||
// Count FPS.
|
||||
// -------------
|
||||
static int fpscount = 0;
|
||||
static unsigned long lasttime = 0;
|
||||
if (Common::Timer::GetTimeMs() - lasttime >= 1000)
|
||||
{
|
||||
lasttime = Common::Timer::GetTimeMs();
|
||||
s_fps = fpscount;
|
||||
fpscount = 0;
|
||||
}
|
||||
if (XFBWrited)
|
||||
++fpscount;
|
||||
s_fps = UpdateFPSCounter();
|
||||
// ---------------------------------------------------------------------
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
@ -1406,15 +1385,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
GL_REPORT_ERRORD();
|
||||
g_Config.iSaveTargetId = 0;
|
||||
|
||||
// reload textures if these settings changed
|
||||
if (g_Config.bSafeTextureCache != g_ActiveConfig.bSafeTextureCache ||
|
||||
g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
|
||||
TextureCache::Invalidate(false);
|
||||
|
||||
if (g_Config.bCopyEFBToTexture != g_ActiveConfig.bCopyEFBToTexture)
|
||||
TextureCache::ClearRenderTargets();
|
||||
|
||||
UpdateActiveConfig();
|
||||
TextureCache::OnConfigChanged(g_ActiveConfig);
|
||||
|
||||
// For testing zbuffer targets.
|
||||
// Renderer::SetZBufferRender();
|
||||
@ -1422,6 +1394,9 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
// GetTargetWidth(), GetTargetHeight());
|
||||
Core::Callback_VideoCopiedToXFB(XFBWrited || (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB));
|
||||
XFBWrited = false;
|
||||
|
||||
// Invalidate EFB cache
|
||||
ClearEFBCache();
|
||||
}
|
||||
|
||||
// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
|
||||
@ -1437,9 +1412,6 @@ void Renderer::ResetAPIState()
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_FALSE);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
|
||||
// make sure to disable wireframe when drawing the clear quad
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
||||
void Renderer::RestoreAPIState()
|
||||
@ -1447,14 +1419,13 @@ void Renderer::RestoreAPIState()
|
||||
// Gets us back into a more game-like state.
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
SetGenerationMode();
|
||||
SetScissorRect();
|
||||
BPFunctions::SetScissor();
|
||||
SetColorMask();
|
||||
SetDepthMode();
|
||||
SetBlendMode(true);
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
|
||||
if (g_ActiveConfig.bWireFrame)
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, g_ActiveConfig.bWireFrame ? GL_LINE : GL_FILL);
|
||||
|
||||
VertexShaderCache::SetCurrentShader(0);
|
||||
PixelShaderCache::SetCurrentShader(0);
|
||||
|
@ -7,6 +7,8 @@
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
void ClearEFBCache();
|
||||
|
||||
class Renderer : public ::Renderer
|
||||
{
|
||||
public:
|
||||
@ -15,7 +17,7 @@ public:
|
||||
|
||||
void SetColorMask();
|
||||
void SetBlendMode(bool forceUpdate);
|
||||
bool SetScissorRect();
|
||||
void SetScissorRect(const TargetRectangle& rc);
|
||||
void SetGenerationMode();
|
||||
void SetDepthMode();
|
||||
void SetLogicOpMode();
|
||||
@ -57,6 +59,9 @@ public:
|
||||
void SetVSConstant4fv(unsigned int const_number, const float *f);
|
||||
void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f);
|
||||
void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
|
||||
|
||||
private:
|
||||
void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const u32* data);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "Globals.h"
|
||||
#include "Hash.h"
|
||||
#include "HiresTextures.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "PixelShaderCache.h"
|
||||
@ -75,11 +76,13 @@ static const GLint c_WrapSettings[4] = {
|
||||
GL_REPEAT,
|
||||
};
|
||||
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height)
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level)
|
||||
{
|
||||
int width = std::max(virtual_width >> level, 1);
|
||||
int height = std::max(virtual_height >> level, 1);
|
||||
std::vector<u32> data(width * height);
|
||||
glBindTexture(textarget, tex);
|
||||
glGetTexImage(textarget, 0, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
|
||||
glGetTexImage(textarget, level, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
|
||||
|
||||
const GLenum err = GL_REPORT_ERROR();
|
||||
if (GL_NO_ERROR != err)
|
||||
@ -118,13 +121,13 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
||||
SetTextureParameters(tm0, tm1);
|
||||
}
|
||||
|
||||
bool TextureCache::TCacheEntry::Save(const char filename[])
|
||||
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
||||
{
|
||||
// TODO: make ogl dump PNGs
|
||||
std::string tga_filename(filename);
|
||||
tga_filename.replace(tga_filename.size() - 3, 3, "tga");
|
||||
|
||||
return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, realW, realH);
|
||||
return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, level);
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
|
||||
@ -278,7 +281,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
if (false == isDynamic || g_ActiveConfig.bCopyEFBToTexture)
|
||||
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
if (s_TempFramebuffer == 0)
|
||||
glGenFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
|
||||
@ -294,7 +297,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, read_texture);
|
||||
|
||||
glViewport(0, 0, virtualW, virtualH);
|
||||
glViewport(0, 0, virtual_width, virtual_height);
|
||||
|
||||
PixelShaderCache::SetCurrentShader((srcFormat == PIXELFMT_Z24) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram());
|
||||
PixelShaderManager::SetColorMatrix(colmat); // set transformation
|
||||
@ -329,7 +332,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
|
||||
if (false == g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
hash = TextureConverter::EncodeToRamFromTexture(
|
||||
int encoded_size = TextureConverter::EncodeToRamFromTexture(
|
||||
addr,
|
||||
read_texture,
|
||||
srcFormat == PIXELFMT_Z24,
|
||||
@ -337,6 +340,17 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
dstFormat,
|
||||
scaleByHalf,
|
||||
srcRect);
|
||||
|
||||
u8* dst = Memory::GetPointer(addr);
|
||||
u64 hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
|
||||
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
|
||||
if (!g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
else if (!TextureCache::Find(addr, hash))
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
|
||||
this->hash = hash;
|
||||
}
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
@ -349,7 +363,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
{
|
||||
static int count = 0;
|
||||
SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
count++).c_str(), GL_TEXTURE_2D, texture, realW, realH);
|
||||
count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ private:
|
||||
const float *colmat);
|
||||
|
||||
void Bind(unsigned int stage);
|
||||
bool Save(const char filename[]);
|
||||
bool Save(const char filename[], unsigned int level);
|
||||
|
||||
private:
|
||||
void SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1);
|
||||
@ -76,7 +76,7 @@ private:
|
||||
TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h);
|
||||
};
|
||||
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height);
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level);
|
||||
|
||||
}
|
||||
|
||||
|
@ -261,78 +261,7 @@ void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const Tar
|
||||
|
||||
}
|
||||
|
||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
{
|
||||
u32 format = copyfmt;
|
||||
|
||||
if (bFromZBuffer)
|
||||
{
|
||||
format |= _GX_TF_ZTF;
|
||||
if (copyfmt == 11)
|
||||
format = GX_TF_Z16;
|
||||
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
|
||||
format |= _GX_TF_CTF;
|
||||
}
|
||||
else
|
||||
if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt))
|
||||
format |= _GX_TF_CTF;
|
||||
|
||||
FRAGMENTSHADER& texconv_shader = GetOrCreateEncodingShader(format);
|
||||
if (texconv_shader.glprogid == 0)
|
||||
return;
|
||||
|
||||
u8 *dest_ptr = Memory::GetPointer(address);
|
||||
|
||||
GLuint source_texture = bFromZBuffer ? FramebufferManager::ResolveAndGetDepthTarget(source) : FramebufferManager::ResolveAndGetRenderTarget(source);
|
||||
|
||||
int width = (source.right - source.left) >> bScaleByHalf;
|
||||
int height = (source.bottom - source.top) >> bScaleByHalf;
|
||||
|
||||
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
|
||||
|
||||
// Invalidate any existing texture covering this memory range.
|
||||
// TODO - don't delete the texture if it already exists, just replace the contents.
|
||||
TextureCache::InvalidateRange(address, size_in_bytes);
|
||||
|
||||
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
|
||||
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
|
||||
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
|
||||
|
||||
// only copy on cache line boundaries
|
||||
// extra pixels are copied but not displayed in the resulting texture
|
||||
s32 expandedWidth = (width + blkW) & (~blkW);
|
||||
s32 expandedHeight = (height + blkH) & (~blkH);
|
||||
|
||||
float sampleStride = bScaleByHalf ? 2.f : 1.f;
|
||||
TextureConversionShader::SetShaderParameters(
|
||||
(float)expandedWidth,
|
||||
(float)Renderer::EFBToScaledY(expandedHeight), // TODO: Why do we scale this?
|
||||
(float)Renderer::EFBToScaledX(source.left),
|
||||
(float)Renderer::EFBToScaledY(EFB_HEIGHT - source.top - expandedHeight),
|
||||
Renderer::EFBToScaledXf(sampleStride),
|
||||
Renderer::EFBToScaledYf(sampleStride));
|
||||
|
||||
TargetRectangle scaledSource;
|
||||
scaledSource.top = 0;
|
||||
scaledSource.bottom = expandedHeight;
|
||||
scaledSource.left = 0;
|
||||
scaledSource.right = expandedWidth / samples;
|
||||
int cacheBytes = 32;
|
||||
if ((format & 0x0f) == 6)
|
||||
cacheBytes = 64;
|
||||
|
||||
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
|
||||
g_renderer->ResetAPIState();
|
||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
TextureCache::DisableStage(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
u64 EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
{
|
||||
u32 format = copyfmt;
|
||||
|
||||
@ -390,19 +319,8 @@ u64 EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
|
||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource,
|
||||
dest_ptr, expandedWidth / samples, expandedHeight, readStride,
|
||||
true, bScaleByHalf > 0 && !bFromZBuffer);
|
||||
return size_in_bytes; // TODO: D3D11 is calculating this value differently!
|
||||
|
||||
u64 hash = GetHash64(dest_ptr, size_in_bytes,
|
||||
g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
if (g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
{
|
||||
// If the texture in RAM is already in the texture cache,
|
||||
// do not copy it again as it has not changed.
|
||||
if (TextureCache::Find(address, hash))
|
||||
return hash;
|
||||
}
|
||||
|
||||
TextureCache::MakeRangeDynamic(address,size_in_bytes);
|
||||
return hash;
|
||||
}
|
||||
|
||||
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight)
|
||||
|
@ -32,15 +32,13 @@ namespace TextureConverter
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
|
||||
u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
||||
|
||||
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc,
|
||||
u8* destAddr, int dstWidth, int dstHeight);
|
||||
|
||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);
|
||||
|
||||
u64 EncodeToRamFromTexture(u32 address, GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
||||
// returns size of the encoded data (in bytes)
|
||||
int EncodeToRamFromTexture(u32 address, GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
||||
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,16 @@ VertexManager::VertexManager()
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void VertexManager::CreateDeviceObjects()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
void VertexManager::DestroyDeviceObjects()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VertexManager::Draw()
|
||||
{
|
||||
if (IndexGenerator::GetNumTriangles() > 0)
|
||||
@ -154,22 +164,14 @@ void VertexManager::vFlush()
|
||||
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
|
||||
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
||||
tex.texTlut[i&3].tlut_format,
|
||||
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips,
|
||||
(tex.texMode1[i&3].max_lod >> 4));
|
||||
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8),
|
||||
tex.texMode1[i&3].max_lod >> 4,
|
||||
tex.texImage1[i&3].image_type);
|
||||
|
||||
if (tentry)
|
||||
{
|
||||
// 0s are probably for no manual wrapping needed.
|
||||
PixelShaderManager::SetTexDims(i, tentry->realW, tentry->realH, 0, 0);
|
||||
|
||||
if (g_ActiveConfig.iLog & CONF_SAVETEXTURES)
|
||||
{
|
||||
// save the textures
|
||||
char strfile[255];
|
||||
sprintf(strfile, "%stex%.3d_%d.tga",
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_Config.iSaveTargetId, i);
|
||||
tentry->Save(strfile);
|
||||
}
|
||||
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "error loading texture");
|
||||
@ -268,6 +270,8 @@ void VertexManager::vFlush()
|
||||
#endif
|
||||
g_Config.iSaveTargetId++;
|
||||
|
||||
ClearEFBCache();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,8 @@ public:
|
||||
VertexManager();
|
||||
|
||||
NativeVertexFormat* CreateNativeVertexFormat();
|
||||
|
||||
void CreateDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
private:
|
||||
void Draw();
|
||||
// temp
|
||||
|
@ -41,7 +41,9 @@ VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
||||
GLuint VertexShaderCache::CurrentShader;
|
||||
bool VertexShaderCache::ShaderEnabled;
|
||||
|
||||
static VERTEXSHADER *pShaderLast = NULL;
|
||||
VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry = NULL;
|
||||
VERTEXSHADERUID VertexShaderCache::last_uid;
|
||||
|
||||
static int s_nMaxVertexInstructions;
|
||||
|
||||
|
||||
@ -50,7 +52,7 @@ void VertexShaderCache::Init()
|
||||
glEnable(GL_VERTEX_PROGRAM_ARB);
|
||||
ShaderEnabled = true;
|
||||
CurrentShader = 0;
|
||||
memset(&last_vertex_shader_uid, 0xFF, sizeof(last_vertex_shader_uid));
|
||||
last_entry = NULL;
|
||||
|
||||
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);
|
||||
if (strstr((const char*)glGetString(GL_VENDOR), "Humper") != NULL) s_nMaxVertexInstructions = 4096;
|
||||
@ -74,31 +76,34 @@ VERTEXSHADER* VertexShaderCache::SetShader(u32 components)
|
||||
{
|
||||
VERTEXSHADERUID uid;
|
||||
GetVertexShaderId(&uid, components);
|
||||
if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount)
|
||||
if (last_entry)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return pShaderLast;
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
ValidateVertexShaderIDs(API_OPENGL, vshaders[uid].safe_uid, vshaders[uid].shader.strprog, components);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
}
|
||||
memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID));
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
VSCache::iterator iter = vshaders.find(uid);
|
||||
if (iter != vshaders.end())
|
||||
{
|
||||
iter->second.frameCount = frameCount;
|
||||
VSCacheEntry &entry = iter->second;
|
||||
if (&entry.shader != pShaderLast) {
|
||||
pShaderLast = &entry.shader;
|
||||
}
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return pShaderLast;
|
||||
ValidateVertexShaderIDs(API_OPENGL, entry.safe_uid, entry.shader.strprog, components);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
// Make an entry in the table
|
||||
VSCacheEntry& entry = vshaders[uid];
|
||||
entry.frameCount = frameCount;
|
||||
pShaderLast = &entry.shader;
|
||||
last_entry = &entry;
|
||||
const char *code = GenerateVertexShaderCode(components, API_OPENGL);
|
||||
GetSafeVertexShaderId(&entry.safe_uid, components);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) {
|
||||
@ -118,7 +123,7 @@ VERTEXSHADER* VertexShaderCache::SetShader(u32 components)
|
||||
INCSTAT(stats.numVertexShadersCreated);
|
||||
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return pShaderLast;
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram)
|
||||
@ -182,9 +187,8 @@ bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrpr
|
||||
cgDestroyProgram(tempprog);
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
vs.strprog = pstrprogram;
|
||||
#endif
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
vs.strprog = pstrprogram;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -32,9 +32,7 @@ struct VERTEXSHADER
|
||||
VERTEXSHADER() : glprogid(0) {}
|
||||
GLuint glprogid; // opengl program id
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
std::string strprog;
|
||||
#endif
|
||||
};
|
||||
|
||||
class VertexShaderCache
|
||||
@ -42,8 +40,8 @@ class VertexShaderCache
|
||||
struct VSCacheEntry
|
||||
{
|
||||
VERTEXSHADER shader;
|
||||
int frameCount;
|
||||
VSCacheEntry() : frameCount(0) {}
|
||||
VERTEXSHADERUIDSAFE safe_uid;
|
||||
VSCacheEntry() {}
|
||||
void Destroy() {
|
||||
// printf("Destroying vs %i\n", shader.glprogid);
|
||||
glDeleteProgramsARB(1, &shader.glprogid);
|
||||
@ -55,6 +53,9 @@ class VertexShaderCache
|
||||
|
||||
static VSCache vshaders;
|
||||
|
||||
static VSCacheEntry* last_entry;
|
||||
static VERTEXSHADERUID last_uid;
|
||||
|
||||
static GLuint CurrentShader;
|
||||
static bool ShaderEnabled;
|
||||
|
||||
|
@ -155,6 +155,7 @@ void VideoBackend::ShowConfig(void *_hParent)
|
||||
|
||||
bool VideoBackend::Initialize(void *&window_handle)
|
||||
{
|
||||
InitializeShared();
|
||||
InitBackendInfo();
|
||||
|
||||
frameCount = 0;
|
||||
@ -234,6 +235,7 @@ void VideoBackend::Shutdown()
|
||||
OpcodeDecoder_Shutdown();
|
||||
delete g_renderer;
|
||||
g_renderer = NULL;
|
||||
g_texture_cache = NULL;
|
||||
}
|
||||
OpenGL_Shutdown();
|
||||
}
|
||||
|
Reference in New Issue
Block a user