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