openMSX
GLHQScaler.cc
Go to the documentation of this file.
1#include "GLHQScaler.hh"
2#include "GLUtil.hh"
3#include "HQCommon.hh"
4#include "FrameSource.hh"
5#include "FileContext.hh"
6#include "File.hh"
7#include "narrow.hh"
8#include "ranges.hh"
9#include "vla.hh"
10#include <array>
11#include <cstring>
12#include <utility>
13
14namespace openmsx {
15
17 : GLScaler("hq")
18 , fallback(fallback_)
19{
20 for (auto& p : program) {
21 p.activate();
22 glUniform1i(p.getUniformLocation("edgeTex"), 2);
23 glUniform1i(p.getUniformLocation("offsetTex"), 3);
24 glUniform1i(p.getUniformLocation("weightTex"), 4);
25 }
26
27 // GL_LUMINANCE_ALPHA is no longer supported in newer openGL versions
28 auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
29 edgeTexture.bind();
30 glTexImage2D(GL_TEXTURE_2D, // target
31 0, // level
32 format, // internal format
33 320, // width
34 240, // height
35 0, // border
36 format, // format
37 GL_UNSIGNED_BYTE, // type
38 nullptr); // data
39#if OPENGL_VERSION >= OPENGL_3_3
40 GLint swizzleMask[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
41 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
42#endif
43 edgeBuffer.setImage(320, 240);
44
45 const auto& context = systemFileContext();
46 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
47 std::string offsetsName = "shaders/HQ_xOffsets.dat";
48 std::string weightsName = "shaders/HQ_xWeights.dat";
49 for (auto i : xrange(3)) {
50 int n = i + 2;
51 offsetsName[10] = narrow<char>('0' + n);
52 File offsetsFile(context.resolve(offsetsName));
53 offsetTexture[i].bind();
54 glTexImage2D(GL_TEXTURE_2D, // target
55 0, // level
56 GL_RGBA, // internal format
57 n * 64, // width
58 n * 64, // height
59 0, // border
60 GL_RGBA, // format
61 GL_UNSIGNED_BYTE, // type
62 offsetsFile.mmap().data());// data
63
64 weightsName[10] = narrow<char>('0' + n);
65 File weightsFile(context.resolve(weightsName));
66 weightTexture[i].bind();
67 glTexImage2D(GL_TEXTURE_2D, // target
68 0, // level
69 GL_RGB, // internal format
70 n * 64, // width
71 n * 64, // height
72 0, // border
73 GL_RGB, // format
74 GL_UNSIGNED_BYTE, // type
75 weightsFile.mmap().data());// data
76 }
77 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
78}
79
81 gl::ColorTexture& src, gl::ColorTexture* superImpose,
82 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
83 unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
84 unsigned logSrcHeight)
85{
86 unsigned factorX = dstWidth / srcWidth; // 1 - 4
87 unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY);
88
89 if ((srcWidth == 320) && (factorX > 1) && (factorX == factorY)) {
90 assert(src.getHeight() == 2 * 240);
91 setup(superImpose != nullptr);
92 glActiveTexture(GL_TEXTURE4);
93 weightTexture[factorX - 2].bind();
94 glActiveTexture(GL_TEXTURE3);
95 offsetTexture[factorX - 2].bind();
96 glActiveTexture(GL_TEXTURE2);
97 edgeTexture.bind();
98 glActiveTexture(GL_TEXTURE0);
99 execute(src, superImpose,
100 srcStartY, srcEndY, srcWidth,
101 dstStartY, dstEndY, dstWidth,
102 logSrcHeight);
103 } else {
104 fallback.scaleImage(src, superImpose,
105 srcStartY, srcEndY, srcWidth,
106 dstStartY, dstEndY, dstWidth,
107 logSrcHeight);
108 }
109}
110
111using Pixel = uint32_t;
113 unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
114 FrameSource& paintFrame)
115{
116 if ((lineWidth != 320) || (srcEndY > 240)) return;
117
118 std::array<Endian::L32, 320 / 2> tmpBuf2; // 2 x uint16_t
119 #ifndef NDEBUG
120 // Avoid UMR. In optimized mode we don't care.
121 ranges::fill(tmpBuf2, 0);
122 #endif
123
124 VLA_SSE_ALIGNED(Pixel, buf1, lineWidth);
125 VLA_SSE_ALIGNED(Pixel, buf2, lineWidth);
126 auto curr = paintFrame.getLine(narrow<int>(srcStartY) - 1, buf1);
127 auto next = paintFrame.getLine(narrow<int>(srcStartY) + 0, buf2);
128 EdgeHQ edgeOp(0, 8, 16);
129 calcEdgesGL(curr, next, tmpBuf2, edgeOp);
130
131 edgeBuffer.bind();
132 if (auto* mapped = edgeBuffer.mapWrite()) {
133 for (auto y : xrange(srcStartY, srcEndY)) {
134 curr = next;
135 std::swap(buf1, buf2);
136 next = paintFrame.getLine(narrow<int>(y + 1), buf2);
137 calcEdgesGL(curr, next, tmpBuf2, edgeOp);
138 memcpy(mapped + 320 * size_t(y), tmpBuf2.data(), 320 * sizeof(uint16_t));
139 }
140 edgeBuffer.unmap();
141
142 auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
143 edgeTexture.bind();
144 glTexSubImage2D(GL_TEXTURE_2D, // target
145 0, // level
146 0, // offset x
147 narrow<GLint>(srcStartY), // offset y
148 narrow<GLint>(lineWidth), // width
149 narrow<GLint>(srcEndY - srcStartY), // height
150 format, // format
151 GL_UNSIGNED_BYTE, // type
152 edgeBuffer.getOffset(0, srcStartY));// data
153 }
154 edgeBuffer.unbind();
155}
156
157} // namespace openmsx
#define OPENGL_3_3
Definition GLUtil.hh:20
#define OPENGL_VERSION
Definition GLUtil.hh:21
GLsizei getHeight() const
Definition GLUtil.hh:107
void unmap() const
Unmaps the contents of this buffer.
Definition GLUtil.hh:306
void unbind() const
Unbind this buffer.
Definition GLUtil.hh:274
void setImage(GLuint width, GLuint height)
Sets the image for this buffer.
Definition GLUtil.hh:248
T * getOffset(GLuint x, GLuint y)
Gets a pointer relative to the start of this buffer.
Definition GLUtil.hh:282
void bind() const
Bind this PixelBuffer.
Definition GLUtil.hh:266
T * mapWrite()
Maps the contents of this buffer into memory.
Definition GLUtil.hh:295
void bind()
Makes this texture the active GL texture.
Definition GLUtil.hh:77
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
GLHQScaler(GLScaler &fallback)
Definition GLHQScaler.cc:16
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.
Definition GLHQScaler.cc:80
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(gl::ColorTexture &src, 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:121
void format(SectorAccessibleDisk &disk, MSXBootSectorType bootType)
Format the given disk (= a single partition).
This file implemented 3 utility functions:
Definition Autofire.cc:9
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:63
constexpr void fill(ForwardRange &&range, const T &value)
Definition ranges.hh:305
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition vla.hh:50
constexpr auto xrange(T e)
Definition xrange.hh:132