diff options
author | Pierre Ossman <ossman@cendio.se> | 2014-02-28 11:54:34 +0100 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2014-07-07 13:21:35 +0200 |
commit | 6e5cd5db59b2ddd7dfa94248aa2631f63391d631 (patch) | |
tree | cf7c0a7c7e5aababa5feccc218ab2c923c143179 /common | |
parent | 6655d96dc475942f91af38a879627fd254a37c2e (diff) | |
download | tigervnc-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.cxx | 15 | ||||
-rw-r--r-- | common/rfb/PixelFormat.h | 6 | ||||
-rw-r--r-- | common/rfb/PixelFormat.inl | 53 |
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; |