summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2014-02-28 11:54:34 +0100
committerPierre Ossman <ossman@cendio.se>2014-07-07 13:21:35 +0200
commit6e5cd5db59b2ddd7dfa94248aa2631f63391d631 (patch)
treecf7c0a7c7e5aababa5feccc218ab2c923c143179 /common
parent6655d96dc475942f91af38a879627fd254a37c2e (diff)
downloadtigervnc-6e5cd5db59b2ddd7dfa94248aa2631f63391d631.tar.gz
tigervnc-6e5cd5db59b2ddd7dfa94248aa2631f63391d631.zip
Converting to RGB might involve a precision increase
Need to do more than a simple shift to get the appropriate new value. This isn't quite as exact as a proper multiplication and division, but the error is so small it's not worth the extra cycles.
Diffstat (limited to 'common')
-rw-r--r--common/rfb/PixelFormat.cxx15
-rw-r--r--common/rfb/PixelFormat.h6
-rw-r--r--common/rfb/PixelFormat.inl53
3 files changed, 59 insertions, 15 deletions
diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx
index 8df5140f..3604a6b2 100644
--- a/common/rfb/PixelFormat.cxx
+++ b/common/rfb/PixelFormat.cxx
@@ -567,16 +567,23 @@ static int bits(rdr::U16 value)
void PixelFormat::updateState(void)
{
- int redBits, greenBits, blueBits;
int endianTest = 1;
redBits = bits(redMax);
greenBits = bits(greenMax);
blueBits = bits(blueMax);
- redConvShift = 16 - redBits;
- greenConvShift = 16 - greenBits;
- blueConvShift = 16 - blueBits;
+ maxBits = redBits;
+ if (greenBits > maxBits)
+ maxBits = greenBits;
+ if (blueBits > maxBits)
+ maxBits = blueBits;
+
+ minBits = redBits;
+ if (greenBits < minBits)
+ minBits = greenBits;
+ if (blueBits < minBits)
+ minBits = blueBits;
if (((*(char*)&endianTest) == 0) != bigEndian)
endianMismatch = true;
diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h
index aef309cf..dd414744 100644
--- a/common/rfb/PixelFormat.h
+++ b/common/rfb/PixelFormat.h
@@ -89,9 +89,9 @@ namespace rfb {
int blueShift;
protected:
- int redConvShift;
- int greenConvShift;
- int blueConvShift;
+ /* Pre-computed values to keep algorithms simple */
+ int redBits, greenBits, blueBits;
+ int maxBits, minBits;
bool endianMismatch;
};
}
diff --git a/common/rfb/PixelFormat.inl b/common/rfb/PixelFormat.inl
index 90d8e6da..5743e495 100644
--- a/common/rfb/PixelFormat.inl
+++ b/common/rfb/PixelFormat.inl
@@ -1,4 +1,4 @@
-/* Copyright 2009 Pierre Ossman for Cendio AB
+/* Copyright 2009-2014 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -78,10 +78,28 @@ inline void PixelFormat::bufferFromPixel(rdr::U8* buffer, Pixel p) const
inline void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, rdr::U16 *r, rdr::U16 *g, rdr::U16 *b) const
{
if (trueColour) {
- /* We don't need to mask since we shift out unwanted bits */
- *r = (p >> redShift) << redConvShift;
- *g = (p >> greenShift) << greenConvShift;
- *b = (p >> blueShift) << blueConvShift;
+ int mb, rb, gb, bb;
+
+ /* Bit replication is much cheaper than multiplication and division */
+
+ mb = minBits;
+ rb = redBits;
+ gb = greenBits;
+ bb = blueBits;
+
+ *r = (p >> redShift) << (16 - rb);
+ *g = (p >> greenShift) << (16 - gb);
+ *b = (p >> blueShift) << (16 - bb);
+
+ while (mb < 16) {
+ *r = *r | (*r >> rb);
+ *g = *g | (*g >> gb);
+ *b = *b | (*b >> bb);
+ mb <<= 1;
+ rb <<= 1;
+ gb <<= 1;
+ bb <<= 1;
+ }
} else if (cm) {
int ir, ig, ib;
cm->lookup(p, &ir, &ig, &ib);
@@ -100,9 +118,28 @@ inline void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, rdr::U16 *r, rdr::
inline void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, rdr::U8 *r, rdr::U8 *g, rdr::U8 *b) const
{
if (trueColour) {
- *r = (p >> redShift) << (redConvShift - 8);
- *g = (p >> greenShift) << (greenConvShift - 8);
- *b = (p >> blueShift) << (blueConvShift - 8);
+ int mb, rb, gb, bb;
+
+ /* Bit replication is much cheaper than multiplication and division */
+
+ mb = minBits;
+ rb = redBits;
+ gb = greenBits;
+ bb = blueBits;
+
+ *r = (p >> redShift) << (8 - rb);
+ *g = (p >> greenShift) << (8 - gb);
+ *b = (p >> blueShift) << (8 - bb);
+
+ while (mb < 8) {
+ *r = *r | (*r >> rb);
+ *g = *g | (*g >> gb);
+ *b = *b | (*b >> bb);
+ mb <<= 1;
+ rb <<= 1;
+ gb <<= 1;
+ bb <<= 1;
+ }
} else {
rdr::U16 r2, g2, b2;