gsdx: Allow dump and capture PNG compression to be changed

Valid values for png_compression_level are from 0 (no compression) to 9
(max compression). The default is 1.

v2: Use zlib Z_BEST_SPEED (1) and Z_BEST_COMPRESSION (9) defines.
This commit is contained in:
Jonathan Li 2016-02-24 21:52:17 +00:00
parent a97cbf038c
commit 6b950d0408
17 changed files with 43 additions and 31 deletions

View File

@ -488,6 +488,8 @@ bool GSCapture::BeginCapture(float fps, GSVector2i recomendedResolution, float a
m_size.x = theApp.GetConfig("capture_resx", 1280);
m_size.y = theApp.GetConfig("capture_resy", 1024);
m_compression_level = theApp.GetConfig("png_compression_level", Z_BEST_SPEED);
#ifdef __linux__
for(int i = 0; i < m_threads; i++) {
m_workers.push_back(new GSPng::Worker());
@ -524,8 +526,8 @@ bool GSCapture::DeliverFrame(const void* bits, int pitch, bool rgba)
#elif __linux__
std::string out_file = m_out_dir + format("/frame.%010d.png", m_frame);
//GSPng::Save(GSPng::RGB_PNG, out_file, (uint8*)bits, m_size.x, m_size.y, pitch);
m_workers[m_frame%m_threads]->Push(shared_ptr<GSPng::Transaction>(new GSPng::Transaction(GSPng::RGB_PNG, out_file, static_cast<const uint8*>(bits), m_size.x, m_size.y, pitch)));
//GSPng::Save(GSPng::RGB_PNG, out_file, (uint8*)bits, m_size.x, m_size.y, pitch, m_compression_level);
m_workers[m_frame%m_threads]->Push(shared_ptr<GSPng::Transaction>(new GSPng::Transaction(GSPng::RGB_PNG, out_file, static_cast<const uint8*>(bits), m_size.x, m_size.y, pitch, m_compression_level)));
m_frame++;

View File

@ -45,6 +45,7 @@ class GSCapture
#elif __linux__
vector<GSPng::Worker*> m_workers;
int m_compression_level;
#endif

View File

@ -42,7 +42,7 @@ struct {
namespace GSPng {
bool SaveFile(const string& file, Format fmt, uint8* image, uint8* row,
int width, int height, int pitch,
int width, int height, int pitch, int compression,
bool rb_swapped = false, bool first_image = false)
{
int channel_bit_depth = pixel[fmt].channel_bit_depth;
@ -71,8 +71,11 @@ namespace GSPng {
if (setjmp(png_jmpbuf(png_ptr)))
throw GSDXRecoverableError();
if (compression < 0 || compression > Z_BEST_COMPRESSION)
compression = Z_BEST_SPEED;
png_init_io(png_ptr, fp);
png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
png_set_compression_level(png_ptr, compression);
png_set_IHDR(png_ptr, info_ptr, width, height, channel_bit_depth, type,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
@ -91,8 +94,7 @@ namespace GSPng {
png_write_end(png_ptr, nullptr);
success = true;
}
catch (GSDXRecoverableError&) {
} catch (GSDXRecoverableError&) {
fprintf(stderr, "Failed to write image %s\n", file.c_str());
}
@ -103,7 +105,7 @@ namespace GSPng {
return success;
}
bool Save(GSPng::Format fmt, const string& file, uint8* image, int w, int h, int pitch, bool rb_swapped)
bool Save(GSPng::Format fmt, const string& file, uint8* image, int w, int h, int pitch, int compression, bool rb_swapped)
{
std::string root = file;
root.replace(file.length() - 4, 4, "");
@ -113,7 +115,7 @@ namespace GSPng {
std::unique_ptr<uint8[]> row(new uint8[pixel[fmt].bytes_per_pixel_out * w]);
std::string filename = root + pixel[fmt].extension[0];
if (!SaveFile(filename, fmt, image, row.get(), w, h, pitch, rb_swapped, true))
if (!SaveFile(filename, fmt, image, row.get(), w, h, pitch, compression, rb_swapped, true))
return false;
// Second image
@ -121,11 +123,11 @@ namespace GSPng {
return true;
filename = root + pixel[fmt].extension[1];
return SaveFile(filename, fmt, image, row.get(), w, h, pitch);
return SaveFile(filename, fmt, image, row.get(), w, h, pitch, compression);
}
Transaction::Transaction(GSPng::Format fmt, const string& file, const uint8* image, int w, int h, int pitch)
: m_fmt(fmt), m_file(file), m_w(w), m_h(h), m_pitch(pitch)
Transaction::Transaction(GSPng::Format fmt, const string& file, const uint8* image, int w, int h, int pitch, int compression)
: m_fmt(fmt), m_file(file), m_w(w), m_h(h), m_pitch(pitch), m_compression(compression)
{
// Note: yes it would be better to use shared pointer
m_image = (uint8*)_aligned_malloc(pitch*h, 32);
@ -141,7 +143,7 @@ namespace GSPng {
void Worker::Process(shared_ptr<Transaction>& item)
{
Save(item->m_fmt, item->m_file, item->m_image, item->m_w, item->m_h, item->m_pitch);
Save(item->m_fmt, item->m_file, item->m_image, item->m_w, item->m_h, item->m_pitch, item->m_compression);
}
}

View File

@ -44,12 +44,13 @@ namespace GSPng {
int m_w;
int m_h;
int m_pitch;
int m_compression;
Transaction(GSPng::Format fmt, const string& file, const uint8* image, int w, int h, int pitch);
Transaction(GSPng::Format fmt, const string& file, const uint8* image, int w, int h, int pitch, int compression);
~Transaction();
};
bool Save(GSPng::Format fmt, const string& file, uint8* image, int w, int h, int pitch, bool rb_swapped = false);
bool Save(GSPng::Format fmt, const string& file, uint8* image, int w, int h, int pitch, int compression, bool rb_swapped = false);
class Worker : public GSJobQueue<shared_ptr<Transaction>, 16 >
{

View File

@ -469,7 +469,7 @@ void GSRenderer::VSync(int field)
if(GSTexture* t = m_dev->GetCurrent())
{
t->Save(m_snapshot + ".bmp");
t->Save(m_snapshot + ".bmp", true);
}
m_snapshot.clear();

View File

@ -445,13 +445,13 @@ void GSRendererHW::Draw()
(int)context->CLAMP.MINU, (int)context->CLAMP.MAXU,
(int)context->CLAMP.MINV, (int)context->CLAMP.MAXV);
tex->m_texture->Save(root_hw+s, true);
tex->m_texture->Save(root_hw+s, false, true);
if(tex->m_palette)
{
s = format("%05d_f%lld_tpx_%05x_%d.dds", s_n, frame, context->TEX0.CBP, context->TEX0.CPSM);
tex->m_palette->Save(root_hw+s, true);
tex->m_palette->Save(root_hw+s, false, true);
}
}

View File

@ -46,7 +46,7 @@ public:
virtual bool Update(const GSVector4i& r, const void* data, int pitch) = 0;
virtual bool Map(GSMap& m, const GSVector4i* r = NULL) = 0;
virtual void Unmap() = 0;
virtual bool Save(const string& fn, bool dds = false) = 0;
virtual bool Save(const string& fn, bool user_image = false, bool dds = false) = 0;
virtual void Invalidate() {}
virtual uint32 GetID() { return 0; }

View File

@ -93,7 +93,7 @@ void GSTexture11::Unmap()
}
}
bool GSTexture11::Save(const string& fn, bool dds)
bool GSTexture11::Save(const string& fn, bool user_image, bool dds)
{
CComPtr<ID3D11Texture2D> res;
D3D11_TEXTURE2D_DESC desc;
@ -179,7 +179,8 @@ bool GSTexture11::Save(const string& fn, bool dds)
return false;
}
bool success = GSPng::Save(format, fn, static_cast<uint8*>(sm.pData), desc.Width, desc.Height, sm.RowPitch);
int compression = user_image ? Z_BEST_COMPRESSION : theApp.GetConfig("png_compression_level", Z_BEST_SPEED);
bool success = GSPng::Save(format, fn, static_cast<uint8*>(sm.pData), desc.Width, desc.Height, sm.RowPitch, compression);
m_ctx->Unmap(res, 0);

View File

@ -40,7 +40,7 @@ public:
bool Update(const GSVector4i& r, const void* data, int pitch);
bool Map(GSMap& m, const GSVector4i* r);
void Unmap();
bool Save(const string& fn, bool dds = false);
bool Save(const string& fn, bool user_image = false, bool dds = false);
operator ID3D11Texture2D*();
operator ID3D11ShaderResourceView*();

View File

@ -142,7 +142,7 @@ void GSTexture9::Unmap()
}
}
bool GSTexture9::Save(const string& fn, bool dds)
bool GSTexture9::Save(const string& fn, bool user_image, bool dds)
{
bool rb_swapped = true;
CComPtr<IDirect3DSurface9> surface;
@ -201,7 +201,8 @@ bool GSTexture9::Save(const string& fn, bool dds)
return false;
}
bool success = GSPng::Save(format, fn, static_cast<uint8*>(slr.pBits), desc.Width, desc.Height, slr.Pitch, rb_swapped);
int compression = user_image ? Z_BEST_COMPRESSION : theApp.GetConfig("png_compression_level", Z_BEST_SPEED);
bool success = GSPng::Save(format, fn, static_cast<uint8*>(slr.pBits), desc.Width, desc.Height, slr.Pitch, compression, rb_swapped);
surface->UnlockRect();
return success;

View File

@ -38,7 +38,7 @@ public:
bool Update(const GSVector4i& r, const void* data, int pitch);
bool Map(GSMap& m, const GSVector4i* r);
void Unmap();
bool Save(const string& fn, bool dds = false);
bool Save(const string& fn, bool user_image = false, bool dds = false);
operator IDirect3DSurface9*();
operator IDirect3DTexture9*();

View File

@ -37,5 +37,5 @@ public:
bool Update(const GSVector4i& r, const void* data, int pitch) {return true;}
bool Map(GSMap& m, const GSVector4i* r) {return false;}
void Unmap() {}
bool Save(const string& fn, bool dds = false) {return false;}
bool Save(const string& fn, bool user_image = false, bool dds = false) { return false; }
};

View File

@ -421,7 +421,7 @@ void GSTextureOGL::Unmap()
{
}
bool GSTextureOGL::Save(const string& fn, bool dds)
bool GSTextureOGL::Save(const string& fn, bool user_image, bool dds)
{
// Collect the texture data
uint32 pitch = 4 * m_size.x;
@ -470,7 +470,8 @@ bool GSTextureOGL::Save(const string& fn, bool dds)
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
return GSPng::Save(fmt, fn, image.get(), m_size.x, m_size.y, pitch);
int compression = user_image ? Z_BEST_COMPRESSION : theApp.GetConfig("png_compression_level", Z_BEST_SPEED);
return GSPng::Save(fmt, fn, image.get(), m_size.x, m_size.y, pitch, compression);
}
uint32 GSTextureOGL::GetMemUsage()

View File

@ -63,7 +63,7 @@ class GSTextureOGL : public GSTexture
bool Update(const GSVector4i& r, const void* data, int pitch);
bool Map(GSMap& m, const GSVector4i* r = NULL);
void Unmap();
bool Save(const string& fn, bool dds = false);
bool Save(const string& fn, bool user_image = false, bool dds = false);
bool IsBackbuffer() { return (m_type == GSTexture::Backbuffer); }
bool IsDss() { return (m_type == GSTexture::DepthStencil); }

View File

@ -85,7 +85,7 @@ void GSTextureSW::Unmap()
m_mapped.clear();
}
bool GSTextureSW::Save(const string& fn, bool dds)
bool GSTextureSW::Save(const string& fn, bool user_image, bool dds)
{
if(dds) return false; // not implemented
@ -94,5 +94,6 @@ bool GSTextureSW::Save(const string& fn, bool dds)
#else
GSPng::Format fmt = GSPng::RGB_PNG;
#endif
return GSPng::Save(fmt, fn, static_cast<uint8*>(m_data), m_size.x, m_size.y, m_pitch);
int compression = user_image ? Z_BEST_COMPRESSION : theApp.GetConfig("png_compression_level", Z_BEST_SPEED);
return GSPng::Save(fmt, fn, static_cast<uint8*>(m_data), m_size.x, m_size.y, m_pitch, compression);
}

View File

@ -38,5 +38,5 @@ public:
bool Update(const GSVector4i& r, const void* data, int pitch);
bool Map(GSMap& m, const GSVector4i* r);
void Unmap();
bool Save(const string& fn, bool dds = false);
bool Save(const string& fn, bool user_image = false, bool dds = false);
};

View File

@ -109,6 +109,8 @@ using namespace std;
#include <memory>
#include <zlib.h>
#if _MSC_VER >= 1800 || !defined(_WIN32)
#include <unordered_map>
#include <unordered_set>