OXYGENHUB
◆ main openmsx / src / video / scalers / GLHQScaler.cc
5.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "GLHQScaler.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 "inplace_buffer.hh"
10
#include "narrow.hh"
11
12
#include <algorithm>
13
#include <array>
14
#include <cstring>
15
#include <utility>
16
17
namespace openmsx {
18
19
GLHQScaler::GLHQScaler(GLScaler& fallback_, unsigned maxWidth_, unsigned maxHeight_)
20
	: GLScaler("hq")
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
		glUniform1i(p.getUniformLocation("weightTex"), 4);
30
		edgePosScaleUnif[i] = p.getUniformLocation("edgePosScale");
31
	}
32
33
	// GL_LUMINANCE_ALPHA is no longer supported in newer openGL versions
34
	auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
35
	edgeTexture.bind();
36
	glTexImage2D(GL_TEXTURE_2D,    // target
37
	             0,                // level
38
	             format,           // internal format
39
	             maxWidth,         // width
40
	             maxHeight,        // height
41
	             0,                // border
42
	             format,           // format
43
	             GL_UNSIGNED_BYTE, // type
44
	             nullptr);         // data
45
#if OPENGL_VERSION >= OPENGL_3_3
46
	GLint swizzleMask[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
47
	glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
48
#endif
49
	edgeBuffer.allocate(maxWidth * maxHeight);
50
51
	const auto& context = systemFileContext();
52
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
53
	std::string offsetsName = "shaders/HQ_xOffsets.dat";
54
	std::string weightsName = "shaders/HQ_xWeights.dat";
55
	for (auto i : xrange(3)) {
56
		int n = i + 2;
57
		offsetsName[10] = narrow<char>('0' + n);
58
		auto offsets = File(context.resolve(offsetsName)).mmap<const uint8_t>();
59
		offsetTexture[i].bind();
60
		glTexImage2D(GL_TEXTURE_2D,       // target
61
		             0,                   // level
62
		             GL_RGBA,             // internal format
63
		             n * 64,              // width
64
		             n * 64,              // height
65
		             0,                   // border
66
		             GL_RGBA,             // format
67
		             GL_UNSIGNED_BYTE,    // type
68
		             offsets.data());     // data
69
70
		weightsName[10] = narrow<char>('0' + n);
71
		auto weights = File(context.resolve(weightsName)).mmap<const uint8_t>();
72
		weightTexture[i].bind();
73
		glTexImage2D(GL_TEXTURE_2D,       // target
74
		             0,                   // level
75
		             GL_RGB,              // internal format
76
		             n * 64,              // width
77
		             n * 64,              // height
78
		             0,                   // border
79
		             GL_RGB,              // format
80
		             GL_UNSIGNED_BYTE,    // type
81
		             weights.data());     // data
82
	}
83
	glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
84
}
85
86
void GLHQScaler::scaleImage(
87
	gl::ColorTexture& src, gl::ColorTexture* superImpose,
88
	unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
89
	unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
90
	unsigned logSrcHeight)
91
{
92
	unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY); // 1 - 4
93
94
	if ((factorY >= 2) && ((srcWidth % 320) == 0)) {
95
		assert(src.getHeight() == 2 * 240);
96
		setup(superImpose != nullptr);
97
		glActiveTexture(GL_TEXTURE4);
98
		weightTexture[factorY - 2].bind();
99
		glActiveTexture(GL_TEXTURE3);
100
		offsetTexture[factorY - 2].bind();
101
		glActiveTexture(GL_TEXTURE2);
102
		edgeTexture.bind();
103
		glActiveTexture(GL_TEXTURE0);
104
105
		int i = superImpose ? 1 : 0;
106
		glUniform2f(edgePosScaleUnif[i],
107
		            float(src.getWidth()) / float(maxWidth),
108
		            float(src.getHeight()) / float(maxHeight));
109
110
		execute(src, superImpose,
111
		        srcStartY, srcEndY, srcWidth,
112
		        dstStartY, dstEndY, dstWidth,
113
		        logSrcHeight);
114
	} else {
115
		fallback.scaleImage(src, superImpose,
116
		                    srcStartY, srcEndY, srcWidth,
117
		                    dstStartY, dstEndY, dstWidth,
118
		                    logSrcHeight);
119
	}
120
}
121
122
using Pixel = uint32_t;
123
void GLHQScaler::uploadBlock(
124
	unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
125
	FrameSource& paintFrame)
126
{
127
	if ((lineWidth % 320) != 0) return;
128
129
	assert(maxWidth <= 1280);
130
	inplace_buffer<Endian::L32, 1280 / 2> tmpBuf2(uninitialized_tag{}, lineWidth / 2); // 2 x uint16_t
131
	#ifndef NDEBUG
132
	// Avoid UMR. In optimized mode we don't care.
133
	std::ranges::fill(tmpBuf2, 0);
134
	#endif
135
136
	inplace_buffer<Pixel, 1280> buf1(uninitialized_tag{}, lineWidth);
137
	inplace_buffer<Pixel, 1280> buf2(uninitialized_tag{}, lineWidth);
138
	auto curr = paintFrame.getLine(narrow<int>(srcStartY) - 1, buf1);
139
	auto next = paintFrame.getLine(narrow<int>(srcStartY) + 0, buf2);
140
	EdgeHQ edgeOp;
141
	calcEdgesGL(curr, next, tmpBuf2, edgeOp);
142
143
	edgeBuffer.bind();
144
	auto mapped = edgeBuffer.mapWrite();
145
	auto numLines = srcEndY - srcStartY;
146
	for (auto yy : xrange(numLines)) {
147
		curr = next;
148
		std::swap(buf1, buf2);
149
		next = paintFrame.getLine(narrow<int>(yy + srcStartY + 1), buf2);
150
		calcEdgesGL(curr, next, tmpBuf2, edgeOp);
151
		auto dest = mapped.subspan(yy * size_t(lineWidth), lineWidth);
152
		assert(dest.size_bytes() == std::span{tmpBuf2}.size_bytes()); // note: convert L32 -> 2 x uint16_t
153
		memcpy(dest.data(), tmpBuf2.data(), std::span{tmpBuf2}.size_bytes());
154
	}
155
	edgeBuffer.unmap();
156
157
	auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
158
	edgeTexture.bind();
159
	glTexSubImage2D(GL_TEXTURE_2D,            // target
160
			0,                        // level
161
			0,                        // offset x
162
			narrow<GLint>(srcStartY), // offset y
163
			narrow<GLint>(lineWidth), // width
164
			narrow<GLint>(numLines),  // height
165
			format,                   // format
166
			GL_UNSIGNED_BYTE,         // type
167
			mapped.data());           // data
168
	edgeBuffer.unbind();
169
}
170
171
} // namespace openmsx