Support frame and video dumping from VideoCommon

This commit is contained in:
iwubcode
2017-05-30 23:44:03 -05:00
parent 79387dddb2
commit a9f0d1783b
17 changed files with 306 additions and 158 deletions

View File

@ -66,22 +66,6 @@ GLenum GetGLTypeForTextureFormat(AbstractTextureFormat format)
}
} // Anonymous namespace
bool SaveTexture(const std::string& filename, u32 textarget, u32 tex, int virtual_width,
int virtual_height, unsigned int level)
{
if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL)
return false;
int width = std::max(virtual_width >> level, 1);
int height = std::max(virtual_height >> level, 1);
std::vector<u8> data(width * height * 4);
glActiveTexture(GL_TEXTURE9);
glBindTexture(textarget, tex);
glGetTexImage(textarget, level, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
OGLTexture::SetStage();
return TextureToPng(data.data(), width * 4, filename, width, height, true);
}
OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
{
glGenTextures(1, &m_texId);
@ -164,15 +148,73 @@ void OGLTexture::Bind(unsigned int stage)
}
}
bool OGLTexture::Save(const std::string& filename, unsigned int level)
std::optional<AbstractTexture::RawTextureInfo> OGLTexture::MapFullImpl()
{
// We can't dump compressed textures currently (it would mean drawing them to a RGBA8
// framebuffer, and saving that). TextureCache does not call Save for custom textures
// anyway, so this is fine for now.
_assert_(m_config.format == AbstractTextureFormat::RGBA8);
if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL)
return {};
return SaveTexture(filename, GL_TEXTURE_2D_ARRAY, m_texId, m_config.width, m_config.height,
level);
m_staging_data.reserve(m_config.width * m_config.height * 4);
glActiveTexture(GL_TEXTURE9);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId);
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_staging_data.data());
OGLTexture::SetStage();
return AbstractTexture::RawTextureInfo{reinterpret_cast<u8*>(m_staging_data.data()),
m_config.width * 4, m_config.width, m_config.height};
}
std::optional<AbstractTexture::RawTextureInfo> OGLTexture::MapRegionImpl(u32 level, u32 x, u32 y,
u32 width, u32 height)
{
if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL)
return {};
m_staging_data.reserve(m_config.width * m_config.height * 4);
glActiveTexture(GL_TEXTURE9);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId);
if (g_ogl_config.bSupportTextureSubImage)
{
glGetTextureSubImage(GL_TEXTURE_2D_ARRAY, level, GLint(x), GLint(y), 0, GLsizei(width),
GLsizei(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, GLsizei(width * height * 4),
m_staging_data.data());
}
else
{
MapRegionSlow(level, x, y, width, height);
}
OGLTexture::SetStage();
return AbstractTexture::RawTextureInfo{m_staging_data.data(), width * 4, width, height};
}
void OGLTexture::MapRegionSlow(u32 level, u32 x, u32 y, u32 width, u32 height)
{
glActiveTexture(GL_TEXTURE9);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId);
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_staging_data.data());
// Now copy the region out of the staging data
const u32 partial_stride = width * 4;
std::vector<u8> partial_data;
partial_data.resize(partial_stride * height);
const u32 staging_stride = m_config.width * 4;
const u32 x_offset = x * 4;
auto staging_location = m_staging_data.begin() + staging_stride * y;
auto partial_location = partial_data.begin();
for (size_t i = 0; i < height; ++i)
{
auto starting_location = staging_location + x_offset;
std::copy(starting_location, starting_location + partial_stride, partial_location);
staging_location += staging_stride;
partial_location += partial_stride;
}
// Now swap the region back in for the staging data
m_staging_data.swap(partial_data);
}
void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* source,

View File

@ -4,6 +4,8 @@
#pragma once
#include <vector>
#include "Common/GL/GLUtil.h"
#include "VideoCommon/AbstractTexture.h"
@ -17,7 +19,6 @@ public:
~OGLTexture();
void Bind(unsigned int stage) override;
bool Save(const std::string& filename, unsigned int level) override;
void CopyRectangleFromTexture(const AbstractTexture* source,
const MathUtil::Rectangle<int>& srcrect,
@ -32,8 +33,14 @@ public:
static void SetStage();
private:
std::optional<RawTextureInfo> MapFullImpl() override;
std::optional<RawTextureInfo> MapRegionImpl(u32 level, u32 x, u32 y, u32 width,
u32 height) override;
void MapRegionSlow(u32 level, u32 x, u32 y, u32 width, u32 height);
GLuint m_texId;
GLuint m_framebuffer = 0;
std::vector<u8> m_staging_data;
};
} // namespace OGL

View File

@ -460,6 +460,7 @@ Renderer::Renderer()
GLExtensions::Supports("GL_EXT_copy_image") ||
GLExtensions::Supports("GL_OES_copy_image")) &&
!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_COPYIMAGE);
g_ogl_config.bSupportTextureSubImage = GLExtensions::Supports("ARB_get_texture_sub_image");
// Desktop OpenGL supports the binding layout if it supports 420pack
// OpenGL ES 3.1 supports it implicitly without an extension
@ -792,7 +793,7 @@ Renderer::Renderer()
Renderer::~Renderer()
{
FlushFrameDump();
FinishFrameData();
//FinishFrameData();
DestroyFrameDumpResources();
}
@ -1361,7 +1362,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ti
// The FlushFrameDump call here is necessary even after frame dumping is stopped.
// If left out, screenshots are "one frame" behind, as an extra frame is dumped and buffered.
FlushFrameDump();
/*FlushFrameDump();
if (IsFrameDumping())
{
// Currently, we only use the off-screen buffer as a frame dump source if full-resolution
@ -1378,7 +1379,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ti
// GL_READ_FRAMEBUFFER is set by GL_FRAMEBUFFER in DrawFrame -> Draw{EFB,VirtualXFB,RealXFB}.
DumpFrame(flipped_trc, ticks);
}
}
}*/
// Finish up the current frame, print some stats
@ -1510,7 +1511,7 @@ void Renderer::DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc,
void Renderer::FlushFrameDump()
{
if (!m_last_frame_exported)
/*if (!m_last_frame_exported)
return;
FinishFrameData();
@ -1521,7 +1522,7 @@ void Renderer::FlushFrameDump()
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;
m_last_frame_exported = false;*/
}
void Renderer::DumpFrame(const TargetRectangle& flipped_trc, u64 ticks)

View File

@ -59,6 +59,7 @@ struct VideoConfig
bool bSupportsImageLoadStore;
bool bSupportsAniso;
bool bSupportsBitfield;
bool bSupportTextureSubImage;
const char* gl_vendor;
const char* gl_renderer;