openMSX
HQ2xScaler.cc
Go to the documentation of this file.
1 /*
2 Original code: Copyright (C) 2003 MaxSt ( maxst@hiend3d.com )
3 openMSX adaptation by Maarten ter Huurne
4 
5 License: LGPL
6 
7 Visit the HiEnd3D site for info:
8  http://www.hiend3d.com/hq2x.html
9 */
10 
11 #include "HQ2xScaler.hh"
12 #include "HQCommon.hh"
13 #include "LineScalers.hh"
14 #include "unreachable.hh"
15 #include "build-info.hh"
16 #include <cstdint>
17 
18 namespace openmsx {
19 
20 template <typename Pixel> struct HQ_1x1on2x2
21 {
22  void operator()(const Pixel* in0, const Pixel* in1, const Pixel* in2,
23  Pixel* out0, Pixel* out1, unsigned srcWidth,
24  unsigned* edgeBuf, EdgeHQ edgeOp) __restrict;
25 };
26 
27 template <typename Pixel> struct HQ_1x1on1x2
28 {
29  void operator()(const Pixel* in0, const Pixel* in1, const Pixel* in2,
30  Pixel* out0, Pixel* out1, unsigned srcWidth,
31  unsigned* edgeBuf, EdgeHQ edgeOp) __restrict;
32 };
33 
34 template <typename Pixel>
36  const Pixel* __restrict in0, const Pixel* __restrict in1,
37  const Pixel* __restrict in2,
38  Pixel* __restrict out0, Pixel* __restrict out1,
39  unsigned srcWidth, unsigned* __restrict edgeBuf,
40  EdgeHQ edgeOp) __restrict
41 {
42  unsigned c1, c2, c3, c4, c5, c6, c7, c8, c9;
43  c2 = c3 = readPixel(in0[0]);
44  c5 = c6 = readPixel(in1[0]);
45  c8 = c9 = readPixel(in2[0]);
46 
47  unsigned pattern = 0;
48  if (edgeOp(c5, c8)) pattern |= 3 << 6;
49  if (edgeOp(c5, c2)) pattern |= 3 << 9;
50 
51  for (unsigned x = 0; x < srcWidth; ++x) {
52  c1 = c2; c4 = c5; c7 = c8;
53  c2 = c3; c5 = c6; c8 = c9;
54  if (x != srcWidth - 1) {
55  c3 = readPixel(in0[x + 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 (edgeOp(c8, c4)) pattern |= 1 << 0; // B - l: c5-c9 6
63  //if (edgeOp(c5, c7)) pattern |= 1 << 1; // B - l: c6-c8 7
64  //if (edgeOp(c5, c4)) pattern |= 1 << 2; // l: c5-c6 8
65  // overlaps with top and left
66  //if (edgeOp(c5, c1)) pattern |= 1 << 3; // l: c2-c6 9, t: c4-c8 0
67  //if (edgeOp(c4, c2)) pattern |= 1 << 4; // l: c5-c3 10, t: c5-c7 1
68  // non-overlapping pixels
69  if (edgeOp(c5, c8)) pattern |= 1 << 5; // B
70  if (edgeOp(c5, c9)) pattern |= 1 << 6; // BR
71  if (edgeOp(c6, c8)) pattern |= 1 << 7; // BR
72  if (edgeOp(c5, c6)) pattern |= 1 << 8; // R
73  // overlaps with top
74  //if (edgeOp(c2, c6)) pattern |= 1 << 9; // R - t: c5-c9 6
75  //if (edgeOp(c5, c3)) pattern |= 1 << 10; // R - t: c6-c8 7
76  //if (edgeOp(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 "HQ2xScaler-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  EdgeHQ edgeOp) __restrict
99 {
100  // +---+---+---+
101  // | 1 | 2 | 3 |
102  // +---+---+---+
103  // | 4 | 5 | 6 |
104  // +---+---+---+
105  // | 7 | 8 | 9 |
106  // +---+---+---+
107 
108  unsigned c1, c2, c3, c4, c5, c6, c7, c8, c9;
109  c2 = c3 = readPixel(in0[0]);
110  c5 = c6 = readPixel(in1[0]);
111  c8 = c9 = readPixel(in2[0]);
112 
113  unsigned pattern = 0;
114  if (edgeOp(c5, c8)) pattern |= 3 << 6;
115  if (edgeOp(c5, c2)) pattern |= 3 << 9;
116 
117  for (unsigned x = 0; x < srcWidth; ++x) {
118  c1 = c2; c4 = c5; c7 = c8;
119  c2 = c3; c5 = c6; c8 = c9;
120  if (x != srcWidth - 1) {
121  c3 = readPixel(in0[x + 1]);
122  c6 = readPixel(in1[x + 1]);
123  c9 = readPixel(in2[x + 1]);
124  }
125 
126  pattern = (pattern >> 6) & 0x001F; // left overlap
127  // overlaps with left
128  //if (edgeOp(c8, c4)) pattern |= 1 << 0; // B - l: c5-c9 6
129  //if (edgeOp(c5, c7)) pattern |= 1 << 1; // B - l: c6-c8 7
130  //if (edgeOp(c5, c4)) pattern |= 1 << 2; // l: c5-c6 8
131  // overlaps with top and left
132  //if (edgeOp(c5, c1)) pattern |= 1 << 3; // l: c2-c6 9, t: c4-c8 0
133  //if (edgeOp(c4, c2)) pattern |= 1 << 4; // l: c5-c3 10, t: c5-c7 1
134  // non-overlapping pixels
135  if (edgeOp(c5, c8)) pattern |= 1 << 5; // B
136  if (edgeOp(c5, c9)) pattern |= 1 << 6; // BR
137  if (edgeOp(c6, c8)) pattern |= 1 << 7; // BR
138  if (edgeOp(c5, c6)) pattern |= 1 << 8; // R
139  // overlaps with top
140  //if (edgeOp(c2, c6)) pattern |= 1 << 9; // R - t: c5-c9 6
141  //if (edgeOp(c5, c3)) pattern |= 1 << 10; // R - t: c6-c8 7
142  //if (edgeOp(c5, c2)) pattern |= 1 << 11; // t: c5-c8 5
143  pattern |= ((edgeBuf[x] & (1 << 5) ) << 6) |
144  ((edgeBuf[x] & ((1 << 6) | (1 << 7))) << 3);
145  edgeBuf[x] = pattern;
146 
147  unsigned pixel0, pixel1;
148 
149 #include "HQ2xScaler-1x1to1x2.nn"
150 
151  out0[x] = writePixel<Pixel>(pixel0);
152  out1[x] = writePixel<Pixel>(pixel1);
153  }
154 }
155 
156 
157 
158 template <class Pixel>
160  : Scaler2<Pixel>(pixelOps_)
161  , pixelOps(pixelOps_)
162 {
163 }
164 
165 template <class Pixel>
167  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
168  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
169 {
170  PolyScale<Pixel, Scale_2on3<Pixel>> postScale(pixelOps);
171  EdgeHQ edgeOp = createEdgeHQ(pixelOps);
172  doHQScale2<Pixel>(HQ_1x1on2x2<Pixel>(), edgeOp, postScale,
173  src, srcStartY, srcEndY, srcWidth,
174  dst, dstStartY, dstEndY, srcWidth * 3);
175 }
176 
177 template <class Pixel>
179  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
180  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
181 {
183  EdgeHQ edgeOp = createEdgeHQ(pixelOps);
184  doHQScale2<Pixel>(HQ_1x1on2x2<Pixel>(), edgeOp, postScale,
185  src, srcStartY, srcEndY, srcWidth,
186  dst, dstStartY, dstEndY, srcWidth * 2);
187 }
188 
189 template <class Pixel>
191  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
192  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
193 {
194  PolyScale<Pixel, Scale_4on3<Pixel>> postScale(pixelOps);
195  EdgeHQ edgeOp = createEdgeHQ(pixelOps);
196  doHQScale2<Pixel>(HQ_1x1on2x2<Pixel>(), edgeOp, postScale,
197  src, srcStartY, srcEndY, srcWidth,
198  dst, dstStartY, dstEndY, (srcWidth * 3) / 2);
199 }
200 
201 template <class Pixel>
203  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
204  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
205 {
207  EdgeHQ edgeOp = createEdgeHQ(pixelOps);
208  doHQScale2<Pixel>(HQ_1x1on1x2<Pixel>(), edgeOp, postScale,
209  src, srcStartY, srcEndY, srcWidth,
210  dst, dstStartY, dstEndY, srcWidth);
211 }
212 
213 template <class Pixel>
215  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
216  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
217 {
218  PolyScale<Pixel, Scale_4on3<Pixel>> postScale(pixelOps);
219  EdgeHQ edgeOp = createEdgeHQ(pixelOps);
220  doHQScale2<Pixel>(HQ_1x1on1x2<Pixel>(), edgeOp, postScale,
221  src, srcStartY, srcEndY, srcWidth,
222  dst, dstStartY, dstEndY, (srcWidth * 3) / 4);
223 }
224 
225 template <class Pixel>
227  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
228  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
229 {
230  PolyScale<Pixel, Scale_2on1<Pixel>> postScale(pixelOps);
231  EdgeHQ edgeOp = createEdgeHQ(pixelOps);
232  doHQScale2<Pixel>(HQ_1x1on1x2<Pixel>(), edgeOp, postScale,
233  src, srcStartY, srcEndY, srcWidth,
234  dst, dstStartY, dstEndY, srcWidth / 2);
235 }
236 
237 // Force template instantiation.
238 #if HAVE_16BPP
239 template class HQ2xScaler<uint16_t>;
240 #endif
241 #if HAVE_32BPP
242 template class HQ2xScaler<uint32_t>;
243 #endif
244 
245 } // namespace openmsx
void operator()(const Pixel *in0, const Pixel *in1, const Pixel *in2, Pixel *out0, Pixel *out1, unsigned srcWidth, unsigned *edgeBuf, EdgeHQ edgeOp)
Definition: HQ2xScaler.cc:35
void scale1x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:166
void scale2x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:190
Base class for 2x scalers.
Definition: Scaler2.hh:11
Polymorphic wrapper around another line scaler.
Definition: LineScalers.hh:310
uint32_t Pixel
Runs the hq2x scaler algorithm.
Definition: HQ2xScaler.hh:12
Interface for getting lines from a video frame.
Definition: FrameSource.hh:14
void scale1x1to1x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:202
EdgeHQ createEdgeHQ(const PixelOperations< Pixel > &pixelOps)
Definition: HQCommon.hh:84
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
void scale2x1to1x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:226
HQ2xScaler(const PixelOperations< Pixel > &pixelOps)
Definition: HQ2xScaler.cc:159
void operator()(const Pixel *in0, const Pixel *in1, const Pixel *in2, Pixel *out0, Pixel *out1, unsigned srcWidth, unsigned *edgeBuf, EdgeHQ edgeOp)
Definition: HQ2xScaler.cc:93
void scale4x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:214
void scale1x1to2x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:178