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::VSync(int field) { GSPerfMonAutoTimer pmat(&m_perfmon); m_perfmon.Put(GSPerfMon::Frame); Flush(); if(s_dump && s_n >= s_saven) { m_regs->Dump(root_sw + format("%05d_f%lld_gs_reg.txt", s_n, m_perfmon.GetFrame())); } 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 #if 0 // This will scale the OSD to the PS2's output resolution. // Will be affected by 2x, 4x, etc scaling. m_dev->m_osd.m_real_size = m_real_size #elif 0 // This will scale the OSD to the window's size. // Will maintiain the font size no matter what size the window is. GSVector4i window_size = m_wnd->GetClientRect(); m_dev->m_osd.m_real_size.x = window_size.v[2]; m_dev->m_osd.m_real_size.y = window_size.v[3]; #else // This will scale the OSD to the native resolution. // Will size font relative to the window's size. // TODO this should probably be done with native calls m_dev->m_osd.m_real_size.x = 1024; m_dev->m_osd.m_real_size.y = 768; #endif m_dev->Present(m_wnd->GetClientRect().fit(m_aspectratio), m_shader); // snapshot if(!m_snapshot.empty()) { if(!m_dump && m_shift_key) { GSFreezeData fd = {0, nullptr}; Freeze(&fd, true); fd.data = new uint8[fd.size]; Freeze(&fd, false); #ifdef LZMA_SUPPORTED if (m_control_key) m_dump = std::unique_ptr<GSDumpBase>(new GSDump(m_snapshot, m_crc, fd, m_regs)); else m_dump = std::unique_ptr<GSDumpBase>(new GSDumpXz(m_snapshot, m_crc, fd, m_regs)); #else m_dump = std::unique_ptr<GSDumpBase>(new GSDump(m_snapshot, m_crc, fd, m_regs)); #endif delete [] fd.data; } if(GSTexture* t = m_dev->GetCurrent()) { t->Save(m_snapshot + ".bmp"); } m_snapshot.clear(); } else if(m_dump) { if(m_dump->VSync(field, !m_control_key, m_regs)) m_dump.reset(); } // 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); } } } }
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); } } } }