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:24
#define OPENGL_VERSION
Definition: GLUtil.hh:25
GLsizei getHeight() const
Definition: GLUtil.hh:111
void unmap() const
Unmaps the contents of this buffer.
Definition: GLUtil.hh:310
void unbind() const
Unbind this buffer.
Definition: GLUtil.hh:278
void setImage(GLuint width, GLuint height)
Sets the image for this buffer.
Definition: GLUtil.hh:252
T * getOffset(GLuint x, GLuint y)
Gets a pointer relative to the start of this buffer.
Definition: GLUtil.hh:286
void bind() const
Bind this PixelBuffer.
Definition: GLUtil.hh:270
T * mapWrite()
Maps the contents of this buffer into memory.
Definition: GLUtil.hh:299
void bind()
Makes this texture the active GL texture.
Definition: GLUtil.hh:81
std::span< const uint8_t > mmap()
Map file in memory.
Definition: File.cc:102
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
void uploadBlock(unsigned srcStartY, unsigned srcEndY, unsigned lineWidth, FrameSource &paintFrame) override
Definition: GLHQScaler.cc:112
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)
Definition: GLScaler.cc:40
std::array< gl::ShaderProgram, 2 > program
Definition: GLScaler.hh:80
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:46
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:120
std::optional< Context > context
Definition: GLContext.cc:10
void format(SectorAccessibleDisk &disk, bool dos1)
Format the given disk (= a single partition).
This file implemented 3 utility functions:
Definition: Autofire.cc:9
const FileContext & systemFileContext()
Definition: FileContext.cc:155
uint32_t 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:106
constexpr void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:287
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:133