openMSX
Scale3xScaler.cc
Go to the documentation of this file.
1 /*
2 Original code: Copyright (C) 2001-2003 Andrea Mazzoleni
3 openMSX adaptation by Maarten ter Huurne
4 
5 This file is based on code from the Scale2x project.
6 This modified version is licensed under GPL; the original code is dual-licensed
7 under GPL and under a custom license.
8 
9 Visit the Scale2x site for info:
10  http://scale2x.sourceforge.net/
11 */
12 
13 #include "Scale3xScaler.hh"
14 #include "FrameSource.hh"
15 #include "ScalerOutput.hh"
16 #include "vla.hh"
17 #include "build-info.hh"
18 #include <cstdint>
19 
20 namespace openmsx {
21 
22 template <class Pixel>
24  : Scaler3<Pixel>(pixelOps_)
25 {
26 }
27 
28 template <class Pixel>
30  Pixel* __restrict dst, const Pixel* __restrict src0,
31  const Pixel* __restrict src1, const Pixel* __restrict src2,
32  unsigned srcWidth) __restrict
33 {
34  /* A B C
35  * D E F
36  * G H I
37  *
38  * E0 = D == B && B != F && D != H ? D : E;
39  * E1 = (D == B && B != F && D != H && E != C) ||
40  * (B == F && B != D && F != H && E != A) ? B : E;
41  * E2 = B == F && B != D && F != H ? F : E;
42  */
43 
44  // First pixel.
45  Pixel top = src0[0];
46  Pixel mid = src1[0];
47  Pixel right = src1[1];
48  Pixel bot = src2[0];
49 
50  dst[0] = mid;
51  dst[1] = (mid != right) && (top != bot) &&
52  (((top == mid ) && (mid != src0[1])) ||
53  ((top == right) && (mid != top)))
54  ? top : mid;
55  dst[2] = (mid != right) && (top != bot) && (top == right)
56  ? top : mid;
57 
58  // Central pixels.
59  for (unsigned x = 1; x < srcWidth - 1; ++x) {
60  Pixel left = mid;
61  mid = right;
62  right = src1[x + 1];
63  top = src0[x];
64  bot = src2[x];
65  dst[3 * x + 0] = (left != right) && (top != bot) &&
66  (top == left)
67  ? top : mid;
68  dst[3 * x + 1] = (left != right) && (top != bot) &&
69  (((top == left ) && (mid != src0[x + 1])) ||
70  ((top == right) && (mid != src0[x - 1])))
71  ? top : mid;
72  dst[3 * x + 2] = (left != right) && (top != bot) &&
73  (top == right)
74  ? top : mid;
75  }
76 
77  // Last pixel.
78  Pixel left = mid;
79  mid = right;
80  top = src0[srcWidth - 1];
81  bot = src2[srcWidth - 1];
82  dst[3 * srcWidth - 3] = (left != mid) && (top != bot) && (top ==left)
83  ? top : mid;
84  dst[3 * srcWidth - 2] = (left != mid) && (top != bot) &&
85  (((top == left) && (mid != top)) ||
86  ((top == mid ) && (mid != src0[srcWidth - 2])))
87  ? top : mid;
88  dst[3 * srcWidth - 1] = mid;
89 }
90 
91 template <class Pixel>
93  Pixel* __restrict dst, const Pixel* __restrict src0,
94  const Pixel* __restrict src1, const Pixel* __restrict src2,
95  unsigned srcWidth) __restrict
96 {
97  /*
98  * A B C
99  * D E F
100  * G H I
101  *
102  * E3 = (D == B && B != F && D != H && E != G) ||
103  * (D == H && D != B && H != F && E != A) ? D : E;
104  * E4 = E
105  * E5 = (B == F && B != D && F != H && E != I) ||
106  * (H == F && D != H && B != F && E != C) ? F : E;
107  */
108 
109  // First pixel.
110  Pixel mid = src1[0];
111  Pixel right = src1[1];
112  Pixel top = src0[0];
113  Pixel bot = src2[0];
114  dst[0] = mid;
115  dst[1] = mid;
116  dst[2] = (mid != right) && (top != bot) &&
117  (((right == top) && (mid != src2[1])) ||
118  ((right == bot) && (mid != src0[1])))
119  ? right : mid;
120 
121  // Central pixels.
122  for (unsigned x = 1; x < srcWidth - 1; ++x) {
123  Pixel left = mid;
124  mid = right;
125  right = src1[x + 1];
126  top = src0[x];
127  bot = src2[x];
128  dst[3 * x + 0] = (left != right) && (top != bot) &&
129  (((left == top) && (mid != src2[x - 1])) ||
130  ((left == bot) && (mid != src0[x - 1])))
131  ? left : mid;
132  dst[3 * x + 1] = mid;
133  dst[3 * x + 2] = (left != right) && (top != bot) &&
134  (((right == top) && (mid != src2[x + 1])) ||
135  ((right == bot) && (mid != src0[x + 1])))
136  ? right : mid;
137  }
138 
139  // Last pixel.
140  Pixel left = mid;
141  mid = right;
142  top = src0[srcWidth - 1];
143  bot = src2[srcWidth - 1];
144  dst[3 * srcWidth - 3] = (left != mid) && (top != bot) &&
145  (((left == top) && (mid != src2[srcWidth - 2])) ||
146  ((left == bot) && (mid != src0[srcWidth - 2])))
147  ? left : mid;
148  dst[3 * srcWidth - 2] = mid;
149  dst[3 * srcWidth - 1] = mid;
150 }
151 
152 template <class Pixel>
154  unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
155  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
156 {
157  VLA_SSE_ALIGNED(Pixel, buf0_, srcWidth); auto* buf0 = buf0_;
158  VLA_SSE_ALIGNED(Pixel, buf1_, srcWidth); auto* buf1 = buf1_;
159  VLA_SSE_ALIGNED(Pixel, buf2_, srcWidth); auto* buf2 = buf2_;
160 
161  int srcY = srcStartY;
162  auto* srcPrev = src.getLinePtr(srcY - 1, srcWidth, buf0);
163  auto* srcCurr = src.getLinePtr(srcY + 0, srcWidth, buf1);
164 
165  for (unsigned dstY = dstStartY; dstY < dstEndY; srcY += 1, dstY += 3) {
166  auto* srcNext = src.getLinePtr(srcY + 1, srcWidth, buf2);
167 
168  auto* dstUpper = dst.acquireLine(dstY + 0);
169  scaleLine1on3Half(dstUpper, srcPrev, srcCurr, srcNext, srcWidth);
170  dst.releaseLine(dstY + 0, dstUpper);
171 
172  auto* dstMiddle = dst.acquireLine(dstY + 1);
173  scaleLine1on3Mid(dstMiddle, srcPrev, srcCurr, srcNext, srcWidth);
174  dst.releaseLine(dstY + 1, dstMiddle);
175 
176  auto* dstLower = dst.acquireLine(dstY + 2);
177  scaleLine1on3Half(dstLower, srcNext, srcCurr, srcPrev, srcWidth);
178  dst.releaseLine(dstY + 2, dstLower);
179 
180  srcPrev = srcCurr;
181  srcCurr = srcNext;
182  std::swap(buf0, buf1);
183  std::swap(buf1, buf2);
184  }
185 }
186 
187 // Force template instantiation.
188 #if HAVE_16BPP
189 template class Scale3xScaler<uint16_t>;
190 #endif
191 #if HAVE_32BPP
192 template class Scale3xScaler<uint32_t>;
193 #endif
194 
195 } // namespace openmsx
virtual Pixel * acquireLine(unsigned y)=0
Scale3xScaler(const PixelOperations< Pixel > &pixelOps)
uint32_t Pixel
Interface for getting lines from a video frame.
Definition: FrameSource.hh:14
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
virtual void releaseLine(unsigned y, Pixel *buf)=0
const Pixel * getLinePtr(int line, unsigned width, Pixel *buf) const
Gets a pointer to the pixels of the given line number.
Definition: FrameSource.hh:91
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1377
void scale1x1to3x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Runs the Scale3x scaler algorithm.
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition: vla.hh:44
Base class for 3x scalers.
Definition: Scaler3.hh:11