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 "vla.hh"
8#include <cstring>
9#include <utility>
10
11namespace openmsx {
12
14 : GLScaler("hqlite")
15 , fallback(fallback_)
16{
17 for (auto& p : program) {
18 p.activate();
19 glUniform1i(p.getUniformLocation("edgeTex"), 2);
20 glUniform1i(p.getUniformLocation("offsetTex"), 3);
21 }
22
23 // GL_LUMINANCE_ALPHA is no longer supported in newer openGL versions
24 auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
25 edgeTexture.bind();
26 glTexImage2D(GL_TEXTURE_2D, // target
27 0, // level
28 format, // internal format
29 320, // width
30 240, // height
31 0, // border
32 format, // format
33 GL_UNSIGNED_BYTE, // type
34 nullptr); // data
35#if OPENGL_VERSION >= OPENGL_3_3
36 GLint swizzleMask1[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
37 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask1);
38#endif
39 edgeBuffer.setImage(320, 240);
40
41 const auto& context = systemFileContext();
42 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
43 std::string offsetName = "shaders/HQ_xLiteOffsets.dat";
44 for (auto i : xrange(3)) {
45 int n = i + 2;
46 offsetName[10] = char('0') + n;
47 File offsetFile(context.resolve(offsetName));
48 offsetTexture[i].bind();
49 glTexImage2D(GL_TEXTURE_2D, // target
50 0, // level
51 format, // internal format
52 n * 64, // width
53 n * 64, // height
54 0, // border
55 format, // format
56 GL_UNSIGNED_BYTE, // type
57 offsetFile.mmap().data());// data
58#if OPENGL_VERSION >= OPENGL_3_3
59 GLint swizzleMask2[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
60 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask2);
61#endif
62 }
63 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
64}
65
67 gl::ColorTexture& src, gl::ColorTexture* superImpose,
68 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
69 unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
70 unsigned logSrcHeight)
71{
72 unsigned factorX = dstWidth / srcWidth; // 1 - 4
73 unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY);
74
75 if ((srcWidth == 320) && (factorX > 1) && (factorX == factorY)) {
76 setup(superImpose != nullptr);
77 src.setInterpolation(true);
78 glActiveTexture(GL_TEXTURE3);
79 offsetTexture[factorX - 2].bind();
80 glActiveTexture(GL_TEXTURE2);
81 edgeTexture.bind();
82 glActiveTexture(GL_TEXTURE0);
83 execute(src, superImpose,
84 srcStartY, srcEndY, srcWidth,
85 dstStartY, dstEndY, dstWidth,
86 logSrcHeight);
87 src.setInterpolation(false);
88 } else {
89 fallback.scaleImage(src, superImpose,
90 srcStartY, srcEndY, srcWidth,
91 dstStartY, dstEndY, dstWidth,
92 logSrcHeight);
93 }
94}
95
96using Pixel = uint32_t;
98 unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
99 FrameSource& paintFrame)
100{
101 if ((lineWidth != 320) || (srcEndY > 240)) return;
102
103 Endian::L32 tmpBuf2[320 / 2]; // 2 x uint16_t
104 #ifndef NDEBUG
105 // Avoid UMR. In optimized mode we don't care.
106 memset(tmpBuf2, 0, sizeof(tmpBuf2));
107 #endif
108
109 VLA_SSE_ALIGNED(Pixel, buf1_, lineWidth); auto* buf1 = buf1_;
110 VLA_SSE_ALIGNED(Pixel, buf2_, lineWidth); auto* buf2 = buf2_;
111 const auto* curr = paintFrame.getLinePtr(srcStartY - 1, lineWidth, buf1);
112 const auto* next = paintFrame.getLinePtr(srcStartY + 0, lineWidth, buf2);
113 calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
114
115 edgeBuffer.bind();
116 if (auto* mapped = edgeBuffer.mapWrite()) {
117 for (auto y : xrange(srcStartY, srcEndY)) {
118 curr = next;
119 std::swap(buf1, buf2);
120 next = paintFrame.getLinePtr(y + 1, lineWidth, buf2);
121 calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
122 memcpy(mapped + 320 * y, tmpBuf2, 320 * sizeof(uint16_t));
123 }
124 edgeBuffer.unmap();
125
126 auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
127 edgeTexture.bind();
128 glTexSubImage2D(GL_TEXTURE_2D, // target
129 0, // level
130 0, // offset x
131 srcStartY, // offset y
132 lineWidth, // width
133 srcEndY - srcStartY, // height
134 format, // format
135 GL_UNSIGNED_BYTE, // type
136 edgeBuffer.getOffset(0, srcStartY)); // data
137 }
138 edgeBuffer.unbind();
139}
140
141} // 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:101
Interface for getting lines from a video frame.
Definition: FrameSource.hh:17
const Pixel * getLinePtr(int line, unsigned width, Pixel *buf) const
Gets a pointer to the pixels of the given line number.
Definition: FrameSource.hh:93
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:15
void setup(bool superImpose)
Definition: GLScaler.cc:39
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:45
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.
gl::ShaderProgram program[2]
Definition: GLScaler.hh:79
std::optional< Context > context
Definition: GLContext.cc:9
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(const uint32_t *curr, const uint32_t *next, Endian::L32 *edges2, EdgeOp edgeOp)
Definition: HQCommon.hh:105
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:44
constexpr auto xrange(T e)
Definition: xrange.hh:133