18template<std::
unsigned_
integral Pixel>
22 if constexpr (
sizeof(
Pixel) == 2) {
23 return ((p & 0xF800) << 8) |
27 return p & 0xF8F8F8F8;
31template<std::
unsigned_
integral Pixel>
35 if constexpr (
sizeof(
Pixel) == 2) {
36 return ((p & 0xF80000) >> 8) |
37 ((p & 0x00FC00) >> 5) |
38 ((p & 0x0000F8) >> 3);
40 return (p & 0xF8F8F8F8) | ((p & 0xE0E0E0E0) >> 5);
47 EdgeHQ(
unsigned shiftR_,
unsigned shiftG_,
unsigned shiftB_)
48 : shiftR(shiftR_), shiftG(shiftG_), shiftB(shiftB_)
52 [[nodiscard]]
inline bool operator()(uint32_t c1, uint32_t c2)
const
54 if (c1 == c2)
return false;
56 unsigned r1 = (c1 >> shiftR) & 0xFF;
57 unsigned g1 = (c1 >> shiftG) & 0xFF;
58 unsigned b1 = (c1 >> shiftB) & 0xFF;
60 unsigned r2 = (c2 >> shiftR) & 0xFF;
61 unsigned g2 = (c2 >> shiftG) & 0xFF;
62 unsigned b2 = (c2 >> shiftB) & 0xFF;
64 auto dr = narrow_cast<int>(r1 - r2);
65 auto dg = narrow_cast<int>(g1 - g2);
66 auto db = narrow_cast<int>(b1 - b2);
68 int dy = dr + dg + db;
69 if (dy < -0xC0 || dy > 0xC0)
return true;
72 if (du < -0x1C || du > 0x1C)
return true;
75 if (dv < -0x30 || dv > 0x30)
return true;
80 const unsigned shiftR;
81 const unsigned shiftG;
82 const unsigned shiftB;
85template<std::
unsigned_
integral Pixel>
88 if constexpr (
sizeof(
Pixel) == 2) {
99 [[nodiscard]]
inline bool operator()(uint32_t c1, uint32_t c2)
const
105template<
typename EdgeOp>
106void calcEdgesGL(std::span<const uint32_t> curr, std::span<const uint32_t> next,
107 std::span<Endian::L32> edges2, EdgeOp edgeOp)
109 assert(curr.size() == 320);
110 assert(next.size() == 320);
111 assert(edges2.size() == 320 / 2);
151 using Pixel = uint32_t;
153 uint32_t pattern = 0;
156 if (edgeOp(c5, c8)) pattern |= 0x1800'0000;
158 for (
auto xx :
xrange((320 - 2) / 2)) {
159 pattern = (pattern >> (16 + 9)) & 0x001C;
160 pattern |= (edges2[xx] << 3) & 0xC460'C460;
162 if (edgeOp(c5, c8)) pattern |= 0x0000'0080;
163 Pixel c6 = curr[2 * xx + 1];
164 if (edgeOp(c6, c8)) pattern |= 0x0004'0800;
165 if (edgeOp(c5, c6)) pattern |= 0x0010'2000;
166 Pixel c9 = next[2 * xx + 1];
167 if (edgeOp(c5, c9)) pattern |= 0x0008'1000;
169 if (edgeOp(c6, c9)) pattern |= 0x0080'0000;
170 c5 = curr[2 * xx + 2];
171 if (edgeOp(c5, c9)) pattern |= 0x0800'0000;
172 if (edgeOp(c6, c5)) pattern |= 0x2000'0000;
173 c8 = next[2 * xx + 2];
174 if (edgeOp(c6, c8)) pattern |= 0x1000'0000;
176 edges2[xx] = pattern;
179 pattern = (pattern >> (16 + 9)) & 0x001C;
180 pattern |= (edges2[159] << 3) & 0xC460'C460;
182 if (edgeOp(c5, c8)) pattern |= 0x0000'0080;
183 Pixel c6 = curr[319];
184 if (edgeOp(c6, c8)) pattern |= 0x0004'0800;
185 if (edgeOp(c5, c6)) pattern |= 0x0010'2000;
186 Pixel c9 = next[319];
187 if (edgeOp(c5, c9)) pattern |= 0x0008'1000;
189 if (edgeOp(c6, c9)) pattern |= 0x1880'0000;
191 edges2[159] = pattern;
194template<std::
unsigned_
integral Pixel,
typename EdgeOp>
196 std::span<const Pixel> srcPrev, std::span<const Pixel> srcCurr,
197 std::span<uint16_t> edgeBuf, EdgeOp edgeOp)
199 auto srcWidth = edgeBuf.size();
200 assert(srcPrev.size() == srcWidth);
201 assert(srcCurr.size() == srcWidth);
206 uint16_t pattern = edgeOp(c1, c2) ? ((1 << 6) | (1 << 7)) : 0;
207 for (; x < (srcWidth - 1); ++x) {
211 if (edgeOp(c1, c2)) pattern |= (1 << 5);
212 if (edgeOp(c1, n2)) pattern |= (1 << 6);
213 if (edgeOp(c2, n1)) pattern |= (1 << 7);
214 edgeBuf[x] = pattern;
218 if (edgeOp(c1, c2)) pattern |= (1 << 5) | (1 << 6) | (1 << 7);
219 edgeBuf[x] = pattern;
222template<std::
unsigned_
integral Pixel,
typename HQScale,
typename EdgeOp>
224 FrameSource& src,
unsigned srcStartY,
unsigned ,
unsigned srcWidth,
227 VLA(uint16_t, edgeBuf, srcWidth);
234 int srcY = narrow<int>(srcStartY);
235 auto srcPrev = src.
getLine(srcY - 1, buf1);
236 auto srcCurr = src.
getLine(srcY + 0, buf2);
240 bool isCopy = postScale.
isCopy();
241 for (
unsigned dstY = dstStartY; dstY < dstEndY; srcY += 1, dstY += 2) {
242 auto srcNext = src.
getLine(srcY + 1, buf3);
246 hqScale(srcPrev, srcCurr, srcNext, dst0, dst1,
249 hqScale(srcPrev, srcCurr, srcNext, bufA, bufB,
251 postScale(bufA, dst0);
252 postScale(bufB, dst1);
263template<std::
unsigned_
integral Pixel,
typename HQScale,
typename EdgeOp>
265 FrameSource& src,
unsigned srcStartY,
unsigned ,
unsigned srcWidth,
268 VLA(uint16_t, edgeBuf, srcWidth);
276 int srcY = narrow<int>(srcStartY);
277 auto srcPrev = src.
getLine(srcY - 1, buf1);
278 auto srcCurr = src.
getLine(srcY + 0, buf2);
282 bool isCopy = postScale.
isCopy();
283 for (
unsigned dstY = dstStartY; dstY < dstEndY; srcY += 1, dstY += 3) {
284 auto srcNext = src.
getLine(srcY + 1, buf3);
289 hqScale(srcPrev, srcCurr, srcNext, dst0, dst1, dst2,
292 hqScale(srcPrev, srcCurr, srcNext, bufA, bufB, bufC,
294 postScale(bufA, dst0);
295 postScale(bufB, dst1);
296 postScale(bufC, dst2);
bool operator()(uint32_t c1, uint32_t c2) const
EdgeHQ(unsigned shiftR_, unsigned shiftG_, unsigned shiftB_)
Interface for getting lines from a video frame.
std::span< const Pixel > getLine(int line, std::span< Pixel > buf) const
Gets a pointer to the pixels of the given line number.
unsigned getGshift() const
unsigned getBshift() const
unsigned getRshift() const
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...
virtual void releaseLine(unsigned y, std::span< Pixel > buf)=0
virtual std::span< Pixel > acquireLine(unsigned y)=0
This file implemented 3 utility functions:
void calcInitialEdges(std::span< const Pixel > srcPrev, std::span< const Pixel > srcCurr, std::span< uint16_t > edgeBuf, EdgeOp edgeOp)
EdgeHQ createEdgeHQ(const PixelOperations< Pixel > &pixelOps)
Pixel writePixel(uint32_t p)
void doHQScale3(HQScale hqScale, EdgeOp edgeOp, PolyLineScaler< Pixel > &postScale, FrameSource &src, unsigned srcStartY, unsigned, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
uint32_t readPixel(Pixel p)
void doHQScale2(HQScale hqScale, EdgeOp edgeOp, PolyLineScaler< Pixel > &postScale, FrameSource &src, unsigned srcStartY, unsigned, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
void calcEdgesGL(std::span< const uint32_t > curr, std::span< const uint32_t > next, std::span< Endian::L32 > edges2, EdgeOp edgeOp)
void swap(openmsx::MemBuffer< T > &l, openmsx::MemBuffer< T > &r) noexcept
bool operator()(uint32_t c1, uint32_t c2) const
#define VLA(TYPE, NAME, LENGTH)
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
constexpr auto xrange(T e)