Skip to content

Commit

Permalink
Merge pull request #4344 from degasus/framedump_ogl
Browse files Browse the repository at this point in the history
OGL: Use PBO for framedump, with async readback.
  • Loading branch information
degasus committed Nov 8, 2016
2 parents 136a104 + 741debe commit 363dec7
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 12 deletions.
73 changes: 61 additions & 12 deletions Source/Core/VideoBackends/OGL/Render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,9 @@ Renderer::Renderer()

Renderer::~Renderer()
{
FlushFrameDump();
if (m_frame_dumping_pbo[0])
glDeleteBuffers(2, m_frame_dumping_pbo.data());
}

void Renderer::Shutdown()
Expand Down Expand Up @@ -1447,19 +1450,9 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,

glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);

if (IsFrameDumping())
{
std::vector<u8> image(flipped_trc.GetWidth() * flipped_trc.GetHeight() * 4);

glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(flipped_trc.left, flipped_trc.bottom, flipped_trc.GetWidth(),
flipped_trc.GetHeight(), GL_RGBA, GL_UNSIGNED_BYTE, image.data());
FlushFrameDump();
DumpFrame(flipped_trc, ticks);

AVIDump::Frame state = AVIDump::FetchState(ticks);
DumpFrameData(image.data(), flipped_trc.GetWidth(), flipped_trc.GetHeight(),
flipped_trc.GetWidth() * 4, state, true);
FinishFrameData();
}
// Finish up the current frame, print some stats

SetWindowSize(fbStride, fbHeight);
Expand Down Expand Up @@ -1588,6 +1581,62 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
ClearEFBCache();
}

void Renderer::FlushFrameDump()
{
if (!m_last_frame_exported)
return;

FinishFrameData();
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_frame_dumping_pbo[0]);
m_frame_pbo_is_mapped[0] = true;
void* data = glMapBufferRange(
GL_PIXEL_PACK_BUFFER, 0, m_last_frame_width[0] * m_last_frame_height[0] * 4, GL_MAP_READ_BIT);
DumpFrameData(reinterpret_cast<u8*>(data), m_last_frame_width[0], m_last_frame_height[0],
m_last_frame_width[0] * 4, m_last_frame_state, true);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
m_last_frame_exported = false;
}

void Renderer::DumpFrame(const TargetRectangle& flipped_trc, u64 ticks)
{
if (!IsFrameDumping())
return;

if (!m_frame_dumping_pbo[0])
{
glGenBuffers(2, m_frame_dumping_pbo.data());
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_frame_dumping_pbo[0]);
}
else
{
std::swap(m_frame_dumping_pbo[0], m_frame_dumping_pbo[1]);
std::swap(m_frame_pbo_is_mapped[0], m_frame_pbo_is_mapped[1]);
std::swap(m_last_frame_width[0], m_last_frame_width[1]);
std::swap(m_last_frame_height[0], m_last_frame_height[1]);
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_frame_dumping_pbo[0]);
if (m_frame_pbo_is_mapped[0])
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
m_frame_pbo_is_mapped[0] = false;
}

if (flipped_trc.GetWidth() != m_last_frame_width[0] ||
flipped_trc.GetHeight() != m_last_frame_height[0])
{
m_last_frame_width[0] = flipped_trc.GetWidth();
m_last_frame_height[0] = flipped_trc.GetHeight();
glBufferData(GL_PIXEL_PACK_BUFFER, m_last_frame_width[0] * m_last_frame_height[0] * 4, nullptr,
GL_STREAM_READ);
}

m_last_frame_state = AVIDump::FetchState(ticks);
m_last_frame_exported = true;

glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(flipped_trc.left, flipped_trc.bottom, m_last_frame_width[0], m_last_frame_height[0],
GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}

// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
void Renderer::ResetAPIState()
{
Expand Down
12 changes: 12 additions & 0 deletions Source/Core/VideoBackends/OGL/Render.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

#include <array>
#include <string>
#include "VideoCommon/RenderBase.h"

Expand Down Expand Up @@ -111,5 +112,16 @@ class Renderer : public ::Renderer

void BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_texture, int src_width,
int src_height);

void FlushFrameDump();
void DumpFrame(const TargetRectangle& flipped_trc, u64 ticks);

// avi dumping state to delay one frame
std::array<u32, 2> m_frame_dumping_pbo = {};
std::array<bool, 2> m_frame_pbo_is_mapped = {};
std::array<int, 2> m_last_frame_width = {};
std::array<int, 2> m_last_frame_height = {};
bool m_last_frame_exported = false;
AVIDump::Frame m_last_frame_state;
};
}

0 comments on commit 363dec7

Please sign in to comment.