]> git.cworth.org Git - apitrace/commitdiff
Encode the snapshots as png's.
authorZack Rusin <zack@kde.org>
Mon, 25 Apr 2011 04:05:48 +0000 (00:05 -0400)
committerZack Rusin <zack@kde.org>
Mon, 25 Apr 2011 04:05:48 +0000 (00:05 -0400)
Saves between 2x and 1000x of space when passing them to the gui.
It's also a huge performance win because the json parser needs to
parse between 2x and 1000x less data.

glstate.py
gui/apisurface.cpp
image.cpp
image.hpp

index 2c183762b7f7e8471bb8f4e41b8886f8f4dba0dc..dee76e9ac5f69c086303e9f747433ffbde5645a5 100644 (file)
@@ -3019,6 +3019,7 @@ class StateDumper:
         print '#include <iostream>'
         print '#include <algorithm>'
         print
+        print '#include "image.hpp"'
         print '#include "json.hpp"'
         print '#include "glimports.hpp"'
         print '#include "glproc.hpp"'
@@ -3190,7 +3191,11 @@ writeTextureImage(JSONWriter &json, GLenum target, GLint level)
         glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 
         json.beginMember("__data__");
-        json.writeBase64(pixels, depth * width * height * 4 * sizeof *pixels);
+        char *pngBuffer;
+        int pngBufferSize;
+        Image::writePixelsToBuffer(pixels, width, height, 4, false, &pngBuffer, &pngBufferSize);
+        json.writeBase64(pngBuffer, pngBufferSize);
+        free(pngBuffer);
         json.endMember(); // __data__
 
         delete [] pixels;
@@ -3241,7 +3246,13 @@ writeDrawBufferImage(JSONWriter &json, GLenum format)
         glReadBuffer(readbuffer);
 
         json.beginMember("__data__");
-        json.writeBase64(pixels, width * height * channels * sizeof *pixels);
+        char *pngBuffer;
+        int pngBufferSize;
+        Image::writePixelsToBuffer(pixels, width, height, channels, false, &pngBuffer, &pngBufferSize);
+        //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
+        //          <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
+        json.writeBase64(pngBuffer, pngBufferSize);
+        free(pngBuffer);
         json.endMember(); // __data__
 
         delete [] pixels;
index c875c6ff432662fcbedc267ae41f8451034abfda..1123ead1668393be8d1615c59b842bad6665083a 100644 (file)
@@ -27,69 +27,12 @@ void ApiSurface::setNumChannels(int numChannels)
     m_numChannels = numChannels;
 }
 
-static inline int
-rgba8_to_argb(quint8 r, quint8 g, quint8 b, quint8 a)
-{
-    return (a << 24 | r << 16 | g << 8 | b);
-}
-
-static inline int
-rgbaf2argb(float r, float g, float b, float a)
-{
-    quint8 rb = r * 255;
-    quint8 gb = g * 255;
-    quint8 bb = b * 255;
-    quint8 ab = a * 255;
-
-    return (ab << 24 | rb << 16 | gb << 8 | bb);
-}
-
 void ApiSurface::contentsFromBase64(const QByteArray &base64)
 {
     QByteArray dataArray = QByteArray::fromBase64(base64);
-    const quint8 *data = (const quint8*)dataArray.data();
-    int width = m_size.width();
-    int height = m_size.height();
-
-    if (width <= 0 || height <= 0)
-        return;
-
-    int *pixelData = (int*)malloc(sizeof(int) * width * height);
-
-    //XXX not sure if this will work when
-    //    QSysInfo::ByteOrder == QSysInfo::BigEndian
-
-    if (m_numChannels == 4) {
-        for (int y = 0; y < height; ++y) {
-            for (int x = 0; x < width; ++x) {
-                int pixel = rgba8_to_argb(data[(y * width + x) * 4 + 0],
-                                          data[(y * width + x) * 4 + 1],
-                                          data[(y * width + x) * 4 + 2],
-                                          data[(y * width + x) * 4 + 3]);
-                pixelData[y * width + x] = pixel;
-            }
-        }
-    } else if (m_numChannels == 1) {
-        for (int y = 0; y < height; ++y) {
-            for (int x = 0; x < width; ++x) {
-                int pixel = rgba8_to_argb(data[y * width + x],
-                                          data[y * width + x],
-                                          data[y * width + x],
-                                          255);
-                pixelData[y * width + x] = pixel;
-            }
-        }
-    } else {
-        Q_ASSERT(0);
-    }
-
-    m_image = QImage((uchar*)pixelData,
-                     width, height,
-                     QImage::Format_ARGB32).mirrored();
+    m_image.loadFromData(dataArray, "png");
+    m_image = m_image.mirrored();
     m_thumb = m_image.scaled(64, 64, Qt::KeepAspectRatio);
-    //m_image.save("testoutput.png");
-
-    free(pixelData);
 }
 
 QImage ApiSurface::image() const
index 937f486bfbc01cbe3676b54ce67be52f84b1a754..1f96c29bb5c60c8d30d657e7a0c6ad7a09f1f3b0 100644 (file)
--- a/image.cpp
+++ b/image.cpp
@@ -28,6 +28,7 @@
 
 #include <math.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 #include <fstream>
 
@@ -309,6 +310,115 @@ double Image::compare(Image &ref)
     return precision;
 }
 
+struct png_tmp_buffer
+{
+    char *buffer;
+    size_t size;
+};
+
+static void
+pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+    struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_ptr->io_ptr;
+    size_t nsize = buf->size + length;
+
+    /* allocate or grow buffer */
+    if (buf->buffer)
+        buf->buffer = (char*)realloc(buf->buffer, nsize);
+    else
+        buf->buffer = (char*)malloc(nsize);
+
+    if (!buf->buffer)
+        png_error(png_ptr, "Buffer allocation error");
+
+    memcpy(buf->buffer + buf->size, data, length);
+    buf->size += length;
+}
+
+bool writePixelsToBuffer(unsigned char *pixels,
+                         unsigned width, unsigned height, unsigned numChannels,
+                         bool flipped,
+                         char **buffer,
+                         int *size)
+{
+    struct png_tmp_buffer png_mem;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    int type;
+
+    png_mem.buffer = NULL;
+    png_mem.size = 0;
+
+    switch (numChannels) {
+    case 4:
+        type = PNG_COLOR_TYPE_RGB_ALPHA;
+        break;
+    case 3:
+        type = PNG_COLOR_TYPE_RGB;
+        break;
+    case 2:
+        type = PNG_COLOR_TYPE_GRAY_ALPHA;
+        break;
+    case 1:
+        type = PNG_COLOR_TYPE_GRAY;
+        break;
+    default:
+        goto no_png;
+    }
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr)
+        goto no_png;
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_write_struct(&png_ptr,  NULL);
+        goto no_png;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) {
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+        goto no_png;
+    }
+
+    png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL);
+
+    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
+                 type, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+    png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
+
+    png_write_info(png_ptr, info_ptr);
+
+    if (!flipped) {
+        for (unsigned y = 0; y < height; ++y) {
+            png_bytep row = (png_bytep)(pixels + y*width*numChannels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    } else {
+        unsigned y = height;
+        while (y--) {
+            png_bytep row = (png_bytep)(pixels + y*width*numChannels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    }
+
+    png_write_end(png_ptr, info_ptr);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
 
+    *buffer = png_mem.buffer;
+    *size = png_mem.size;
+
+    return true;
+
+no_png:
+    *buffer = NULL;
+    *size = 0;
+
+    if (png_mem.buffer)
+        free(png_mem.buffer);
+    return false;
+}
 
 } /* namespace Image */
index 5a9704eb821b9fba736e9c00233b1b0996df2aea..f46fb31e69712f4cebe322dea04b71c13e48a686 100644 (file)
--- a/image.hpp
+++ b/image.hpp
@@ -77,6 +77,11 @@ public:
     double compare(Image &ref);
 };
 
+bool writePixelsToBuffer(unsigned char *pixels,
+                         unsigned w, unsigned h, unsigned numChannels,
+                         bool flipped,
+                         char **buffer,
+                         int *size);
 
 Image *
 readPNG(const char *filename);