openMSX
GLHQScaler.cc
Go to the documentation of this file.
1 #include "GLHQScaler.hh"
2 #include "GLUtil.hh"
3 #include "HQCommon.hh"
4 #include "FrameSource.hh"
5 #include "FileContext.hh"
6 #include "File.hh"
7 #include "StringOp.hh"
8 #include "vla.hh"
9 #include <cstring>
10 #include <algorithm>
11 
12 using std::string;
13 
14 namespace openmsx {
15 
17 {
18  for (int i = 0; i < 2; ++i) {
19  string header = string("#define SUPERIMPOSE ")
20  + char('0' + i) + '\n';
21  VertexShader vertexShader (header, "hq.vert");
22  FragmentShader fragmentShader(header, "hq.frag");
23  scalerProgram[i].attach(vertexShader);
24  scalerProgram[i].attach(fragmentShader);
25  scalerProgram[i].link();
26 
27  scalerProgram[i].activate();
28  glUniform1i(scalerProgram[i].getUniformLocation("colorTex"), 0);
29  if (i == 1) {
30  glUniform1i(scalerProgram[i].getUniformLocation("videoTex"), 1);
31  }
32  glUniform1i(scalerProgram[i].getUniformLocation("edgeTex"), 2);
33  glUniform1i(scalerProgram[i].getUniformLocation("offsetTex"), 3);
34  glUniform1i(scalerProgram[i].getUniformLocation("weightTex"), 4);
35  glUniform2f(scalerProgram[i].getUniformLocation("texSize"),
36  320.0f, 2 * 240.0f);
37  }
38 
39  edgeTexture.bind();
40  edgeTexture.setWrapMode(false);
41  glTexImage2D(GL_TEXTURE_2D, // target
42  0, // level
43  GL_LUMINANCE16, // internal format
44  320, // width
45  240, // height
46  0, // border
47  GL_LUMINANCE, // format
48  GL_UNSIGNED_SHORT,// type
49  nullptr); // data
50  edgeBuffer.setImage(320, 240);
51 
52  SystemFileContext context;
53  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
54  for (int i = 0; i < 3; ++i) {
55  int n = i + 2;
56  string offsetsName = StringOp::Builder() <<
57  "shaders/HQ" << n << "xOffsets.dat";
58  File offsetsFile(context.resolve(offsetsName));
59  offsetTexture[i].setWrapMode(false);
60  offsetTexture[i].bind();
61  size_t size; // dummy
62  glTexImage2D(GL_TEXTURE_2D, // target
63  0, // level
64  GL_RGBA8, // internal format
65  n * 64, // width
66  n * 64, // height
67  0, // border
68  GL_RGBA, // format
69  GL_UNSIGNED_BYTE, // type
70  offsetsFile.mmap(size));// data
71 
72  string weightsName = StringOp::Builder() <<
73  "shaders/HQ" << n << "xWeights.dat";
74  File weightsFile(context.resolve(weightsName));
75  weightTexture[i].setWrapMode(false);
76  weightTexture[i].bind();
77  glTexImage2D(GL_TEXTURE_2D, // target
78  0, // level
79  GL_RGB8, // internal format
80  n * 64, // width
81  n * 64, // height
82  0, // border
83  GL_RGB, // format
84  GL_UNSIGNED_BYTE, // type
85  weightsFile.mmap(size));// data
86  }
87  glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
88 }
89 
91  ColorTexture& src, ColorTexture* superImpose,
92  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
93  unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
94  unsigned logSrcHeight)
95 {
96  unsigned factorX = dstWidth / srcWidth; // 1 - 4
97  unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY);
98 
99  auto& prog = scalerProgram[superImpose ? 1 : 0];
100  if ((srcWidth == 320) && (factorX > 1) && (factorX == factorY)) {
101  assert(src.getHeight() == 2 * 240);
102  glActiveTexture(GL_TEXTURE4);
103  weightTexture[factorX - 2].bind();
104  glActiveTexture(GL_TEXTURE3);
105  offsetTexture[factorX - 2].bind();
106  glActiveTexture(GL_TEXTURE2);
107  edgeTexture.bind();
108  if (superImpose) {
109  glActiveTexture(GL_TEXTURE1);
110  superImpose->bind();
111  }
112  glActiveTexture(GL_TEXTURE0);
113  prog.activate();
114  drawMultiTex(src, srcStartY, srcEndY, src.getHeight(), logSrcHeight,
115  dstStartY, dstEndY, dstWidth);
116  } else {
117  GLScaler::scaleImage(src, superImpose,
118  srcStartY, srcEndY, srcWidth,
119  dstStartY, dstEndY, dstWidth,
120  logSrcHeight);
121  }
122 }
123 
124 typedef unsigned Pixel;
126  unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
127  FrameSource& paintFrame)
128 {
129  if (lineWidth != 320) return;
130 
131  uint32_t tmpBuf2[320 / 2]; // 2 x uint16_t
132  #ifndef NDEBUG
133  // Avoid UMR. In optimized mode we don't care.
134  memset(tmpBuf2, 0, sizeof(tmpBuf2));
135  #endif
136 
137  VLA_SSE_ALIGNED(Pixel, buf1_, lineWidth); auto* buf1 = buf1_;
138  VLA_SSE_ALIGNED(Pixel, buf2_, lineWidth); auto* buf2 = buf2_;
139  auto* curr = paintFrame.getLinePtr(srcStartY - 1, lineWidth, buf1);
140  auto* next = paintFrame.getLinePtr(srcStartY + 0, lineWidth, buf2);
141  EdgeHQ edgeOp(0, 8, 16);
142  calcEdgesGL(curr, next, tmpBuf2, edgeOp);
143 
144  edgeBuffer.bind();
145  if (auto* mapped = edgeBuffer.mapWrite()) {
146  for (unsigned y = srcStartY; y < srcEndY; ++y) {
147  curr = next;
148  std::swap(buf1, buf2);
149  next = paintFrame.getLinePtr(y + 1, lineWidth, buf2);
150  calcEdgesGL(curr, next, tmpBuf2, edgeOp);
151  memcpy(mapped + 320 * y, tmpBuf2, 320 * sizeof(uint16_t));
152  }
153  edgeBuffer.unmap();
154 
155  edgeTexture.bind();
156  glTexSubImage2D(GL_TEXTURE_2D, // target
157  0, // level
158  0, // offset x
159  srcStartY, // offset y
160  lineWidth, // width
161  srcEndY - srcStartY, // height
162  GL_LUMINANCE, // format
163  GL_UNSIGNED_SHORT, // type
164  edgeBuffer.getOffset(0, srcStartY)); // data
165  }
166  edgeBuffer.unbind();
167 }
168 
169 } // namespace openmsx
Wrapper around an OpenGL fragment shader: a program executed on the GPU that computes the colors of p...
Definition: GLUtil.hh:426
void unbind() const
Unbind this buffer.
Definition: GLUtil.hh:340
Wrapper around an OpenGL vertex shader: a program executed on the GPU that computes per-vertex stuff...
Definition: GLUtil.hh:413
virtual void scaleImage(ColorTexture &src, ColorTexture *superImpose, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth, unsigned logSrcHeight)=0
Scales the image in the given area, which must consist of lines which are all equally wide...
Definition: GLScaler.cc:29
void drawMultiTex(ColorTexture &src, unsigned srcStartY, unsigned srcEndY, float physSrcHeight, float logSrcHeight, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth, bool textureFromZero=false)
Helper method to draw a rectangle with multiple texture coordinates.
Definition: GLScaler.cc:48
T * getOffset(GLuint x, GLuint y)
Gets a pointer relative to the start of this buffer.
Definition: GLUtil.hh:348
void activate() const
Makes this program the active shader program.
Definition: GLUtil.cc:383
virtual void uploadBlock(unsigned srcStartY, unsigned srcEndY, unsigned lineWidth, FrameSource &paintFrame)
Definition: GLHQScaler.cc:125
void link()
Links all attached shaders together into one program.
Definition: GLUtil.cc:346
Interface for getting lines from a video frame.
Definition: FrameSource.hh:15
void calcEdgesGL(const uint32_t *curr, const uint32_t *next, uint32_t *edges2, EdgeOp edgeOp)
Definition: HQCommon.hh:104
void bind()
Makes this texture the active GL texture.
Definition: GLUtil.hh:61
void setImage(GLuint width, GLuint height)
Sets the image for this buffer.
Definition: GLUtil.hh:314
const std::string resolve(string_ref filename) const
Definition: FileContext.cc:73
unsigned Pixel
GLsizei getHeight() const
Definition: GLUtil.hh:119
void bind() const
Bind this PixelBuffer.
Definition: GLUtil.hh:332
void unmap() const
Unmaps the contents of this buffer.
Definition: GLUtil.hh:372
T * mapWrite()
Maps the contents of this buffer into memory.
Definition: GLUtil.hh:361
void attach(const Shader &shader)
Adds a given shader to this program.
Definition: GLUtil.cc:334
const Pixel * getLinePtr(int line, unsigned width, Pixel *buf) const
Gets a pointer to the pixels of the given line number.
Definition: FrameSource.hh:95
size_t size() const
void setWrapMode(bool wrap)
Definition: GLUtil.cc:63
virtual void scaleImage(ColorTexture &src, ColorTexture *superImpose, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth, unsigned logSrcHeight)
Scales the image in the given area, which must consist of lines which are all equally wide...
Definition: GLHQScaler.cc:90
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition: vla.hh:44