Home | History | Annotate | Download | only in gldebugger
      1 /*
      2  ** Copyright 2011, The Android Open Source Project
      3  **
      4  ** Licensed under the Apache License, Version 2.0 (the "License");
      5  ** you may not use this file except in compliance with the License.
      6  ** You may obtain a copy of the License at
      7  **
      8  **     http://www.apache.org/licenses/LICENSE-2.0
      9  **
     10  ** Unless required by applicable law or agreed to in writing, software
     11  ** distributed under the License is distributed on an "AS IS" BASIS,
     12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  ** See the License for the specific language governing permissions and
     14  ** limitations under the License.
     15  */
     16 
     17 package com.android.ide.eclipse.gldebugger;
     18 
     19 import com.google.protobuf.ByteString;
     20 
     21 import org.eclipse.jface.dialogs.MessageDialog;
     22 import org.eclipse.swt.graphics.ImageData;
     23 import org.eclipse.swt.graphics.PaletteData;
     24 
     25 import java.nio.ByteBuffer;
     26 import java.util.Arrays;
     27 
     28 public class MessageProcessor {
     29     static void showError(final String message) {
     30         // need to call SWT from UI thread
     31         MessageDialog.openError(null, "MessageProcessor", message);
     32     }
     33 
     34     /**
     35      * data layout: uint32 total decompressed length, (chunks: uint32 chunk
     36      * decompressed size, uint32 chunk compressed size, chunk data)+. 0 chunk
     37      * compressed size means chunk is not compressed
     38      */
     39     public static byte[] lzfDecompressChunks(final ByteString data) {
     40         ByteBuffer in = data.asReadOnlyByteBuffer();
     41         in.order(GLFramesView.TARGET_BYTE_ORDER);
     42         ByteBuffer out = ByteBuffer.allocate(in.getInt());
     43         byte[] inChunk = new byte[0];
     44         byte[] outChunk = new byte[0];
     45         while (in.remaining() > 0) {
     46             int decompressed = in.getInt();
     47             int compressed = in.getInt();
     48             if (decompressed > outChunk.length)
     49                 outChunk = new byte[decompressed];
     50             if (compressed == 0) {
     51                 in.get(outChunk, 0, decompressed);
     52                 out.put(outChunk, 0, decompressed);
     53             } else {
     54                 if (compressed > inChunk.length)
     55                     inChunk = new byte[compressed];
     56                 in.get(inChunk, 0, compressed);
     57                 int size = org.liblzf.CLZF
     58                         .lzf_decompress(inChunk, compressed, outChunk, outChunk.length);
     59                 assert size == decompressed;
     60                 out.put(outChunk, 0, size);
     61             }
     62         }
     63         assert !out.hasRemaining();
     64         return out.array();
     65     }
     66 
     67     /** same data layout as LZFDecompressChunks */
     68     public static byte[] lzfCompressChunks(final byte[] in, final int inSize) {
     69         byte[] chunk = new byte[256 * 1024]; // chunk size is arbitrary
     70         final ByteBuffer out = ByteBuffer.allocate(4 + (inSize + chunk.length - 1)
     71                 / chunk.length * (chunk.length + 4 * 2));
     72         out.order(GLFramesView.TARGET_BYTE_ORDER);
     73         out.putInt(inSize);
     74         for (int i = 0; i < inSize; i += chunk.length) {
     75             int chunkIn = chunk.length;
     76             if (i + chunkIn > inSize)
     77                 chunkIn = inSize - i;
     78             final byte[] inChunk = java.util.Arrays.copyOfRange(in, i, i + chunkIn);
     79             final int chunkOut = org.liblzf.CLZF
     80                     .lzf_compress(inChunk, chunkIn, chunk, chunk.length);
     81             out.putInt(chunkIn);
     82             out.putInt(chunkOut);
     83             if (chunkOut == 0) // compressed bigger than chunk (uncompressed)
     84                 out.put(inChunk);
     85             else
     86                 out.put(chunk, 0, chunkOut);
     87         }
     88         return Arrays.copyOf(out.array(), out.position());
     89     }
     90 
     91     /**
     92      * returns new ref, which is also the decoded image; ref could be bigger
     93      * than pixels, in which case the first pixels.length bytes form the image
     94      */
     95     public static byte[] decodeReferencedImage(byte[] ref, byte[] pixels) {
     96         if (ref.length < pixels.length)
     97             ref = new byte[pixels.length];
     98         for (int i = 0; i < pixels.length; i++)
     99             ref[i] ^= pixels[i];
    100         for (int i = pixels.length; i < ref.length; i++)
    101             ref[i] = 0; // clear unused ref to maintain consistency
    102         return ref;
    103     }
    104 
    105     public static ImageData receiveImage(int width, int height, int format,
    106             int type, final ByteString data) {
    107         assert width > 0 && height > 0;
    108         int bpp = 0;
    109         int redMask = 0, blueMask = 0, greenMask = 0;
    110         switch (GLEnum.valueOf(type)) {
    111             case GL_UNSIGNED_SHORT_5_6_5:
    112             case GL_UNSIGNED_SHORT_4_4_4_4:
    113             case GL_UNSIGNED_SHORT_5_5_5_1:
    114                 format = type;
    115                 break;
    116             case GL_UNSIGNED_BYTE:
    117                 break;
    118             default:
    119                 showError("unsupported texture type " + type);
    120                 return null;
    121         }
    122 
    123         switch (GLEnum.valueOf(format)) {
    124             case GL_ALPHA:
    125             case GL_LUMINANCE:
    126                 redMask = blueMask = greenMask = 0xff;
    127                 bpp = 8;
    128                 break;
    129             case GL_LUMINANCE_ALPHA:
    130                 blueMask = 0xff;
    131                 redMask = 0xff00;
    132                 bpp = 16;
    133                 break;
    134             case GL_RGB:
    135                 blueMask = 0xff;
    136                 greenMask = 0xff00;
    137                 redMask = 0xff0000;
    138                 bpp = 24;
    139                 break;
    140             case GL_RGBA:
    141                 blueMask = 0xff00;
    142                 greenMask = 0xff0000;
    143                 redMask = 0xff000000;
    144                 bpp = 32;
    145                 break;
    146             case GL_UNSIGNED_SHORT_5_6_5:
    147                 blueMask = ((1 << 5) - 1) << 0;
    148                 greenMask = ((1 << 6) - 1) << 5;
    149                 redMask = ((1 << 5) - 1) << 11;
    150                 bpp = 16;
    151                 break;
    152             case GL_UNSIGNED_SHORT_4_4_4_4:
    153                 blueMask = ((1 << 4) - 1) << 4;
    154                 greenMask = ((1 << 4) - 1) << 8;
    155                 redMask = ((1 << 4) - 1) << 12;
    156                 bpp = 16;
    157                 break;
    158             case GL_UNSIGNED_SHORT_5_5_5_1:
    159                 blueMask = ((1 << 5) - 1) << 1;
    160                 greenMask = ((1 << 5) - 1) << 6;
    161                 redMask = ((1 << 5) - 1) << 11;
    162                 bpp = 16;
    163                 break;
    164             default:
    165                 showError("unsupported texture format: " + format);
    166                 return null;
    167         }
    168         byte[] pixels = lzfDecompressChunks(data);
    169         assert pixels.length == width * height * (bpp / 8);
    170         PaletteData palette = new PaletteData(redMask, greenMask, blueMask);
    171         return new ImageData(width, height, bpp, palette, 1, pixels);
    172     }
    173 }
    174