openMSX
LineScalers.hh
Go to the documentation of this file.
1 #ifndef LINESCALERS_HH
2 #define LINESCALERS_HH
3 
4 #include "PixelOperations.hh"
5 #include "likely.hh"
6 #include <type_traits>
7 #include <cstddef>
8 #include <cstring>
9 #include <cassert>
10 #ifdef __SSE2__
11 #include "emmintrin.h"
12 #endif
13 #ifdef __SSSE3__
14 #include "tmmintrin.h"
15 #endif
16 
17 namespace openmsx {
18 
19 // Tag classes
20 struct TagCopy {};
21 template <typename CLASS, typename TAG> struct IsTagged
22  : std::is_base_of<TAG, CLASS> {};
23 
24 
25 // Scalers
26 
34 template <typename Pixel> class Scale_1on3
35 {
36 public:
37  void operator()(const Pixel* in, Pixel* out, size_t width);
38 };
39 
40 template <typename Pixel> class Scale_1on4
41 {
42 public:
43  void operator()(const Pixel* in, Pixel* out, size_t width);
44 };
45 
46 template <typename Pixel> class Scale_1on6
47 {
48 public:
49  void operator()(const Pixel* in, Pixel* out, size_t width);
50 };
51 
52 template <typename Pixel> class Scale_1on2
53 {
54 public:
55  void operator()(const Pixel* in, Pixel* out, size_t width);
56 };
57 
58 template <typename Pixel> class Scale_1on1 : public TagCopy
59 {
60 public:
61  void operator()(const Pixel* in, Pixel* out, size_t width);
62 };
63 
64 template <typename Pixel> class Scale_2on1
65 {
66 public:
67  explicit Scale_2on1(PixelOperations<Pixel> pixelOps);
68  void operator()(const Pixel* in, Pixel* out, size_t width);
69 private:
70  PixelOperations<Pixel> pixelOps;
71 };
72 
73 template <typename Pixel> class Scale_6on1
74 {
75 public:
76  explicit Scale_6on1(PixelOperations<Pixel> pixelOps);
77  void operator()(const Pixel* in, Pixel* out, size_t width);
78 private:
79  PixelOperations<Pixel> pixelOps;
80 };
81 
82 template <typename Pixel> class Scale_4on1
83 {
84 public:
85  explicit Scale_4on1(PixelOperations<Pixel> pixelOps);
86  void operator()(const Pixel* in, Pixel* out, size_t width);
87 private:
88  PixelOperations<Pixel> pixelOps;
89 };
90 
91 template <typename Pixel> class Scale_3on1
92 {
93 public:
94  explicit Scale_3on1(PixelOperations<Pixel> pixelOps);
95  void operator()(const Pixel* in, Pixel* out, size_t width);
96 private:
97  PixelOperations<Pixel> pixelOps;
98 };
99 
100 template <typename Pixel> class Scale_3on2
101 {
102 public:
103  explicit Scale_3on2(PixelOperations<Pixel> pixelOps);
104  void operator()(const Pixel* in, Pixel* out, size_t width);
105 private:
106  PixelOperations<Pixel> pixelOps;
107 };
108 
109 template <typename Pixel> class Scale_3on4
110 {
111 public:
112  explicit Scale_3on4(PixelOperations<Pixel> pixelOps);
113  void operator()(const Pixel* in, Pixel* out, size_t width);
114 private:
115  PixelOperations<Pixel> pixelOps;
116 };
117 
118 template <typename Pixel> class Scale_3on8
119 {
120 public:
121  explicit Scale_3on8(PixelOperations<Pixel> pixelOps);
122  void operator()(const Pixel* in, Pixel* out, size_t width);
123 private:
124  PixelOperations<Pixel> pixelOps;
125 };
126 
127 template <typename Pixel> class Scale_2on3
128 {
129 public:
130  explicit Scale_2on3(PixelOperations<Pixel> pixelOps);
131  void operator()(const Pixel* in, Pixel* out, size_t width);
132 private:
133  PixelOperations<Pixel> pixelOps;
134 };
135 
136 template <typename Pixel> class Scale_4on3
137 {
138 public:
139  explicit Scale_4on3(PixelOperations<Pixel> pixelOps);
140  void operator()(const Pixel* in, Pixel* out, size_t width);
141 private:
142  PixelOperations<Pixel> pixelOps;
143 };
144 
145 template <typename Pixel> class Scale_8on3
146 {
147 public:
148  explicit Scale_8on3(PixelOperations<Pixel> pixelOps);
149  void operator()(const Pixel* in, Pixel* out, size_t width);
150 private:
151  PixelOperations<Pixel> pixelOps;
152 };
153 
154 template <typename Pixel> class Scale_2on9
155 {
156 public:
157  explicit Scale_2on9(PixelOperations<Pixel> pixelOps);
158  void operator()(const Pixel* in, Pixel* out, size_t width);
159 private:
160  PixelOperations<Pixel> pixelOps;
161 };
162 
163 template <typename Pixel> class Scale_4on9
164 {
165 public:
166  explicit Scale_4on9(PixelOperations<Pixel> pixelOps);
167  void operator()(const Pixel* in, Pixel* out, size_t width);
168 private:
169  PixelOperations<Pixel> pixelOps;
170 };
171 
172 template <typename Pixel> class Scale_8on9
173 {
174 public:
175  explicit Scale_8on9(PixelOperations<Pixel> pixelOps);
176  void operator()(const Pixel* in, Pixel* out, size_t width);
177 private:
178  PixelOperations<Pixel> pixelOps;
179 };
180 
181 template <typename Pixel> class Scale_4on5
182 {
183 public:
184  explicit Scale_4on5(PixelOperations<Pixel> pixelOps);
185  void operator()(const Pixel* in, Pixel* out, size_t width);
186 private:
187  PixelOperations<Pixel> pixelOps;
188 };
189 
190 template <typename Pixel> class Scale_7on8
191 {
192 public:
193  explicit Scale_7on8(PixelOperations<Pixel> pixelOps);
194  void operator()(const Pixel* in, Pixel* out, size_t width);
195 private:
196  PixelOperations<Pixel> pixelOps;
197 };
198 
199 template <typename Pixel> class Scale_17on20
200 {
201 public:
202  explicit Scale_17on20(PixelOperations<Pixel> pixelOps);
203  void operator()(const Pixel* in, Pixel* out, size_t width);
204 private:
205  PixelOperations<Pixel> pixelOps;
206 };
207 
208 template <typename Pixel> class Scale_9on10
209 {
210 public:
211  explicit Scale_9on10(PixelOperations<Pixel> pixelOps);
212  void operator()(const Pixel* in, Pixel* out, size_t width);
213 private:
214  PixelOperations<Pixel> pixelOps;
215 };
216 
217 
225 template <typename Pixel, unsigned w1 = 1, unsigned w2 = 1> class BlendLines
226 {
227 public:
228  explicit BlendLines(PixelOperations<Pixel> pixelOps);
229  void operator()(const Pixel* in1, const Pixel* in2,
230  Pixel* out, size_t width);
231 private:
232  PixelOperations<Pixel> pixelOps;
233 };
234 
237 template<typename Pixel>
238 class ZoomLine
239 {
240 public:
241  explicit ZoomLine(PixelOperations<Pixel> pixelOps);
242  void operator()(const Pixel* in, unsigned inWidth,
243  Pixel* out, unsigned outWidth) const;
244 private:
245  PixelOperations<Pixel> pixelOps;
246 };
247 
248 
257 template <typename Pixel> class AlphaBlendLines
258 {
259 public:
260  explicit AlphaBlendLines(PixelOperations<Pixel> pixelOps);
261  void operator()(const Pixel* in1, const Pixel* in2,
262  Pixel* out, size_t width);
263  void operator()(Pixel in1, const Pixel* in2,
264  Pixel* out, size_t width);
265 private:
266  PixelOperations<Pixel> pixelOps;
267 };
268 
269 
282 template<typename Pixel>
284 {
285 public:
294  virtual void operator()(const Pixel* in, Pixel* out, size_t outWidth) = 0;
295 
301  virtual bool isCopy() const = 0;
302 
303 protected:
304  ~PolyLineScaler() = default;
305 };
306 
310 template<typename Pixel, typename Scaler>
311 class PolyScale final : public PolyLineScaler<Pixel>
312 {
313 public:
315  : scaler()
316  {
317  }
319  : scaler(pixelOps)
320  {
321  }
322  void operator()(const Pixel* in, Pixel* out, size_t outWidth) override
323  {
324  scaler(in, out, outWidth);
325  }
326  bool isCopy() const override
327  {
329  }
330 private:
331  Scaler scaler;
332 };
333 
337 template<typename Pixel, typename Scaler>
338 class PolyScaleRef final : public PolyLineScaler<Pixel>
339 {
340 public:
341  explicit PolyScaleRef(Scaler& scaler_)
342  : scaler(scaler_)
343  {
344  }
345  void operator()(const Pixel* in, Pixel* out, size_t outWidth) override
346  {
347  scaler(in, out, outWidth);
348  }
349  bool isCopy() const override
350  {
352  }
353 private:
354  Scaler& scaler;
355 };
356 
357 
358 // implementation
359 
360 template <typename Pixel, unsigned N>
361 static inline void scale_1onN(
362  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
363 {
364  size_t i = 0, j = 0;
365  for (/* */; i < (width - (N - 1)); i += N, j += 1) {
366  Pixel pix = in[j];
367  for (unsigned k = 0; k < N; ++k) {
368  out[i + k] = pix;
369  }
370  }
371  for (unsigned k = 0; k < (N - 1); ++k) {
372  if ((i + k) < width) out[i + k] = 0;
373  }
374 }
375 
376 template <typename Pixel>
377 void Scale_1on3<Pixel>::operator()(const Pixel* in, Pixel* out, size_t width)
378 {
379  scale_1onN<Pixel, 3>(in, out, width);
380 }
381 
382 template <typename Pixel>
383 void Scale_1on4<Pixel>::operator()(const Pixel* in, Pixel* out, size_t width)
384 {
385  scale_1onN<Pixel, 4>(in, out, width);
386 }
387 
388 template <typename Pixel>
389 void Scale_1on6<Pixel>::operator()(const Pixel* in, Pixel* out, size_t width)
390 {
391  scale_1onN<Pixel, 6>(in, out, width);
392 }
393 
394 #ifdef __SSE2__
395 template<typename Pixel> static inline __m128i unpacklo(__m128i x, __m128i y)
396 {
397  if (sizeof(Pixel) == 4) {
398  return _mm_unpacklo_epi32(x, y);
399  } else if (sizeof(Pixel) == 2) {
400  return _mm_unpacklo_epi16(x, y);
401  } else {
402  UNREACHABLE;
403  }
404 }
405 template<typename Pixel> static inline __m128i unpackhi(__m128i x, __m128i y)
406 {
407  if (sizeof(Pixel) == 4) {
408  return _mm_unpackhi_epi32(x, y);
409  } else if (sizeof(Pixel) == 2) {
410  return _mm_unpackhi_epi16(x, y);
411  } else {
412  UNREACHABLE;
413  }
414 }
415 
416 template<typename Pixel>
417 static inline void scale_1on2_SSE(const Pixel* in_, Pixel* out_, size_t srcWidth)
418 {
419  size_t bytes = srcWidth * sizeof(Pixel);
420  assert((bytes % (4 * sizeof(__m128i))) == 0);
421  assert(bytes != 0);
422 
423  auto* in = reinterpret_cast<const char*>(in_) + bytes;
424  auto* out = reinterpret_cast< char*>(out_) + 2 * bytes;
425 
426  auto x = -ptrdiff_t(bytes);
427  do {
428  __m128i a0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + x + 0));
429  __m128i a1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + x + 16));
430  __m128i a2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + x + 32));
431  __m128i a3 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + x + 48));
432  __m128i l0 = unpacklo<Pixel>(a0, a0);
433  __m128i h0 = unpackhi<Pixel>(a0, a0);
434  __m128i l1 = unpacklo<Pixel>(a1, a1);
435  __m128i h1 = unpackhi<Pixel>(a1, a1);
436  __m128i l2 = unpacklo<Pixel>(a2, a2);
437  __m128i h2 = unpackhi<Pixel>(a2, a2);
438  __m128i l3 = unpacklo<Pixel>(a3, a3);
439  __m128i h3 = unpackhi<Pixel>(a3, a3);
440  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 2*x + 0), l0);
441  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 2*x + 16), h0);
442  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 2*x + 32), l1);
443  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 2*x + 48), h1);
444  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 2*x + 64), l2);
445  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 2*x + 80), h2);
446  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 2*x + 96), l3);
447  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 2*x + 112), h3);
448  x += 4 * sizeof(__m128i);
449  } while (x < 0);
450 }
451 #endif
452 
453 template <typename Pixel>
455  const Pixel* __restrict in, Pixel* __restrict out, size_t dstWidth)
456 {
457  // This is a fairly simple algorithm (output each input pixel twice).
458  // An ideal compiler should generate optimal (vector) code for it.
459  // I checked the 2013-05-29 dev snapshots of gcc-4.9 and clang-3.4:
460  // - Clang is not able to vectorize this loop. My best tuned C version
461  // of this routine is a little over 4x slower than the tuned
462  // SSE-intrinsics version.
463  // - Gcc can auto-vectorize this routine. Though my best tuned version
464  // (I mean tuned to further improve the auto-vectorization, including
465  // using the new __builtin_assume_aligned() instrinsic) still runs
466  // approx 40% slower than the intrinsics version.
467  // Hopefully in some years the compilers have improved further so that
468  // the instrinsic version is no longer needed.
469  size_t srcWidth = dstWidth / 2;
470 
471 #ifdef __SSE2__
472  size_t chunk = 4 * sizeof(__m128i) / sizeof(Pixel);
473  size_t srcWidth2 = srcWidth & ~(chunk - 1);
474  scale_1on2_SSE(in, out, srcWidth2);
475  in += srcWidth2;
476  out += 2 * srcWidth2;
477  srcWidth -= srcWidth2;
478 #endif
479 
480  // C++ version. Used both on non-x86 machines and (possibly) on x86 for
481  // the last few pixels of the line.
482  for (size_t x = 0; x < srcWidth; ++x) {
483  out[x * 2] = out[x * 2 + 1] = in[x];
484  }
485 }
486 
487 #ifdef __SSE2__
488 // Memcpy-like routine, it can be faster than a generic memcpy because:
489 // - It requires that both input and output are 16-bytes aligned.
490 // - It can only copy (non-zero) integer multiples of 128 bytes.
491 static inline void memcpy_SSE_128(
492  const void* __restrict in_, void* __restrict out_, size_t size)
493 {
494  assert((reinterpret_cast<size_t>(in_ ) % 16) == 0);
495  assert((reinterpret_cast<size_t>(out_) % 16) == 0);
496  assert((size % 128) == 0);
497  assert(size != 0);
498 
499  auto* in = reinterpret_cast<const __m128i*>(in_);
500  auto* out = reinterpret_cast< __m128i*>(out_);
501  auto* end = in + (size / sizeof(__m128i));
502  do {
503  out[0] = in[0];
504  out[1] = in[1];
505  out[2] = in[2];
506  out[3] = in[3];
507  out[4] = in[4];
508  out[5] = in[5];
509  out[6] = in[6];
510  out[7] = in[7];
511  in += 8;
512  out += 8;
513  } while (in != end);
514 }
515 #endif
516 
517 template <typename Pixel>
519  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
520 {
521  size_t nBytes = width * sizeof(Pixel);
522 
523 #ifdef __SSE2__
524  // When using a very recent gcc/clang, this routine is only about
525  // 10% faster than a simple memcpy(). When using gcc-4.6 (still the
526  // default on many systems), it's still about 66% faster.
527  size_t n128 = nBytes & ~127;
528  memcpy_SSE_128(in, out, n128); // copy 128 byte chunks
529  nBytes &= 127; // remaning bytes (if any)
530  if (likely(nBytes == 0)) return;
531  in += n128 / sizeof(Pixel);
532  out += n128 / sizeof(Pixel);
533 #endif
534 
535  memcpy(out, in, nBytes);
536 }
537 
538 
539 template <typename Pixel>
541  : pixelOps(pixelOps_)
542 {
543 }
544 
545 #ifdef __SSE2__
546 template<int IMM8> static inline __m128i shuffle(__m128i x, __m128i y)
547 {
548  return _mm_castps_si128(_mm_shuffle_ps(
549  _mm_castsi128_ps(x), _mm_castsi128_ps(y), IMM8));
550 }
551 
552 template<typename Pixel>
553 static inline __m128i blend(__m128i x, __m128i y, Pixel mask)
554 {
555  if (sizeof(Pixel) == 4) {
556  // 32bpp
557  __m128i p = shuffle<0x88>(x, y);
558  __m128i q = shuffle<0xDD>(x, y);
559  return _mm_avg_epu8(p, q);
560  } else {
561  // 16bpp, first shuffle odd/even pixels in the right position
562 #ifdef __SSSE3__
563  // This can be done faster using SSSE3
564  const __m128i LL = _mm_set_epi8(
565  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
566  0x0D, 0x0C, 0x09, 0x08, 0x05, 0x04, 0x01, 0x00);
567  const __m128i HL = _mm_set_epi8(
568  0x0D, 0x0C, 0x09, 0x08, 0x05, 0x04, 0x01, 0x00,
569  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
570  const __m128i LH = _mm_set_epi8(
571  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
572  0x0F, 0x0E, 0x0B, 0x0A, 0x07, 0x06, 0x03, 0x02);
573  const __m128i HH = _mm_set_epi8(
574  0x0F, 0x0E, 0x0B, 0x0A, 0x07, 0x06, 0x03, 0x02,
575  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
576  __m128i ll = _mm_shuffle_epi8(x, LL);
577  __m128i hl = _mm_shuffle_epi8(y, HL);
578  __m128i lh = _mm_shuffle_epi8(x, LH);
579  __m128i hh = _mm_shuffle_epi8(y, HH);
580  __m128i p = _mm_or_si128(ll, hl);
581  __m128i q = _mm_or_si128(lh, hh);
582 #else
583  // For SSE2 this only generates 1 instruction more, but with
584  // longer dependency chains
585  __m128i s = _mm_unpacklo_epi16(x, y);
586  __m128i t = _mm_unpackhi_epi16(x, y);
587  __m128i u = _mm_unpacklo_epi16(s, t);
588  __m128i v = _mm_unpackhi_epi16(s, t);
589  __m128i p = _mm_unpacklo_epi16(u, v);
590  __m128i q = _mm_unpackhi_epi16(u, v);
591 #endif
592  // Actually blend: (p & q) + (((p ^ q) & mask) >> 1)
593  __m128i m = _mm_set1_epi16(mask);
594  __m128i a = _mm_and_si128(p, q);
595  __m128i b = _mm_xor_si128(p, q);
596  __m128i c = _mm_and_si128(b, m);
597  __m128i d = _mm_srli_epi16(c, 1);
598  return _mm_add_epi16(a, d);
599  }
600 }
601 
602 template<typename Pixel>
603 static inline void scale_2on1_SSE(
604  const Pixel* __restrict in_, Pixel* __restrict out_, size_t dstBytes,
605  Pixel mask)
606 {
607  assert((dstBytes % (4 * sizeof(__m128i))) == 0);
608  assert(dstBytes != 0);
609 
610  auto* in = reinterpret_cast<const char*>(in_) + 2 * dstBytes;
611  auto* out = reinterpret_cast< char*>(out_) + dstBytes;
612 
613  auto x = -ptrdiff_t(dstBytes);
614  do {
615  __m128i a0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 2*x + 0));
616  __m128i a1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 2*x + 16));
617  __m128i a2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 2*x + 32));
618  __m128i a3 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 2*x + 48));
619  __m128i a4 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 2*x + 64));
620  __m128i a5 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 2*x + 80));
621  __m128i a6 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 2*x + 96));
622  __m128i a7 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 2*x + 112));
623  __m128i b0 = blend(a0, a1, mask);
624  __m128i b1 = blend(a2, a3, mask);
625  __m128i b2 = blend(a4, a5, mask);
626  __m128i b3 = blend(a6, a7, mask);
627  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + x + 0), b0);
628  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + x + 16), b1);
629  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + x + 32), b2);
630  _mm_storeu_si128(reinterpret_cast<__m128i*>(out + x + 48), b3);
631  x += 4 * sizeof(__m128i);
632  } while (x < 0);
633 }
634 #endif
635 
636 template <typename Pixel>
638  const Pixel* __restrict in, Pixel* __restrict out, size_t dstWidth)
639 {
640 #ifdef __SSE2__
641  size_t n64 = (dstWidth * sizeof(Pixel)) & ~63;
642  Pixel mask = pixelOps.getBlendMask();
643  scale_2on1_SSE(in, out, n64, mask); // process 64 byte chunks
644  dstWidth &= ((64 / sizeof(Pixel)) - 1); // remaning pixels (if any)
645  if (likely(dstWidth == 0)) return;
646  in += (2 * n64) / sizeof(Pixel);
647  out += n64 / sizeof(Pixel);
648 #endif
649 
650  // pure C++ version
651  for (size_t i = 0; i < dstWidth; ++i) {
652  out[i] = pixelOps.template blend<1, 1>(
653  in[2 * i + 0], in[2 * i + 1]);
654  }
655 }
656 
657 
658 template <typename Pixel>
660  : pixelOps(pixelOps_)
661 {
662 }
663 
664 template <typename Pixel>
666  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
667 {
668  for (size_t i = 0; i < width; ++i) {
669  out[i] = pixelOps.template blend6<1, 1, 1, 1, 1, 1>(&in[6 * i]);
670  }
671 }
672 
673 
674 template <typename Pixel>
676  : pixelOps(pixelOps_)
677 {
678 }
679 
680 template <typename Pixel>
682  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
683 {
684  for (size_t i = 0; i < width; ++i) {
685  out[i] = pixelOps.template blend4<1, 1, 1, 1>(&in[4 * i]);
686  }
687 }
688 
689 
690 template <typename Pixel>
692  : pixelOps(pixelOps_)
693 {
694 }
695 
696 template <typename Pixel>
698  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
699 {
700  for (size_t i = 0; i < width; ++i) {
701  out[i] = pixelOps.template blend3<1, 1, 1>(&in[3 * i]);
702  }
703 }
704 
705 
706 template <typename Pixel>
708  : pixelOps(pixelOps_)
709 {
710 }
711 
712 template <typename Pixel>
714  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
715 {
716  size_t i = 0, j = 0;
717  for (/* */; i < (width - 1); i += 2, j += 3) {
718  out[i + 0] = pixelOps.template blend2<2, 1>(&in[j + 0]);
719  out[i + 1] = pixelOps.template blend2<1, 2>(&in[j + 1]);
720  }
721  if (i < width) out[i] = 0;
722 }
723 
724 
725 template <typename Pixel>
727  : pixelOps(pixelOps_)
728 {
729 }
730 
731 template <typename Pixel>
733  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
734 {
735  size_t i = 0, j = 0;
736  for (/* */; i < (width - 3); i += 4, j += 3) {
737  out[i + 0] = in[j + 0];
738  out[i + 1] = pixelOps.template blend2<1, 2>(&in[j + 0]);
739  out[i + 2] = pixelOps.template blend2<2, 1>(&in[j + 1]);
740  out[i + 3] = in[j + 2];
741  }
742  for (size_t k = 0; k < (4 - 1); ++k) {
743  if ((i + k) < width) out[i + k] = 0;
744  }
745 }
746 
747 
748 template <typename Pixel>
750  : pixelOps(pixelOps_)
751 {
752 }
753 
754 template <typename Pixel>
756  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
757 {
758  size_t i = 0, j = 0;
759  for (/* */; i < (width - 7); i += 8, j += 3) {
760  out[i + 0] = in[j + 0];
761  out[i + 1] = in[j + 0];
762  out[i + 2] = pixelOps.template blend2<2, 1>(&in[j + 0]);
763  out[i + 3] = in[j + 1];
764  out[i + 4] = in[j + 1];
765  out[i + 5] = pixelOps.template blend2<1, 2>(&in[j + 1]);
766  out[i + 6] = in[j + 2];
767  out[i + 7] = in[j + 2];
768  }
769  for (size_t k = 0; k < (8 - 1); ++k) {
770  if ((i + k) < width) out[i + k] = 0;
771  }
772 }
773 
774 
775 template <typename Pixel>
777  : pixelOps(pixelOps_)
778 {
779 }
780 
781 template <typename Pixel>
783  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
784 {
785  size_t i = 0, j = 0;
786  for (/* */; i < (width - 2); i += 3, j += 2) {
787  out[i + 0] = in[j + 0];
788  out[i + 1] = pixelOps.template blend2<1, 1>(&in[j + 0]);
789  out[i + 2] = in[j + 1];
790  }
791  if ((i + 0) < width) out[i + 0] = 0;
792  if ((i + 1) < width) out[i + 1] = 0;
793 }
794 
795 
796 template <typename Pixel>
798  : pixelOps(pixelOps_)
799 {
800 }
801 
802 template <typename Pixel>
804  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
805 {
806  size_t i = 0, j = 0;
807  for (/* */; i < (width - 2); i += 3, j += 4) {
808  out[i + 0] = pixelOps.template blend2<3, 1>(&in[j + 0]);
809  out[i + 1] = pixelOps.template blend2<1, 1>(&in[j + 1]);
810  out[i + 2] = pixelOps.template blend2<1, 3>(&in[j + 2]);
811  }
812  if ((i + 0) < width) out[i + 0] = 0;
813  if ((i + 1) < width) out[i + 1] = 0;
814 }
815 
816 
817 template <typename Pixel>
819  : pixelOps(pixelOps_)
820 {
821 }
822 
823 template <typename Pixel>
825  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
826 {
827  size_t i = 0, j = 0;
828  for (/* */; i < (width - 2); i += 3, j += 8) {
829  out[i + 0] = pixelOps.template blend3<3, 3, 2> (&in[j + 0]);
830  out[i + 1] = pixelOps.template blend4<1, 3, 3, 1>(&in[j + 2]);
831  out[i + 2] = pixelOps.template blend3<2, 3, 3> (&in[j + 5]);
832  }
833  if ((i + 0) < width) out[i + 0] = 0;
834  if ((i + 1) < width) out[i + 1] = 0;
835 }
836 
837 
838 template <typename Pixel>
840  : pixelOps(pixelOps_)
841 {
842 }
843 
844 template <typename Pixel>
846  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
847 {
848  size_t i = 0, j = 0;
849  for (/* */; i < (width - 8); i += 9, j += 2) {
850  out[i + 0] = in[j + 0];
851  out[i + 1] = in[j + 0];
852  out[i + 2] = in[j + 0];
853  out[i + 3] = in[j + 0];
854  out[i + 4] = pixelOps.template blend2<1, 1>(&in[j + 0]);
855  out[i + 5] = in[j + 1];
856  out[i + 6] = in[j + 1];
857  out[i + 7] = in[j + 1];
858  out[i + 8] = in[j + 1];
859  }
860  if ((i + 0) < width) out[i + 0] = 0;
861  if ((i + 1) < width) out[i + 1] = 0;
862  if ((i + 2) < width) out[i + 2] = 0;
863  if ((i + 3) < width) out[i + 3] = 0;
864  if ((i + 4) < width) out[i + 4] = 0;
865  if ((i + 5) < width) out[i + 5] = 0;
866  if ((i + 6) < width) out[i + 6] = 0;
867  if ((i + 7) < width) out[i + 7] = 0;
868 }
869 
870 
871 template <typename Pixel>
873  : pixelOps(pixelOps_)
874 {
875 }
876 
877 template <typename Pixel>
879  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
880 {
881  size_t i = 0, j = 0;
882  for (/* */; i < (width - 8); i += 9, j += 4) {
883  out[i + 0] = in[j + 0];
884  out[i + 1] = in[j + 0];
885  out[i + 2] = pixelOps.template blend2<1, 3>(&in[j + 0]);
886  out[i + 3] = in[j + 1];
887  out[i + 4] = pixelOps.template blend2<1, 1>(&in[j + 1]);
888  out[i + 5] = in[j + 2];
889  out[i + 6] = pixelOps.template blend2<3, 1>(&in[j + 2]);
890  out[i + 7] = in[j + 3];
891  out[i + 8] = in[j + 3];
892  }
893  if ((i + 0) < width) out[i + 0] = 0;
894  if ((i + 1) < width) out[i + 1] = 0;
895  if ((i + 2) < width) out[i + 2] = 0;
896  if ((i + 3) < width) out[i + 3] = 0;
897  if ((i + 4) < width) out[i + 4] = 0;
898  if ((i + 5) < width) out[i + 5] = 0;
899  if ((i + 6) < width) out[i + 6] = 0;
900  if ((i + 7) < width) out[i + 7] = 0;
901 }
902 
903 
904 template <typename Pixel>
906  : pixelOps(pixelOps_)
907 {
908 }
909 
910 template <typename Pixel>
912  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
913 {
914  size_t i = 0, j = 0;
915  for (/* */; i < (width - 8); i += 9, j += 8) {
916  out[i + 0] = in[j + 0];
917  out[i + 1] = pixelOps.template blend2<1, 7>(&in[j + 0]);
918  out[i + 2] = pixelOps.template blend2<1, 3>(&in[j + 1]);
919  out[i + 3] = pixelOps.template blend2<3, 5>(&in[j + 2]);
920  out[i + 4] = pixelOps.template blend2<1, 1>(&in[j + 3]);
921  out[i + 5] = pixelOps.template blend2<5, 3>(&in[j + 4]);
922  out[i + 6] = pixelOps.template blend2<3, 1>(&in[j + 5]);
923  out[i + 7] = pixelOps.template blend2<7, 1>(&in[j + 6]);
924  out[i + 8] = in[j + 7];
925  }
926  if ((i + 0) < width) out[i + 0] = 0;
927  if ((i + 1) < width) out[i + 1] = 0;
928  if ((i + 2) < width) out[i + 2] = 0;
929  if ((i + 3) < width) out[i + 3] = 0;
930  if ((i + 4) < width) out[i + 4] = 0;
931  if ((i + 5) < width) out[i + 5] = 0;
932  if ((i + 6) < width) out[i + 6] = 0;
933  if ((i + 7) < width) out[i + 7] = 0;
934 }
935 
936 
937 template <typename Pixel>
939  : pixelOps(pixelOps_)
940 {
941 }
942 
943 template <typename Pixel>
945  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
946 {
947  assert((width % 5) == 0);
948  for (size_t i = 0, j = 0; i < width; i += 5, j += 4) {
949  out[i + 0] = in[j + 0];
950  out[i + 1] = pixelOps.template blend2<1, 3>(&in[j + 0]);
951  out[i + 2] = pixelOps.template blend2<1, 1>(&in[j + 1]);
952  out[i + 3] = pixelOps.template blend2<3, 1>(&in[j + 2]);
953  out[i + 4] = in[j + 3];
954  }
955 }
956 
957 
958 template <typename Pixel>
960  : pixelOps(pixelOps_)
961 {
962 }
963 
964 template <typename Pixel>
966  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
967 {
968  assert((width % 8) == 0);
969  for (size_t i = 0, j = 0; i < width; i += 8, j += 7) {
970  out[i + 0] = in[j + 0];
971  out[i + 1] = pixelOps.template blend2<1, 6>(&in[j + 0]);
972  out[i + 2] = pixelOps.template blend2<2, 5>(&in[j + 1]);
973  out[i + 3] = pixelOps.template blend2<3, 4>(&in[j + 2]);
974  out[i + 4] = pixelOps.template blend2<4, 3>(&in[j + 3]);
975  out[i + 5] = pixelOps.template blend2<5, 2>(&in[j + 4]);
976  out[i + 6] = pixelOps.template blend2<6, 1>(&in[j + 5]);
977  out[i + 7] = in[j + 6];
978  }
979 }
980 
981 
982 template <typename Pixel>
984  : pixelOps(pixelOps_)
985 {
986 }
987 
988 template <typename Pixel>
990  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
991 {
992  assert((width % 20) == 0);
993  for (size_t i = 0, j = 0; i < width; i += 20, j += 17) {
994  out[i + 0] = in[j + 0];
995  out[i + 1] = pixelOps.template blend2< 3, 14>(&in[j + 0]);
996  out[i + 2] = pixelOps.template blend2< 6, 11>(&in[j + 1]);
997  out[i + 3] = pixelOps.template blend2< 9, 8>(&in[j + 2]);
998  out[i + 4] = pixelOps.template blend2<12, 5>(&in[j + 3]);
999  out[i + 5] = pixelOps.template blend2<15, 2>(&in[j + 4]);
1000  out[i + 6] = in[j + 5];
1001  out[i + 7] = pixelOps.template blend2< 1, 16>(&in[j + 5]);
1002  out[i + 8] = pixelOps.template blend2< 4, 13>(&in[j + 6]);
1003  out[i + 9] = pixelOps.template blend2< 7, 10>(&in[j + 7]);
1004  out[i + 10] = pixelOps.template blend2<10, 7>(&in[j + 8]);
1005  out[i + 11] = pixelOps.template blend2<13, 4>(&in[j + 9]);
1006  out[i + 12] = pixelOps.template blend2<16, 1>(&in[j + 10]);
1007  out[i + 13] = in[j + 11];
1008  out[i + 14] = pixelOps.template blend2< 2, 15>(&in[j + 11]);
1009  out[i + 15] = pixelOps.template blend2< 5, 12>(&in[j + 12]);
1010  out[i + 16] = pixelOps.template blend2< 8, 9>(&in[j + 13]);
1011  out[i + 17] = pixelOps.template blend2<11, 6>(&in[j + 14]);
1012  out[i + 18] = pixelOps.template blend2<14, 3>(&in[j + 15]);
1013  out[i + 19] = in[j + 16];
1014  }
1015 }
1016 
1017 
1018 template <typename Pixel>
1020  : pixelOps(pixelOps_)
1021 {
1022 }
1023 
1024 template <typename Pixel>
1026  const Pixel* __restrict in, Pixel* __restrict out, size_t width)
1027 {
1028  assert((width % 10) == 0);
1029  for (size_t i = 0, j = 0; i < width; i += 10, j += 9) {
1030  out[i + 0] = in[j + 0];
1031  out[i + 1] = pixelOps.template blend2<1, 8>(&in[j + 0]);
1032  out[i + 2] = pixelOps.template blend2<2, 7>(&in[j + 1]);
1033  out[i + 3] = pixelOps.template blend2<3, 6>(&in[j + 2]);
1034  out[i + 4] = pixelOps.template blend2<4, 5>(&in[j + 3]);
1035  out[i + 5] = pixelOps.template blend2<5, 4>(&in[j + 4]);
1036  out[i + 6] = pixelOps.template blend2<6, 3>(&in[j + 5]);
1037  out[i + 7] = pixelOps.template blend2<7, 2>(&in[j + 6]);
1038  out[i + 8] = pixelOps.template blend2<8, 1>(&in[j + 7]);
1039  out[i + 9] = in[j + 8];
1040  }
1041 }
1042 
1043 
1044 template <typename Pixel, unsigned w1, unsigned w2>
1046  : pixelOps(pixelOps_)
1047 {
1048 }
1049 
1050 template <typename Pixel, unsigned w1, unsigned w2>
1052  const Pixel* in1, const Pixel* in2, Pixel* out, size_t width)
1053 {
1054  // It _IS_ allowed that the output is the same as one of the inputs.
1055  // TODO SSE optimizations
1056  // pure C++ version
1057  for (size_t i = 0; i < width; ++i) {
1058  out[i] = pixelOps.template blend<w1, w2>(in1[i], in2[i]);
1059  }
1060 }
1061 
1062 
1063 template<typename Pixel>
1065  : pixelOps(pixelOps_)
1066 {
1067 }
1068 
1069 template<typename Pixel>
1071  const Pixel* in, unsigned inWidth,
1072  Pixel* out, unsigned outWidth) const
1073 {
1074  constexpr unsigned FACTOR = 256;
1075 
1076  unsigned step = FACTOR * inWidth / outWidth;
1077  unsigned i = 0 * FACTOR;
1078  for (unsigned o = 0; o < outWidth; ++o) {
1079  Pixel p0 = in[(i / FACTOR) + 0];
1080  Pixel p1 = in[(i / FACTOR) + 1];
1081  out[o] = pixelOps.lerp(p0, p1, i % FACTOR);
1082  i += step;
1083  }
1084 }
1085 
1086 
1087 template <typename Pixel>
1089  : pixelOps(pixelOps_)
1090 {
1091 }
1092 
1093 template <typename Pixel>
1095  const Pixel* in1, const Pixel* in2, Pixel* out, size_t width)
1096 {
1097  // It _IS_ allowed that the output is the same as one of the inputs.
1098  for (size_t i = 0; i < width; ++i) {
1099  out[i] = pixelOps.alphaBlend(in1[i], in2[i]);
1100  }
1101 }
1102 
1103 template <typename Pixel>
1105  Pixel in1, const Pixel* in2, Pixel* out, size_t width)
1106 {
1107  // It _IS_ allowed that the output is the same as the input.
1108 
1109  // ATM this routine is only called when 'in1' is not fully opaque nor
1110  // fully transparent. This cannot happen in 16bpp modes.
1111  assert(sizeof(Pixel) == 4);
1112 
1113  unsigned alpha = pixelOps.alpha(in1);
1114 
1115  // When one of the two colors is loop-invariant, using the
1116  // pre-multiplied-alpha-blending equation is a tiny bit more efficient
1117  // than using alphaBlend() or even lerp().
1118  // for (size_t i = 0; i < width; ++i) {
1119  // out[i] = pixelOps.lerp(in1, in2[i], alpha);
1120  // }
1121  Pixel in1M = pixelOps.multiply(in1, alpha);
1122  unsigned alpha2 = 256 - alpha;
1123  for (size_t i = 0; i < width; ++i) {
1124  out[i] = in1M + pixelOps.multiply(in2[i], alpha2);
1125  }
1126 }
1127 
1128 } // namespace openmsx
1129 
1130 #endif
openmsx::Scale_3on8
Definition: LineScalers.hh:119
openmsx::AlphaBlendLines::operator()
void operator()(const Pixel *in1, const Pixel *in2, Pixel *out, size_t width)
Definition: LineScalers.hh:1094
openmsx::Scale_2on1::Scale_2on1
Scale_2on1(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:540
openmsx::ZoomLine::ZoomLine
ZoomLine(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:1064
openmsx::Scale_4on1::Scale_4on1
Scale_4on1(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:675
openmsx::Scale_4on3
Definition: LineScalers.hh:137
openmsx::Scale_3on2::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:713
openmsx::PixelOperations
Definition: PixelOperations.hh:143
openmsx::Scale_4on1
Definition: LineScalers.hh:83
openmsx::PolyScaleRef::isCopy
bool isCopy() const override
Is this scale operation actually a copy? This info can be used to (in a multi-step scale operation) i...
Definition: LineScalers.hh:349
openmsx::Scale_2on3::Scale_2on3
Scale_2on3(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:776
openmsx::Scale_6on1::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:665
openmsx::PolyLineScaler
Polymorphic line scaler.
Definition: LineScalers.hh:284
openmsx::Scale_8on3::Scale_8on3
Scale_8on3(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:818
openmsx::Scale_3on4
Definition: LineScalers.hh:110
utf8::unchecked::size
size_t size(std::string_view utf8)
Definition: utf8_unchecked.hh:227
openmsx::Scale_3on2
Definition: LineScalers.hh:101
openmsx::BlendLines::BlendLines
BlendLines(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:1045
openmsx::Scale_8on3::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:824
openmsx::Scale_4on1::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:681
openmsx::Scale_3on1::Scale_3on1
Scale_3on1(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:691
openmsx::PolyScaleRef
Like PolyScale above, but instead keeps a reference to the actual scaler.
Definition: LineScalers.hh:339
openmsx::Scale_4on5::Scale_4on5
Scale_4on5(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:938
openmsx::Scaler
Abstract base class for scalers.
Definition: Scaler.hh:14
t
TclObject t
Definition: TclObject_test.cc:264
openmsx::Scale_6on1
Definition: LineScalers.hh:74
openmsx::BlendLines
BlendLines functor Generate an output line that is an iterpolation of two input lines.
Definition: LineScalers.hh:226
openmsx::Scale_4on3::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:803
openmsx::ZoomLine::operator()
void operator()(const Pixel *in, unsigned inWidth, Pixel *out, unsigned outWidth) const
Definition: LineScalers.hh:1070
openmsx::Scale_17on20::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:989
openmsx::Scale_17on20::Scale_17on20
Scale_17on20(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:983
step
constexpr auto step
Definition: eeprom.cc:9
openmsx::ZoomLine
Stretch (or zoom) a given input line to a wider output line.
Definition: LineScalers.hh:239
openmsx::Scale_3on8::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:755
openmsx::Scale_2on3
Definition: LineScalers.hh:128
openmsx::Scale_4on9::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:878
openmsx::Scale_3on4::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:732
openmsx::Scale_2on1
Definition: LineScalers.hh:65
openmsx::BlendLines::operator()
void operator()(const Pixel *in1, const Pixel *in2, Pixel *out, size_t width)
Definition: LineScalers.hh:1051
openmsx::Scale_4on9
Definition: LineScalers.hh:164
openmsx::Scale_3on1
Definition: LineScalers.hh:92
openmsx::Scale_2on1::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:637
openmsx::Scale_8on9::Scale_8on9
Scale_8on9(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:905
openmsx::Scale_8on3
Definition: LineScalers.hh:146
likely.hh
openmsx::Scale_1on4
Definition: LineScalers.hh:41
openmsx::PolyScale::PolyScale
PolyScale()
Definition: LineScalers.hh:314
openmsx::PolyLineScaler::~PolyLineScaler
~PolyLineScaler()=default
openmsx::Scale_3on1::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:697
openmsx::PolyLineScaler::operator()
virtual void operator()(const Pixel *in, Pixel *out, size_t outWidth)=0
Actually scale a line.
openmsx::Scale_4on9::Scale_4on9
Scale_4on9(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:872
openmsx::Scale_1on2
Definition: LineScalers.hh:53
openmsx::AlphaBlendLines
AlphaBlendLines functor Generate an output line that is a per-pixel-alpha-blend of the two input line...
Definition: LineScalers.hh:258
openmsx::Pixel
uint32_t Pixel
Definition: GLHQLiteScaler.cc:98
UNREACHABLE
#define UNREACHABLE
Definition: unreachable.hh:38
openmsx::AlphaBlendLines::AlphaBlendLines
AlphaBlendLines(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:1088
openmsx::PolyLineScaler::isCopy
virtual bool isCopy() const =0
Is this scale operation actually a copy? This info can be used to (in a multi-step scale operation) i...
openmsx::HL
@ HL
Definition: CPUCore.cc:205
openmsx::TagCopy
Definition: LineScalers.hh:20
openmsx::Scale_9on10::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:1025
openmsx::Scale_1on1::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:518
openmsx::Scale_4on5
Definition: LineScalers.hh:182
openmsx::Scale_9on10::Scale_9on10
Scale_9on10(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:1019
openmsx::Scale_7on8::Scale_7on8
Scale_7on8(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:959
openmsx::PolyScale::PolyScale
PolyScale(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:318
openmsx::Scale_1on3::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:377
openmsx::Scale_1on2::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:454
openmsx::PolyScale
Polymorphic wrapper around another line scaler.
Definition: LineScalers.hh:312
openmsx::Scale_8on9::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:911
openmsx::Scale_4on5::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:944
openmsx::N
constexpr unsigned N
Definition: ResampleHQ.cc:225
openmsx::Scale_17on20
Definition: LineScalers.hh:200
openmsx::Scale_7on8::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:965
openmsx::Scale_1on3
Scale_XonY functors Transforms an input line of pixel to an output line (possibly) with a different w...
Definition: LineScalers.hh:35
openmsx::Scale_2on9
Definition: LineScalers.hh:155
openmsx::Scale_1on1
Definition: LineScalers.hh:59
PixelOperations.hh
likely
#define likely(x)
Definition: likely.hh:14
openmsx::Scale_2on9::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:845
openmsx::x
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1419
openmsx::Scale_3on8::Scale_3on8
Scale_3on8(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:749
openmsx::Scale_8on9
Definition: LineScalers.hh:173
openmsx::Scale_1on6::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:389
openmsx::Scale_2on3::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:782
openmsx::Scale_1on4::operator()
void operator()(const Pixel *in, Pixel *out, size_t width)
Definition: LineScalers.hh:383
openmsx::Scale_3on2::Scale_3on2
Scale_3on2(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:707
openmsx::PolyScaleRef::PolyScaleRef
PolyScaleRef(Scaler &scaler_)
Definition: LineScalers.hh:341
openmsx::mask
constexpr nibble mask[4][13]
Definition: RP5C01.cc:33
openmsx::Scale_4on3::Scale_4on3
Scale_4on3(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:797
openmsx::Scale_9on10
Definition: LineScalers.hh:209
openmsx::Scale_3on4::Scale_3on4
Scale_3on4(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:726
openmsx::Scale_1on6
Definition: LineScalers.hh:47
openmsx::PolyScale::operator()
void operator()(const Pixel *in, Pixel *out, size_t outWidth) override
Actually scale a line.
Definition: LineScalers.hh:322
openmsx::PolyScaleRef::operator()
void operator()(const Pixel *in, Pixel *out, size_t outWidth) override
Actually scale a line.
Definition: LineScalers.hh:345
openmsx::Scale_6on1::Scale_6on1
Scale_6on1(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:659
openmsx::IsTagged
Definition: LineScalers.hh:22
openmsx::Scale_2on9::Scale_2on9
Scale_2on9(PixelOperations< Pixel > pixelOps)
Definition: LineScalers.hh:839
openmsx::Scale_7on8
Definition: LineScalers.hh:191
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::PolyScale::isCopy
bool isCopy() const override
Is this scale operation actually a copy? This info can be used to (in a multi-step scale operation) i...
Definition: LineScalers.hh:326
l3
imat3 l3(ivec3(0, 2, 3), ivec3(4, 5, 6), ivec3(7, 8, 9))