base: Redesign internal frame buffer handling
authorAndreas Sandberg <andreas.sandberg@arm.com>
Sat, 23 May 2015 12:37:03 +0000 (13:37 +0100)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Sat, 23 May 2015 12:37:03 +0000 (13:37 +0100)
Currently, frame buffer handling in gem5 is quite ad hoc. In practice,
we pass around naked pointers to raw pixel data and expect consumers
to convert frame buffers using the (broken) VideoConverter.

This changeset completely redesigns the way we handle frame buffers
internally. In summary, it fixes several color conversion bugs, adds
support for more color formats (e.g., big endian), and makes the code
base easier to follow.

In the new world, gem5 always represents pixel data using the Pixel
struct when pixels need to be passed between different classes (e.g.,
a display controller and the VNC server). Producers of entire frames
(e.g., display controllers) should use the FrameBuffer class to
represent a frame.

Frame producers are expected to create one instance of the FrameBuffer
class in their constructors and register it with its consumers
once. Consumers are expected to check the dimensions of the frame
buffer when they consume it.

Conversion between the external representation and the internal
representation is supported for all common "true color" RGB formats of
up to 32-bit color depth. The external pixel representation is
expected to be between 1 and 4 bytes in either big endian or little
endian. Color channels are assumed to be contiguous ranges of bits
within each pixel word. The external pixel value is scaled to an 8-bit
internal representation using a floating multiplication to map it to
the entire 8-bit range.

20 files changed:
src/base/SConscript
src/base/bitmap.cc
src/base/bitmap.hh
src/base/framebuffer.cc [new file with mode: 0644]
src/base/framebuffer.hh [new file with mode: 0644]
src/base/types.hh
src/base/vnc/SConscript
src/base/vnc/convert.cc [deleted file]
src/base/vnc/convert.hh [deleted file]
src/base/vnc/vncinput.cc
src/base/vnc/vncinput.hh
src/base/vnc/vncserver.cc
src/base/vnc/vncserver.hh
src/dev/arm/hdlcd.cc
src/dev/arm/hdlcd.hh
src/dev/arm/pl111.cc
src/dev/arm/pl111.hh
src/sim/byteswap.hh
src/unittest/SConscript
src/unittest/fbtest.cc [new file with mode: 0644]

index e7c420f78e699172caad6c0a4ff1a7ae37c2f91c..a00f8ad6665477e087b6f70a2373ea508bf949ca 100644 (file)
@@ -42,6 +42,7 @@ Source('cprintf.cc')
 Source('debug.cc')
 if env['USE_FENV']:
     Source('fenv.c')
+Source('framebuffer.cc')
 Source('hostinfo.cc')
 Source('inet.cc')
 Source('inifile.cc')
index d83a30be38803fe63b06b47ec96c1274cf8ff69b..0052503a4b115f425e61c45282b9842645bfdb03 100644 (file)
 #include "base/misc.hh"
 
 // bitmap class ctor
-Bitmap::Bitmap(VideoConvert::Mode mode, uint16_t w, uint16_t h, uint8_t *d)
-    : height(h), width(w),
-      header(getCompleteHeader()),
-      data(d),
-      vc(mode, VideoConvert::rgb8888, width, height)
+Bitmap::Bitmap(const FrameBuffer *_fb)
+    : fb(*_fb)
 {
 }
 
@@ -62,7 +59,7 @@ Bitmap::~Bitmap()
 const Bitmap::CompleteV1Header
 Bitmap::getCompleteHeader() const
 {
-    const uint32_t pixel_array_size(sizeof(PixelType) * width * height);
+    const uint32_t pixel_array_size(sizeof(PixelType) * fb.area());
     const uint32_t file_size(sizeof(CompleteV1Header) + pixel_array_size);
 
     const CompleteV1Header header = {
@@ -76,8 +73,8 @@ Bitmap::getCompleteHeader() const
         // Info/DIB header
         {
             sizeof(InfoHeaderV1),
-            width,
-            height,
+            fb.width(),
+            fb.height(),
             1, /* Color planes */
             32, /* Bits per pixel */
             0, /* No compression */
@@ -93,28 +90,25 @@ Bitmap::getCompleteHeader() const
 }
 
 void
-Bitmap::write(std::ostream *bmp) const
+Bitmap::write(std::ostream &bmp) const
 {
-    assert(data);
+    const CompleteV1Header header(getCompleteHeader());
 
     // 1.  write the header
-    bmp->write(reinterpret_cast<const char *>(&header), sizeof(header));
+    bmp.write(reinterpret_cast<const char *>(&header), sizeof(header));
 
     // 2.  write the bitmap data
-    const uint8_t *pixels(vc.convert(data));
-
     // BMP start store data left to right starting with the bottom row
     // so we need to do some creative flipping
-    for (int y = height - 1; y >= 0; y--) {
-        for (int x = 0; x < width; x++) {
-            bmp->write(
-                (const char *)&pixels[sizeof(PixelType) * (y * width + x)],
-                sizeof(PixelType));
-        }
-    }
+    std::vector<PixelType> line_buffer(fb.width());
+    for (int y = 0; y < fb.height(); ++y) {
+        for (unsigned x = 0; x < fb.width(); ++x)
+            line_buffer[x] = fb.pixel(x, fb.height() - y - 1);
 
-    bmp->flush();
+        bmp.write(reinterpret_cast<const char *>(line_buffer.data()),
+                  line_buffer.size() * sizeof(line_buffer[0]));
+    }
 
-    delete[] pixels;
+    bmp.flush();
 }
 
index b06aff10f880a85018c364670bdb159b1aa2e1e7..0797a26a7f415b0bb54b6e5ef335f13a8fa1ad2e 100644 (file)
@@ -45,7 +45,7 @@
 #include <ostream>
 
 #include "base/compiler.hh"
-#include "base/vnc/convert.hh"
+#include "base/framebuffer.hh"
 
 /**
  * @file Declaration of a class that writes a frame buffer to a bitmap
@@ -59,38 +59,17 @@ class  Bitmap
     /**
      * Create a bitmap that takes data in a given mode & size and
      * outputs to an ostream.
-     *
-     * @param mode the type of data that is being provided
-     * @param h the hight of the image
-     * @param w the width of the image
-     * @param d the data for the image in mode
      */
-    Bitmap(VideoConvert::Mode mode, uint16_t w, uint16_t h, uint8_t *d);
+    Bitmap(const FrameBuffer *fb);
 
     ~Bitmap();
 
-    /**
-     * Provide the converter with the data that should be output. It
-     * will be converted into rgb8888 and written when write() is
-     * called.
-     *
-     * @param d the data
-     */
-    void rawData(uint8_t* d) { data = d; }
-
     /**
      * Write the frame buffer data into the provided ostream
      *
      * @param bmp stream to write to
      */
-    void write(std::ostream *bmp) const;
-
-    /**
-     * Gets a hash over the bitmap for quick comparisons to other bitmaps.
-     *
-     * @return hash of the bitmap
-     */
-    uint64_t getHash() const { return vc.getHash(data); }
+    void write(std::ostream &bmp) const;
 
 
   private:
@@ -121,16 +100,26 @@ class  Bitmap
         InfoHeaderV1 info;
     } M5_ATTR_PACKED;
 
-    typedef uint32_t PixelType;
+    struct BmpPixel32 {
+        BmpPixel32 &operator=(const Pixel &rhs) {
+            red = rhs.red;
+            green = rhs.green;
+            blue = rhs.blue;
+            padding = 0;
+
+            return *this;
+        }
+        uint8_t blue;
+        uint8_t green;
+        uint8_t red;
+        uint8_t padding;
+    } M5_ATTR_PACKED;
 
-    const CompleteV1Header getCompleteHeader() const;
+    typedef BmpPixel32 PixelType;
 
-    const uint16_t height;
-    const uint16_t width;
-    const CompleteV1Header header;
-    uint8_t *data;
+    const CompleteV1Header getCompleteHeader() const;
 
-    VideoConvert vc;
+    const FrameBuffer &fb;
 };
 
 #endif // __BASE_BITMAP_HH__
diff --git a/src/base/framebuffer.cc b/src/base/framebuffer.cc
new file mode 100644 (file)
index 0000000..dc4c2e1
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#include "base/framebuffer.hh"
+
+#include <zlib.h>
+
+#include <cassert>
+
+#include "base/bitfield.hh"
+
+const PixelConverter PixelConverter::rgba8888_le(4, 0, 8, 16, 8, 8, 8);
+const PixelConverter PixelConverter::rgba8888_be(4, 0, 8, 16, 8, 8, 8,
+                                                 BigEndianByteOrder);
+const PixelConverter PixelConverter::rgb565_le(2,  0, 5, 11, 5, 6, 5);
+const PixelConverter PixelConverter::rgb565_be(2,  0, 5, 11, 5, 6, 5,
+                                               BigEndianByteOrder);
+
+const FrameBuffer FrameBuffer::dummy(320, 240);
+
+PixelConverter::PixelConverter(unsigned _length,
+                               unsigned ro, unsigned go, unsigned bo,
+                               unsigned rw, unsigned gw, unsigned bw,
+                               ByteOrder _byte_order)
+    : length(_length),
+      depth(rw + gw + bw),
+      byte_order(_byte_order),
+      ch_r(ro, rw),
+      ch_g(go, gw),
+      ch_b(bo, bw)
+{
+    assert(length > 1);
+}
+
+PixelConverter::Channel::Channel(unsigned _offset, unsigned width)
+    : offset(_offset),
+      mask(::mask(width)),
+      factor(255.0 / mask)
+{
+}
+
+uint32_t
+PixelConverter::readWord(const uint8_t *p) const
+{
+    uint32_t word(0);
+
+    if (byte_order == LittleEndianByteOrder) {
+        for (int i = 0; i < length; ++i)
+            word |= p[i] << (8 * i);
+    } else {
+        for (int i = 0; i < length; ++i)
+            word |= p[i] << (8 * (length - i - 1));
+    }
+
+    return word;
+}
+
+void
+PixelConverter::writeWord(uint8_t *p, uint32_t word) const
+{
+    if (byte_order == LittleEndianByteOrder) {
+        for (int i = 0; i < length; ++i)
+            p[i] = (word >> (8 * i)) & 0xFF;
+    } else {
+        for (int i = 0; i < length; ++i)
+            p[i] = (word >> (8 * (length - i - 1))) & 0xFF;
+    }
+}
+
+
+
+
+FrameBuffer::FrameBuffer(unsigned width, unsigned height)
+    : pixels(width * height),
+      _width(width), _height(height)
+{
+    clear();
+}
+
+FrameBuffer::FrameBuffer()
+    : _width(0), _height(0)
+{
+}
+
+FrameBuffer::~FrameBuffer()
+{
+}
+
+void
+FrameBuffer::resize(unsigned width, unsigned height)
+{
+    _width = width;
+    _height = height;
+
+    pixels.resize(width * height);
+}
+
+void
+FrameBuffer::fill(const Pixel &pixel)
+{
+    for (auto &p : pixels)
+        p = pixel;
+}
+
+void
+FrameBuffer::clear()
+{
+    static const Pixel black(0, 0, 0);
+
+    fill(black);
+}
+
+void
+FrameBuffer::copyIn(const uint8_t *fb, const PixelConverter &conv)
+{
+    for (auto &p : pixels) {
+        p = conv.toPixel(fb);
+        fb += conv.length;
+    }
+}
+
+void
+FrameBuffer::copyOut(uint8_t *fb, const PixelConverter &conv) const
+{
+    for (auto &p : pixels) {
+        conv.fromPixel(fb, p);
+        fb += conv.length;
+    }
+}
+
+uint64_t
+FrameBuffer::getHash() const
+{
+    return adler32(0UL,
+                   reinterpret_cast<const Bytef *>(pixels.data()),
+                   area() * sizeof(Pixel));
+}
diff --git a/src/base/framebuffer.hh b/src/base/framebuffer.hh
new file mode 100644 (file)
index 0000000..457c6d0
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#ifndef __BASE_FRAMEBUFFER_HH__
+#define __BASE_FRAMEBUFFER_HH__
+
+#include <cmath>
+#include <cstdint>
+
+#include <vector>
+
+#include "base/types.hh"
+
+/**
+ * Internal gem5 representation of a Pixel.
+ */
+struct Pixel
+{
+    Pixel()
+        : red(0), green(0), blue(0), padding(0) {}
+
+    Pixel(uint8_t _red, uint8_t _green, uint8_t _blue)
+        : red(_red), green(_green), blue(_blue), padding(0) {}
+
+    uint8_t red;
+    uint8_t green;
+    uint8_t blue;
+    uint8_t padding;
+};
+
+inline bool
+operator==(const Pixel &lhs, const Pixel &rhs)
+{
+    return lhs.red == rhs.red &&
+        lhs.green == rhs.green &&
+        lhs.blue == rhs.blue &&
+        lhs.padding == rhs.padding;
+}
+
+
+/**
+ * Configurable RGB pixel converter.
+ *
+ * This class converts between external RGB representations and gem5's
+ * internal Pixel representation. The class assumes that pixels are
+ * stored in a word of configurable length (up to 32 bits). Individual
+ * pixels are assumed to be represented by contiguous bit ranges in
+ * the word (i.e., it is possible to shift and mask out a contiguous
+ * bit range for each pixel).
+ */
+class PixelConverter
+{
+  public:
+    /**
+     * Color channel conversion and scaling helper class.
+     */
+    struct Channel {
+        /**
+         * @param offset Offset in bits.
+         * @param width Width in bits.
+         */
+        Channel(unsigned offset, unsigned width);
+
+        /**
+         * Get the value of a single color channel represented as an
+         * 8-bit number.
+         */
+        uint8_t toPixel(uint32_t word) const {
+            return round(((word >> offset) & mask) * factor);
+        }
+
+        /**
+         * Convert an 8-bit representation of a color into an external
+         * format.
+         */
+        uint32_t fromPixel(uint8_t ch) const {
+            return (static_cast<uint8_t>(round(ch / factor)) & mask) << offset;
+        }
+
+        /** Offset in bits */
+        unsigned offset;
+        /** Bit mask (after shifting) */
+        unsigned mask;
+        /**
+         * Scaling factor when converting to the full range of an
+         * 8-bit color channel
+         */
+        float factor;
+    };
+
+    PixelConverter(unsigned length,
+                   unsigned ro, unsigned go, unsigned bo,
+                   unsigned rw, unsigned gw, unsigned bw,
+                   ByteOrder byte_order = LittleEndianByteOrder);
+
+    /** Get the Pixel representation of a color word. */
+    Pixel toPixel(uint32_t word) const {
+        return Pixel(ch_r.toPixel(word),
+                     ch_g.toPixel(word),
+                     ch_b.toPixel(word));
+    }
+
+    /** Get a Pixel representation by reading a word from memory. */
+    Pixel toPixel(const uint8_t *rfb) const {
+        return toPixel(readWord(rfb));
+    }
+
+    /** Convert a Pixel into a color word */
+    uint32_t fromPixel(const Pixel &pixel) const {
+        return ch_r.fromPixel(pixel.red) |
+            ch_g.fromPixel(pixel.green) |
+            ch_b.fromPixel(pixel.blue);
+    }
+
+    /**
+     * Convert a pixel into a color word and store the resulting word
+     * in memory.
+     */
+    void fromPixel(uint8_t *rfb, const Pixel &pixel) const {
+        writeWord(rfb, fromPixel(pixel));
+    }
+
+    /**
+     * Read a word of a given length and endianness from memory.
+     *
+     * The number of bytes read from memory is determined by the
+     * length of a color word. Note that some of the bytes may be
+     * padding.
+     *
+     * @param p Pointer to the first byte in the word.
+     * @return Word in host endianness.
+     */
+    uint32_t readWord(const uint8_t *p) const;
+    /**
+     * Write a word of a given length and endianness to memory.
+     *
+     * @param p Pointer to the first byte in memory.
+     * @param word Word to store (host endianness).
+     */
+    void writeWord(uint8_t *p, uint32_t word) const;
+
+    /** Bytes per pixel when stored in memory (including padding) */
+    unsigned length;
+    /**
+     * Number of bits used to represent one pixel value (excluding
+     * padding). This could be less than length * 8 if the pixel value
+     * is padded.
+     */
+    unsigned depth;
+    /** Byte order when stored to memory. */
+    ByteOrder byte_order;
+
+    /** Red channel conversion helper */
+    Channel ch_r;
+    /** Green channel conversion helper */
+    Channel ch_g;
+    /** Blue channel conversion helper */
+    Channel ch_b;
+
+    /** Predefined 32-bit RGB (red in least significant bits, 8
+     * bits/channel, little endian) conversion helper */
+    static const PixelConverter rgba8888_le;
+    /** Predefined 16-bit RGB565 (red in least significant bits,
+     * little endian) conversion helper */
+    static const PixelConverter rgb565_le;
+
+    /** Predefined 32-bit RGB (red in least significant bits, 8
+     * bits/channel, big endian) conversion helper */
+    static const PixelConverter rgba8888_be;
+    /** Predefined 16-bit RGB565 (red in least significant bits,
+     * big endian) conversion helper */
+    static const PixelConverter rgb565_be;
+};
+
+/**
+ * Internal gem5 representation of a frame buffer
+ *
+ * Display controllers and other devices producing images are expected
+ * to use this class to represent the final image.
+ *
+ * Pixels are indexed relative to the upper left corner of the
+ * image. That is, the pixel at position (0, 0) is the upper left
+ * corner. The backing store is a linear vector of Pixels ordered left
+ * to right starting in the upper left corner.
+ */
+class FrameBuffer
+{
+  public:
+    /**
+     * Create a frame buffer of a given size.
+     *
+     * @param width Width in pixels
+     * @param height Height in pixels
+     */
+    FrameBuffer(unsigned width, unsigned height);
+    /** Create an empty (0x0) frame buffer */
+    FrameBuffer();
+
+    virtual ~FrameBuffer();
+
+    /**
+     * Resize the frame buffer.
+     *
+     * This method resizes frame buffer including the backing
+     * store. The contents of the backing store are undefined after
+     * this operation.
+     *
+     * @param with Width in pixels.
+     * @param height Height in pixels.
+     */
+    void resize(unsigned width, unsigned height);
+
+    /** Frame buffer width in pixels */
+    unsigned width() const { return _width; }
+    /** Frame buffer height in pixels */
+    unsigned height() const { return _height; }
+    /** Total number of pixels in frame buffer */
+    unsigned area() const { return _width * _height; }
+
+    /**
+     * Fill the frame buffer with a single pixel value
+     *
+     * @param pixel Pixel value to fill with.
+     */
+    void fill(const Pixel &pixel);
+    /**
+     * Fill the frame buffer with black pixels
+     */
+    void clear();
+
+    /**
+     * Fill the frame buffer with pixel data from an external buffer
+     * of the same width and height as this frame buffer.
+     *
+     * @param fb External frame buffer
+     * @param conv Pixel conversion helper
+     */
+    void copyIn(const uint8_t *fb, const PixelConverter &conv);
+    /**
+     * Fill the frame buffer with pixel data from an external buffer
+     * of the same width and height as this frame buffer.
+     *
+     * @param fb External frame buffer
+     * @param conv Pixel conversion helper
+     */
+    void copyIn(const std::vector<uint8_t> &fb, const PixelConverter &conv) {
+        copyIn(fb.data(), conv);
+    }
+
+    /**
+     * Store the contents of this frame buffer in an external buffer
+     * of the same width and height as this frame buffer.
+     *
+     * @param fb External frame buffer
+     * @param conv Pixel conversion helper
+     */
+    void copyOut(uint8_t *fb, const PixelConverter &conv) const;
+    /**
+     * Store the contents of this frame buffer in an external buffer
+     * of the same width and height as this frame buffer.
+     *
+     * @param fb External frame buffer
+     * @param conv Pixel conversion helper
+     */
+    void copyOut(std::vector<uint8_t> &fb, const PixelConverter &conv) const {
+        copyOut(fb.data(), conv);
+    }
+
+    /**
+     * Get a pixel from an (x, y) coordinate
+     *
+     * @param x Distance from the left margin.
+     * @param y Distance from the top of the frame.
+     */
+    const Pixel &pixel(unsigned x, unsigned y) const {
+        assert(x < _width);
+        assert(y < _height);
+
+        return pixels[y * _width + x];
+    }
+
+    /**
+     * Get a pixel from an (x, y) coordinate
+     *
+     * @param x Distance from the left margin.
+     * @param y Distance from the top of the frame.
+     */
+    Pixel &pixel(unsigned x, unsigned y) {
+        assert(x < _width);
+        assert(y < _height);
+
+        return pixels[y * _width + x];
+    }
+
+    /**
+     * Create a hash of the image that can be used for quick
+     * comparisons.
+     */
+    uint64_t getHash() const;
+
+    /**
+     * Static "dummy" frame buffer.
+     *
+     * This is a dummy frame buffer that can be used as a place holder
+     * for devices that always expect a frame buffer to be present.
+     */
+    static const FrameBuffer dummy;
+
+    /** Frame buffer backing store */
+    std::vector<Pixel> pixels;
+
+  protected:
+    /** Width in pixels */
+    unsigned _width;
+    /** Height in pixels */
+    unsigned _height;
+};
+
+#endif // __BASE_FRAMEBUFFER_HH__
index c4cb4d988d664da8a1a2db621c3e61b41bf33bae..2b6e3f11bcb3a8ed851d948c98f541ec1271e891 100644 (file)
@@ -188,4 +188,9 @@ typedef std::shared_ptr<FaultBase> Fault;
 constexpr decltype(nullptr) NoFault = nullptr;
 #endif
 
+enum ByteOrder {
+    BigEndianByteOrder,
+    LittleEndianByteOrder
+};
+
 #endif // __BASE_TYPES_HH__
index 416743200193039d76d15d1f1f0e2c47ef33790c..271f894ced66b3e34a6679f66769acac89555284 100644 (file)
@@ -39,8 +39,6 @@
 
 Import('*')
 
-Source('convert.cc')
-
 SimObject('Vnc.py')
 Source('vncinput.cc')
 Source('vncserver.cc')
diff --git a/src/base/vnc/convert.cc b/src/base/vnc/convert.cc
deleted file mode 100644 (file)
index 2a52cca..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2011 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- *          William Wang
- */
-
-#include <cassert>
-
-#include "base/vnc/convert.hh"
-#include "base/misc.hh"
-
-/** @file
- * This file provides conversion functions for a variety of video modes
- */
-
-VideoConvert::VideoConvert(Mode input_mode, Mode output_mode, int _width,
-        int _height)
-    : inputMode(input_mode), outputMode(output_mode), width(_width),
-    height(_height)
-{
-    if (inputMode != bgr565 && inputMode != rgb565 &&
-        inputMode != bgr8888 && inputMode != bgr888)
-        fatal("Only support converting from bgr565, rdb565, "
-              "bgr8888 and bgr888\n");
-
-    if (outputMode != rgb8888)
-        fatal("Only support converting to rgb8888\n");
-
-    assert(0 < height && height < 4000);
-    assert(0 < width && width < 4000);
-}
-
-VideoConvert::~VideoConvert()
-{
-}
-
-uint8_t*
-VideoConvert::convert(const uint8_t *fb) const
-{
-    switch (inputMode) {
-      case bgr565:
-        return m565rgb8888(fb, true);
-      case rgb565:
-        return m565rgb8888(fb, false);
-      case bgr8888:
-        return bgr8888rgb8888(fb);
-      case bgr888:
-        return bgr888rgb8888(fb);
-      default:
-        panic("Unimplemented Mode\n");
-    }
-}
-
-uint8_t*
-VideoConvert::m565rgb8888(const uint8_t *fb, bool bgr) const
-{
-    uint8_t *out = new uint8_t[area() * sizeof(uint32_t)];
-    uint32_t *out32 = (uint32_t*)out;
-
-    uint16_t *in16 = (uint16_t*)fb;
-
-    for (int x = 0; x < area(); x++) {
-        Bgr565 inpx;
-        Rgb8888 outpx = 0;
-
-        inpx = in16[x];
-
-        if (bgr) {
-            outpx.red = inpx.blue << 3;
-            outpx.green = inpx.green << 2;
-            outpx.blue = inpx.red << 3;
-        } else {
-            outpx.blue = inpx.blue << 3;
-            outpx.green = inpx.green << 2;
-            outpx.red = inpx.red << 3;
-        }
-
-        out32[x] = outpx;
-    }
-
-    return out;
-}
-
-
-uint8_t*
-VideoConvert::bgr8888rgb8888(const uint8_t *fb) const
-{
-    uint8_t *out = new uint8_t[area() * sizeof(uint32_t)];
-    uint32_t *out32 = (uint32_t*)out;
-
-    uint32_t *in32 = (uint32_t*)fb;
-
-    for (int x = 0; x < area(); x++) {
-        Rgb8888 outpx = 0;
-        Bgr8888 inpx;
-
-
-        inpx = in32[x];
-
-        outpx.red = inpx.blue;
-        outpx.green = inpx.green;
-        outpx.blue = inpx.red;
-
-        out32[x] = outpx;
-    }
-
-    return out;
-}
-
-uint8_t*
-VideoConvert::bgr888rgb8888(const uint8_t *fb) const
-{
-    uint8_t *out = new uint8_t[area() * sizeof(uint32_t)];
-    uint32_t *out32 = (uint32_t*)out;
-
-    typedef uint8_t In24[3];
-    const In24 *in24 = (In24 *)fb;
-    for (int x = 0; x < area(); x++) {
-        Rgb8888 outpx = 0;
-
-        outpx.blue = in24[x][0];
-        outpx.green = in24[x][1];
-        outpx.red = in24[x][2];
-        outpx.alpha = 0xFF;
-
-        out32[x] = outpx;
-    }
-
-    return out;
-}
-
-/*
-uint64_t
-VideoConvert::getHash(const uint8_t *fb) const
-{
-    const uint8_t *fb_e = fb + area();
-
-    uint64_t hash = 1;
-    while (fb < fb_e - 8) {
-        hash += *((const uint64_t*)fb);
-        fb += 8;
-    }
-
-    while (fb < fb_e) {
-        hash += *(fb++);
-    }
-
-    return hash;
-}*/
diff --git a/src/base/vnc/convert.hh b/src/base/vnc/convert.hh
deleted file mode 100644 (file)
index 592076c..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2011 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-/** @file
- * This file provides conversion functions for a variety of video modes
- */
-
-#ifndef __BASE_VNC_CONVERT_HH__
-#define __BASE_VNC_CONVERT_HH__
-
-#include <zlib.h>
-#include "base/bitunion.hh"
-
-class VideoConvert
-{
-  public:
-    enum Mode {
-        UnknownMode,
-        bgr565,
-        rgb565,
-        bgr8888,
-        rgb8888,
-        rgb888,
-        bgr888,
-        bgr444,
-        bgr4444,
-        rgb444,
-        rgb4444
-    };
-
-    // supports bpp32 RGB (bmp) and bpp16 5:6:5 mode BGR (linux)
-    BitUnion32(Rgb8888)
-        Bitfield<7,0> blue;
-        Bitfield<15,8> green;
-        Bitfield<23,16> red;
-        Bitfield<31,24> alpha;
-    EndBitUnion(Rgb8888)
-
-    BitUnion32(Bgr8888)
-        Bitfield<7,0> red;
-        Bitfield<15,8> green;
-        Bitfield<23,16> blue;
-        Bitfield<31,24> alpha;
-    EndBitUnion(Bgr8888)
-
-    BitUnion16(Bgr565)
-        Bitfield<4,0> red;
-        Bitfield<10,5> green;
-        Bitfield<15,11> blue;
-    EndBitUnion(Bgr565)
-
-    BitUnion16(Rgb565)
-        Bitfield<4,0> red;
-        Bitfield<10,5> green;
-        Bitfield<15,11> blue;
-    EndBitUnion(Rgb565)
-
-    /** Setup the converter with the given parameters
-     * @param input_mode type of data that will be provided
-     * @param output_mode type of data that should be output
-     * @param _width width of the frame buffer
-     * @param _height height of the frame buffer
-     */
-    VideoConvert(Mode input_mode, Mode output_mode, int _width, int _height);
-
-    /** Destructor
-     */
-    ~VideoConvert();
-
-    /** Convert the provided frame buffer data into the format specified in the
-     * constructor.
-     * @param fb the frame buffer to convert
-     * @return the converted data (user must free)
-     */
-    uint8_t* convert(const uint8_t *fb) const;
-
-    /** Return the number of pixels that this buffer specifies
-     * @return number of pixels
-     */
-    int area() const { return width * height; }
-
-    /**
-     * Returns a hash on the raw data.
-     *
-     * @return hash of the buffer
-     */
-    inline uint64_t getHash(const uint8_t *fb) const {
-        return adler32(0UL, fb, width * height);
-    }
-
-  private:
-
-    /**
-     * Convert a bgr8888 input to rgb8888.
-     * @param fb the data to convert
-     * @return converted data
-     */
-    uint8_t* bgr8888rgb8888(const uint8_t *fb) const;
-
-    /**
-     * Convert a bgr888 input to rgb8888.
-     * @param fb the data to convert
-     * @return converted data
-     */
-    uint8_t* bgr888rgb8888(const uint8_t *fb) const;
-
-    /**
-     * Convert a bgr565 or rgb565 input to rgb8888.
-     * @param fb the data to convert
-     * @param bgr true if the input data is bgr565
-     * @return converted data
-     */
-    uint8_t* m565rgb8888(const uint8_t *fb, bool bgr) const;
-
-    Mode inputMode;
-    Mode outputMode;
-    int width;
-    int height;
-};
-
-#endif // __BASE_VNC_CONVERT_HH__
-
index 071804583bc6096dacdf91df8eb43c8915443086..017fc387681f5e4fd2558d73defae6d1fb9c93e5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -53,9 +53,10 @@ using namespace std;
 
 VncInput::VncInput(const Params *p)
     : SimObject(p), keyboard(NULL), mouse(NULL),
-      vc(NULL), fbPtr(NULL), videoMode(VideoConvert::UnknownMode),
-      _videoWidth(1), _videoHeight(1), captureEnabled(p->frame_capture),
-      captureCurrentFrame(0), captureLastHash(0), captureBitmap(0)
+      fb(&FrameBuffer::dummy),
+      _videoWidth(fb->width()), _videoHeight(fb->height()),
+      captureEnabled(p->frame_capture),
+      captureCurrentFrame(0), captureLastHash(0)
 {
     if (captureEnabled) {
         // remove existing frame output directory if it exists, then create a
@@ -68,33 +69,40 @@ VncInput::VncInput(const Params *p)
 }
 
 void
-VncInput::setFrameBufferParams(VideoConvert::Mode mode, uint16_t width,
-    uint16_t height)
+VncInput::setFrameBuffer(const FrameBuffer *rfb)
 {
-    DPRINTF(VNC, "Updating video params: mode: %d width: %d height: %d\n", mode,
-            width, height);
+    if (!rfb)
+        panic("Trying to VNC frame buffer to NULL!");
 
-    if (mode != videoMode || width != videoWidth() || height != videoHeight()) {
-        videoMode = mode;
-        _videoWidth = width;
-        _videoHeight = height;
+    fb = rfb;
+
+    // create bitmap of the frame with new attributes
+    if (captureEnabled)
+        captureBitmap.reset(new Bitmap(rfb));
+
+    // Setting a new frame buffer means that we need to send an update
+    // to the client. Mark the internal buffers as dirty to do so.
+    setDirty();
+}
 
-        if (vc)
-            delete vc;
+void
+VncInput::setDirty()
+{
+    const unsigned width(fb->width());
+    const unsigned height(fb->height());
 
-        vc = new VideoConvert(mode, VideoConvert::rgb8888, videoWidth(),
-                videoHeight());
+    if (_videoWidth != width || _videoHeight != height) {
+        DPRINTF(VNC, "Updating video params: width: %d height: %d\n",
+                width, height);
 
-        if (captureEnabled) {
-            // create bitmap of the frame with new attributes
-            if (captureBitmap)
-                delete captureBitmap;
+        _videoWidth = width;
+        _videoHeight = height;
 
-            assert(fbPtr);
-            captureBitmap = new Bitmap(videoMode, width, height, fbPtr);
-            assert(captureBitmap);
-        }
+        frameBufferResized();
     }
+
+     if (captureEnabled)
+        captureFrameBuffer();
 }
 
 void
@@ -103,7 +111,7 @@ VncInput::captureFrameBuffer()
     assert(captureBitmap);
 
     // skip identical frames
-    uint64_t new_hash = captureBitmap->getHash();
+    uint64_t new_hash = fb->getHash();
     if (captureLastHash == new_hash)
         return;
     captureLastHash = new_hash;
@@ -116,8 +124,8 @@ VncInput::captureFrameBuffer()
 
     // create the compressed framebuffer file
     ostream *fb_out = simout.create(captureOutputDirectory + frameFilename,
-                    true);
-    captureBitmap->write(fb_out);
+                                    true);
+    captureBitmap->write(*fb_out);
     simout.close(fb_out);
 
     ++captureCurrentFrame;
index 1686e3f25191840feda65e93db09276c969ddaf8..96235fec7dc352390379cd3f43cb10e06388eebf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -46,8 +46,8 @@
 #define __BASE_VNC_VNC_INPUT_HH__
 
 #include <iostream>
+#include <memory>
 
-#include "base/vnc/convert.hh"
 #include "base/bitmap.hh"
 #include "params/VncInput.hh"
 #include "sim/sim_object.hh"
@@ -160,11 +160,7 @@ class VncInput : public SimObject
      * tell us where the data is instead of constanly copying it around
      * @param rfb frame buffer that we're going to use
      */
-    void
-    setFramebufferAddr(uint8_t* rfb)
-    {
-        fbPtr = rfb;
-    }
+    virtual void setFrameBuffer(const FrameBuffer *rfb);
 
     /** Set up the device that would like to receive notifications when keys are
      * pressed in the vnc client keyboard
@@ -196,32 +192,19 @@ class VncInput : public SimObject
      * the frame buffer has been updated and a new image needs to be sent to the
      * client
      */
-    virtual void setDirty()
-    {
-        if (captureEnabled)
-            captureFrameBuffer();
-    }
-
-    /** Set the mode of the data the frame buffer will be sending us
-     * @param mode the mode
-     */
-    virtual void setFrameBufferParams(VideoConvert::Mode mode, uint16_t width, uint16_t height);
+    virtual void setDirty();
 
   protected:
+    virtual void frameBufferResized() {};
+
     /** The device to notify when we get key events */
     VncKeyboard *keyboard;
 
     /** The device to notify when we get mouse events */
     VncMouse *mouse;
 
-    /** The video converter that transforms data for us */
-    VideoConvert *vc;
-
     /** pointer to the actual data that is stored in the frame buffer device */
-    uint8_t* fbPtr;
-
-    /** The mode of data we're getting frame buffer in */
-    VideoConvert::Mode videoMode;
+    const FrameBuffer *fb;
 
     /** the width of the frame buffer we are sending to the client */
     uint16_t _videoWidth;
@@ -242,7 +225,7 @@ class VncInput : public SimObject
     uint64_t captureLastHash;
 
     /** Cached bitmap object for writing out frame buffers to file */
-    Bitmap *captureBitmap;
+    std::unique_ptr<Bitmap> captureBitmap;
 
     /** Captures the current frame buffer to a file */
     void captureFrameBuffer();
index 6dc2f2f1098ac30be649a25c7a006a42b0942d28..20f3bc8fedf62a387b66b44552cd28cf02c5e01c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -61,6 +61,7 @@
 
 #include <cerrno>
 #include <cstdio>
+#include <cstddef>
 
 #include "base/atomicio.hh"
 #include "base/bitmap.hh"
 
 using namespace std;
 
+const PixelConverter VncServer::pixelConverter(
+    4,        // 4 bytes / pixel
+    16, 8, 0, // R in [23, 16], G in [15, 8], B in [7, 0]
+    8, 8, 8,  // 8 bits / channel
+    LittleEndianByteOrder);
+
 /** @file
  * Implementiation of a VNC server
  */
@@ -122,20 +129,19 @@ VncServer::VncServer(const Params *p)
 
     curState = WaitForProtocolVersion;
 
-    // currently we only support this one pixel format
-    // unpacked 32bit rgb (rgb888 + 8 bits of nothing/alpha)
-    // keep it around for telling the client and making
-    // sure the client cooperates
-    pixelFormat.bpp = 32;
-    pixelFormat.depth = 24;
-    pixelFormat.bigendian = 0;
+    // We currently only support one pixel format. Extract the pixel
+    // representation from our PixelConverter instance and keep it
+    // around for telling the client and making sure it cooperates
+    pixelFormat.bpp = 8 * pixelConverter.length;
+    pixelFormat.depth = pixelConverter.depth;
+    pixelFormat.bigendian = pixelConverter.byte_order == BigEndianByteOrder;
     pixelFormat.truecolor = 1;
-    pixelFormat.redmax = 0xff;
-    pixelFormat.greenmax = 0xff;
-    pixelFormat.bluemax = 0xff;
-    pixelFormat.redshift = 16;
-    pixelFormat.greenshift = 8;
-    pixelFormat.blueshift = 0;
+    pixelFormat.redmax = pixelConverter.ch_r.mask;
+    pixelFormat.greenmax = pixelConverter.ch_g.mask;
+    pixelFormat.bluemax = pixelConverter.ch_b.mask;
+    pixelFormat.redshift = pixelConverter.ch_r.offset;
+    pixelFormat.greenshift = pixelConverter.ch_g.offset;
+    pixelFormat.blueshift = pixelConverter.ch_b.offset;
 
     DPRINTF(VNC, "Vnc server created at port %d\n", p->port);
 }
@@ -615,13 +621,11 @@ void
 VncServer::sendFrameBufferUpdate()
 {
 
-    if (!fbPtr || dataFd <= 0 || curState != NormalPhase || !sendUpdate) {
+    if (dataFd <= 0 || curState != NormalPhase || !sendUpdate) {
         DPRINTF(VNC, "NOT sending framebuffer update\n");
         return;
     }
 
-    assert(vc);
-
     // The client will request data constantly, unless we throttle it
     sendUpdate = false;
 
@@ -650,19 +654,25 @@ VncServer::sendFrameBufferUpdate()
     write(&fbu);
     write(&fbr);
 
-    assert(fbPtr);
+    assert(fb);
 
-    uint8_t *tmp = vc->convert(fbPtr);
-    uint64_t num_pixels = videoWidth() * videoHeight();
-    write(tmp, num_pixels * sizeof(uint32_t));
-    delete [] tmp;
+    std::vector<uint8_t> line_buffer(pixelConverter.length * fb->width());
+    for (int y = 0; y < fb->height(); ++y) {
+        // Convert and send a line at a time
+        uint8_t *raw_pixel(line_buffer.data());
+        for (unsigned x = 0; x < fb->width(); ++x) {
+            pixelConverter.fromPixel(raw_pixel, fb->pixel(x, y));
+            raw_pixel += pixelConverter.length;
+        }
 
+        write(line_buffer.data(), line_buffer.size());
+    }
 }
 
 void
 VncServer::sendFrameBufferResized()
 {
-    assert(fbPtr && dataFd > 0 && curState == NormalPhase);
+    assert(fb && dataFd > 0 && curState == NormalPhase);
     DPRINTF(VNC, "Sending framebuffer resize\n");
 
     FrameBufferUpdate fbu;
@@ -692,19 +702,23 @@ VncServer::sendFrameBufferResized()
 }
 
 void
-VncServer::setFrameBufferParams(VideoConvert::Mode mode, uint16_t width,
-    uint16_t height)
+VncServer::setDirty()
 {
-    VncInput::setFrameBufferParams(mode, width, height);
-
-    if (mode != videoMode || width != videoWidth() || height != videoHeight()) {
-        if (dataFd > 0 && fbPtr && curState == NormalPhase) {
-            if (supportsResizeEnc)
-                sendFrameBufferResized();
-            else
-                // The frame buffer changed size and we can't update the client
-                detach();
-        }
+    VncInput::setDirty();
+
+    sendUpdate = true;
+    sendFrameBufferUpdate();
+}
+
+void
+VncServer::frameBufferResized()
+{
+    if (dataFd > 0 && curState == NormalPhase) {
+        if (supportsResizeEnc)
+            sendFrameBufferResized();
+        else
+            // The frame buffer changed size and we can't update the client
+            detach();
     }
 }
 
index cd1f186f58e4b3913dd3399f8b90fa9e34ec8775..0222a7726f57838ff961c93d4a07bc4f5e1ae70e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -47,7 +47,6 @@
 
 #include <iostream>
 
-#include "base/vnc/convert.hh"
 #include "base/vnc/vncinput.hh"
 #include "base/bitmap.hh"
 #include "base/circlebuf.hh"
@@ -305,24 +304,11 @@ class VncServer : public VncInput
      */
     void sendFrameBufferResized();
 
-  public:
-    /** The frame buffer uses this call to notify the vnc server that
-     * the frame buffer has been updated and a new image needs to be sent to the
-     * client
-     */
-    void
-    setDirty()
-    {
-        VncInput::setDirty();
-        sendUpdate = true;
-        sendFrameBufferUpdate();
-    }
+    static const PixelConverter pixelConverter;
 
-    /** Set the mode of the data the frame buffer will be sending us
-     * @param mode the mode
-     */
-    void setFrameBufferParams(VideoConvert::Mode mode, uint16_t width,
-        uint16_t height);
+  public:
+    void setDirty() M5_ATTR_OVERRIDE;
+    void frameBufferResized() M5_ATTR_OVERRIDE;
 };
 
 #endif
index 37569b22b32d099b7adbe0509c9bd5c0b92ce83e..b1c1c450ba945b4ab3e18d556b7bfa7b6231b20c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 ARM Limited
+ * Copyright (c) 2010-2013, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  * Authors: Chris Emmons
  */
 
+#include "dev/arm/hdlcd.hh"
+
 #include "base/vnc/vncinput.hh"
-#include "base/bitmap.hh"
 #include "base/output.hh"
 #include "base/trace.hh"
 #include "debug/HDLcd.hh"
 #include "debug/Uart.hh"
 #include "dev/arm/amba_device.hh"
 #include "dev/arm/base_gic.hh"
-#include "dev/arm/hdlcd.hh"
 #include "mem/packet.hh"
 #include "mem/packet_access.hh"
 #include "sim/system.hh"
@@ -63,10 +63,11 @@ HDLcd::HDLcd(const Params *p)
       h_sync(0), h_back_porch(0), h_data(0), h_front_porch(0),
       polarities(0), command(0), pixel_format(0),
       red_select(0), green_select(0), blue_select(0),
-      pixelClock(p->pixel_clock), vnc(p->vnc), bmp(NULL), pic(NULL),
+      pixelClock(p->pixel_clock),
+      fb(0, 0), vnc(p->vnc), bmp(&fb), pic(NULL),
       frameReadStartTime(0),
       dmaStartAddr(0), dmaCurAddr(0), dmaMaxAddr(0), dmaPendingNum(0),
-      frameUnderrun(false), virtualDisplayBuffer(NULL), pixelBufferSize(0),
+      frameUnderrun(false), pixelBufferSize(0),
       pixelIndex(0), doUpdateParams(false), frameUnderway(false),
       dmaBytesInFlight(0),
       startFrameEvent(this), endFrameEvent(this), renderPixelEvent(this),
@@ -81,13 +82,11 @@ HDLcd::HDLcd(const Params *p)
         dmaDoneEventFree[i] = &dmaDoneEventAll[i];
 
     if (vnc)
-        vnc->setFramebufferAddr(NULL);
+        vnc->setFrameBuffer(&fb);
 }
 
 HDLcd::~HDLcd()
 {
-    if (virtualDisplayBuffer)
-        delete [] virtualDisplayBuffer;
 }
 
 // read registers and frame buffer
@@ -315,8 +314,14 @@ HDLcd::write(PacketPtr pkt)
 void
 HDLcd::updateVideoParams(bool unserializing = false)
 {
-    const uint16_t bpp = bytesPerPixel() << 3;
-    const size_t buffer_size = bytesPerPixel() * width() * height();
+    const uint16_t bpp M5_VAR_USED = bytesPerPixel() << 3;
+
+    // Workaround configuration bugs where multiple display
+    // controllers are attached to the same VNC server by reattaching
+    // enabled devices. This isn't ideal, but works as long as only
+    // one display controller is active at a time.
+    if (command.enable && vnc)
+        vnc->setFrameBuffer(&fb);
 
     // updating these parameters while LCD is enabled is not supported
     if (frameUnderway && !unserializing)
@@ -328,18 +333,14 @@ HDLcd::updateVideoParams(bool unserializing = false)
     // there must be no outstanding DMA transactions for this to work
     if (!unserializing) {
         assert(dmaPendingNum == 0);
-        if (virtualDisplayBuffer)
-            delete [] virtualDisplayBuffer;
-        virtualDisplayBuffer = new uint8_t[buffer_size];
-        memset(virtualDisplayBuffer, 0, buffer_size);
-    }
 
-    assert(virtualDisplayBuffer);
-    if (vnc)
-        vnc->setFramebufferAddr(virtualDisplayBuffer);
+        virtualDisplayBuffer.resize(bytesPerPixel() * area());
+        fb.resize(width(), height());
+        fb.clear();
 
-    if (bmp)
-        delete bmp;
+        std::fill(virtualDisplayBuffer.begin(), virtualDisplayBuffer.end(),
+                  0);
+    }
 
     DPRINTF(HDLcd, "bpp = %d\n", bpp);
     DPRINTF(HDLcd, "display size = %d x %d\n", width(), height());
@@ -354,61 +355,11 @@ HDLcd::updateVideoParams(bool unserializing = false)
     DPRINTF(HDLcd, "simulated refresh rate ~ %.1ffps generating ~ %.1fMB/s "
             "traffic ([%.1fMHz, T=%d sim clocks] pclk, %d bpp => %.1fMB/s peak requirement)\n",
             fps,
-            fps * buffer_size / 1024 / 1024,
+            fps * virtualDisplayBuffer.size() / 1024 / 1024,
             (double)SimClock::Frequency / pixelClock / 1000000.0,
             pixelClock,
             bpp,
             (double)(SimClock::Frequency / pixelClock * (bpp / 8)) / 1024 / 1024);
-
-    if (pixel_format.big_endian)
-        panic("Big Endian pixel format not implemented by HDLcd controller");
-
-    if (vnc) {
-        if ((bpp == 24) &&
-                (red_select.size == 8) &&
-                (blue_select.size == 8) &&
-                (green_select.size == 8) &&
-                (green_select.offset == 8)) {
-            if ((blue_select.offset == 0) &&
-                    (red_select.offset == 16)) {
-                vnc->setFrameBufferParams(VideoConvert::rgb8888, width(),
-                        height());
-                bmp = new Bitmap(VideoConvert::rgb8888, width(), height(),
-                        virtualDisplayBuffer);
-                DPRINTF(HDLcd, "color mode:  rgb888\n");
-            } else if ((red_select.offset == 0) &&
-                    (blue_select.offset == 16)) {
-                vnc->setFrameBufferParams(VideoConvert::bgr8888, width(),
-                        height());
-                bmp = new Bitmap(VideoConvert::bgr8888, width(), height(),
-                        virtualDisplayBuffer);
-                DPRINTF(HDLcd, "color mode:  bgr888\n");
-            }
-        } else if ((bpp == 16) &&
-                (red_select.size == 5) &&
-                (blue_select.size == 5) &&
-                (green_select.size == 6) &&
-                (green_select.offset == 5)) {
-            if ((blue_select.offset == 0) &&
-                    (red_select.offset == 11)) {
-                vnc->setFrameBufferParams(VideoConvert::rgb565, width(),
-                        height());
-                bmp = new Bitmap(VideoConvert::rgb565, width(), height(),
-                        virtualDisplayBuffer);
-                DPRINTF(HDLcd, "color mode:  rgb565\n");
-            } else if ((red_select.offset == 0) &&
-                    (blue_select.offset == 11)) {
-                vnc->setFrameBufferParams(VideoConvert::bgr565, width(),
-                        height());
-                bmp = new Bitmap(VideoConvert::bgr565, width(), height(),
-                        virtualDisplayBuffer);
-                DPRINTF(HDLcd, "color mode:  bgr565\n");
-            }
-        } else {
-            DPRINTF(HDLcd, "color mode:  undefined\n");
-            panic("Unimplemented video mode\n");
-        }
-    }
 }
 
 void
@@ -424,7 +375,7 @@ HDLcd::startFrame()
         doUpdateParams = false;
     }
     frameUnderway = true;
-    assert(virtualDisplayBuffer);
+    assert(!virtualDisplayBuffer.empty());
     assert(pixelBufferSize == 0);
     assert(dmaBytesInFlight == 0);
     assert(dmaPendingNum == 0);
@@ -484,10 +435,11 @@ HDLcd::fillPixelBuffer()
         // will be uncacheable as well. If we have uncacheable and cacheable
         // requests in the memory system for the same address it won't be
         // pleased
+        uint8_t *const dma_dst(
+            virtualDisplayBuffer.data() + dmaCurAddr - dmaStartAddr);
         event->setTransactionSize(transaction_size);
         dmaPort.dmaAction(MemCmd::ReadReq, dmaCurAddr, transaction_size, event,
-                          virtualDisplayBuffer + dmaCurAddr - dmaStartAddr,
-                          0, Request::UNCACHEABLE);
+                          dma_dst, 0, Request::UNCACHEABLE);
         dmaCurAddr += transaction_size;
         dmaBytesInFlight += transaction_size;
     }
@@ -549,6 +501,16 @@ HDLcd::renderPixel()
     schedule(renderPixelEvent, nextEventTick);
 }
 
+PixelConverter
+HDLcd::pixelConverter() const
+{
+    return PixelConverter(
+        bytesPerPixel(),
+        red_select.offset, green_select.offset, blue_select.offset,
+        red_select.size, green_select.size, blue_select.size,
+        pixel_format.big_endian ? BigEndianByteOrder : LittleEndianByteOrder);
+}
+
 void
 HDLcd::endFrame() {
     assert(pixelBufferSize == 0);
@@ -556,6 +518,8 @@ HDLcd::endFrame() {
     assert(dmaBytesInFlight == 0);
     assert(dmaDoneEventFree.size() == dmaDoneEventAll.size());
 
+    fb.copyIn(virtualDisplayBuffer, pixelConverter());
+
     if (vnc)
         vnc->setDirty();
 
@@ -563,10 +527,9 @@ HDLcd::endFrame() {
         if (!pic)
             pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true);
 
-        assert(bmp);
         assert(pic);
         pic->seekp(0);
-        bmp->write(pic);
+        bmp.write(*pic);
     }
 
     // start the next frame
@@ -664,8 +627,7 @@ HDLcd::serialize(std::ostream &os)
     SERIALIZE_SCALAR(dmaPendingNum);
     SERIALIZE_SCALAR(frameUnderrun);
 
-    const size_t buffer_size = bytesPerPixel() * width() * height();
-    SERIALIZE_ARRAY(virtualDisplayBuffer, buffer_size);
+    arrayParamOut(os, "virtualDisplayBuffer", virtualDisplayBuffer);
 
     SERIALIZE_SCALAR(pixelBufferSize);
     SERIALIZE_SCALAR(pixelIndex);
@@ -777,9 +739,7 @@ HDLcd::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(frameUnderrun);
     UNSERIALIZE_SCALAR(dmaBytesInFlight);
 
-    const size_t buffer_size = bytesPerPixel() * width() * height();
-    virtualDisplayBuffer = new uint8_t[buffer_size];
-    UNSERIALIZE_ARRAY(virtualDisplayBuffer, buffer_size);
+    arrayParamIn(cp, section, "virtualDisplayBuffer", virtualDisplayBuffer);
 
     UNSERIALIZE_SCALAR(pixelBufferSize);
     UNSERIALIZE_SCALAR(pixelIndex);
@@ -823,6 +783,8 @@ HDLcd::unserialize(Checkpoint *cp, const std::string &section)
 
     if (frameUnderway) {
         updateVideoParams(true);
+        fb.resize(width(), height());
+        fb.copyIn(virtualDisplayBuffer, pixelConverter());
         if (vnc)
             vnc->setDirty();
     }
index ba22cc1639c6110b9a25ad7e979ed247a30320eb..61d2dc5d7c87de5a771bd44699cdaea3e37fe277 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 ARM Limited
+ * Copyright (c) 2010-2013, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
 #define __DEV_ARM_HDLCD_HH__
 
 #include <fstream>
+#include <memory>
 
+#include "base/bitmap.hh"
+#include "base/framebuffer.hh"
 #include "dev/arm/amba_device.hh"
 #include "params/HDLcd.hh"
 #include "sim/serialize.hh"
 
 class VncInput;
-class Bitmap;
 
 class HDLcd: public AmbaDmaDevice
 {
@@ -142,6 +144,8 @@ class HDLcd: public AmbaDmaDevice
     /** AXI port width in bytes */
     static const size_t AXI_PORT_WIDTH = 8;
 
+    static const size_t MAX_BURST_SIZE = MAX_BURST_LEN * AXI_PORT_WIDTH;
+
     /**
      * @name RegisterFieldLayouts
      * Bit layout declarations for multi-field registers.
@@ -242,11 +246,13 @@ class HDLcd: public AmbaDmaDevice
     /** Pixel clock period */
     const Tick pixelClock;
 
+    FrameBuffer fb;
+
     /** VNC server */
     VncInput *vnc;
 
     /** Helper to write out bitmaps */
-    Bitmap *bmp;
+    Bitmap bmp;
 
     /** Picture of what the current frame buffer looks like */
     std::ostream *pic;
@@ -325,7 +331,7 @@ class HDLcd: public AmbaDmaDevice
     bool frameUnderrun;
 
     /** HDLcd virtual display buffer */
-    uint8_t *virtualDisplayBuffer;
+    std::vector<uint8_t> virtualDisplayBuffer;
 
     /** Size of the pixel buffer */
     size_t pixelBufferSize;
@@ -402,6 +408,8 @@ class HDLcd: public AmbaDmaDevice
         return fb_line_count.fb_line_count;
     }
 
+    inline size_t area() const { return height() * width(); }
+
     /**
      * Gets the total number of pixel clocks per display line.
      *
@@ -436,6 +444,8 @@ class HDLcd: public AmbaDmaDevice
     /** Called when it is time to render a pixel */
     void renderPixel();
 
+    PixelConverter pixelConverter() const;
+
     /** Start of frame event */
     EventWrapper<HDLcd, &HDLcd::startFrame> startFrameEvent;
 
index a5b9b412c45c1626a461aef041f10b97031d649f..fcce09f50b6357344893af8f134471cb3a8f8662 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012 ARM Limited
+ * Copyright (c) 2010-2012, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -39,7 +39,6 @@
  */
 
 #include "base/vnc/vncinput.hh"
-#include "base/bitmap.hh"
 #include "base/output.hh"
 #include "base/trace.hh"
 #include "debug/PL111.hh"
@@ -63,7 +62,9 @@ Pl111::Pl111(const Params *p)
       clcdCrsrCtrl(0), clcdCrsrConfig(0), clcdCrsrPalette0(0),
       clcdCrsrPalette1(0), clcdCrsrXY(0), clcdCrsrClip(0), clcdCrsrImsc(0),
       clcdCrsrIcr(0), clcdCrsrRis(0), clcdCrsrMis(0),
-      pixelClock(p->pixel_clock), vnc(p->vnc), bmp(NULL), pic(NULL),
+      pixelClock(p->pixel_clock),
+      converter(PixelConverter::rgba8888_le), fb(LcdMaxWidth, LcdMaxHeight),
+      vnc(p->vnc), bmp(&fb), pic(NULL),
       width(LcdMaxWidth), height(LcdMaxHeight),
       bytesPerPixel(4), startTime(0), startAddr(0), maxAddr(0), curAddr(0),
       waterMark(0), dmaPendingNum(0), readEvent(this), fillFifoEvent(this),
@@ -83,7 +84,7 @@ Pl111::Pl111(const Params *p)
         dmaDoneEventFree[i] = &dmaDoneEventAll[i];
 
     if (vnc)
-        vnc->setFramebufferAddr(dmaBuffer);
+        vnc->setFrameBuffer(&fb);
 }
 
 Pl111::~Pl111()
@@ -378,45 +379,66 @@ Pl111::write(PacketPtr pkt)
     return pioDelay;
 }
 
+PixelConverter
+Pl111::pixelConverter() const
+{
+    unsigned rw, gw, bw;
+    unsigned offsets[3];
+
+    switch (lcdControl.lcdbpp) {
+      case bpp24:
+        rw = gw = bw = 8;
+        offsets[0] = 0;
+        offsets[1] = 8;
+        offsets[2] = 16;
+        break;
+
+      case bpp16m565:
+        rw = 5;
+        gw = 6;
+        bw = 5;
+        offsets[0] = 0;
+        offsets[1] = 5;
+        offsets[2] = 11;
+        break;
+
+      default:
+        panic("Unimplemented video mode\n");
+    }
+
+    if (lcdControl.bgr) {
+        return PixelConverter(
+            bytesPerPixel,
+            offsets[2], offsets[1], offsets[0],
+            rw, gw, bw,
+            LittleEndianByteOrder);
+    } else {
+        return PixelConverter(
+            bytesPerPixel,
+            offsets[0], offsets[1], offsets[2],
+            rw, gw, bw,
+            LittleEndianByteOrder);
+    }
+}
+
 void
 Pl111::updateVideoParams()
 {
-        if (lcdControl.lcdbpp == bpp24) {
-            bytesPerPixel = 4;
-        } else if (lcdControl.lcdbpp == bpp16m565) {
-            bytesPerPixel = 2;
-        }
+    if (lcdControl.lcdbpp == bpp24) {
+        bytesPerPixel = 4;
+    } else if (lcdControl.lcdbpp == bpp16m565) {
+        bytesPerPixel = 2;
+    }
 
-        if (vnc) {
-            if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr)
-                vnc->setFrameBufferParams(VideoConvert::bgr8888, width,
-                       height);
-            else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr)
-                vnc->setFrameBufferParams(VideoConvert::rgb8888, width,
-                       height);
-            else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr)
-                vnc->setFrameBufferParams(VideoConvert::bgr565, width,
-                       height);
-            else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr)
-                vnc->setFrameBufferParams(VideoConvert::rgb565, width,
-                       height);
-            else
-                panic("Unimplemented video mode\n");
-        }
+    fb.resize(width, height);
+    converter = pixelConverter();
 
-        if (bmp)
-            delete bmp;
-
-        if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr)
-            bmp = new Bitmap(VideoConvert::bgr8888, width, height, dmaBuffer);
-        else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr)
-            bmp = new Bitmap(VideoConvert::rgb8888, width, height, dmaBuffer);
-        else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr)
-            bmp = new Bitmap(VideoConvert::bgr565, width, height, dmaBuffer);
-        else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr)
-            bmp = new Bitmap(VideoConvert::rgb565, width, height, dmaBuffer);
-        else
-            panic("Unimplemented video mode\n");
+    // Workaround configuration bugs where multiple display
+    // controllers are attached to the same VNC server by reattaching
+    // enabled devices. This isn't ideal, but works as long as only
+    // one display controller is active at a time.
+    if (lcdControl.lcdpwr && vnc)
+        vnc->setFrameBuffer(&fb);
 }
 
 void
@@ -493,6 +515,7 @@ Pl111::dmaDone()
         }
 
         assert(!readEvent.scheduled());
+        fb.copyIn(dmaBuffer, converter);
         if (vnc)
             vnc->setDirty();
 
@@ -502,10 +525,9 @@ Pl111::dmaDone()
             if (!pic)
                 pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true);
 
-            assert(bmp);
             assert(pic);
             pic->seekp(0);
-            bmp->write(pic);
+            bmp.write(*pic);
         }
 
         // schedule the next read based on when the last frame started
@@ -721,6 +743,7 @@ Pl111::unserialize(Checkpoint *cp, const std::string &section)
 
     if (lcdControl.lcdpwr) {
         updateVideoParams();
+        fb.copyIn(dmaBuffer, converter);
         if (vnc)
             vnc->setDirty();
     }
index a7c1584731ddd951a7ec95ccbb3e2a8a06686e58..85973bbc7374c65352fb8a123df286ddbe10be46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012 ARM Limited
+ * Copyright (c) 2010-2012, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
 #define __DEV_ARM_PL111_HH__
 
 #include <fstream>
+#include <memory>
 
+#include "base/bitmap.hh"
+#include "base/framebuffer.hh"
 #include "dev/arm/amba_device.hh"
 #include "params/Pl111.hh"
 #include "sim/serialize.hh"
 
 class VncInput;
-class Bitmap;
 
 class Pl111: public AmbaDmaDevice
 {
@@ -256,11 +258,14 @@ class Pl111: public AmbaDmaDevice
     /** Pixel clock */
     Tick pixelClock;
 
+    PixelConverter converter;
+    FrameBuffer fb;
+
     /** VNC server */
     VncInput *vnc;
 
     /** Helper to write out bitmaps */
-    Bitmap *bmp;
+    Bitmap bmp;
 
     /** Picture of what the current frame buffer looks like */
     std::ostream *pic;
@@ -295,6 +300,8 @@ class Pl111: public AmbaDmaDevice
     /** Number of pending dma reads */
     uint32_t dmaPendingNum;
 
+    PixelConverter pixelConverter() const;
+
     /** Send updated parameters to the vnc server */
     void updateVideoParams();
 
index b46c1e552dc6324385afcce211f2b87c497dc8c1..7e5d6809ecdc051ada9d49c123bfbba1c2d43069 100644 (file)
@@ -58,8 +58,6 @@
 #include <libkern/OSByteOrder.h>
 #endif
 
-enum ByteOrder {BigEndianByteOrder, LittleEndianByteOrder};
-
 //These functions actually perform the swapping for parameters
 //of various bit lengths
 inline uint64_t
index 2926311a53ed386ab8090447746302ea7e14f423..ae22225b3a392490f5d1312158cbbecb24835f46 100644 (file)
@@ -37,6 +37,7 @@ UnitTest('bitvectest', 'bitvectest.cc')
 UnitTest('circletest', 'circletest.cc')
 UnitTest('cprintftest', 'cprintftest.cc')
 UnitTest('cprintftime', 'cprintftest.cc')
+UnitTest('fbtest', 'fbtest.cc')
 UnitTest('initest', 'initest.cc')
 UnitTest('nmtest', 'nmtest.cc')
 UnitTest('rangemaptest', 'rangemaptest.cc')
diff --git a/src/unittest/fbtest.cc b/src/unittest/fbtest.cc
new file mode 100644 (file)
index 0000000..8a8f959
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#include "base/framebuffer.hh"
+#include "unittest/unittest.hh"
+
+static Pixel pixel_red(0xff, 0x00, 0x00);
+static Pixel pixel_green(0x00, 0xff, 0x00);
+static Pixel pixel_blue(0x00, 0x00, 0xff);
+
+int
+main()
+{
+    UnitTest::setCase("Pixel conversion RGBA8888");
+    {
+        EXPECT_EQ(PixelConverter::rgba8888_le.fromPixel(pixel_red),
+                  0x000000ffU);
+        EXPECT_EQ(PixelConverter::rgba8888_le.fromPixel(pixel_green),
+                  0x0000ff00U);
+        EXPECT_EQ(PixelConverter::rgba8888_le.fromPixel(pixel_blue),
+                  0x00ff0000U);
+
+        EXPECT_EQ(PixelConverter::rgba8888_le.toPixel(0x000000ffU),
+                  pixel_red);
+        EXPECT_EQ(PixelConverter::rgba8888_le.toPixel(0x0000ff00U),
+                  pixel_green);
+        EXPECT_EQ(PixelConverter::rgba8888_le.toPixel(0x00ff0000U),
+                  pixel_blue);
+    }
+
+    UnitTest::setCase("Pixel conversion RGB565");
+    {
+        EXPECT_EQ(PixelConverter::rgb565_le.fromPixel(pixel_red),   0x001fU);
+        EXPECT_EQ(PixelConverter::rgb565_le.fromPixel(pixel_green), 0x07e0U);
+        EXPECT_EQ(PixelConverter::rgb565_le.fromPixel(pixel_blue),  0xf800U);
+
+        EXPECT_EQ(PixelConverter::rgb565_le.toPixel(0x001fU), pixel_red);
+        EXPECT_EQ(PixelConverter::rgb565_le.toPixel(0x07e0U), pixel_green);
+        EXPECT_EQ(PixelConverter::rgb565_le.toPixel(0xf800U), pixel_blue);
+    }
+
+    UnitTest::setCase("Pixel->Mem RGBA8888 LE");
+    {
+        uint8_t data[] = { 0xde, 0xad, 0xbe, 0xef };
+        PixelConverter::rgba8888_le.fromPixel(data, pixel_red);
+        EXPECT_EQ(data[0], 0xff);
+        EXPECT_EQ(data[1], 0x00);
+        EXPECT_EQ(data[3], 0x00);
+        EXPECT_EQ(data[3], 0x00);
+        EXPECT_EQ(PixelConverter::rgba8888_le.toPixel(data), pixel_red);
+
+        PixelConverter::rgba8888_le.fromPixel(data, pixel_green);
+        EXPECT_EQ(data[0], 0x00);
+        EXPECT_EQ(data[1], 0xff);
+        EXPECT_EQ(data[3], 0x00);
+        EXPECT_EQ(data[3], 0x00);
+        EXPECT_EQ(PixelConverter::rgba8888_le.toPixel(data), pixel_green);
+
+        PixelConverter::rgba8888_le.fromPixel(data, pixel_blue);
+        EXPECT_EQ(data[0], 0x00);
+        EXPECT_EQ(data[1], 0x00);
+        EXPECT_EQ(data[2], 0xff);
+        EXPECT_EQ(data[3], 0x00);
+        EXPECT_EQ(PixelConverter::rgba8888_le.toPixel(data), pixel_blue);
+    }
+
+    UnitTest::setCase("Mem->Pixel RGBA8888 LE");
+    {
+        uint8_t red[] = { 0xff, 0x00, 0x00, 0x00 };
+        uint8_t green[] = { 0x00, 0xff, 0x00, 0x00 };
+        uint8_t blue[] = { 0x00, 0x00, 0xff, 0x00 };
+
+        EXPECT_EQ(PixelConverter::rgba8888_le.toPixel(red), pixel_red);
+        EXPECT_EQ(PixelConverter::rgba8888_le.toPixel(green), pixel_green);
+        EXPECT_EQ(PixelConverter::rgba8888_le.toPixel(blue), pixel_blue);
+    }
+
+    UnitTest::setCase("Mem->Pixel RGBA8888 BE");
+    {
+        uint8_t red[] = { 0x00, 0x00, 0x00, 0xff };
+        uint8_t green[] = { 0x00, 0x00, 0xff, 0x00 };
+        uint8_t blue[] = { 0x00, 0xff, 0x00, 0x00 };
+
+        EXPECT_EQ(PixelConverter::rgba8888_be.toPixel(red), pixel_red);
+        EXPECT_EQ(PixelConverter::rgba8888_be.toPixel(green), pixel_green);
+        EXPECT_EQ(PixelConverter::rgba8888_be.toPixel(blue), pixel_blue);
+    }
+
+    return UnitTest::printResults();
+}