openMSX
HQ2xLiteScaler.cc
Go to the documentation of this file.
1 /*
2  * Lightweight version of the hq2x scaler (http://www.hiend3d.com/hq2x.html)
3  *
4  * The difference between this version and the full version of hq2x is the
5  * calculation of the distance between two colors. Here it's simplified to
6  * just color1 == color2
7  * Because of this simplification a lot of the interpolation code can also
8  * be simplified.
9  * For low color images the result is very close to the full hq2x image but
10  * it is calculated _a_lot_ faster.
11  */
12 
13 #include "HQ2xLiteScaler.hh"
14 #include "HQCommon.hh"
15 #include "LineScalers.hh"
16 #include "unreachable.hh"
17 #include "build-info.hh"
18 #include <cstdint>
19 
20 namespace openmsx {
21 
22 template <typename Pixel> struct HQLite_1x1on2x2
23 {
24  void operator()(const Pixel* in0, const Pixel* in1, const Pixel* in2,
25  Pixel* out0, Pixel* out1, unsigned srcWidth,
26  unsigned* edgeBuf, EdgeHQLite edgeOp) __restrict;
27 };
28 
29 template <typename Pixel> struct HQLite_1x1on1x2
30 {
31  void operator()(const Pixel* in0, const Pixel* in1, const Pixel* in2,
32  Pixel* out0, Pixel* out1, unsigned srcWidth,
33  unsigned* edgeBuf, EdgeHQLite edgeOp) __restrict;
34 };
35 
36 template <typename Pixel>
38  const Pixel* __restrict in0, const Pixel* __restrict in1,
39  const Pixel* __restrict in2,
40  Pixel* __restrict out0, Pixel* __restrict out1,
41  unsigned srcWidth, unsigned* __restrict edgeBuf,
42  EdgeHQLite /*edgeOp*/) __restrict
43 {
44  unsigned c2, c4, c5, c6, c8, c9;
45  c2 = readPixel(in0[0]);
46  c5 = c6 = readPixel(in1[0]);
47  c8 = c9 = readPixel(in2[0]);
48 
49  unsigned pattern = 0;
50  if (c5 != c8) pattern |= 3 << 6;
51  if (c5 != c2) pattern |= 3 << 9;
52 
53  for (unsigned x = 0; x < srcWidth; ++x) {
54  c4 = c5; c5 = c6; c8 = c9;
55  if (x != srcWidth - 1) {
56  c6 = readPixel(in1[x + 1]);
57  c9 = readPixel(in2[x + 1]);
58  }
59 
60  pattern = (pattern >> 6) & 0x001F; // left overlap
61  // overlaps with left
62  //if (c8 != c4) pattern |= 1 << 0; // B - l: c5-c9 6
63  //if (c5 != c7) pattern |= 1 << 1; // B - l: c6-c8 7
64  //if (c5 != c4) pattern |= 1 << 2; // l: c5-c6 8
65  // overlaps with top and left
66  //if (c5 != c1) pattern |= 1 << 3; // l: c2-c6 9, t: c4-c8 0
67  //if (c4 != c2) pattern |= 1 << 4; // l: c5-c3 10, t: c5-c7 1
68  // non-overlapping pixels
69  if (c5 != c8) pattern |= 1 << 5; // B
70  if (c5 != c9) pattern |= 1 << 6; // BR
71  if (c6 != c8) pattern |= 1 << 7; // BR
72  if (c5 != c6) pattern |= 1 << 8; // R
73  // overlaps with top
74  //if (c2 != c6) pattern |= 1 << 9; // R - t: c5-c9 6
75  //if (c5 != c3) pattern |= 1 << 10; // R - t: c6-c8 7
76  //if (c5 != c2) pattern |= 1 << 11; // t: c5-c8 5
77  pattern |= ((edgeBuf[x] & (1 << 5) ) << 6) |
78  ((edgeBuf[x] & ((1 << 6) | (1 << 7))) << 3);
79  edgeBuf[x] = pattern;
80 
81  unsigned pixel0, pixel1, pixel2, pixel3;
82 
83 #include "HQ2xLiteScaler-1x1to2x2.nn"
84 
85  out0[2 * x + 0] = writePixel<Pixel>(pixel0);
86  out0[2 * x + 1] = writePixel<Pixel>(pixel1);
87  out1[2 * x + 0] = writePixel<Pixel>(pixel2);
88  out1[2 * x + 1] = writePixel<Pixel>(pixel3);
89  }
90 }
91 
92 template <typename Pixel>
94  const Pixel* __restrict in0, const Pixel* __restrict in1,
95  const Pixel* __restrict in2,
96  Pixel* __restrict out0, Pixel* __restrict out1,
97  unsigned srcWidth, unsigned* __restrict edgeBuf,
98  EdgeHQLite /*edgeOp*/) __restrict
99 {
100  // +---+---+---+
101  // | 1 | 2 | 3 |
102  // +---+---+---+
103  // | 4 | 5 | 6 |
104  // +---+---+---+
105  // | 7 | 8 | 9 |
106  // +---+---+---+
107  unsigned c2, c4, c5, c6, c8, c9;
108  c2 = readPixel(in0[0]);
109  c5 = c6 = readPixel(in1[0]);
110  c8 = c9 = readPixel(in2[0]);
111 
112  unsigned pattern = 0;
113  if (c5 != c8) pattern |= 3 << 6;
114  if (c5 != c2) pattern |= 3 << 9;
115 
116  for (unsigned x = 0; x < srcWidth; ++x) {
117  c4 = c5; c5 = c6; c8 = c9;
118  if (x != srcWidth - 1) {
119  c6 = readPixel(in1[x + 1]);
120  c9 = readPixel(in2[x + 1]);
121  }
122 
123  pattern = (pattern >> 6) & 0x001F; // left overlap
124  // overlaps with left
125  //if (c8 != c4) pattern |= 1 << 0; // B - l: c5-c9 6
126  //if (c5 != c7) pattern |= 1 << 1; // B - l: c6-c8 7
127  //if (c5 != c4) pattern |= 1 << 2; // l: c5-c6 8
128  // overlaps with top and left
129  //if (c5 != c1) pattern |= 1 << 3; // l: c2-c6 9, t: c4-c8 0
130  //if (c4 != c2) pattern |= 1 << 4; // l: c5-c3 10, t: c5-c7 1
131  // non-overlapping pixels
132  if (c5 != c8) pattern |= 1 << 5; // B
133  if (c5 != c9) pattern |= 1 << 6; // BR
134  if (c6 != c8) pattern |= 1 << 7; // BR
135  if (c5 != c6) pattern |= 1 << 8; // R
136  // overlaps with top
137  //if (c2 != c6) pattern |= 1 << 9; // R - t: c5-c9 6
138  //if (c5 != c3) pattern |= 1 << 10; // R - t: c6-c8 7
139  //if (c5 != c2) pattern |= 1 << 11; // t: c5-c8 5
140  pattern |= ((edgeBuf[x] & (1 << 5) ) << 6) |
141  ((edgeBuf[x] & ((1 << 6) | (1 << 7))) << 3);
142  edgeBuf[x] = pattern;
143 
144  unsigned pixel0, pixel1;
145 
146 #include "HQ2xLiteScaler-1x1to1x2.nn"
147 
148  out0[x] = writePixel<Pixel>(pixel0);
149  out1[x] = writePixel<Pixel>(pixel1);
150  }
151 }
152 
153 
154 
155 template <class Pixel>
157  : Scaler2<Pixel>(pixelOps_)
158  , pixelOps(pixelOps_)
159 {
160 }
161 
162 template <class Pixel>
164  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
165  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
166 {
167  PolyScale<Pixel, Scale_2on3<Pixel>> postScale(pixelOps);
168  EdgeHQLite edgeOp;
169  doHQScale2<Pixel>(HQLite_1x1on2x2<Pixel>(), edgeOp, postScale,
170  src, srcStartY, srcEndY, srcWidth,
171  dst, dstStartY, dstEndY, srcWidth * 3);
172 }
173 
174 template <class Pixel>
176  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
177  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
178 {
180  EdgeHQLite edgeOp;
181  doHQScale2<Pixel>(HQLite_1x1on2x2<Pixel>(), edgeOp, postScale,
182  src, srcStartY, srcEndY, srcWidth,
183  dst, dstStartY, dstEndY, srcWidth * 2);
184 }
185 
186 template <class Pixel>
188  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
189  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
190 {
191  PolyScale<Pixel, Scale_4on3<Pixel>> postScale(pixelOps);
192  EdgeHQLite edgeOp;
193  doHQScale2<Pixel>(HQLite_1x1on2x2<Pixel>(), edgeOp, postScale,
194  src, srcStartY, srcEndY, srcWidth,
195  dst, dstStartY, dstEndY, (srcWidth * 3) / 2);
196 }
197 
198 template <class Pixel>
200  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
201  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
202 {
204  EdgeHQLite edgeOp;
205  doHQScale2<Pixel>(HQLite_1x1on1x2<Pixel>(), edgeOp, postScale,
206  src, srcStartY, srcEndY, srcWidth,
207  dst, dstStartY, dstEndY, srcWidth);
208 }
209 
210 template <class Pixel>
212  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
213  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
214 {
215  PolyScale<Pixel, Scale_4on3<Pixel>> postScale(pixelOps);
216  EdgeHQLite edgeOp;
217  doHQScale2<Pixel>(HQLite_1x1on1x2<Pixel>(), edgeOp, postScale,
218  src, srcStartY, srcEndY, srcWidth,
219  dst, dstStartY, dstEndY, (srcWidth * 3) / 4);
220 }
221 
222 template <class Pixel>
224  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
225  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
226 {
227  PolyScale<Pixel, Scale_2on1<Pixel>> postScale(pixelOps);
228  EdgeHQLite edgeOp;
229  doHQScale2<Pixel>(HQLite_1x1on1x2<Pixel>(), edgeOp, postScale,
230  src, srcStartY, srcEndY, srcWidth,
231  dst, dstStartY, dstEndY, srcWidth / 2);
232 }
233 
234 // Force template instantiation.
235 #if HAVE_16BPP
236 template class HQ2xLiteScaler<uint16_t>;
237 #endif
238 #if HAVE_32BPP
239 template class HQ2xLiteScaler<uint32_t>;
240 #endif
241 
242 } // namespace openmsx
openmsx::PixelOperations
Definition: PixelOperations.hh:142
openmsx::HQ2xLiteScaler
Definition: HQ2xLiteScaler.hh:9
openmsx::Scaler2
Base class for 2x scalers.
Definition: Scaler2.hh:11
openmsx::HQ2xLiteScaler::scale4x1to3x2
void scale4x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xLiteScaler.cc:211
openmsx::HQ2xLiteScaler::HQ2xLiteScaler
HQ2xLiteScaler(const PixelOperations< Pixel > &pixelOps)
Definition: HQ2xLiteScaler.cc:156
openmsx::HQLite_1x1on2x2
Definition: HQ2xLiteScaler.cc:22
openmsx::HQLite_1x1on1x2
Definition: HQ2xLiteScaler.cc:29
openmsx::ScalerOutput
Definition: Scaler.hh:8
openmsx::HQ2xLiteScaler::scale1x1to2x2
void scale1x1to2x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xLiteScaler.cc:175
openmsx::EdgeHQLite
Definition: HQCommon.hh:95
openmsx::Pixel
uint32_t Pixel
Definition: GLHQLiteScaler.cc:93
openmsx::HQLite_1x1on1x2::operator()
void operator()(const Pixel *in0, const Pixel *in1, const Pixel *in2, Pixel *out0, Pixel *out1, unsigned srcWidth, unsigned *edgeBuf, EdgeHQLite edgeOp)
Definition: HQ2xLiteScaler.cc:93
openmsx::HQ2xLiteScaler::scale2x1to1x2
void scale2x1to1x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xLiteScaler.cc:223
openmsx::HQLite_1x1on2x2::operator()
void operator()(const Pixel *in0, const Pixel *in1, const Pixel *in2, Pixel *out0, Pixel *out1, unsigned srcWidth, unsigned *edgeBuf, EdgeHQLite edgeOp)
Definition: HQ2xLiteScaler.cc:37
openmsx::PolyScale
Polymorphic wrapper around another line scaler.
Definition: LineScalers.hh:311
build-info.hh
openmsx::HQ2xLiteScaler::scale2x1to3x2
void scale2x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xLiteScaler.cc:187
LineScalers.hh
openmsx::x
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1377
HQ2xLiteScaler.hh
openmsx::FrameSource
Interface for getting lines from a video frame.
Definition: FrameSource.hh:13
openmsx::HQ2xLiteScaler::scale1x1to1x2
void scale1x1to1x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xLiteScaler.cc:199
unreachable.hh
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
openmsx::HQ2xLiteScaler::scale1x1to3x2
void scale1x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xLiteScaler.cc:163
HQCommon.hh