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 
17 using namespace gl;
18 
19 namespace openmsx {
20 
21 GLPostProcessor::GLPostProcessor(
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  , height(height_)
30 {
31  scaleAlgorithm = RenderSettings::NO_SCALER;
32 
33  frameCounter = 0;
34  noiseX = noiseY = 0.0f;
35  preCalcNoise(renderSettings.getNoise());
36  initBuffers();
37 
38  storedFrame = false;
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 
75 void 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 
87 void 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 
241 std::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 
265 void 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 
280  if (superImposeVideoFrame) {
281  int w = superImposeVideoFrame->getWidth();
282  int h = superImposeVideoFrame->getHeight();
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 
302 void 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 
358 void 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 
389 void 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 
437 void 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 
487 constexpr int GRID_SIZE = 16;
488 constexpr int GRID_SIZE1 = GRID_SIZE + 1;
489 constexpr int NUM_INDICES = (GRID_SIZE1 * 2 + 2) * GRID_SIZE - 2;
490 struct Vertex {
494 };
495 
496 void 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 
568 void 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:25
#define OPENGL_VERSION
Definition: GLUtil.hh:26
BaseSetting * setting
Definition: Interpreter.cc:27
int g
GLuint get() const
Definition: GLUtil.hh:464
GLsizei getHeight() const
Definition: GLUtil.hh:112
GLsizei getWidth() const
Definition: GLUtil.hh:111
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:373
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:82
Wrapper around an OpenGL vertex shader: a program executed on the GPU that computes per-vertex stuff.
Definition: GLUtil.hh:358
Represents the output window/screen of openMSX.
Definition: Display.hh:33
unsigned getWidth() const
Get the width of (all) lines in this frame.
Definition: FrameSource.hh:60
unsigned getHeight() const
Gets the number of lines in this frame.
Definition: FrameSource.hh:45
const Pixel * getLinePtr(int line, unsigned width, Pixel *buf) const
Gets a pointer to the pixels of the given line number.
Definition: FrameSource.hh:92
std::unique_ptr< RawFrame > rotateFrames(std::unique_ptr< RawFrame > finishedFrame, EmuTime::param time) override
Sets up the "abcdFrame" variables for a new frame.
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?
float getHorizontalStretch() const
FloatSetting & getNoiseSetting()
The amount of noise to add to the frame.
FloatSetting & getHorizontalStretchSetting()
Amount of horizontal stretch.
DisplayDeform getDisplayDeform()
Display deformation (normal, 3d) ATM this only works when using the SDLGL-PP renderer.
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:140
mat4 rotateX(float angle)
Definition: gl_transform.hh:93
vecN< 2, int > ivec2
Definition: gl_vec.hh:142
vecN< 2, float > vec2
Definition: gl_vec.hh:139
matMxN< 3, 3, float > mat3
Definition: gl_mat.hh:113
vecN< N, T > normalize(const vecN< N, T > &x)
Definition: gl_vec.hh:350
constexpr vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
Definition: gl_vec.hh:296
std::optional< Context > context
Definition: GLContext.cc:9
constexpr T radians(T d)
Definition: gl_vec.hh:160
constexpr mat4 frustum(float left, float right, float bottom, float top, float nearVal, float farVal)
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:118
constexpr int NUM_INDICES
auto find(InputRange &&range, const T &value)
Definition: ranges.hh:130
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:72
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
Definition: xrange.hh:170
constexpr auto xrange(T e)
Definition: xrange.hh:155
constexpr auto end(const zstring_view &x)
Definition: zstring_view.hh:84