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 "openmsx.hh"
9 #include "memory.hh"
10 #include <cstring>
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 #ifdef GL_VERSION_2_0
27  if (GLEW_VERSION_2_0) {
28  scalerProgram[i].activate();
29  glUniform1i(scalerProgram[i].getUniformLocation("colorTex"), 0);
30  if (i == 1) {
31  glUniform1i(scalerProgram[i].getUniformLocation("videoTex"), 1);
32  }
33  glUniform1i(scalerProgram[i].getUniformLocation("edgeTex"), 2);
34  glUniform1i(scalerProgram[i].getUniformLocation("offsetTex"), 3);
35  glUniform1i(scalerProgram[i].getUniformLocation("weightTex"), 4);
36  glUniform2f(scalerProgram[i].getUniformLocation("texSize"),
37  320.0f, 2 * 240.0f);
38  }
39 #endif
40  }
41 
42  edgeTexture.bind();
43  edgeTexture.setWrapMode(false);
44  glTexImage2D(GL_TEXTURE_2D, // target
45  0, // level
46  GL_LUMINANCE16, // internal format
47  320, // width
48  240, // height
49  0, // border
50  GL_LUMINANCE, // format
51  GL_UNSIGNED_SHORT,// type
52  nullptr); // data
53  edgeBuffer.setImage(320, 240);
54 
55  SystemFileContext context;
56  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
57  for (int i = 0; i < 3; ++i) {
58  int n = i + 2;
59  string offsetsName = StringOp::Builder() <<
60  "shaders/HQ" << n << "xOffsets.dat";
61  File offsetsFile(context.resolve(offsetsName));
62  offsetTexture[i].setWrapMode(false);
63  offsetTexture[i].bind();
64  size_t size; // dummy
65  glTexImage2D(GL_TEXTURE_2D, // target
66  0, // level
67  GL_RGBA8, // internal format
68  n * 64, // width
69  n * 64, // height
70  0, // border
71  GL_RGBA, // format
72  GL_UNSIGNED_BYTE, // type
73  offsetsFile.mmap(size));// data
74 
75  string weightsName = StringOp::Builder() <<
76  "shaders/HQ" << n << "xWeights.dat";
77  File weightsFile(context.resolve(weightsName));
78  weightTexture[i].setWrapMode(false);
79  weightTexture[i].bind();
80  glTexImage2D(GL_TEXTURE_2D, // target
81  0, // level
82  GL_RGB8, // internal format
83  n * 64, // width
84  n * 64, // height
85  0, // border
86  GL_RGB, // format
87  GL_UNSIGNED_BYTE, // type
88  weightsFile.mmap(size));// data
89  }
90  glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
91 }
92 
94  ColorTexture& src, ColorTexture* superImpose,
95  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
96  unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
97  unsigned logSrcHeight)
98 {
99  unsigned factorX = dstWidth / srcWidth; // 1 - 4
100  unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY);
101 
102  auto& prog = scalerProgram[superImpose ? 1 : 0];
103  if ((srcWidth == 320) && (factorX > 1) && (factorX == factorY)) {
104  assert(src.getHeight() == 2 * 240);
105  glActiveTexture(GL_TEXTURE4);
106  weightTexture[factorX - 2].bind();
107  glActiveTexture(GL_TEXTURE3);
108  offsetTexture[factorX - 2].bind();
109  glActiveTexture(GL_TEXTURE2);
110  edgeTexture.bind();
111  if (superImpose) {
112  glActiveTexture(GL_TEXTURE1);
113  superImpose->bind();
114  }
115  glActiveTexture(GL_TEXTURE0);
116  prog.activate();
117  drawMultiTex(src, srcStartY, srcEndY, src.getHeight(), logSrcHeight,
118  dstStartY, dstEndY, dstWidth);
119  } else {
120  GLScaler::scaleImage(src, superImpose,
121  srcStartY, srcEndY, srcWidth,
122  dstStartY, dstEndY, dstWidth,
123  logSrcHeight);
124  }
125 }
126 
127 typedef unsigned Pixel;
129  unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
130  FrameSource& paintFrame)
131 {
132  if (lineWidth != 320) return;
133 
134  unsigned tmpBuf2[320 / 2];
135  #ifndef NDEBUG
136  // Avoid UMR. In optimized mode we don't care.
137  memset(tmpBuf2, 0, sizeof(tmpBuf2));
138  #endif
139 
140  EdgeHQ edgeOp(0, 8, 16);
141  const Pixel* curr = paintFrame.getLinePtr<Pixel>(srcStartY - 1, lineWidth);
142  const Pixel* next = paintFrame.getLinePtr<Pixel>(srcStartY + 0, lineWidth);
143  calcEdgesGL(curr, next, tmpBuf2, edgeOp);
144 
145  edgeBuffer.bind();
146  if (unsigned short* mapped = edgeBuffer.mapWrite()) {
147  for (unsigned y = srcStartY; y < srcEndY; ++y) {
148  curr = next;
149  next = paintFrame.getLinePtr<Pixel>(y + 1, lineWidth);
150  calcEdgesGL(curr, next, tmpBuf2, edgeOp);
151  memcpy(mapped + 320 * y, tmpBuf2, 320 * sizeof(unsigned short));
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