openMSX
GLHQLiteScaler.cc
Go to the documentation of this file.
1#include "GLHQLiteScaler.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("hqlite")
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 }
25
26 // GL_LUMINANCE_ALPHA is no longer supported in newer openGL versions
27 auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
28 edgeTexture.bind();
29 glTexImage2D(GL_TEXTURE_2D, // target
30 0, // level
31 format, // internal format
32 320, // width
33 240, // height
34 0, // border
35 format, // format
36 GL_UNSIGNED_BYTE, // type
37 nullptr); // data
38#if OPENGL_VERSION >= OPENGL_3_3
39 GLint swizzleMask1[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
40 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask1);
41#endif
42 edgeBuffer.setImage(320, 240);
43
44 const auto& context = systemFileContext();
45 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
46 std::string offsetName = "shaders/HQ_xLiteOffsets.dat";
47 for (auto i : xrange(3)) {
48 int n = i + 2;
49 offsetName[10] = narrow<char>('0' + n);
50 File offsetFile(context.resolve(offsetName));
51 offsetTexture[i].bind();
52 glTexImage2D(GL_TEXTURE_2D, // target
53 0, // level
54 format, // internal format
55 n * 64, // width
56 n * 64, // height
57 0, // border
58 format, // format
59 GL_UNSIGNED_BYTE, // type
60 offsetFile.mmap().data());// data
61#if OPENGL_VERSION >= OPENGL_3_3
62 GLint swizzleMask2[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
63 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask2);
64#endif
65 }
66 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
67}
68
70 gl::ColorTexture& src, gl::ColorTexture* superImpose,
71 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
72 unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
73 unsigned logSrcHeight)
74{
75 unsigned factorX = dstWidth / srcWidth; // 1 - 4
76 unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY);
77
78 if ((srcWidth == 320) && (factorX > 1) && (factorX == factorY)) {
79 setup(superImpose != nullptr);
80 src.setInterpolation(true);
81 glActiveTexture(GL_TEXTURE3);
82 offsetTexture[factorX - 2].bind();
83 glActiveTexture(GL_TEXTURE2);
84 edgeTexture.bind();
85 glActiveTexture(GL_TEXTURE0);
86 execute(src, superImpose,
87 srcStartY, srcEndY, srcWidth,
88 dstStartY, dstEndY, dstWidth,
89 logSrcHeight);
90 src.setInterpolation(false);
91 } else {
92 fallback.scaleImage(src, superImpose,
93 srcStartY, srcEndY, srcWidth,
94 dstStartY, dstEndY, dstWidth,
95 logSrcHeight);
96 }
97}
98
99using Pixel = uint32_t;
101 unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
102 FrameSource& paintFrame)
103{
104 if ((lineWidth != 320) || (srcEndY > 240)) return;
105
106 std::array<Endian::L32, 320 / 2> tmpBuf2; // 2 x uint16_t
107 #ifndef NDEBUG
108 // Avoid UMR. In optimized mode we don't care.
109 ranges::fill(tmpBuf2, 0);
110 #endif
111
112 VLA_SSE_ALIGNED(Pixel, buf1, lineWidth);
113 VLA_SSE_ALIGNED(Pixel, buf2, lineWidth);
114 auto curr = paintFrame.getLine(narrow<int>(srcStartY) - 1, buf1);
115 auto next = paintFrame.getLine(narrow<int>(srcStartY) + 0, buf2);
116 calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
117
118 edgeBuffer.bind();
119 if (auto* mapped = edgeBuffer.mapWrite()) {
120 for (auto y : xrange(srcStartY, srcEndY)) {
121 curr = next;
122 std::swap(buf1, buf2);
123 next = paintFrame.getLine(narrow<int>(y + 1), buf2);
124 calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
125 memcpy(mapped + 320 * size_t(y), tmpBuf2.data(), 320 * sizeof(uint16_t));
126 }
127 edgeBuffer.unmap();
128
129 auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
130 edgeTexture.bind();
131 glTexSubImage2D(GL_TEXTURE_2D, // target
132 0, // level
133 0, // offset x
134 narrow<GLint>(srcStartY), // offset y
135 narrow<GLint>(lineWidth), // width
136 narrow<GLint>(srcEndY - srcStartY), // height
137 format, // format
138 GL_UNSIGNED_BYTE, // type
139 edgeBuffer.getOffset(0, srcStartY));// data
140 }
141 edgeBuffer.unbind();
142}
143
144} // namespace openmsx
#define OPENGL_3_3
Definition: GLUtil.hh:24
#define OPENGL_VERSION
Definition: GLUtil.hh:25
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 setInterpolation(bool interpolation)
Enable/disable bilinear interpolation for this texture.
Definition: GLUtil.cc:47
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
GLHQLiteScaler(GLScaler &fallback)
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)
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