openMSX
GLPostProcessor.cc
Go to the documentation of this file.
1#include "GLPostProcessor.hh"
2#include "GLContext.hh"
3#include "GLScaler.hh"
4#include "GLScalerFactory.hh"
5#include "FloatSetting.hh"
6#include "OutputSurface.hh"
7#include "RawFrame.hh"
8#include "gl_transform.hh"
9#include "narrow.hh"
10#include "random.hh"
11#include "ranges.hh"
12#include "stl.hh"
13#include "xrange.hh"
14#include <cassert>
15#include <cstdint>
16#include <numeric>
17
18using namespace gl;
19
20namespace openmsx {
21
23 MSXMotherBoard& motherBoard_, Display& display_,
24 OutputSurface& screen_, const std::string& videoSource,
25 unsigned maxWidth_, unsigned height_, bool canDoInterlace_)
26 : PostProcessor(motherBoard_, display_, screen_,
27 videoSource, maxWidth_, height_, canDoInterlace_)
28 , height(height_)
29{
30 preCalcNoise(renderSettings.getNoise());
31 initBuffers();
32
33 for (auto i : xrange(2)) {
34 colorTex[i].bind();
35 colorTex[i].setInterpolation(true);
36 auto [w, h] = screen.getLogicalSize();
37 glTexImage2D(GL_TEXTURE_2D, // target
38 0, // level
39 GL_RGB, // internal format
40 w, // width
41 h, // height
42 0, // border
43 GL_RGB, // format
44 GL_UNSIGNED_BYTE, // type
45 nullptr); // data
46 fbo[i] = FrameBufferObject(colorTex[i]);
47 }
48
49 VertexShader vertexShader ("monitor3D.vert");
50 FragmentShader fragmentShader("monitor3D.frag");
51 monitor3DProg.attach(vertexShader);
52 monitor3DProg.attach(fragmentShader);
53 monitor3DProg.bindAttribLocation(0, "a_position");
54 monitor3DProg.bindAttribLocation(1, "a_normal");
55 monitor3DProg.bindAttribLocation(2, "a_texCoord");
56 monitor3DProg.link();
57 preCalcMonitor3D(renderSettings.getHorizontalStretch());
58
61}
62
64{
67}
68
69void GLPostProcessor::initBuffers()
70{
71 // combined positions and texture coordinates
72 static constexpr std::array pos_tex = {
73 vec2(-1, 1), vec2(-1,-1), vec2( 1,-1), vec2( 1, 1), // pos
74 vec2( 0, 1), vec2( 0, 0), vec2( 1, 0), vec2( 1, 1), // tex
75 };
76 glBindBuffer(GL_ARRAY_BUFFER, vbo.get());
77 glBufferData(GL_ARRAY_BUFFER, sizeof(pos_tex), pos_tex.data(), GL_STATIC_DRAW);
78 glBindBuffer(GL_ARRAY_BUFFER, 0);
79}
80
81void GLPostProcessor::createRegions()
82{
83 regions.clear();
84
85 const unsigned srcHeight = paintFrame->getHeight();
86 const unsigned dstHeight = screen.getLogicalHeight();
87
88 unsigned g = std::gcd(srcHeight, dstHeight);
89 unsigned srcStep = srcHeight / g;
90 unsigned dstStep = dstHeight / g;
91
92 // TODO: Store all MSX lines in RawFrame and only scale the ones that fit
93 // on the PC screen, as a preparation for resizable output window.
94 unsigned srcStartY = 0;
95 unsigned dstStartY = 0;
96 while (dstStartY < dstHeight) {
97 // Currently this is true because the source frame height
98 // is always >= dstHeight/(dstStep/srcStep).
99 assert(srcStartY < srcHeight);
100
101 // get region with equal lineWidth
102 unsigned lineWidth = getLineWidth(paintFrame, srcStartY, srcStep);
103 unsigned srcEndY = srcStartY + srcStep;
104 unsigned dstEndY = dstStartY + dstStep;
105 while ((srcEndY < srcHeight) && (dstEndY < dstHeight) &&
106 (getLineWidth(paintFrame, srcEndY, srcStep) == lineWidth)) {
107 srcEndY += srcStep;
108 dstEndY += dstStep;
109 }
110
111 regions.emplace_back(srcStartY, srcEndY,
112 dstStartY, dstEndY,
113 lineWidth);
114
115 // next region
116 srcStartY = srcEndY;
117 dstStartY = dstEndY;
118 }
119}
120
122{
124 interleaveCount ^= 1;
125 if (interleaveCount) {
126 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
127 glClear(GL_COLOR_BUFFER_BIT);
128 return;
129 }
130 }
131
132 auto deform = renderSettings.getDisplayDeform();
133 float horStretch = renderSettings.getHorizontalStretch();
134 int glow = renderSettings.getGlow();
135 bool renderToTexture = (deform != RenderSettings::DEFORM_NORMAL) ||
136 (horStretch != 320.0f) ||
137 (glow != 0) ||
139
140 if ((screen.getViewOffset() != ivec2()) || // any part of the screen not covered by the viewport?
141 (deform == RenderSettings::DEFORM_3D) || !paintFrame) {
142 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
143 glClear(GL_COLOR_BUFFER_BIT);
144 if (!paintFrame) {
145 return;
146 }
147 }
148
149 // New scaler algorithm selected?
150 auto algo = renderSettings.getScaleAlgorithm();
151 if (scaleAlgorithm != algo) {
152 scaleAlgorithm = algo;
154
155 // Re-upload frame data, this is both
156 // - Chunks of RawFrame with a specific line width, possibly
157 // with some extra lines above and below each chunk that are
158 // also converted to this line width.
159 // - Extra data that is specific for the scaler (ATM only the
160 // hq and hqlite scalers require this).
161 // Re-uploading the first is not strictly needed. But switching
162 // scalers doesn't happen that often, so it also doesn't hurt
163 // and it keeps the code simpler.
164 uploadFrame();
165 }
166
167 auto [scrnWidth, scrnHeight] = screen.getLogicalSize();
168 if (renderToTexture) {
169 glViewport(0, 0, scrnWidth, scrnHeight);
170 glBindTexture(GL_TEXTURE_2D, 0);
171 fbo[frameCounter & 1].push();
172 }
173
174 for (auto& r : regions) {
175 //fprintf(stderr, "post processing lines %d-%d: %d\n",
176 // r.srcStartY, r.srcEndY, r.lineWidth);
177 auto it = find_unguarded(textures, r.lineWidth, &TextureData::width);
178 auto* superImpose = superImposeVideoFrame
179 ? &superImposeTex : nullptr;
180 currScaler->scaleImage(
181 it->tex, superImpose,
182 r.srcStartY, r.srcEndY, r.lineWidth, // src
183 r.dstStartY, r.dstEndY, scrnWidth, // dst
184 paintFrame->getHeight()); // dst
185 }
186
187 drawNoise();
188 drawGlow(glow);
189
190 if (renderToTexture) {
191 fbo[frameCounter & 1].pop();
192 colorTex[frameCounter & 1].bind();
193 auto [x, y] = screen.getViewOffset();
194 auto [w, h] = screen.getViewSize();
195 glViewport(x, y, w, h);
196
197 if (deform == RenderSettings::DEFORM_3D) {
198 drawMonitor3D();
199 } else {
200 float x1 = (320.0f - float(horStretch)) / (2.0f * 320.0f);
201 float x2 = 1.0f - x1;
202 std::array tex = {
203 vec2(x1, 1), vec2(x1, 0), vec2(x2, 0), vec2(x2, 1)
204 };
205
206 auto& glContext = *gl::context;
207 glContext.progTex.activate();
208 glUniform4f(glContext.unifTexColor,
209 1.0f, 1.0f, 1.0f, 1.0f);
210 mat4 I;
211 glUniformMatrix4fv(glContext.unifTexMvp,
212 1, GL_FALSE, &I[0][0]);
213
214 glBindBuffer(GL_ARRAY_BUFFER, vbo.get());
215 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
216 glEnableVertexAttribArray(0);
217
218 glBindBuffer(GL_ARRAY_BUFFER, stretchVBO.get());
219 glBufferData(GL_ARRAY_BUFFER, sizeof(tex), tex.data(), GL_STREAM_DRAW);
220 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
221 glEnableVertexAttribArray(1);
222
223 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
224
225 glDisableVertexAttribArray(1);
226 glDisableVertexAttribArray(0);
227 glBindBuffer(GL_ARRAY_BUFFER, 0);
228 }
229 storedFrame = true;
230 } else {
231 storedFrame = false;
232 }
233 //gl::checkGLError("GLPostProcessor::paint");
234}
235
236std::unique_ptr<RawFrame> GLPostProcessor::rotateFrames(
237 std::unique_ptr<RawFrame> finishedFrame, EmuTime::param time)
238{
239 std::unique_ptr<RawFrame> reuseFrame =
240 PostProcessor::rotateFrames(std::move(finishedFrame), time);
241 uploadFrame();
242 ++frameCounter;
243 noiseX = random_float(0.0f, 1.0f);
244 noiseY = random_float(0.0f, 1.0f);
245 return reuseFrame;
246}
247
249{
251 auto& noiseSetting = renderSettings.getNoiseSetting();
252 auto& horizontalStretch = renderSettings.getHorizontalStretchSetting();
253 if (&setting == &noiseSetting) {
254 preCalcNoise(noiseSetting.getFloat());
255 } else if (&setting == &horizontalStretch) {
256 preCalcMonitor3D(horizontalStretch.getFloat());
257 }
258}
259
260void GLPostProcessor::uploadFrame()
261{
262 createRegions();
263
264 const unsigned srcHeight = paintFrame->getHeight();
265 for (auto& r : regions) {
266 // upload data
267 // TODO get before/after data from scaler
268 int before = 1;
269 unsigned after = 1;
270 uploadBlock(narrow<unsigned>(std::max(0, narrow<int>(r.srcStartY) - before)),
271 std::min(srcHeight, r.srcEndY + after),
272 r.lineWidth);
273 }
274
276 int w = narrow<GLsizei>(superImposeVideoFrame->getWidth());
277 int h = narrow<GLsizei>(superImposeVideoFrame->getHeight());
278 if (superImposeTex.getWidth() != w ||
279 superImposeTex.getHeight() != h) {
280 superImposeTex.resize(w, h);
281 superImposeTex.setInterpolation(true);
282 }
283 superImposeTex.bind();
284 glTexSubImage2D(
285 GL_TEXTURE_2D, // target
286 0, // level
287 0, // offset x
288 0, // offset y
289 w, // width
290 h, // height
291 GL_RGBA, // format
292 GL_UNSIGNED_BYTE, // type
293 const_cast<RawFrame*>(superImposeVideoFrame)->getLineDirect<unsigned>(0).data()); // data
294 }
295}
296
297void GLPostProcessor::uploadBlock(
298 unsigned srcStartY, unsigned srcEndY, unsigned lineWidth)
299{
300 // create texture/pbo if needed
301 auto it = ranges::find(textures, lineWidth, &TextureData::width);
302 if (it == end(textures)) {
303 TextureData textureData;
304
305 textureData.tex.resize(narrow<GLsizei>(lineWidth),
306 narrow<GLsizei>(height * 2)); // *2 for interlace
307 textureData.pbo.setImage(lineWidth, height * 2);
308 textures.push_back(std::move(textureData));
309 it = end(textures) - 1;
310 }
311 auto& tex = it->tex;
312 auto& pbo = it->pbo;
313
314 // bind texture
315 tex.bind();
316
317 // upload data
318 pbo.bind();
319 uint32_t* mapped = pbo.mapWrite();
320 for (auto y : xrange(srcStartY, srcEndY)) {
321 auto* dest = mapped + y * size_t(lineWidth);
322 auto line = paintFrame->getLine(narrow<int>(y), std::span{dest, lineWidth});
323 if (line.data() != dest) {
324 ranges::copy(line, dest);
325 }
326 }
327 pbo.unmap();
328#if defined(__APPLE__)
329 // The nVidia GL driver for the GeForce 8000/9000 series seems to hang
330 // on texture data replacements that are 1 pixel wide and start on a
331 // line number that is a non-zero multiple of 16.
332 if (lineWidth == 1 && srcStartY != 0 && srcStartY % 16 == 0) {
333 srcStartY--;
334 }
335#endif
336 glTexSubImage2D(
337 GL_TEXTURE_2D, // target
338 0, // level
339 0, // offset x
340 narrow<GLint>(srcStartY), // offset y
341 narrow<GLint>(lineWidth), // width
342 narrow<GLint>(srcEndY - srcStartY), // height
343 GL_RGBA, // format
344 GL_UNSIGNED_BYTE, // type
345 pbo.getOffset(0, srcStartY)); // data
346 pbo.unbind();
347
348 // possibly upload scaler specific data
349 if (currScaler) {
350 currScaler->uploadBlock(srcStartY, srcEndY, lineWidth, *paintFrame);
351 }
352}
353
354void GLPostProcessor::drawGlow(int glow)
355{
356 if ((glow == 0) || !storedFrame) return;
357
358 auto& glContext = *gl::context;
359 glContext.progTex.activate();
360 glEnable(GL_BLEND);
361 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
362 colorTex[(frameCounter & 1) ^ 1].bind();
363 glUniform4f(glContext.unifTexColor,
364 1.0f, 1.0f, 1.0f, narrow<float>(glow) * 31.0f / 3200.0f);
365 mat4 I;
366 glUniformMatrix4fv(glContext.unifTexMvp, 1, GL_FALSE, &I[0][0]);
367
368 glBindBuffer(GL_ARRAY_BUFFER, vbo.get());
369
370 const vec2* offset = nullptr;
371 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, offset); // pos
372 offset += 4; // see initBuffers()
373 glEnableVertexAttribArray(0);
374
375 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, offset); // tex
376 glEnableVertexAttribArray(1);
377
378 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
379
380 glDisableVertexAttribArray(1);
381 glDisableVertexAttribArray(0);
382 glBindBuffer(GL_ARRAY_BUFFER, 0);
383 glDisable(GL_BLEND);
384}
385
386void GLPostProcessor::preCalcNoise(float factor)
387{
388 std::array<uint8_t, 256 * 256> buf1;
389 std::array<uint8_t, 256 * 256> buf2;
390 auto& generator = global_urng(); // fast (non-cryptographic) random numbers
391 std::normal_distribution<float> distribution(0.0f, 1.0f);
392 for (auto i : xrange(256 * 256)) {
393 float r = distribution(generator);
394 int s = std::clamp(int(roundf(r * factor)), -255, 255);
395 buf1[i] = narrow<uint8_t>((s > 0) ? s : 0);
396 buf2[i] = narrow<uint8_t>((s < 0) ? -s : 0);
397 }
398
399 // GL_LUMINANCE is no longer supported in newer openGL versions
400 auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RED : GL_LUMINANCE;
401 noiseTextureA.bind();
402 glTexImage2D(
403 GL_TEXTURE_2D, // target
404 0, // level
405 format, // internal format
406 256, // width
407 256, // height
408 0, // border
409 format, // format
410 GL_UNSIGNED_BYTE, // type
411 buf1.data()); // data
412#if OPENGL_VERSION >= OPENGL_3_3
413 GLint swizzleMask1[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
414 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask1);
415#endif
416
417 noiseTextureB.bind();
418 glTexImage2D(
419 GL_TEXTURE_2D, // target
420 0, // level
421 format, // internal format
422 256, // width
423 256, // height
424 0, // border
425 format, // format
426 GL_UNSIGNED_BYTE, // type
427 buf2.data()); // data
428#if OPENGL_VERSION >= OPENGL_3_3
429 GLint swizzleMask2[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
430 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask2);
431#endif
432}
433
434void GLPostProcessor::drawNoise()
435{
436 if (renderSettings.getNoise() == 0.0f) return;
437
438 // Rotate and mirror noise texture in consecutive frames to avoid
439 // seeing 'patterns' in the noise.
440 static constexpr std::array pos = {
441 std::array{vec2{-1, -1}, vec2{ 1, -1}, vec2{ 1, 1}, vec2{-1, 1}},
442 std::array{vec2{-1, 1}, vec2{ 1, 1}, vec2{ 1, -1}, vec2{-1, -1}},
443 std::array{vec2{-1, 1}, vec2{-1, -1}, vec2{ 1, -1}, vec2{ 1, 1}},
444 std::array{vec2{ 1, 1}, vec2{ 1, -1}, vec2{-1, -1}, vec2{-1, 1}},
445 std::array{vec2{ 1, 1}, vec2{-1, 1}, vec2{-1, -1}, vec2{ 1, -1}},
446 std::array{vec2{ 1, -1}, vec2{-1, -1}, vec2{-1, 1}, vec2{ 1, 1}},
447 std::array{vec2{ 1, -1}, vec2{ 1, 1}, vec2{-1, 1}, vec2{-1, -1}},
448 std::array{vec2{-1, -1}, vec2{-1, 1}, vec2{ 1, 1}, vec2{ 1, -1}},
449 };
450 vec2 noise(noiseX, noiseY);
451 const std::array tex = {
452 noise + vec2(0.0f, 1.875f),
453 noise + vec2(2.0f, 1.875f),
454 noise + vec2(2.0f, 0.0f ),
455 noise + vec2(0.0f, 0.0f ),
456 };
457
458 auto& glContext = *gl::context;
459 glContext.progTex.activate();
460
461 glEnable(GL_BLEND);
462 glBlendFunc(GL_ONE, GL_ONE);
463 glUniform4f(glContext.unifTexColor, 1.0f, 1.0f, 1.0f, 1.0f);
464 mat4 I;
465 glUniformMatrix4fv(glContext.unifTexMvp, 1, GL_FALSE, &I[0][0]);
466
467 unsigned seq = frameCounter & 7;
468 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, pos[seq].data());
469 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, tex.data());
470 glEnableVertexAttribArray(0);
471 glEnableVertexAttribArray(1);
472
473 noiseTextureA.bind();
474 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
475 glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
476 noiseTextureB.bind();
477 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
478
479 glDisableVertexAttribArray(1);
480 glDisableVertexAttribArray(0);
481 glBlendEquation(GL_FUNC_ADD); // restore default
482 glDisable(GL_BLEND);
483}
484
485static constexpr int GRID_SIZE = 16;
486static constexpr int GRID_SIZE1 = GRID_SIZE + 1;
487static constexpr int NUM_INDICES = (GRID_SIZE1 * 2 + 2) * GRID_SIZE - 2;
488struct Vertex {
492};
493
494void GLPostProcessor::preCalcMonitor3D(float width)
495{
496 // precalculate vertex-positions, -normals and -texture-coordinates
497 std::array<std::array<Vertex, GRID_SIZE1>, GRID_SIZE1> vertices;
498
499 constexpr float GRID_SIZE2 = float(GRID_SIZE) / 2.0f;
500 float s = width / 320.0f;
501 float b = (320.0f - width) / (2.0f * 320.0f);
502
503 for (auto sx : xrange(GRID_SIZE1)) {
504 for (auto sy : xrange(GRID_SIZE1)) {
505 Vertex& v = vertices[sx][sy];
506 float x = (narrow<float>(sx) - GRID_SIZE2) / GRID_SIZE2;
507 float y = (narrow<float>(sy) - GRID_SIZE2) / GRID_SIZE2;
508
509 v.position = vec3(x, y, (x * x + y * y) / -12.0f);
510 v.normal = normalize(vec3(x / 6.0f, y / 6.0f, 1.0f)) * 1.2f;
511 v.tex = vec2((float(sx) / GRID_SIZE) * s + b,
512 float(sy) / GRID_SIZE);
513 }
514 }
515
516 // calculate indices
517 std::array<uint16_t, NUM_INDICES> indices;
518
519 uint16_t* ind = indices.data();
520 for (auto y : xrange(GRID_SIZE)) {
521 for (auto x : xrange(GRID_SIZE1)) {
522 *ind++ = narrow<uint16_t>((y + 0) * GRID_SIZE1 + x);
523 *ind++ = narrow<uint16_t>((y + 1) * GRID_SIZE1 + x);
524 }
525 // skip 2, filled in later
526 ind += 2;
527 }
528 assert((ind - indices.data()) == NUM_INDICES + 2);
529 ind = indices.data();
530 repeat(GRID_SIZE - 1, [&] {
531 ind += 2 * GRID_SIZE1;
532 // repeat prev and next index to restart strip
533 ind[0] = ind[-1];
534 ind[1] = ind[ 2];
535 ind += 2;
536 });
537
538 // upload calculated values to buffers
539 glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer.get());
540 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(),
541 GL_STATIC_DRAW);
542 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.get());
543 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices.data(),
544 GL_STATIC_DRAW);
545 glBindBuffer(GL_ARRAY_BUFFER, 0);
546 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
547
548 // calculate transformation matrices
549 mat4 proj = frustum(-1, 1, -1, 1, 1, 10);
550 mat4 tran = translate(vec3(0.0f, 0.4f, -2.0f));
551 mat4 rotX = rotateX(radians(-10.0f));
552 mat4 scal = scale(vec3(2.2f, 2.2f, 2.2f));
553
554 mat3 normal = mat3(rotX);
555 mat4 mvp = proj * tran * rotX * scal;
556
557 // set uniforms
558 monitor3DProg.activate();
559 glUniform1i(monitor3DProg.getUniformLocation("u_tex"), 0);
560 glUniformMatrix4fv(monitor3DProg.getUniformLocation("u_mvpMatrix"),
561 1, GL_FALSE, &mvp[0][0]);
562 glUniformMatrix3fv(monitor3DProg.getUniformLocation("u_normalMatrix"),
563 1, GL_FALSE, &normal[0][0]);
564}
565
566void GLPostProcessor::drawMonitor3D()
567{
568 monitor3DProg.activate();
569
570 char* base = nullptr;
571 glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer.get());
572 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer.get());
573 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
574 base);
575 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
576 base + sizeof(vec3));
577 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
578 base + sizeof(vec3) + sizeof(vec3));
579 glEnableVertexAttribArray(0);
580 glEnableVertexAttribArray(1);
581 glEnableVertexAttribArray(2);
582
583 glDrawElements(GL_TRIANGLE_STRIP, NUM_INDICES, GL_UNSIGNED_SHORT, nullptr);
584 glDisableVertexAttribArray(2);
585 glDisableVertexAttribArray(1);
586 glDisableVertexAttribArray(0);
587
588 glBindBuffer(GL_ARRAY_BUFFER, 0);
589 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
590}
591
592} // namespace openmsx
#define OPENGL_3_3
Definition: GLUtil.hh:24
#define OPENGL_VERSION
Definition: GLUtil.hh:25
BaseSetting * setting
Definition: Interpreter.cc:28
int g
GLuint get() const
Definition: GLUtil.hh:463
GLsizei getHeight() const
Definition: GLUtil.hh:111
GLsizei getWidth() const
Definition: GLUtil.hh:110
void resize(GLsizei width, GLsizei height)
Definition: GLUtil.cc:71
Wrapper around an OpenGL fragment shader: a program executed on the GPU that computes the colors of p...
Definition: GLUtil.hh:372
void activate() const
Makes this program the active shader program.
Definition: GLUtil.cc:265
void attach(const Shader &shader)
Adds a given shader to this program.
Definition: GLUtil.cc:220
void link()
Links all attached shaders together into one program.
Definition: GLUtil.cc:232
void bindAttribLocation(unsigned index, const char *name)
Bind the given name for a vertex shader attribute to the given location.
Definition: GLUtil.cc:252
GLint getUniformLocation(const char *name) const
Gets a reference to a uniform variable declared in the shader source.
Definition: GLUtil.cc:257
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
Wrapper around an OpenGL vertex shader: a program executed on the GPU that computes per-vertex stuff.
Definition: GLUtil.hh:357
Represents the output window/screen of openMSX.
Definition: Display.hh:33
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
unsigned getWidth() const
Get the width of (all) lines in this frame.
Definition: FrameSource.hh:64
unsigned getHeight() const
Gets the number of lines in this frame.
Definition: FrameSource.hh:49
std::unique_ptr< RawFrame > rotateFrames(std::unique_ptr< RawFrame > finishedFrame, EmuTime::param time) override
Sets up the "abcdFrame" variables for a new frame.
GLPostProcessor(MSXMotherBoard &motherBoard, Display &display, OutputSurface &screen, const std::string &videoSource, unsigned maxWidth, unsigned height, bool canDoInterlace)
void paint(OutputSurface &output) override
Paint this layer.
void update(const Setting &setting) noexcept override
A frame buffer where pixels can be written to.
gl::ivec2 getLogicalSize() const
bool isViewScaled() const
gl::ivec2 getViewOffset() const
gl::ivec2 getViewSize() const
int getLogicalHeight() const
Abstract base class for post processors.
virtual std::unique_ptr< RawFrame > rotateFrames(std::unique_ptr< RawFrame > finishedFrame, EmuTime::param time)
Sets up the "abcdFrame" variables for a new frame.
FrameSource * paintFrame
Represents a frame as it should be displayed.
const RawFrame * superImposeVideoFrame
Video frame on which to superimpose the (VDP) output.
static unsigned getLineWidth(FrameSource *frame, unsigned y, unsigned step)
Returns the maximum width for lines [y..y+step).
RenderSettings & renderSettings
Render settings.
OutputSurface & screen
The surface which is visible to the user.
int getGlow() const
The amount of glow [0..100].
bool getInterleaveBlackFrame() const
Is black frame interleaving enabled?
FloatSetting & getNoiseSetting()
The amount of noise to add to the frame.
float getHorizontalStretch() const
DisplayDeform getDisplayDeform()
Display deformation (normal, 3d) ATM this only works when using the SDLGL-PP renderer.
FloatSetting & getHorizontalStretchSetting()
Amount of horizontal stretch.
ScaleAlgorithm getScaleAlgorithm() const
The current scaling algorithm.
void detach(Observer< T > &observer)
Definition: Subject.hh:56
void attach(Observer< T > &observer)
Definition: Subject.hh:50
void update(const Setting &setting) noexcept override
Definition: VideoLayer.cc:48
Definition: gl_mat.hh:23
vecN< 3, float > vec3
Definition: gl_vec.hh:151
mat4 rotateX(float angle)
Definition: gl_transform.hh:93
vecN< 2, int > ivec2
Definition: gl_vec.hh:153
vecN< 2, float > vec2
Definition: gl_vec.hh:150
matMxN< 3, 3, float > mat3
Definition: gl_mat.hh:122
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:267
std::optional< Context > context
Definition: GLContext.cc:10
constexpr T radians(T d)
Definition: gl_vec.hh:171
constexpr mat4 frustum(float left, float right, float bottom, float top, float nearVal, float farVal)
vecN< N, T > normalize(const vecN< N, T > &x)
Definition: gl_vec.hh:348
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:285
constexpr vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
Definition: gl_vec.hh:294
constexpr mat4 translate(const vec3 &xyz)
Definition: gl_transform.hh:36
constexpr mat4 scale(const vec3 &xyz)
Definition: gl_transform.hh:19
void format(SectorAccessibleDisk &disk, MSXBootSectorType bootType)
Format the given disk (= a single partition).
std::unique_ptr< GLScaler > createScaler(RenderSettings &renderSettings)
Instantiates a Scaler.
This file implemented 3 utility functions:
Definition: Autofire.cc:9
auto copy(InputRange &&range, OutputIter out)
Definition: ranges.hh:232
auto find(InputRange &&range, const T &value)
Definition: ranges.hh:160
auto & global_urng()
Return reference to a (shared) global random number generator.
Definition: random.hh:8
float random_float(float from, float upto)
Return a random float in the range [from, upto) (note: half-open interval).
Definition: random.hh:50
ITER find_unguarded(ITER first, ITER last, const VAL &val, Proj proj={})
Faster alternative to 'find' when it's guaranteed that the value will be found (if not the behavior i...
Definition: stl.hh:63
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
Definition: xrange.hh:147
constexpr auto xrange(T e)
Definition: xrange.hh:132
constexpr auto end(const zstring_view &x)