summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/base/SConscript1
-rw-r--r--src/base/bitmap.cc38
-rw-r--r--src/base/bitmap.hh51
-rw-r--r--src/base/framebuffer.cc173
-rw-r--r--src/base/framebuffer.hh355
-rw-r--r--src/base/types.hh5
-rw-r--r--src/base/vnc/SConscript2
-rw-r--r--src/base/vnc/convert.cc183
-rw-r--r--src/base/vnc/convert.hh158
-rw-r--r--src/base/vnc/vncinput.cc62
-rw-r--r--src/base/vnc/vncinput.hh33
-rw-r--r--src/base/vnc/vncserver.cc84
-rw-r--r--src/base/vnc/vncserver.hh24
-rw-r--r--src/dev/arm/hdlcd.cc124
-rw-r--r--src/dev/arm/hdlcd.hh18
-rw-r--r--src/dev/arm/pl111.cc103
-rw-r--r--src/dev/arm/pl111.hh13
-rw-r--r--src/sim/byteswap.hh2
-rw-r--r--src/unittest/SConscript1
-rw-r--r--src/unittest/fbtest.cc126
20 files changed, 924 insertions, 632 deletions
diff --git a/src/base/SConscript b/src/base/SConscript
index e7c420f78..a00f8ad66 100644
--- a/src/base/SConscript
+++ b/src/base/SConscript
@@ -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')
diff --git a/src/base/bitmap.cc b/src/base/bitmap.cc
index d83a30be3..0052503a4 100644
--- a/src/base/bitmap.cc
+++ b/src/base/bitmap.cc
@@ -47,11 +47,8 @@
#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();
}
diff --git a/src/base/bitmap.hh b/src/base/bitmap.hh
index b06aff10f..0797a26a7 100644
--- a/src/base/bitmap.hh
+++ b/src/base/bitmap.hh
@@ -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
index 000000000..dc4c2e1c2
--- /dev/null
+++ b/src/base/framebuffer.cc
@@ -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
index 000000000..457c6d06d
--- /dev/null
+++ b/src/base/framebuffer.hh
@@ -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__
diff --git a/src/base/types.hh b/src/base/types.hh
index c4cb4d988..2b6e3f11b 100644
--- a/src/base/types.hh
+++ b/src/base/types.hh
@@ -188,4 +188,9 @@ typedef std::shared_ptr<FaultBase> Fault;
constexpr decltype(nullptr) NoFault = nullptr;
#endif
+enum ByteOrder {
+ BigEndianByteOrder,
+ LittleEndianByteOrder
+};
+
#endif // __BASE_TYPES_HH__
diff --git a/src/base/vnc/SConscript b/src/base/vnc/SConscript
index 416743200..271f894ce 100644
--- a/src/base/vnc/SConscript
+++ b/src/base/vnc/SConscript
@@ -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
index 2a52ccaec..000000000
--- a/src/base/vnc/convert.cc
+++ /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
index 592076cbf..000000000
--- a/src/base/vnc/convert.hh
+++ /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__
-
diff --git a/src/base/vnc/vncinput.cc b/src/base/vnc/vncinput.cc
index 071804583..017fc3876 100644
--- a/src/base/vnc/vncinput.cc
+++ b/src/base/vnc/vncinput.cc
@@ -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;
diff --git a/src/base/vnc/vncinput.hh b/src/base/vnc/vncinput.hh
index 1686e3f25..96235fec7 100644
--- a/src/base/vnc/vncinput.hh
+++ b/src/base/vnc/vncinput.hh
@@ -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();
diff --git a/src/base/vnc/vncserver.cc b/src/base/vnc/vncserver.cc
index 6dc2f2f10..20f3bc8fe 100644
--- a/src/base/vnc/vncserver.cc
+++ b/src/base/vnc/vncserver.cc
@@ -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"
@@ -74,6 +75,12 @@
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();
}
}
diff --git a/src/base/vnc/vncserver.hh b/src/base/vnc/vncserver.hh
index cd1f186f5..0222a7726 100644
--- a/src/base/vnc/vncserver.hh
+++ b/src/base/vnc/vncserver.hh
@@ -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
diff --git a/src/dev/arm/hdlcd.cc b/src/dev/arm/hdlcd.cc
index 37569b22b..b1c1c450b 100644
--- a/src/dev/arm/hdlcd.cc
+++ b/src/dev/arm/hdlcd.cc
@@ -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
@@ -37,15 +37,15 @@
* 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();
}
diff --git a/src/dev/arm/hdlcd.hh b/src/dev/arm/hdlcd.hh
index ba22cc163..61d2dc5d7 100644
--- a/src/dev/arm/hdlcd.hh
+++ b/src/dev/arm/hdlcd.hh
@@ -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
@@ -83,13 +83,15 @@
#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;
diff --git a/src/dev/arm/pl111.cc b/src/dev/arm/pl111.cc
index a5b9b412c..fcce09f50 100644
--- a/src/dev/arm/pl111.cc
+++ b/src/dev/arm/pl111.cc
@@ -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();
}
diff --git a/src/dev/arm/pl111.hh b/src/dev/arm/pl111.hh
index a7c158473..85973bbc7 100644
--- a/src/dev/arm/pl111.hh
+++ b/src/dev/arm/pl111.hh
@@ -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
@@ -47,13 +47,15 @@
#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();
diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh
index b46c1e552..7e5d6809e 100644
--- a/src/sim/byteswap.hh
+++ b/src/sim/byteswap.hh
@@ -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
diff --git a/src/unittest/SConscript b/src/unittest/SConscript
index 2926311a5..ae22225b3 100644
--- a/src/unittest/SConscript
+++ b/src/unittest/SConscript
@@ -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
index 000000000..8a8f959ae
--- /dev/null
+++ b/src/unittest/fbtest.cc
@@ -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();
+}