openMSX
SaI3xScaler.cc
Go to the documentation of this file.
1 // 2xSaI is Copyright (c) 1999-2001 by Derek Liauw Kie Fa.
2 // http://elektron.its.tudelft.nl/~dalikifa/
3 // 2xSaI is free under GPL.
4 //
5 // Modified for use in openMSX by Maarten ter Huurne.
6 
7 #include "SaI3xScaler.hh"
8 #include "FrameSource.hh"
9 #include "ScalerOutput.hh"
10 #include "vla.hh"
11 #include "build-info.hh"
12 #include <cassert>
13 #include <cstdint>
14 
15 namespace openmsx {
16 
17 template <typename Pixel>
19  : Scaler3<Pixel>(pixelOps_)
20  , pixelOps(pixelOps_)
21 {
22 }
23 
24 template <class Pixel>
26  FrameSource& src, unsigned srcStartY, unsigned srcEndY,
27  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
28 {
29  unsigned dstHeight = dst.getHeight();
30  unsigned stopDstY = (dstEndY == dstHeight)
31  ? dstEndY : dstEndY - 3;
32  unsigned srcY = srcStartY, dstY = dstStartY;
33  for (/* */; dstY < stopDstY; srcY += 1, dstY += 3) {
34  Pixel color = src.getLineColor<Pixel>(srcY);
35  for (int i = 0; i < 3; ++i) {
36  dst.fillLine(dstY + i, color);
37  }
38  }
39  if (dstY != dstHeight) {
40  unsigned nextLineWidth = src.getLineWidth(srcY + 1);
41  assert(src.getLineWidth(srcY) == 1);
42  assert(nextLineWidth != 1);
43  this->dispatchScale(src, srcY, srcEndY, nextLineWidth,
44  dst, dstY, dstEndY);
45  }
46 }
47 
48 template <typename Pixel>
50 {
51  return pixelOps.template blend<1, 1>(p1, p2);
52 }
53 
54 static const unsigned redblueMask = 0xF81F;
55 static const unsigned greenMask = 0x7E0;
56 
57 // TODO use PixelOperations::lerp()
58 template <typename Pixel>
59 static Pixel bilinear(unsigned a, unsigned b, unsigned x);
60 
61 template<> uint16_t bilinear<uint16_t>(unsigned a, unsigned b, unsigned x)
62 {
63  if (a == b) return a;
64 
65  const unsigned areaB = x >> 11; // reduce 16 bit fraction to 5 bits
66  const unsigned areaA = 0x20 - areaB;
67 
68  a = (a & redblueMask) | ((a & greenMask) << 16);
69  b = (b & redblueMask) | ((b & greenMask) << 16);
70  const unsigned result = ((areaA * a) + (areaB * b)) >> 5;
71  return (result & redblueMask) | ((result >> 16) & greenMask);
72 }
73 
74 template<> uint32_t bilinear<uint32_t>(unsigned a, unsigned b, unsigned x)
75 {
76  if (a == b) return a;
77 
78  const unsigned areaB = x >> 8; // reduce 16 bit fraction to 8 bits
79  const unsigned areaA = 0x100 - areaB;
80 
81  const unsigned result0 =
82  ((a & 0x00FF00FF) * areaA + (b & 0x00FF00FF) * areaB) >> 8;
83  const unsigned result1 =
84  ((a & 0xFF00FF00) >> 8) * areaA + ((b & 0xFF00FF00) >> 8) * areaB;
85  return (result0 & 0x00FF00FF) | (result1 & 0xFF00FF00);
86 }
87 
88 // TODO move to PixelOperations
89 template<typename Pixel> static Pixel bilinear4(
90  unsigned a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned y);
91 
92 template<> uint16_t bilinear4<uint16_t>(
93  unsigned a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned y)
94 {
95  x >>= 11;
96  y >>= 11;
97  const unsigned xy = (x * y) >> 5;
98 
99  const unsigned areaA = 0x20 + xy - x - y;
100  const unsigned areaB = x - xy;
101  const unsigned areaC = y - xy;
102  const unsigned areaD = xy;
103 
104  a = (a & redblueMask) | ((a & greenMask) << 16);
105  b = (b & redblueMask) | ((b & greenMask) << 16);
106  c = (c & redblueMask) | ((c & greenMask) << 16);
107  d = (d & redblueMask) | ((d & greenMask) << 16);
108  unsigned result = (
109  (areaA * a) + (areaB * b) + (areaC * c) + (areaD * d)
110  ) >> 5;
111  return (result & redblueMask) | ((result >> 16) & greenMask);
112 }
113 
114 template<> uint32_t bilinear4<uint32_t>(
115  unsigned a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned y)
116 {
117  x >>= 8;
118  y >>= 8;
119  const unsigned xy = (x * y) >> 8;
120 
121  const unsigned areaA = (1 << 8) + xy - x - y;
122  const unsigned areaB = x - xy;
123  const unsigned areaC = y - xy;
124  const unsigned areaD = xy;
125 
126  const unsigned result0 =
127  ((a & 0x00FF00FF) * areaA + (b & 0x00FF00FF) * areaB +
128  (c & 0x00FF00FF) * areaC + (d & 0x00FF00FF) * areaD) >> 8;
129  const unsigned result1 =
130  ((a & 0xFF00FF00) >> 8) * areaA + ((b & 0xFF00FF00) >> 8) * areaB +
131  ((c & 0xFF00FF00) >> 8) * areaC + ((d & 0xFF00FF00) >> 8) * areaD;
132  return (result0 & 0x00FF00FF) | (result1 & 0xFF00FF00);
133 }
134 
135 template <typename Pixel>
136 class Blender
137 {
138 public:
139  template <unsigned x>
140  inline static Pixel blend(unsigned a, unsigned b);
141 
142  template <unsigned x, unsigned y>
143  inline static Pixel blend(unsigned a, unsigned b, unsigned c, unsigned d);
144 };
145 
146 template <unsigned X, unsigned OLD, unsigned NEW>
147 struct Round {
148  static_assert(OLD > NEW, "!");
149  static const unsigned result =
150  (X >> (OLD - NEW)) + ((X >> (OLD - NEW - 1)) & 1);
151 };
152 
153 template <typename Pixel>
154 template <unsigned x>
155 inline Pixel Blender<Pixel>::blend(unsigned a, unsigned b)
156 {
157  if (a == b) return a;
158 
159  const unsigned bits = (sizeof(Pixel) == 2) ? 5 : 8;
160  const unsigned areaB = Round<x, 16, bits>::result;
161  const unsigned areaA = (1 << bits) - areaB;
162 
163  if (sizeof(Pixel) == 2) {
164  a = (a & redblueMask) | ((a & greenMask) << 16);
165  b = (b & redblueMask) | ((b & greenMask) << 16);
166  const unsigned result = ((areaA * a) + (areaB * b)) >> bits;
167  return (result & redblueMask) | ((result >> 16) & greenMask);
168  } else {
169  const unsigned result0 =
170  ((a & 0x00FF00FF) * areaA +
171  (b & 0x00FF00FF) * areaB) >> bits;
172  const unsigned result1 =
173  ((a & 0xFF00FF00) >> bits) * areaA +
174  ((b & 0xFF00FF00) >> bits) * areaB;
175  return (result0 & 0x00FF00FF) | (result1 & 0xFF00FF00);
176  }
177 }
178 
179 template <typename Pixel>
180 template <unsigned wx, unsigned wy>
182  unsigned a, unsigned b, unsigned c, unsigned d)
183 {
184  const unsigned bits = (sizeof(Pixel) == 2) ? 5 : 8;
185  const unsigned xy = (wx * wy) >> 16;
186  const unsigned areaB = Round<wx - xy, 16, bits>::result;
187  const unsigned areaC = Round<wy - xy, 16, bits>::result;
188  const unsigned areaD = Round<xy, 16, bits>::result;
189  const unsigned areaA = (1 << bits) - areaB - areaC - areaD;
190 
191  if (sizeof(Pixel) == 2) {
192  a = (a & redblueMask) | ((a & greenMask) << 16);
193  b = (b & redblueMask) | ((b & greenMask) << 16);
194  c = (c & redblueMask) | ((c & greenMask) << 16);
195  d = (d & redblueMask) | ((d & greenMask) << 16);
196  unsigned result = (
197  (areaA * a) + (areaB * b) + (areaC * c) + (areaD * d)
198  ) >> bits;
199  return (result & redblueMask) | ((result >> 16) & greenMask);
200  } else {
201  const unsigned result0 =
202  ((a & 0x00FF00FF) * areaA +
203  (b & 0x00FF00FF) * areaB +
204  (c & 0x00FF00FF) * areaC +
205  (d & 0x00FF00FF) * areaD) >> bits;
206  const unsigned result1 =
207  ((a & 0xFF00FF00) >> bits) * areaA +
208  ((b & 0xFF00FF00) >> bits) * areaB +
209  ((c & 0xFF00FF00) >> bits) * areaC +
210  ((d & 0xFF00FF00) >> bits) * areaD;
211  return (result0 & 0x00FF00FF) | (result1 & 0xFF00FF00);
212  }
213 }
214 
215 template <unsigned i>
217 {
218 public:
219  template <typename Pixel>
220  inline static void fill(Pixel*& dp, unsigned sa) {
221  *dp++ = sa;
222  PixelStripRepeater<i - 1>::template fill<Pixel>(dp, sa);
223  }
224 
225  template <unsigned NX, unsigned y, typename Pixel>
226  inline static void blendBackslash(
227  Pixel*& dp,
228  unsigned sa, unsigned sb, unsigned sc, unsigned sd,
229  unsigned se, unsigned sg, unsigned sj, unsigned sl)
230  {
231  // Fractional parts of the fixed point X coordinates.
232  const unsigned x1 = ((NX - i) << 16) / NX;
233  const unsigned y1 = y;
234  const unsigned f1 = (x1 >> 1) + (0x10000 >> 2);
235  const unsigned f2 = (y1 >> 1) + (0x10000 >> 2);
236  if (y1 <= f1 && sa == sj && sa != se) {
237  *dp++ = Blender<Pixel>::template blend<f1 - y1>(sa, sb);
238  } else if (y1 >= f1 && sa == sg && sa != sl) {
239  *dp++ = Blender<Pixel>::template blend<y1 - f1>(sa, sc);
240  } else if (x1 >= f2 && sa == se && sa != sj) {
241  *dp++ = Blender<Pixel>::template blend<x1 - f2>(sa, sb);
242  } else if (x1 <= f2 && sa == sl && sa != sg) {
243  *dp++ = Blender<Pixel>::template blend<f2 - x1>(sa, sc);
244  } else if (y1 >= x1) {
245  *dp++ = Blender<Pixel>::template blend<y1 - x1>(sa, sc);
246  } else if (y1 <= x1) {
247  *dp++ = Blender<Pixel>::template blend<x1 - y1>(sa, sb);
248  }
249  PixelStripRepeater<i - 1>::template blendBackslash<NX, y, Pixel>(
250  dp, sa, sb, sc, sd, se, sg, sj, sl );
251  }
252 
253  template <unsigned NX, unsigned y, typename Pixel>
254  inline static void blendSlash(
255  Pixel*& dp,
256  unsigned sa, unsigned sb, unsigned sc, unsigned sd,
257  unsigned sf, unsigned sh, unsigned si, unsigned sk)
258  {
259  // Fractional parts of the fixed point X coordinates.
260  const unsigned x1 = ((NX - i) << 16) / NX;
261  const unsigned x2 = 0x10000 - x1;
262  const unsigned y1 = y;
263  const unsigned y2 = 0x10000 - y1;
264  const unsigned f1 = (x1 >> 1) + (0x10000 >> 2);
265  const unsigned f2 = (y1 >> 1) + (0x10000 >> 2);
266  if (y2 >= f1 && sb == sh && sb != sf) {
267  *dp++ = Blender<Pixel>::template blend<y2 - f1>(sb, sa);
268  } else if (y2 <= f1 && sb == si && sb != sk) {
269  *dp++ = Blender<Pixel>::template blend<f1 - y2>(sb, sd);
270  } else if (x2 >= f2 && sb == sf && sb != sh) {
271  *dp++ = Blender<Pixel>::template blend<x2 - f2>(sb, sa);
272  } else if (x2 <= f2 && sb == sk && sb != si) {
273  *dp++ = Blender<Pixel>::template blend<f2 - x2>(sb, sd);
274  } else if (y2 >= x1) {
275  *dp++ = Blender<Pixel>::template blend<y2 - x1>(sb, sa);
276  } else if (y2 <= x1) {
277  *dp++ = Blender<Pixel>::template blend<x1 - y2>(sb, sd);
278  }
279  PixelStripRepeater<i - 1>::template blendSlash<NX, y, Pixel>(
280  dp, sa, sb, sc, sd, sf, sh, si, sk );
281  }
282 
283  template <unsigned NX, unsigned y, typename Pixel>
284  inline static void blend4(
285  Pixel*& dp, unsigned sa, unsigned sb, unsigned sc, unsigned sd)
286  {
287  const unsigned x = ((NX - i) << 16) / NX;
288  *dp++ = Blender<Pixel>::template blend<x, y>(sa, sb, sc, sd);
289  PixelStripRepeater<i - 1>::template blend4<NX, y, Pixel>(dp, sa, sb, sc, sd);
290  }
291 };
292 template <>
294 {
295 public:
296  template <typename Pixel>
297  inline static void fill(Pixel*& /*dp*/, unsigned /*sa*/) { }
298 
299  template <unsigned NX, unsigned y, typename Pixel>
300  inline static void blendBackslash(
301  Pixel*& /*dp*/, unsigned /*sa*/, unsigned /*sb*/,
302  unsigned /*sc*/, unsigned /*sd*/, unsigned /*se*/,
303  unsigned /*sg*/, unsigned /*sj*/, unsigned /*sl*/) { }
304 
305  template <unsigned NX, unsigned y, typename Pixel>
306  inline static void blendSlash(
307  Pixel*& /*dp*/, unsigned /*sa*/, unsigned /*sb*/,
308  unsigned /*sc*/, unsigned /*sd*/, unsigned /*sf*/,
309  unsigned /*sh*/, unsigned /*si*/, unsigned /*sk*/) { }
310 
311  template <unsigned NX, unsigned y, typename Pixel>
312  inline static void blend4(Pixel*& /*dp*/, unsigned /*sa*/,
313  unsigned /*sb*/, unsigned /*sc*/, unsigned /*sd*/) { }
314 };
315 
316 template <unsigned i>
318 {
319 public:
320  template <unsigned NX, unsigned NY, typename Pixel>
321  inline static void scaleFixedLine(
322  const Pixel* __restrict src0, const Pixel* __restrict src1,
323  const Pixel* __restrict src2, const Pixel* __restrict src3,
324  unsigned srcWidth, ScalerOutput<Pixel>& dst, unsigned& dstY)
325  {
326  auto* dstLine = dst.acquireLine(dstY);
327  auto* dp = dstLine;
328  // Calculate fixed point coordinate.
329  const unsigned y1 = ((NY - i) << 16) / NY;
330 
331  unsigned pos1 = 0;
332  unsigned pos2 = 0;
333  unsigned pos3 = 1;
334  Pixel sb = src1[0];
335  Pixel sd = src2[0];
336  for (unsigned srcX = 0; srcX < srcWidth; srcX++) {
337  const unsigned pos0 = pos1;
338  pos1 = pos2;
339  pos2 = pos3;
340  pos3 = std::min(pos1 + 3, srcWidth) - 1;
341  // Get source pixels.
342  const Pixel sa = sb; // current pixel
343  sb = src1[pos2]; // next pixel
344  const Pixel sc = sd;
345  sd = src2[pos2];
346 
347  // Compute and write color of destination pixel.
348  if (sa == sb && sc == sd && sa == sc) {
349  // All the same color; fill.
350  PixelStripRepeater<NX>::template fill<Pixel>(dp, sa);
351  } else if (sa == sd && sb != sc) {
352  // Pattern in the form of a backslash.
353  PixelStripRepeater<NX>::template blendBackslash<NX, y1, Pixel>(
354  dp, sa, sb, sc, sd, src0[pos1], src1[pos0], src2[pos3], src3[pos2]);
355  } else if (sb == sc && sa != sd) {
356  // Pattern in the form of a slash.
357  PixelStripRepeater<NX>::template blendSlash<NX, y1, Pixel>(
358  dp, sa, sb, sc, sd, src0[pos2], src2[pos0], src1[pos3], src3[pos1]);
359  } else {
360  // No pattern; use bilinear interpolatation.
361  PixelStripRepeater<NX>::template blend4<NX, y1, Pixel>(
362  dp, sa, sb, sc, sd);
363  }
364  }
365  dst.releaseLine(dstY, dstLine);
366  ++dstY;
367 
368  LineRepeater<i - 1>::template scaleFixedLine<NX, NY, Pixel>(
369  src0, src1, src2, src3, srcWidth, dst, dstY);
370  }
371 };
372 template <>
373 class LineRepeater<0>
374 {
375 public:
376  template <unsigned NX, unsigned NY, typename Pixel>
377  inline static void scaleFixedLine(
378  const Pixel* /*src0*/, const Pixel* /*src1*/, const Pixel* /*src2*/,
379  const Pixel* /*src3*/, unsigned /*srcWidth*/,
380  ScalerOutput<Pixel>& /*dst*/, unsigned& /*dstY*/)
381  { }
382 };
383 
384 template <typename Pixel>
385 template <unsigned NX, unsigned NY>
386 void SaI3xScaler<Pixel>::scaleFixed(FrameSource& src,
387  unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
388  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
389 {
390  assert(dst.getWidth() == srcWidth * NX);
391  assert(dst.getHeight() == src.getHeight() * NY);
392 
393  VLA_SSE_ALIGNED(Pixel, buf0_, srcWidth); auto* buf0 = buf0_;
394  VLA_SSE_ALIGNED(Pixel, buf1_, srcWidth); auto* buf1 = buf1_;
395  VLA_SSE_ALIGNED(Pixel, buf2_, srcWidth); auto* buf2 = buf2_;
396  VLA_SSE_ALIGNED(Pixel, buf3_, srcWidth); auto* buf3 = buf3_;
397 
398  int srcY = srcStartY;
399  auto* src0 = src.getLinePtr(srcY - 1, srcWidth, buf0);
400  auto* src1 = src.getLinePtr(srcY + 0, srcWidth, buf1);
401  auto* src2 = src.getLinePtr(srcY + 1, srcWidth, buf2);
402 
403  for (unsigned dstY = dstStartY; dstY < dstEndY; srcY++) {
404  auto* src3 = src.getLinePtr(srcY + 2, srcWidth, buf3);
405  LineRepeater<NY>::template scaleFixedLine<NX, NY, Pixel>(
406  src0, src1, src2, src3, srcWidth, dst, dstY);
407  src0 = src1;
408  src1 = src2;
409  src2 = src3;
410  std::swap(buf0, buf1);
411  std::swap(buf1, buf2);
412  std::swap(buf2, buf3);
413  }
414 }
415 
416 template <typename Pixel>
417 void SaI3xScaler<Pixel>::scaleAny(FrameSource& src,
418  unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
419  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY) __restrict
420 {
421  // Calculate fixed point end coordinates and deltas.
422  const unsigned wfinish = (srcWidth - 1) << 16;
423  const unsigned dw = wfinish / (dst.getWidth() - 1);
424  const unsigned hfinish = (src.getHeight() - 1) << 16;
425  const unsigned dh = hfinish / (dst.getHeight() - 1);
426 
427  VLA_SSE_ALIGNED(Pixel, buf0, srcWidth);
428  VLA_SSE_ALIGNED(Pixel, buf1, srcWidth);
429  VLA_SSE_ALIGNED(Pixel, buf2, srcWidth);
430  VLA_SSE_ALIGNED(Pixel, buf3, srcWidth);
431 
432  unsigned h = 0;
433  for (unsigned dstY = dstStartY; dstY < dstEndY; dstY++) {
434  // Get source line pointers.
435  int line = srcStartY + (h >> 16);
436  // TODO possible optimization: reuse srcN from previous step
437  auto* src0 = src.getLinePtr(line - 1, srcWidth, buf0);
438  auto* src1 = src.getLinePtr(line + 0, srcWidth, buf1);
439  auto* src2 = src.getLinePtr(line + 1, srcWidth, buf2);
440  auto* src3 = src.getLinePtr(line + 2, srcWidth, buf3);
441 
442  // Get destination line pointer.
443  auto* dstLine = dst.acquireLine(dstY);
444  auto* dp = dstLine;
445 
446  // Fractional parts of the fixed point Y coordinates.
447  const unsigned y1 = h & 0xffff;
448  const unsigned y2 = 0x10000 - y1;
449  // Next line.
450  h += dh;
451 
452  unsigned pos1 = 0;
453  unsigned pos2 = 0;
454  unsigned pos3 = 1;
455  Pixel B = src1[0];
456  Pixel D = src2[0];
457  for (unsigned w = 0; w < wfinish; ) {
458  const unsigned pos0 = pos1;
459  pos1 = pos2;
460  pos2 = pos3;
461  pos3 = std::min(pos1 + 3, srcWidth) - 1;
462  // Get source pixels.
463  const Pixel A = B; // current pixel
464  B = src1[pos2]; // next pixel
465  const Pixel C = D;
466  D = src2[pos2];
467 
468  // Compute and write color of destination pixel.
469  if (A == B && C == D && A == C) { // 0
470  do {
471  *dp++ = A;
472  w += dw;
473  } while ((w >> 16) == pos1);
474  } else if (A == D && B != C) { // 1
475  do {
476  // Fractional parts of the fixed point X coordinates.
477  const unsigned x1 = w & 0xffff;
478  const unsigned f1 = (x1 >> 1) + (0x10000 >> 2);
479  const unsigned f2 = (y1 >> 1) + (0x10000 >> 2);
480  Pixel product1;
481  if (y1 <= f1 && A == src2[pos3] && A != src0[pos1]) { // close to B
482  product1 = bilinear<Pixel>(A, B, f1 - y1);
483  } else if (y1 >= f1 && A == src1[pos0] && A != src3[pos2]) { // close to C
484  product1 = bilinear<Pixel>(A, C, y1 - f1);
485  } else if (x1 >= f2 && A == src0[pos1] && A != src2[pos3]) { // close to B
486  product1 = bilinear<Pixel>(A, B, x1 - f2);
487  } else if (x1 <= f2 && A == src3[pos2] && A != src1[pos0]) { // close to C
488  product1 = bilinear<Pixel>(A, C, f2 - x1);
489  } else if (y1 >= x1) { // close to C
490  product1 = bilinear<Pixel>(A, C, y1 - x1);
491  } else {
492  assert(y1 < x1); // close to B
493  product1 = bilinear<Pixel>(A, B, x1 - y1);
494  }
495  *dp++ = product1;
496  w += dw;
497  } while ((w >> 16) == pos1);
498  } else if (B == C && A != D) { // 2
499  do {
500  // Fractional parts of the fixed point X coordinates.
501  const unsigned x1 = w & 0xffff;
502  const unsigned x2 = 0x10000 - x1;
503  const unsigned f1 = (x1 >> 1) + (0x10000 >> 2);
504  const unsigned f2 = (y1 >> 1) + (0x10000 >> 2);
505  Pixel product1;
506  if (y2 >= f1 && B == src2[pos0] && B != src0[pos2]) { // close to A
507  product1 = bilinear<Pixel>(B, A, y2 - f1);
508  } else if (y2 <= f1 && B == src1[pos3] && B != src3[pos1]) { // close to D
509  product1 = bilinear<Pixel>(B, D, f1 - y2);
510  } else if (x2 >= f2 && B == src0[pos2] && B != src2[pos0]) { // close to A
511  product1 = bilinear<Pixel>(B, A, x2 - f2);
512  } else if (x2 <= f2 && B == src3[pos1] && B != src1[pos3]) { // close to D
513  product1 = bilinear<Pixel>(B, D, f2 - x2);
514  } else if (y2 >= x1) { // close to A
515  product1 = bilinear<Pixel>(B, A, y2 - x1);
516  } else {
517  assert(y2 < x1); // close to D
518  product1 = bilinear<Pixel>(B, D, x1 - y2);
519  }
520  *dp++ = product1;
521  w += dw;
522  } while ((w >> 16) == pos1);
523  } else { // 3
524  do {
525  // Fractional parts of the fixed point X coordinates.
526  const unsigned x1 = w & 0xffff;
527  *dp++ = bilinear4<Pixel>(A, B, C, D, x1, y1);
528  w += dw;
529  } while ((w >> 16) == pos1);
530  }
531  }
532  dst.releaseLine(dstY, dstLine);
533  }
534 }
535 
536 template <typename Pixel>
538  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
539  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
540 {
541  scaleFixed<3, 3>(src, srcStartY, srcEndY, srcWidth, dst, dstStartY, dstEndY);
542 }
543 
544 
545 // Force template instantiation.
546 #if HAVE_16BPP
547 template class SaI3xScaler<uint16_t>;
548 #endif
549 #if HAVE_32BPP
550 template class SaI3xScaler<uint32_t>;
551 #endif
552 
553 } // namespace openmsx
const Pixel getLineColor(unsigned line) const
Get the (single) color of the given line.
Definition: FrameSource.hh:76
uint32_t bilinear4< uint32_t >(unsigned a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned y)
Definition: SaI3xScaler.cc:114
SaI3xScaler(const PixelOperations< Pixel > &pixelOps)
Definition: SaI3xScaler.cc:18
static void scaleFixedLine(const Pixel *src0, const Pixel *src1, const Pixel *src2, const Pixel *src3, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned &dstY)
Definition: SaI3xScaler.cc:321
static void blendBackslash(Pixel *&, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned)
Definition: SaI3xScaler.cc:300
uint32_t bilinear< uint32_t >(unsigned a, unsigned b, unsigned x)
Definition: SaI3xScaler.cc:74
void scaleBlank1to3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: SaI3xScaler.cc:25
void scale1x1to3x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: SaI3xScaler.cc:537
2xSaI algorithm: edge-detection which produces a rounded look.
Definition: SaI3xScaler.hh:13
Interface for getting lines from a video frame.
Definition: FrameSource.hh:15
static void fill(Pixel *&dp, unsigned sa)
Definition: SaI3xScaler.cc:220
unsigned Pixel
static void blend4(Pixel *&dp, unsigned sa, unsigned sb, unsigned sc, unsigned sd)
Definition: SaI3xScaler.cc:284
static void fill(Pixel *&, unsigned)
Definition: SaI3xScaler.cc:297
static void blend4(Pixel *&, unsigned, unsigned, unsigned, unsigned)
Definition: SaI3xScaler.cc:312
virtual void releaseLine(unsigned y, Pixel *buf)=0
virtual void fillLine(unsigned y, Pixel color)=0
static void blendBackslash(Pixel *&dp, unsigned sa, unsigned sb, unsigned sc, unsigned sd, unsigned se, unsigned sg, unsigned sj, unsigned sl)
Definition: SaI3xScaler.cc:226
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:7
virtual unsigned getHeight() const =0
static void blendSlash(Pixel *&, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned)
Definition: SaI3xScaler.cc:306
virtual Pixel * acquireLine(unsigned y)=0
static void blendSlash(Pixel *&dp, unsigned sa, unsigned sb, unsigned sc, unsigned sd, unsigned sf, unsigned sh, unsigned si, unsigned sk)
Definition: SaI3xScaler.cc:254
uint16_t bilinear< uint16_t >(unsigned a, unsigned b, unsigned x)
Definition: SaI3xScaler.cc:61
uint16_t bilinear4< uint16_t >(unsigned a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned y)
Definition: SaI3xScaler.cc:92
static Pixel blend(unsigned a, unsigned b)
Definition: SaI3xScaler.cc:155
virtual unsigned getLineWidth(unsigned line) const =0
Gets the number of display pixels on the given line.
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition: vla.hh:44
static void scaleFixedLine(const Pixel *, const Pixel *, const Pixel *, const Pixel *, unsigned, ScalerOutput< Pixel > &, unsigned &)
Definition: SaI3xScaler.cc:377
Base class for 3x scalers.
Definition: Scaler3.hh:11