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