openMSX
HQ2xScaler.cc
Go to the documentation of this file.
1/*
2Original code: Copyright (C) 2003 MaxSt ( maxst@hiend3d.com )
3openMSX adaptation by Maarten ter Huurne
4
5License: LGPL
6
7Visit the HiEnd3D site for info:
8 http://www.hiend3d.com/hq2x.html
9*/
10
11#include "HQ2xScaler.hh"
12#include "HQCommon.hh"
13#include "LineScalers.hh"
14#include "unreachable.hh"
15#include "xrange.hh"
16#include "build-info.hh"
17#include <cstdint>
18
19namespace openmsx {
20
21template<std::unsigned_integral Pixel> struct HQ_1x1on2x2
22{
23 void operator()(std::span<const Pixel> in0, std::span<const Pixel> in1, std::span<const Pixel> in2,
24 std::span<Pixel> out0, std::span<Pixel> out1,
25 std::span<uint16_t> edgeBuf, EdgeHQ edgeOp);
26};
27
28template<std::unsigned_integral Pixel> struct HQ_1x1on1x2
29{
30 void operator()(std::span<const Pixel> in0, std::span<const Pixel> in1, std::span<const Pixel> in2,
31 std::span<Pixel> out0, std::span<Pixel> out1,
32 std::span<uint16_t> edgeBuf, EdgeHQ edgeOp);
33};
34
35template<std::unsigned_integral Pixel>
37 std::span<const Pixel> in0, std::span<const Pixel> in1, std::span<const Pixel> in2,
38 std::span<Pixel> out0, std::span<Pixel> out1,
39 std::span<uint16_t> edgeBuf,
40 EdgeHQ edgeOp)
41{
42 auto srcWidth = edgeBuf.size();
43 assert(in0.size() == srcWidth);
44 assert(in1.size() == srcWidth);
45 assert(in2.size() == srcWidth);
46 assert(out0.size() == 2 * srcWidth);
47 assert(out1.size() == 2 * srcWidth);
48
49 auto c2 = readPixel(in0[0]); auto c3 = c2;
50 auto c5 = readPixel(in1[0]); auto c6 = c5;
51 auto c8 = readPixel(in2[0]); auto c9 = c8;
52
53 unsigned pattern = 0;
54 if (edgeOp(c5, c8)) pattern |= 3 << 6;
55 if (edgeOp(c5, c2)) pattern |= 3 << 9;
56
57 for (auto x : xrange(srcWidth)) {
58 auto c1 = c2;
59 auto c4 = c5;
60 auto c7 = c8;
61 c2 = c3;
62 c5 = c6;
63 c8 = c9;
64 if (x != srcWidth - 1) {
65 c3 = readPixel(in0[x + 1]);
66 c6 = readPixel(in1[x + 1]);
67 c9 = readPixel(in2[x + 1]);
68 }
69
70 pattern = (pattern >> 6) & 0x001F; // left overlap
71 // overlaps with left
72 //if (edgeOp(c8, c4)) pattern |= 1 << 0; // B - l: c5-c9 6
73 //if (edgeOp(c5, c7)) pattern |= 1 << 1; // B - l: c6-c8 7
74 //if (edgeOp(c5, c4)) pattern |= 1 << 2; // l: c5-c6 8
75 // overlaps with top and left
76 //if (edgeOp(c5, c1)) pattern |= 1 << 3; // l: c2-c6 9, t: c4-c8 0
77 //if (edgeOp(c4, c2)) pattern |= 1 << 4; // l: c5-c3 10, t: c5-c7 1
78 // non-overlapping pixels
79 if (edgeOp(c5, c8)) pattern |= 1 << 5; // B
80 if (edgeOp(c5, c9)) pattern |= 1 << 6; // BR
81 if (edgeOp(c6, c8)) pattern |= 1 << 7; // BR
82 if (edgeOp(c5, c6)) pattern |= 1 << 8; // R
83 // overlaps with top
84 //if (edgeOp(c2, c6)) pattern |= 1 << 9; // R - t: c5-c9 6
85 //if (edgeOp(c5, c3)) pattern |= 1 << 10; // R - t: c6-c8 7
86 //if (edgeOp(c5, c2)) pattern |= 1 << 11; // t: c5-c8 5
87 pattern |= ((edgeBuf[x] & (1 << 5) ) << 6) |
88 ((edgeBuf[x] & ((1 << 6) | (1 << 7))) << 3);
89 edgeBuf[x] = narrow_cast<uint16_t>(pattern);
90
91 unsigned pixel0, pixel1, pixel2, pixel3;
92
93#include "HQ2xScaler-1x1to2x2.nn"
94
95 out0[2 * x + 0] = writePixel<Pixel>(pixel0);
96 out0[2 * x + 1] = writePixel<Pixel>(pixel1);
97 out1[2 * x + 0] = writePixel<Pixel>(pixel2);
98 out1[2 * x + 1] = writePixel<Pixel>(pixel3);
99 }
100}
101
102template<std::unsigned_integral Pixel>
104 std::span<const Pixel> in0, std::span<const Pixel> in1, std::span<const Pixel> in2,
105 std::span<Pixel> out0, std::span<Pixel> out1,
106 std::span<uint16_t> edgeBuf,
107 EdgeHQ edgeOp)
108{
109 // +---+---+---+
110 // | 1 | 2 | 3 |
111 // +---+---+---+
112 // | 4 | 5 | 6 |
113 // +---+---+---+
114 // | 7 | 8 | 9 |
115 // +---+---+---+
116 auto srcWidth = edgeBuf.size();
117 assert(in0.size() == srcWidth);
118 assert(in1.size() == srcWidth);
119 assert(in2.size() == srcWidth);
120 assert(out0.size() == srcWidth);
121 assert(out1.size() == srcWidth);
122
123 auto c2 = readPixel(in0[0]); auto c3 = c2;
124 auto c5 = readPixel(in1[0]); auto c6 = c5;
125 auto c8 = readPixel(in2[0]); auto c9 = c8;
126
127 unsigned pattern = 0;
128 if (edgeOp(c5, c8)) pattern |= 3 << 6;
129 if (edgeOp(c5, c2)) pattern |= 3 << 9;
130
131 for (auto x : xrange(srcWidth)) {
132 auto c1 = c2;
133 auto c4 = c5;
134 auto c7 = c8;
135 c2 = c3;
136 c5 = c6;
137 c8 = c9;
138 if (x != srcWidth - 1) {
139 c3 = readPixel(in0[x + 1]);
140 c6 = readPixel(in1[x + 1]);
141 c9 = readPixel(in2[x + 1]);
142 }
143
144 pattern = (pattern >> 6) & 0x001F; // left overlap
145 // overlaps with left
146 //if (edgeOp(c8, c4)) pattern |= 1 << 0; // B - l: c5-c9 6
147 //if (edgeOp(c5, c7)) pattern |= 1 << 1; // B - l: c6-c8 7
148 //if (edgeOp(c5, c4)) pattern |= 1 << 2; // l: c5-c6 8
149 // overlaps with top and left
150 //if (edgeOp(c5, c1)) pattern |= 1 << 3; // l: c2-c6 9, t: c4-c8 0
151 //if (edgeOp(c4, c2)) pattern |= 1 << 4; // l: c5-c3 10, t: c5-c7 1
152 // non-overlapping pixels
153 if (edgeOp(c5, c8)) pattern |= 1 << 5; // B
154 if (edgeOp(c5, c9)) pattern |= 1 << 6; // BR
155 if (edgeOp(c6, c8)) pattern |= 1 << 7; // BR
156 if (edgeOp(c5, c6)) pattern |= 1 << 8; // R
157 // overlaps with top
158 //if (edgeOp(c2, c6)) pattern |= 1 << 9; // R - t: c5-c9 6
159 //if (edgeOp(c5, c3)) pattern |= 1 << 10; // R - t: c6-c8 7
160 //if (edgeOp(c5, c2)) pattern |= 1 << 11; // t: c5-c8 5
161 pattern |= ((edgeBuf[x] & (1 << 5) ) << 6) |
162 ((edgeBuf[x] & ((1 << 6) | (1 << 7))) << 3);
163 edgeBuf[x] = narrow_cast<uint16_t>(pattern);
164
165 unsigned pixel0, pixel1;
166
167#include "HQ2xScaler-1x1to1x2.nn"
168
169 out0[x] = writePixel<Pixel>(pixel0);
170 out1[x] = writePixel<Pixel>(pixel1);
171 }
172}
173
174
175
176template<std::unsigned_integral Pixel>
178 : Scaler2<Pixel>(pixelOps_)
179 , pixelOps(pixelOps_)
180{
181}
182
183template<std::unsigned_integral Pixel>
185 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
186 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
187{
188 PolyScale<Pixel, Scale_2on3<Pixel>> postScale(pixelOps);
189 EdgeHQ edgeOp = createEdgeHQ(pixelOps);
190 doHQScale2<Pixel>(HQ_1x1on2x2<Pixel>(), edgeOp, postScale,
191 src, srcStartY, srcEndY, srcWidth,
192 dst, dstStartY, dstEndY);
193}
194
195template<std::unsigned_integral Pixel>
197 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
198 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
199{
201 EdgeHQ edgeOp = createEdgeHQ(pixelOps);
202 doHQScale2<Pixel>(HQ_1x1on2x2<Pixel>(), edgeOp, postScale,
203 src, srcStartY, srcEndY, srcWidth,
204 dst, dstStartY, dstEndY);
205}
206
207template<std::unsigned_integral Pixel>
209 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
210 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
211{
212 PolyScale<Pixel, Scale_4on3<Pixel>> postScale(pixelOps);
213 EdgeHQ edgeOp = createEdgeHQ(pixelOps);
214 doHQScale2<Pixel>(HQ_1x1on2x2<Pixel>(), edgeOp, postScale,
215 src, srcStartY, srcEndY, srcWidth,
216 dst, dstStartY, dstEndY);
217}
218
219template<std::unsigned_integral Pixel>
221 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
222 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
223{
225 EdgeHQ edgeOp = createEdgeHQ(pixelOps);
226 doHQScale2<Pixel>(HQ_1x1on1x2<Pixel>(), edgeOp, postScale,
227 src, srcStartY, srcEndY, srcWidth,
228 dst, dstStartY, dstEndY);
229}
230
231template<std::unsigned_integral Pixel>
233 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
234 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
235{
236 PolyScale<Pixel, Scale_4on3<Pixel>> postScale(pixelOps);
237 EdgeHQ edgeOp = createEdgeHQ(pixelOps);
238 doHQScale2<Pixel>(HQ_1x1on1x2<Pixel>(), edgeOp, postScale,
239 src, srcStartY, srcEndY, srcWidth,
240 dst, dstStartY, dstEndY);
241}
242
243template<std::unsigned_integral Pixel>
245 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
246 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
247{
248 PolyScale<Pixel, Scale_2on1<Pixel>> postScale(pixelOps);
249 EdgeHQ edgeOp = createEdgeHQ(pixelOps);
250 doHQScale2<Pixel>(HQ_1x1on1x2<Pixel>(), edgeOp, postScale,
251 src, srcStartY, srcEndY, srcWidth,
252 dst, dstStartY, dstEndY);
253}
254
255// Force template instantiation.
256#if HAVE_16BPP
257template class HQ2xScaler<uint16_t>;
258#endif
259#if HAVE_32BPP
260template class HQ2xScaler<uint32_t>;
261#endif
262
263} // namespace openmsx
Interface for getting lines from a video frame.
Definition: FrameSource.hh:20
Runs the hq2x scaler algorithm.
Definition: HQ2xScaler.hh:13
void scale1x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:184
void scale1x1to2x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:196
HQ2xScaler(const PixelOperations< Pixel > &pixelOps)
Definition: HQ2xScaler.cc:177
void scale2x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:208
void scale1x1to1x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:220
void scale4x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:232
void scale2x1to1x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Definition: HQ2xScaler.cc:244
Polymorphic wrapper around another line scaler.
Definition: LineScalers.hh:313
Base class for 2x scalers.
Definition: Scaler2.hh:12
This file implemented 3 utility functions:
Definition: Autofire.cc:9
uint32_t Pixel
EdgeHQ createEdgeHQ(const PixelOperations< Pixel > &pixelOps)
Definition: HQCommon.hh:86
uint32_t readPixel(Pixel p)
Definition: HQCommon.hh:19
void operator()(std::span< const Pixel > in0, std::span< const Pixel > in1, std::span< const Pixel > in2, std::span< Pixel > out0, std::span< Pixel > out1, std::span< uint16_t > edgeBuf, EdgeHQ edgeOp)
Definition: HQ2xScaler.cc:103
void operator()(std::span< const Pixel > in0, std::span< const Pixel > in1, std::span< const Pixel > in2, std::span< Pixel > out0, std::span< Pixel > out1, std::span< uint16_t > edgeBuf, EdgeHQ edgeOp)
Definition: HQ2xScaler.cc:36
constexpr auto xrange(T e)
Definition: xrange.hh:132