openMSX
HQCommon.hh
Go to the documentation of this file.
1 #ifndef HQCOMMON_HH
2 #define HQCOMMON_HH
3 
4 #include "FrameSource.hh"
5 #include "ScalerOutput.hh"
6 #include "LineScalers.hh"
7 #include "PixelOperations.hh"
8 #include "build-info.hh"
9 #include <cassert>
10 
11 namespace openmsx {
12 
13 template <typename Pixel>
14 static inline unsigned readPixel(Pixel p)
15 {
16  // TODO: Use surface info instead.
17  if (sizeof(Pixel) == 2) {
18  return ((p & 0xF800) << 8) |
19  ((p & 0x07C0) << 5) | // drop lowest green bit
20  ((p & 0x001F) << 3);
21  } else {
22  return p & 0xF8F8F8F8;
23  }
24 }
25 
26 template <typename Pixel>
27 static inline Pixel writePixel(unsigned p)
28 {
29  // TODO: Use surface info instead.
30  if (sizeof(Pixel) == 2) {
31  return ((p & 0xF80000) >> 8) |
32  ((p & 0x00FC00) >> 5) |
33  ((p & 0x0000F8) >> 3);
34  } else {
35  return (p & 0xF8F8F8F8) | ((p & 0xE0E0E0E0) >> 5);
36  }
37 }
38 
39 class EdgeHQ
40 {
41 public:
42  EdgeHQ(unsigned shiftR_, unsigned shiftG_, unsigned shiftB_)
43  : shiftR(shiftR_), shiftG(shiftG_), shiftB(shiftB_)
44  {
45  }
46 
47  inline bool operator()(unsigned c1, unsigned c2) const
48  {
49  if (c1 == c2) return false;
50 
51  unsigned r1 = (c1 >> shiftR) & 0xFF;
52  unsigned g1 = (c1 >> shiftG) & 0xFF;
53  unsigned b1 = (c1 >> shiftB) & 0xFF;
54 
55  unsigned r2 = (c2 >> shiftR) & 0xFF;
56  unsigned g2 = (c2 >> shiftG) & 0xFF;
57  unsigned b2 = (c2 >> shiftB) & 0xFF;
58 
59  int dr = r1 - r2;
60  int dg = g1 - g2;
61  int db = b1 - b2;
62 
63  int dy = dr + dg + db;
64  if (dy < -0xC0 || dy > 0xC0) return true;
65 
66  int du = dr - db;
67  if (du < -0x1C || du > 0x1C) return true;
68 
69  int dv = 3 * dg - dy;
70  if (dv < -0x30 || dv > 0x30) return true;
71 
72  return false;
73  }
74 private:
75  const unsigned shiftR;
76  const unsigned shiftG;
77  const unsigned shiftB;
78 };
79 
80 template<typename Pixel>
82 {
83  if (sizeof(Pixel) == 2) {
84  return EdgeHQ(0, 8, 16);
85  } else {
86  return EdgeHQ(pixelOps.getRshift(),
87  pixelOps.getGshift(),
88  pixelOps.getBshift());
89  }
90 }
91 
92 struct EdgeHQLite
93 {
94  inline bool operator()(unsigned c1, unsigned c2) const
95  {
96  return c1 != c2;
97  }
98 };
99 
100 template <typename EdgeOp>
101 void calcEdgesGL(const unsigned* __restrict curr, const unsigned* __restrict next,
102  unsigned* __restrict edges2, EdgeOp edgeOp)
103 {
104  typedef unsigned Pixel;
105  if (OPENMSX_BIGENDIAN) {
106  unsigned pattern = 0;
107  Pixel c5 = curr[0];
108  Pixel c8 = next[0];
109  if (edgeOp(c5, c8)) pattern |= 0x1400;
110 
111  for (unsigned xx = 0; xx < (320 - 2) / 2; ++xx) {
112  pattern = (pattern << (16 + 1)) & 0xA8000000;
113  pattern |= ((edges2[xx] >> 5) & 0x01F001F0);
114 
115  if (edgeOp(c5, c8)) pattern |= 0x02000000;
116  Pixel c6 = curr[2 * xx + 1];
117  if (edgeOp(c6, c8)) pattern |= 0x10002000;
118  if (edgeOp(c5, c6)) pattern |= 0x40008000;
119  Pixel c9 = next[2 * xx + 1];
120  if (edgeOp(c5, c9)) pattern |= 0x04000800;
121 
122  if (edgeOp(c6, c9)) pattern |= 0x0200;
123  c5 = curr[2 * xx + 2];
124  if (edgeOp(c5, c9)) pattern |= 0x1000;
125  if (edgeOp(c6, c5)) pattern |= 0x4000;
126  c8 = next[2 * xx + 2];
127  if (edgeOp(c6, c8)) pattern |= 0x0400;
128 
129  edges2[xx] = pattern;
130  }
131 
132  pattern = (pattern << (16 + 1)) & 0xA8000000;
133  pattern |= ((edges2[159] >> 5) & 0x01F001F0);
134 
135  if (edgeOp(c5, c8)) pattern |= 0x02000000;
136  Pixel c6 = curr[319];
137  if (edgeOp(c6, c8)) pattern |= 0x10002000;
138  if (edgeOp(c5, c6)) pattern |= 0x40008000;
139  Pixel c9 = next[319];
140  if (edgeOp(c5, c9)) pattern |= 0x04000800;
141 
142  if (edgeOp(c6, c9)) pattern |= 0x1600;
143 
144  edges2[159] = pattern;
145  } else {
146  unsigned pattern = 0;
147  Pixel c5 = curr[0];
148  Pixel c8 = next[0];
149  if (edgeOp(c5, c8)) pattern |= 0x14000000;
150 
151  for (unsigned xx = 0; xx < (320 - 2) / 2; ++xx) {
152  pattern = (pattern >> (16 -1)) & 0xA800;
153  pattern |= ((edges2[xx] >> 5) & 0x01F001F0);
154 
155  if (edgeOp(c5, c8)) pattern |= 0x0200;
156  Pixel c6 = curr[2 * xx + 1];
157  if (edgeOp(c6, c8)) pattern |= 0x20001000;
158  if (edgeOp(c5, c6)) pattern |= 0x80004000;
159  Pixel c9 = next[2 * xx + 1];
160  if (edgeOp(c5, c9)) pattern |= 0x08000400;
161 
162  if (edgeOp(c6, c9)) pattern |= 0x02000000;
163  c5 = curr[2 * xx + 2];
164  if (edgeOp(c5, c9)) pattern |= 0x10000000;
165  if (edgeOp(c6, c5)) pattern |= 0x40000000;
166  c8 = next[2 * xx + 2];
167  if (edgeOp(c6, c8)) pattern |= 0x04000000;
168 
169  edges2[xx] = pattern;
170  }
171 
172  pattern = (pattern >> (16 -1)) & 0xA800;
173  pattern |= ((edges2[159] >> 5) & 0x01F001F0);
174 
175  if (edgeOp(c5, c8)) pattern |= 0x0200;
176  Pixel c6 = curr[319];
177  if (edgeOp(c6, c8)) pattern |= 0x20001000;
178  if (edgeOp(c5, c6)) pattern |= 0x80004000;
179  Pixel c9 = next[319];
180  if (edgeOp(c5, c9)) pattern |= 0x08000400;
181 
182  if (edgeOp(c6, c9)) pattern |= 0x16000000;
183 
184  edges2[159] = pattern;
185  }
186 }
187 
188 template <typename Pixel, typename EdgeOp>
189 static void calcInitialEdges(
190  const Pixel* __restrict srcPrev, const Pixel* __restrict srcCurr,
191  unsigned srcWidth, unsigned* __restrict edgeBuf, EdgeOp edgeOp)
192 {
193  unsigned x = 0;
194  unsigned c1 = readPixel(srcPrev[x]);
195  unsigned c2 = readPixel(srcCurr[x]);
196  unsigned pattern = edgeOp(c1, c2) ? ((1 << 6) | (1 << 7)) : 0;
197  for (/* */; x < (srcWidth - 1); ++x) {
198  pattern >>= 6;
199  unsigned n1 = readPixel(srcPrev[x + 1]);
200  unsigned n2 = readPixel(srcCurr[x + 1]);
201  if (edgeOp(c1, c2)) pattern |= (1 << 5);
202  if (edgeOp(c1, n2)) pattern |= (1 << 6);
203  if (edgeOp(c2, n1)) pattern |= (1 << 7);
204  edgeBuf[x] = pattern;
205  c1 = n1; c2 = n2;
206  }
207  pattern >>= 6;
208  if (edgeOp(c1, c2)) pattern |= (1 << 5) | (1 << 6) | (1 << 7);
209  edgeBuf[x] = pattern;
210 }
211 
212 template <typename Pixel, typename HQScale, typename EdgeOp>
213 static void doHQScale2(HQScale hqScale, EdgeOp edgeOp, PolyLineScaler<Pixel>& postScale,
214  FrameSource& src, unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
215  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth)
216 {
217  int srcY = srcStartY;
218  const Pixel* srcPrev = src.getLinePtr<Pixel>(srcY - 1, srcWidth);
219  const Pixel* srcCurr = src.getLinePtr<Pixel>(srcY + 0, srcWidth);
220 
221  assert(srcWidth <= 1024);
222  unsigned edgeBuf[1024];
223  calcInitialEdges(srcPrev, srcCurr, srcWidth, edgeBuf, edgeOp);
224 
225  bool isCopy = postScale.isCopy();
226  for (unsigned dstY = dstStartY; dstY < dstEndY; srcY += 1, dstY += 2) {
227  Pixel buf0[2 * 1024], buf1[2 * 1024];
228  const Pixel* srcNext = src.getLinePtr<Pixel>(srcY + 1, srcWidth);
229  Pixel* dst0 = dst.acquireLine(dstY + 0);
230  Pixel* dst1 = dst.acquireLine(dstY + 1);
231  if (isCopy) {
232  hqScale(srcPrev, srcCurr, srcNext, dst0, dst1,
233  srcWidth, edgeBuf, edgeOp);
234  } else {
235  hqScale(srcPrev, srcCurr, srcNext, buf0, buf1,
236  srcWidth, edgeBuf, edgeOp);
237  postScale(buf0, dst0, dstWidth);
238  postScale(buf1, dst1, dstWidth);
239  }
240  dst.releaseLine(dstY + 0, dst0);
241  dst.releaseLine(dstY + 1, dst1);
242  srcPrev = srcCurr;
243  srcCurr = srcNext;
244  }
245 }
246 
247 template <typename Pixel, typename HQScale, typename EdgeOp>
248 static void doHQScale3(HQScale hqScale, EdgeOp edgeOp, PolyLineScaler<Pixel>& postScale,
249  FrameSource& src, unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
250  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth)
251 {
252  int srcY = srcStartY;
253  const Pixel* srcPrev = src.getLinePtr<Pixel>(srcY - 1, srcWidth);
254  const Pixel* srcCurr = src.getLinePtr<Pixel>(srcY + 0, srcWidth);
255 
256  assert(srcWidth <= 1024);
257  unsigned edgeBuf[1024];
258  calcInitialEdges(srcPrev, srcCurr, srcWidth, edgeBuf, edgeOp);
259 
260  bool isCopy = postScale.isCopy();
261  for (unsigned dstY = dstStartY; dstY < dstEndY; srcY += 1, dstY += 3) {
262  Pixel buf0[3 * 1024], buf1[3 * 1024], buf2[3 * 1024];
263  const Pixel* srcNext = src.getLinePtr<Pixel>(srcY + 1, srcWidth);
264  Pixel* dst0 = dst.acquireLine(dstY + 0);
265  Pixel* dst1 = dst.acquireLine(dstY + 1);
266  Pixel* dst2 = dst.acquireLine(dstY + 2);
267  if (isCopy) {
268  hqScale(srcPrev, srcCurr, srcNext, dst0, dst1, dst2,
269  srcWidth, edgeBuf, edgeOp);
270  } else {
271  hqScale(srcPrev, srcCurr, srcNext, buf0, buf1, buf2,
272  srcWidth, edgeBuf, edgeOp);
273  postScale(buf0, dst0, dstWidth);
274  postScale(buf1, dst1, dstWidth);
275  postScale(buf2, dst2, dstWidth);
276  }
277  dst.releaseLine(dstY + 0, dst0);
278  dst.releaseLine(dstY + 1, dst1);
279  dst.releaseLine(dstY + 2, dst2);
280  srcPrev = srcCurr;
281  srcCurr = srcNext;
282  }
283 }
284 
285 } // namespace openmsx
286 
287 #endif