openMSX
GLHQLiteScaler.cc
Go to the documentation of this file.
1#include "GLHQLiteScaler.hh"
2
3#include "File.hh"
4#include "FileContext.hh"
5#include "FrameSource.hh"
6#include "GLUtil.hh"
7#include "HQCommon.hh"
8
9#include "narrow.hh"
10#include "ranges.hh"
11#include "vla.hh"
12
13#include <array>
14#include <cstring>
15#include <utility>
16
17namespace openmsx {
18
19GLHQLiteScaler::GLHQLiteScaler(GLScaler& fallback_, unsigned maxWidth_, unsigned maxHeight_)
20 : GLScaler("hqlite")
21 , fallback(fallback_)
22 , maxWidth(maxWidth_), maxHeight(maxHeight_)
23{
24 for (auto i : xrange(2)) {
25 auto& p = program[i];
26 p.activate();
27 glUniform1i(p.getUniformLocation("edgeTex"), 2);
28 glUniform1i(p.getUniformLocation("offsetTex"), 3);
29 edgePosScaleUnif[i] = p.getUniformLocation("edgePosScale");
30 }
31
32 // GL_LUMINANCE_ALPHA is no longer supported in newer openGL versions
33 auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
34 edgeTexture.bind();
35 glTexImage2D(GL_TEXTURE_2D, // target
36 0, // level
37 format, // internal format
38 maxWidth, // width
39 maxHeight, // height
40 0, // border
41 format, // format
42 GL_UNSIGNED_BYTE, // type
43 nullptr); // data
44#if OPENGL_VERSION >= OPENGL_3_3
45 GLint swizzleMask1[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
46 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask1);
47#endif
48 edgeBuffer.allocate(maxWidth * maxHeight);
49
50 const auto& context = systemFileContext();
51 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
52 std::string offsetName = "shaders/HQ_xLiteOffsets.dat";
53 for (auto i : xrange(3)) {
54 int n = i + 2;
55 offsetName[10] = narrow<char>('0' + n);
56 File offsetFile(context.resolve(offsetName));
57 offsetTexture[i].bind();
58 glTexImage2D(GL_TEXTURE_2D, // target
59 0, // level
60 format, // internal format
61 n * 64, // width
62 n * 64, // height
63 0, // border
64 format, // format
65 GL_UNSIGNED_BYTE, // type
66 offsetFile.mmap().data());// data
67#if OPENGL_VERSION >= OPENGL_3_3
68 GLint swizzleMask2[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
69 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask2);
70#endif
71 }
72 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
73}
74
76 gl::ColorTexture& src, gl::ColorTexture* superImpose,
77 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
78 unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
79 unsigned logSrcHeight)
80{
81 unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY); // 1 - 4
82
83 if ((factorY >= 2) && ((srcWidth % 320) == 0)) {
84 setup(superImpose != nullptr);
85 src.setInterpolation(true);
86 glActiveTexture(GL_TEXTURE3);
87 offsetTexture[factorY - 2].bind();
88 glActiveTexture(GL_TEXTURE2);
89 edgeTexture.bind();
90 glActiveTexture(GL_TEXTURE0);
91
92 int i = superImpose ? 1 : 0;
93 glUniform2f(edgePosScaleUnif[i], src.getWidth() / float(maxWidth), src.getHeight() / float(maxHeight));
94
95 execute(src, superImpose,
96 srcStartY, srcEndY, srcWidth,
97 dstStartY, dstEndY, dstWidth,
98 logSrcHeight);
99 src.setInterpolation(false);
100 } else {
101 fallback.scaleImage(src, superImpose,
102 srcStartY, srcEndY, srcWidth,
103 dstStartY, dstEndY, dstWidth,
104 logSrcHeight);
105 }
106}
107
108using Pixel = uint32_t;
110 unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
111 FrameSource& paintFrame)
112{
113 if ((lineWidth % 320) != 0) return;
114
115 assert(maxWidth <= 1280);
116 std::array<Endian::L32, 1280 / 2> tmpBufMax; // 2 x uint16_t
117 auto tmpBuf2 = subspan(tmpBufMax, 0, lineWidth / 2);
118 #ifndef NDEBUG
119 // Avoid UMR. In optimized mode we don't care.
120 ranges::fill(tmpBuf2, 0);
121 #endif
122
123 VLA_SSE_ALIGNED(Pixel, buf1, lineWidth);
124 VLA_SSE_ALIGNED(Pixel, buf2, lineWidth);
125 auto curr = paintFrame.getLine(narrow<int>(srcStartY) - 1, buf1);
126 auto next = paintFrame.getLine(narrow<int>(srcStartY) + 0, buf2);
127 calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
128
129 edgeBuffer.bind();
130 auto mapped = edgeBuffer.mapWrite();
131 auto numLines = srcEndY - srcStartY;
132 for (auto yy : xrange(numLines)) {
133 curr = next;
134 std::swap(buf1, buf2);
135 next = paintFrame.getLine(narrow<int>(yy + srcStartY + 1), buf2);
136 calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
137 auto dest = mapped.subspan(yy * size_t(lineWidth), lineWidth);
138 assert(dest.size_bytes() == tmpBuf2.size_bytes()); // note: convert L32 -> 2 x uint16_t
139 memcpy(dest.data(), tmpBuf2.data(), tmpBuf2.size_bytes());
140 }
141 edgeBuffer.unmap();
142
143 auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
144 edgeTexture.bind();
145 glTexSubImage2D(GL_TEXTURE_2D, // target
146 0, // level
147 0, // offset x
148 narrow<GLint>(srcStartY), // offset y
149 narrow<GLint>(lineWidth), // width
150 narrow<GLint>(numLines), // height
151 format, // format
152 GL_UNSIGNED_BYTE, // type
153 mapped.data()); // data
154 edgeBuffer.unbind();
155}
156
157} // namespace openmsx
#define OPENGL_3_3
Definition GLUtil.hh:24
#define OPENGL_VERSION
Definition GLUtil.hh:25
GLsizei getHeight() const
Definition GLUtil.hh:118
GLsizei getWidth() const
Definition GLUtil.hh:117
void allocate(GLuint size)
Allocate the maximum required size for this buffer.
Definition GLUtil.hh:246
void unmap() const
Unmaps the contents of this buffer.
Definition GLUtil.hh:290
void unbind() const
Unbind this buffer.
Definition GLUtil.hh:271
void bind() const
Bind this PixelBuffer.
Definition GLUtil.hh:263
std::span< T > mapWrite()
Maps the contents of this buffer into memory.
Definition GLUtil.hh:279
void bind() const
Makes this texture the active GL texture.
Definition GLUtil.hh:88
void setInterpolation(bool interpolation)
Enable/disable bilinear interpolation for this texture.
Definition GLUtil.cc:62
std::span< const uint8_t > mmap()
Map file in memory.
Definition File.cc:102
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.
void uploadBlock(unsigned srcStartY, unsigned srcEndY, unsigned lineWidth, FrameSource &paintFrame) override
GLHQLiteScaler(GLScaler &fallback, unsigned maxWidth, unsigned maxHeight)
void scaleImage(gl::ColorTexture &src, gl::ColorTexture *superImpose, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth, unsigned logSrcHeight) override
Scales the image in the given area, which must consist of lines which are all equally wide.
Abstract base class for OpenGL scalers.
Definition GLScaler.hh:16
void setup(bool superImpose)
Setup scaler.
Definition GLScaler.cc:40
std::array< gl::ShaderProgram, 2 > program
Definition GLScaler.hh:85
void execute(const gl::ColorTexture &src, const gl::ColorTexture *superImpose, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth, unsigned logSrcHeight, bool textureFromZero=false)
Helper method to draw a rectangle with multiple texture coordinates.
Definition GLScaler.cc:48
virtual void scaleImage(gl::ColorTexture &src, gl::ColorTexture *superImpose, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth, unsigned logSrcHeight)=0
Scales the image in the given area, which must consist of lines which are all equally wide.
EndianT< uint32_t, ConvLittle< BIG > > L32
Definition endian.hh:122
void format(SectorAccessibleDisk &disk, MSXBootSectorType bootType)
Format the given disk (= a single partition).
This file implemented 3 utility functions:
Definition Autofire.cc:11
const FileContext & systemFileContext()
CharacterConverter::Pixel Pixel
void calcEdgesGL(std::span< const uint32_t > curr, std::span< const uint32_t > next, std::span< Endian::L32 > edges2, EdgeOp edgeOp)
Definition HQCommon.hh:53
constexpr void fill(ForwardRange &&range, const T &value)
Definition ranges.hh:315
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
Definition ranges.hh:481
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition vla.hh:50
constexpr auto xrange(T e)
Definition xrange.hh:132