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