mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-09-10 23:02:59 +02:00
At higher resolutions it takes too much time to save a screenshot at the maximum compression level. So let's allow the user to set the compression level. This re-uses the png_compression_level setting. The default compression level is 1 for speed, but if the user wishes to increase the compression level (without using an external tool) and doesn't mind if the screenshot takes more time to save then they can increase the compression level up to a maximum of 9 (which can take quite a while). Fixes #1527.
680 lines
16 KiB
C++
680 lines
16 KiB
C++
/*
|
|
* Copyright (C) 2007-2009 Gabest
|
|
* http://www.gabest.org
|
|
*
|
|
* This Program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This Program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GNU Make; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "GSRenderer.h"
|
|
#if defined(__unix__)
|
|
#include <X11/keysym.h>
|
|
#endif
|
|
|
|
const unsigned int s_interlace_nb = 8;
|
|
const unsigned int s_post_shader_nb = 5;
|
|
const unsigned int s_aspect_ratio_nb = 3;
|
|
|
|
GSRenderer::GSRenderer()
|
|
: m_shader(0)
|
|
, m_shift_key(false)
|
|
, m_control_key(false)
|
|
, m_framelimit(false)
|
|
, m_texture_shuffle(false)
|
|
, m_real_size(0,0)
|
|
, m_wnd(NULL)
|
|
, m_dev(NULL)
|
|
{
|
|
m_GStitleInfoBuffer[0] = 0;
|
|
|
|
m_interlace = theApp.GetConfigI("interlace") % s_interlace_nb;
|
|
m_aspectratio = theApp.GetConfigI("AspectRatio") % s_aspect_ratio_nb;
|
|
m_shader = theApp.GetConfigI("TVShader") % s_post_shader_nb;
|
|
m_filter = theApp.GetConfigI("filter");
|
|
m_vsync = theApp.GetConfigB("vsync");
|
|
m_aa1 = theApp.GetConfigB("aa1");
|
|
m_fxaa = theApp.GetConfigB("fxaa");
|
|
m_shaderfx = theApp.GetConfigB("shaderfx");
|
|
m_shadeboost = theApp.GetConfigB("ShadeBoost");
|
|
}
|
|
|
|
GSRenderer::~GSRenderer()
|
|
{
|
|
/*if(m_dev)
|
|
{
|
|
m_dev->Reset(1, 1, GSDevice::Windowed);
|
|
}*/
|
|
|
|
delete m_dev;
|
|
|
|
if(m_wnd)
|
|
{
|
|
delete m_wnd;
|
|
}
|
|
}
|
|
|
|
bool GSRenderer::CreateWnd(const string& title, int w, int h)
|
|
{
|
|
return m_wnd->Create(title.c_str(), w, h);
|
|
}
|
|
|
|
bool GSRenderer::CreateDevice(GSDevice* dev)
|
|
{
|
|
ASSERT(dev);
|
|
ASSERT(!m_dev);
|
|
|
|
if(!dev->Create(m_wnd))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_dev = dev;
|
|
m_dev->SetVSync(m_vsync && m_framelimit);
|
|
|
|
return true;
|
|
}
|
|
|
|
void GSRenderer::ResetDevice()
|
|
{
|
|
if(m_dev) m_dev->Reset(1, 1);
|
|
}
|
|
|
|
bool GSRenderer::Merge(int field)
|
|
{
|
|
bool en[2];
|
|
|
|
GSVector4i fr[2];
|
|
GSVector4i dr[2];
|
|
|
|
GSVector2i display_baseline = { INT_MAX, INT_MAX };
|
|
GSVector2i frame_baseline = { INT_MAX, INT_MAX };
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
{
|
|
en[i] = IsEnabled(i);
|
|
|
|
if(en[i])
|
|
{
|
|
fr[i] = GetFrameRect(i);
|
|
dr[i] = GetDisplayRect(i);
|
|
|
|
display_baseline.x = min(dr[i].left, display_baseline.x);
|
|
display_baseline.y = min(dr[i].top, display_baseline.y);
|
|
frame_baseline.x = min(fr[i].left, frame_baseline.x);
|
|
frame_baseline.y = min(fr[i].top, frame_baseline.y);
|
|
|
|
//printf("[%d]: %d %d %d %d, %d %d %d %d\n", i, fr[i].x,fr[i].y,fr[i].z,fr[i].w , dr[i].x,dr[i].y,dr[i].z,dr[i].w);
|
|
}
|
|
}
|
|
|
|
if(!en[0] && !en[1])
|
|
{
|
|
return false;
|
|
}
|
|
|
|
GL_PUSH("Renderer Merge %d", s_n);
|
|
|
|
// try to avoid fullscreen blur, could be nice on tv but on a monitor it's like double vision, hurts my eyes (persona 4, guitar hero)
|
|
//
|
|
// NOTE: probably the technique explained in graphtip.pdf (Antialiasing by Supersampling / 4. Reading Odd/Even Scan Lines Separately with the PCRTC then Blending)
|
|
|
|
bool samesrc =
|
|
en[0] && en[1] &&
|
|
m_regs->DISP[0].DISPFB.FBP == m_regs->DISP[1].DISPFB.FBP &&
|
|
m_regs->DISP[0].DISPFB.FBW == m_regs->DISP[1].DISPFB.FBW &&
|
|
m_regs->DISP[0].DISPFB.PSM == m_regs->DISP[1].DISPFB.PSM;
|
|
|
|
// bool blurdetected = false;
|
|
|
|
if(samesrc /*&& m_regs->PMODE.SLBG == 0 && m_regs->PMODE.MMOD == 1 && m_regs->PMODE.ALP == 0x80*/)
|
|
{
|
|
if(fr[0].eq(fr[1] + GSVector4i(0, -1, 0, 0)) && dr[0].eq(dr[1] + GSVector4i(0, 0, 0, 1))
|
|
|| fr[1].eq(fr[0] + GSVector4i(0, -1, 0, 0)) && dr[1].eq(dr[0] + GSVector4i(0, 0, 0, 1)))
|
|
{
|
|
// persona 4:
|
|
//
|
|
// fr[0] = 0 0 640 448
|
|
// fr[1] = 0 1 640 448
|
|
// dr[0] = 159 50 779 498
|
|
// dr[1] = 159 50 779 497
|
|
//
|
|
// second image shifted up by 1 pixel and blended over itself
|
|
//
|
|
// god of war:
|
|
//
|
|
// fr[0] = 0 1 512 448
|
|
// fr[1] = 0 0 512 448
|
|
// dr[0] = 127 50 639 497
|
|
// dr[1] = 127 50 639 498
|
|
//
|
|
// same just the first image shifted
|
|
|
|
int top = min(fr[0].top, fr[1].top);
|
|
int bottom = max(dr[0].bottom, dr[1].bottom);
|
|
|
|
fr[0].top = top;
|
|
fr[1].top = top;
|
|
dr[0].bottom = bottom;
|
|
dr[1].bottom = bottom;
|
|
|
|
// blurdetected = true;
|
|
}
|
|
else if(dr[0].eq(dr[1]) && (fr[0].eq(fr[1] + GSVector4i(0, 1, 0, 1)) || fr[1].eq(fr[0] + GSVector4i(0, 1, 0, 1))))
|
|
{
|
|
// dq5:
|
|
//
|
|
// fr[0] = 0 1 512 445
|
|
// fr[1] = 0 0 512 444
|
|
// dr[0] = 127 50 639 494
|
|
// dr[1] = 127 50 639 494
|
|
|
|
int top = min(fr[0].top, fr[1].top);
|
|
int bottom = min(fr[0].bottom, fr[1].bottom);
|
|
|
|
fr[0].top = fr[1].top = top;
|
|
fr[0].bottom = fr[1].bottom = bottom;
|
|
|
|
// blurdetected = true;
|
|
}
|
|
//printf("samesrc = %d blurdetected = %d\n",samesrc,blurdetected);
|
|
}
|
|
|
|
GSVector2i fs(0, 0);
|
|
GSVector2i ds(0, 0);
|
|
|
|
GSTexture* tex[2] = {NULL, NULL};
|
|
int y_offset[2] = {0, 0};
|
|
|
|
if(samesrc && fr[0].bottom == fr[1].bottom)
|
|
{
|
|
tex[0] = GetOutput(0, y_offset[0]);
|
|
tex[1] = tex[0]; // saves one texture fetch
|
|
y_offset[1] = y_offset[0];
|
|
}
|
|
else
|
|
{
|
|
if(en[0]) tex[0] = GetOutput(0, y_offset[0]);
|
|
if(en[1]) tex[1] = GetOutput(1, y_offset[1]);
|
|
}
|
|
|
|
GSVector4 src[2];
|
|
GSVector4 src_hw[2];
|
|
GSVector4 dst[2];
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
{
|
|
if(!en[i] || !tex[i]) continue;
|
|
|
|
GSVector4i r = fr[i];
|
|
GSVector4 scale = GSVector4(tex[i]->GetScale()).xyxy();
|
|
|
|
src[i] = GSVector4(r) * scale / GSVector4(tex[i]->GetSize()).xyxy();
|
|
src_hw[i] = (GSVector4(r) + GSVector4 (0, y_offset[i], 0, y_offset[i])) * scale / GSVector4(tex[i]->GetSize()).xyxy();
|
|
|
|
GSVector2 off(0, 0);
|
|
GSVector2i display_diff(dr[i].left - display_baseline.x, dr[i].top - display_baseline.y);
|
|
GSVector2i frame_diff(fr[i].left - frame_baseline.x, fr[i].top - frame_baseline.y);
|
|
|
|
// Time Crisis 2/3 uses two side by side images when in split screen mode.
|
|
// Though ignore cases where baseline and display rectangle offsets only differ by 1 pixel, causes blurring and wrong resolution output on FFXII
|
|
if(display_diff.x > 2)
|
|
{
|
|
off.x = tex[i]->GetScale().x * display_diff.x;
|
|
}
|
|
// If the DX offset is too small then consider the status of frame memory offsets, prevents blurring on Tenchu: Fatal Shadows, Worms 3D
|
|
else if(display_diff.x || frame_diff.x)
|
|
{
|
|
off.x = tex[i]->GetScale().x * frame_diff.x;
|
|
}
|
|
|
|
if(display_diff.y >= 4) // Shouldn't this be 2?
|
|
{
|
|
off.y = tex[i]->GetScale().y * display_diff.y;
|
|
|
|
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
|
|
{
|
|
off.y /= 2;
|
|
}
|
|
}
|
|
else if(display_diff.y || frame_diff.y)
|
|
{
|
|
off.y = tex[i]->GetScale().y * frame_diff.y;
|
|
}
|
|
|
|
dst[i] = GSVector4(off).xyxy() + scale * GSVector4(r.rsize());
|
|
|
|
fs.x = max(fs.x, (int)(dst[i].z + 0.5f));
|
|
fs.y = max(fs.y, (int)(dst[i].w + 0.5f));
|
|
}
|
|
|
|
ds = fs;
|
|
|
|
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
|
|
{
|
|
ds.y *= 2;
|
|
}
|
|
m_real_size = ds;
|
|
|
|
bool slbg = m_regs->PMODE.SLBG;
|
|
bool mmod = m_regs->PMODE.MMOD;
|
|
|
|
if(tex[0] || tex[1])
|
|
{
|
|
if(tex[0] == tex[1] && !slbg && (src[0] == src[1] & dst[0] == dst[1]).alltrue())
|
|
{
|
|
// the two outputs are identical, skip drawing one of them (the one that is alpha blended)
|
|
|
|
tex[0] = NULL;
|
|
}
|
|
|
|
GSVector4 c = GSVector4((int)m_regs->BGCOLOR.R, (int)m_regs->BGCOLOR.G, (int)m_regs->BGCOLOR.B, (int)m_regs->PMODE.ALP) / 255;
|
|
|
|
m_dev->Merge(tex, src_hw, dst, fs, slbg, mmod, c);
|
|
|
|
if(m_regs->SMODE2.INT && m_interlace > 0)
|
|
{
|
|
if(m_interlace == 7 && m_regs->SMODE2.FFMD) // Auto interlace enabled / Odd frame interlace setting
|
|
{
|
|
int field2 = 0;
|
|
int mode = 2;
|
|
m_dev->Interlace(ds, field ^ field2, mode, tex[1] ? tex[1]->GetScale().y : tex[0]->GetScale().y);
|
|
}
|
|
else
|
|
{
|
|
int field2 = 1 - ((m_interlace - 1) & 1);
|
|
int mode = (m_interlace - 1) >> 1;
|
|
m_dev->Interlace(ds, field ^ field2, mode, tex[1] ? tex[1]->GetScale().y : tex[0]->GetScale().y);
|
|
}
|
|
}
|
|
|
|
if(m_shadeboost)
|
|
{
|
|
m_dev->ShadeBoost();
|
|
}
|
|
|
|
if(m_shaderfx)
|
|
{
|
|
m_dev->ExternalFX();
|
|
}
|
|
|
|
if(m_fxaa)
|
|
{
|
|
m_dev->FXAA();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
GSVector2i GSRenderer::GetInternalResolution()
|
|
{
|
|
return m_real_size;
|
|
}
|
|
|
|
void GSRenderer::SetFrameLimit(bool limit)
|
|
{
|
|
m_framelimit = limit;
|
|
|
|
if(m_dev) m_dev->SetVSync(m_vsync && m_framelimit);
|
|
}
|
|
|
|
void GSRenderer::SetVSync(bool enabled)
|
|
{
|
|
m_vsync = enabled;
|
|
|
|
if(m_dev) m_dev->SetVSync(m_vsync);
|
|
}
|
|
|
|
void GSRenderer::VSync(int field)
|
|
{
|
|
GSPerfMonAutoTimer pmat(&m_perfmon);
|
|
|
|
m_perfmon.Put(GSPerfMon::Frame);
|
|
|
|
Flush();
|
|
|
|
if(!m_dev->IsLost(true))
|
|
{
|
|
if(!Merge(field ? 1 : 0))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ResetDevice();
|
|
}
|
|
|
|
m_dev->AgePool();
|
|
|
|
// osd
|
|
|
|
if((m_perfmon.GetFrame() & 0x1f) == 0)
|
|
{
|
|
m_perfmon.Update();
|
|
|
|
double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame);
|
|
|
|
string s;
|
|
|
|
#ifdef GSTITLEINFO_API_FORCE_VERBOSE
|
|
if(1)//force verbose reply
|
|
#else
|
|
if(m_wnd->IsManaged())
|
|
#endif
|
|
{
|
|
//GSdx owns the window's title, be verbose.
|
|
|
|
string s2 = m_regs->SMODE2.INT ? (string("Interlaced ") + (m_regs->SMODE2.FFMD ? "(frame)" : "(field)")) : "Progressive";
|
|
|
|
s = format(
|
|
"%lld | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d S/%d P/%d D | %d%% CPU | %.2f | %.2f",
|
|
m_perfmon.GetFrame(), GetInternalResolution().x, GetInternalResolution().y, fps, (int)(100.0 * fps / GetTvRefreshRate()),
|
|
s2.c_str(),
|
|
theApp.m_gs_interlace[m_interlace].name.c_str(),
|
|
theApp.m_gs_aspectratio[m_aspectratio].name.c_str(),
|
|
(int)m_perfmon.Get(GSPerfMon::SyncPoint),
|
|
(int)m_perfmon.Get(GSPerfMon::Prim),
|
|
(int)m_perfmon.Get(GSPerfMon::Draw),
|
|
m_perfmon.CPU(),
|
|
m_perfmon.Get(GSPerfMon::Swizzle) / 1024,
|
|
m_perfmon.Get(GSPerfMon::Unswizzle) / 1024
|
|
);
|
|
|
|
double fillrate = m_perfmon.Get(GSPerfMon::Fillrate);
|
|
|
|
if(fillrate > 0)
|
|
{
|
|
s += format(" | %.2f mpps", fps * fillrate / (1024 * 1024));
|
|
|
|
int sum = 0;
|
|
|
|
for(int i = 0; i < 16; i++)
|
|
{
|
|
sum += m_perfmon.CPU(GSPerfMon::WorkerDraw0 + i);
|
|
}
|
|
|
|
s += format(" | %d%% CPU", sum);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Satisfy PCSX2's request for title info: minimal verbosity due to more external title text
|
|
|
|
s = format("%dx%d | %s", GetInternalResolution().x, GetInternalResolution().y, theApp.m_gs_interlace[m_interlace].name.c_str());
|
|
}
|
|
|
|
if(m_capture.IsCapturing())
|
|
{
|
|
s += " | Recording...";
|
|
}
|
|
|
|
if(m_wnd->IsManaged())
|
|
{
|
|
m_wnd->SetWindowText(s.c_str());
|
|
}
|
|
else
|
|
{
|
|
// note: do not use TryEnterCriticalSection. It is unnecessary code complication in
|
|
// an area that absolutely does not matter (even if it were 100 times slower, it wouldn't
|
|
// be noticeable). Besides, these locks are extremely short -- overhead of conditional
|
|
// is way more expensive than just waiting for the CriticalSection in 1 of 10,000,000 tries. --air
|
|
|
|
std::lock_guard<std::mutex> lock(m_pGSsetTitle_Crit);
|
|
|
|
strncpy(m_GStitleInfoBuffer, s.c_str(), countof(m_GStitleInfoBuffer) - 1);
|
|
|
|
m_GStitleInfoBuffer[sizeof(m_GStitleInfoBuffer) - 1] = 0; // make sure null terminated even if text overflows
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// [TODO]
|
|
// We don't have window title rights, or the window has no title,
|
|
// so let's use actual OSD!
|
|
}
|
|
|
|
if(m_frameskip)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// present
|
|
|
|
m_dev->Present(m_wnd->GetClientRect().fit(m_aspectratio), m_shader);
|
|
|
|
// snapshot
|
|
|
|
if(!m_snapshot.empty())
|
|
{
|
|
bool shift = false;
|
|
|
|
#ifdef _WIN32
|
|
|
|
shift = !!(::GetAsyncKeyState(VK_SHIFT) & 0x8000);
|
|
|
|
#else
|
|
|
|
shift = m_shift_key;
|
|
|
|
#endif
|
|
|
|
if(!m_dump && shift)
|
|
{
|
|
GSFreezeData fd;
|
|
fd.size = 0;
|
|
fd.data = NULL;
|
|
Freeze(&fd, true);
|
|
fd.data = new uint8[fd.size];
|
|
Freeze(&fd, false);
|
|
|
|
m_dump.Open(m_snapshot, m_crc, fd, m_regs);
|
|
|
|
delete [] fd.data;
|
|
}
|
|
|
|
if(GSTexture* t = m_dev->GetCurrent())
|
|
{
|
|
t->Save(m_snapshot + ".bmp");
|
|
}
|
|
|
|
m_snapshot.clear();
|
|
}
|
|
else
|
|
{
|
|
if(m_dump)
|
|
{
|
|
bool control = false;
|
|
|
|
#ifdef _WIN32
|
|
|
|
control = !!(::GetAsyncKeyState(VK_CONTROL) & 0x8000);
|
|
|
|
#else
|
|
|
|
control = m_control_key;
|
|
|
|
#endif
|
|
|
|
m_dump.VSync(field, !control, m_regs);
|
|
}
|
|
}
|
|
|
|
// capture
|
|
|
|
if(m_capture.IsCapturing())
|
|
{
|
|
if(GSTexture* current = m_dev->GetCurrent())
|
|
{
|
|
GSVector2i size = m_capture.GetSize();
|
|
|
|
if(GSTexture* offscreen = m_dev->CopyOffscreen(current, GSVector4(0, 0, 1, 1), size.x, size.y))
|
|
{
|
|
GSTexture::GSMap m;
|
|
|
|
if(offscreen->Map(m))
|
|
{
|
|
m_capture.DeliverFrame(m.bits, m.pitch, !m_dev->IsRBSwapped());
|
|
|
|
offscreen->Unmap();
|
|
}
|
|
|
|
m_dev->Recycle(offscreen);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool GSRenderer::MakeSnapshot(const string& path)
|
|
{
|
|
if(m_snapshot.empty())
|
|
{
|
|
time_t t = time(NULL);
|
|
|
|
char buff[16];
|
|
|
|
if(strftime(buff, sizeof(buff), "%Y%m%d%H%M%S", localtime(&t)))
|
|
{
|
|
m_snapshot = format("%s_%s", path.c_str(), buff);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GSRenderer::BeginCapture()
|
|
{
|
|
GSVector4i disp = m_wnd->GetClientRect().fit(m_aspectratio);
|
|
float aspect = (float)disp.width() / max(1, disp.height());
|
|
|
|
return m_capture.BeginCapture(GetTvRefreshRate(), GetInternalResolution(), aspect);
|
|
}
|
|
|
|
void GSRenderer::EndCapture()
|
|
{
|
|
m_capture.EndCapture();
|
|
}
|
|
|
|
void GSRenderer::KeyEvent(GSKeyEventData* e)
|
|
{
|
|
#ifdef _WIN32
|
|
if(e->type == KEYPRESS)
|
|
{
|
|
|
|
int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1;
|
|
|
|
switch(e->key)
|
|
{
|
|
case VK_F5:
|
|
m_interlace = (m_interlace + s_interlace_nb + step) % s_interlace_nb;
|
|
printf("GSdx: Set deinterlace mode to %d (%s).\n", (int)m_interlace, theApp.m_gs_interlace.at(m_interlace).name.c_str());
|
|
return;
|
|
case VK_F6:
|
|
if( m_wnd->IsManaged() )
|
|
m_aspectratio = (m_aspectratio + s_aspect_ratio_nb + step) % s_aspect_ratio_nb;
|
|
return;
|
|
case VK_F7:
|
|
m_shader = (m_shader + s_post_shader_nb + step) % s_post_shader_nb;
|
|
printf("GSdx: Set shader to: %d.\n", (int)m_shader);
|
|
return;
|
|
case VK_DELETE:
|
|
m_aa1 = !m_aa1;
|
|
printf("GSdx: (Software) Edge anti-aliasing is now %s.\n", m_aa1 ? "enabled" : "disabled");
|
|
return;
|
|
case VK_INSERT:
|
|
m_mipmap = !m_mipmap;
|
|
printf("GSdx: (Software) Mipmapping is now %s.\n", m_mipmap ? "enabled" : "disabled");
|
|
return;
|
|
case VK_PRIOR:
|
|
m_fxaa = !m_fxaa;
|
|
printf("GSdx: FXAA anti-aliasing is now %s.\n", m_fxaa ? "enabled" : "disabled");
|
|
return;
|
|
case VK_HOME:
|
|
m_shaderfx = !m_shaderfx;
|
|
printf("GSdx: External post-processing is now %s.\n", m_shaderfx ? "enabled" : "disabled");
|
|
return;
|
|
}
|
|
|
|
}
|
|
#elif defined(__unix__)
|
|
if(e->type == KEYPRESS)
|
|
{
|
|
int step = m_shift_key ? -1 : 1;
|
|
|
|
switch(e->key)
|
|
{
|
|
case XK_F5:
|
|
m_interlace = (m_interlace + s_interlace_nb + step) % s_interlace_nb;
|
|
printf("GSdx: Set deinterlace mode to %d (%s).\n", (int)m_interlace, theApp.m_gs_interlace.at(m_interlace).name.c_str());
|
|
return;
|
|
case XK_F6:
|
|
if( m_wnd->IsManaged() )
|
|
m_aspectratio = (m_aspectratio + s_aspect_ratio_nb + step) % s_aspect_ratio_nb;
|
|
return;
|
|
case XK_F7:
|
|
m_shader = (m_shader + s_post_shader_nb + step) % s_post_shader_nb;
|
|
printf("GSdx: Set shader %d.\n", (int)m_shader);
|
|
return;
|
|
case XK_Delete:
|
|
m_aa1 = !m_aa1;
|
|
printf("GSdx: (Software) Edge anti-aliasing is now %s.\n", m_aa1 ? "enabled" : "disabled");
|
|
return;
|
|
case XK_Insert:
|
|
m_mipmap = !m_mipmap;
|
|
printf("GSdx: (Software) Mipmapping is now %s.\n", m_mipmap ? "enabled" : "disabled");
|
|
return;
|
|
case XK_Prior:
|
|
m_fxaa = !m_fxaa;
|
|
printf("GSdx: FXAA anti-aliasing is now %s.\n", m_fxaa ? "enabled" : "disabled");
|
|
return;
|
|
case XK_Home:
|
|
m_shaderfx = !m_shaderfx;
|
|
printf("GSdx: External post-processing is now %s.\n", m_shaderfx ? "enabled" : "disabled");
|
|
return;
|
|
case XK_Shift_L:
|
|
case XK_Shift_R:
|
|
m_shift_key = true;
|
|
return;
|
|
case XK_Control_L:
|
|
case XK_Control_R:
|
|
m_control_key = true;
|
|
return;
|
|
}
|
|
|
|
}
|
|
else if(e->type == KEYRELEASE)
|
|
{
|
|
switch(e->key)
|
|
{
|
|
case XK_Shift_L:
|
|
case XK_Shift_R:
|
|
m_shift_key = false;
|
|
return;
|
|
case XK_Control_L:
|
|
case XK_Control_R:
|
|
m_control_key = false;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void GSRenderer::PurgePool()
|
|
{
|
|
m_dev->PurgePool();
|
|
}
|