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 "vla.hh"
8 #include <cstring>
9 #include <utility>
10 
11 using std::string;
12 
13 namespace openmsx {
14 
16  : GLScaler("hq")
17  , fallback(fallback_)
18 {
19  for (auto& p : program) {
20  p.activate();
21  glUniform1i(p.getUniformLocation("edgeTex"), 2);
22  glUniform1i(p.getUniformLocation("offsetTex"), 3);
23  glUniform1i(p.getUniformLocation("weightTex"), 4);
24  }
25 
26  // GL_LUMINANCE_ALPHA is no longer supported in newer openGL versions
27  auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
28  edgeTexture.bind();
29  glTexImage2D(GL_TEXTURE_2D, // target
30  0, // level
31  format, // internal format
32  320, // width
33  240, // height
34  0, // border
35  format, // format
36  GL_UNSIGNED_BYTE, // type
37  nullptr); // data
38 #if OPENGL_VERSION >= OPENGL_3_3
39  GLint swizzleMask[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
40  glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
41 #endif
42  edgeBuffer.setImage(320, 240);
43 
44  auto context = systemFileContext();
45  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
46  string offsetsName = "shaders/HQ_xOffsets.dat";
47  string weightsName = "shaders/HQ_xWeights.dat";
48  for (auto i : xrange(3)) {
49  int n = i + 2;
50  offsetsName[10] = char('0') + n;
51  File offsetsFile(context.resolve(offsetsName));
52  offsetTexture[i].bind();
53  glTexImage2D(GL_TEXTURE_2D, // target
54  0, // level
55  GL_RGBA, // internal format
56  n * 64, // width
57  n * 64, // height
58  0, // border
59  GL_RGBA, // format
60  GL_UNSIGNED_BYTE, // type
61  offsetsFile.mmap().data());// data
62 
63  weightsName[10] = char('0') + n;
64  File weightsFile(context.resolve(weightsName));
65  weightTexture[i].bind();
66  glTexImage2D(GL_TEXTURE_2D, // target
67  0, // level
68  GL_RGB, // internal format
69  n * 64, // width
70  n * 64, // height
71  0, // border
72  GL_RGB, // format
73  GL_UNSIGNED_BYTE, // type
74  weightsFile.mmap().data());// data
75  }
76  glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
77 }
78 
80  gl::ColorTexture& src, gl::ColorTexture* superImpose,
81  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
82  unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
83  unsigned logSrcHeight)
84 {
85  unsigned factorX = dstWidth / srcWidth; // 1 - 4
86  unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY);
87 
88  if ((srcWidth == 320) && (factorX > 1) && (factorX == factorY)) {
89  assert(src.getHeight() == 2 * 240);
90  setup(superImpose != nullptr);
91  glActiveTexture(GL_TEXTURE4);
92  weightTexture[factorX - 2].bind();
93  glActiveTexture(GL_TEXTURE3);
94  offsetTexture[factorX - 2].bind();
95  glActiveTexture(GL_TEXTURE2);
96  edgeTexture.bind();
97  glActiveTexture(GL_TEXTURE0);
98  execute(src, superImpose,
99  srcStartY, srcEndY, srcWidth,
100  dstStartY, dstEndY, dstWidth,
101  logSrcHeight);
102  } else {
103  fallback.scaleImage(src, superImpose,
104  srcStartY, srcEndY, srcWidth,
105  dstStartY, dstEndY, dstWidth,
106  logSrcHeight);
107  }
108 }
109 
110 using Pixel = uint32_t;
112  unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
113  FrameSource& paintFrame)
114 {
115  if ((lineWidth != 320) || (srcEndY > 240)) return;
116 
117  Endian::L32 tmpBuf2[320 / 2]; // 2 x uint16_t
118  #ifndef NDEBUG
119  // Avoid UMR. In optimized mode we don't care.
120  memset(tmpBuf2, 0, sizeof(tmpBuf2));
121  #endif
122 
123  VLA_SSE_ALIGNED(Pixel, buf1_, lineWidth); auto* buf1 = buf1_;
124  VLA_SSE_ALIGNED(Pixel, buf2_, lineWidth); auto* buf2 = buf2_;
125  const auto* curr = paintFrame.getLinePtr(srcStartY - 1, lineWidth, buf1);
126  const auto* next = paintFrame.getLinePtr(srcStartY + 0, lineWidth, buf2);
127  EdgeHQ edgeOp(0, 8, 16);
128  calcEdgesGL(curr, next, tmpBuf2, edgeOp);
129 
130  edgeBuffer.bind();
131  if (auto* mapped = edgeBuffer.mapWrite()) {
132  for (auto y : xrange(srcStartY, srcEndY)) {
133  curr = next;
134  std::swap(buf1, buf2);
135  next = paintFrame.getLinePtr(y + 1, lineWidth, buf2);
136  calcEdgesGL(curr, next, tmpBuf2, edgeOp);
137  memcpy(mapped + 320 * y, tmpBuf2, 320 * sizeof(uint16_t));
138  }
139  edgeBuffer.unmap();
140 
141  auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
142  edgeTexture.bind();
143  glTexSubImage2D(GL_TEXTURE_2D, // target
144  0, // level
145  0, // offset x
146  srcStartY, // offset y
147  lineWidth, // width
148  srcEndY - srcStartY, // height
149  format, // format
150  GL_UNSIGNED_BYTE, // type
151  edgeBuffer.getOffset(0, srcStartY)); // data
152  }
153  edgeBuffer.unbind();
154 }
155 
156 } // namespace openmsx
#define OPENGL_3_3
Definition: GLUtil.hh:26
#define OPENGL_VERSION
Definition: GLUtil.hh:27
GLsizei getHeight() const
Definition: GLUtil.hh:113
void unmap() const
Unmaps the contents of this buffer.
Definition: GLUtil.hh:312
void unbind() const
Unbind this buffer.
Definition: GLUtil.hh:280
void setImage(GLuint width, GLuint height)
Sets the image for this buffer.
Definition: GLUtil.hh:254
T * getOffset(GLuint x, GLuint y)
Gets a pointer relative to the start of this buffer.
Definition: GLUtil.hh:288
void bind() const
Bind this PixelBuffer.
Definition: GLUtil.hh:272
T * mapWrite()
Maps the contents of this buffer into memory.
Definition: GLUtil.hh:301
void bind()
Makes this texture the active GL texture.
Definition: GLUtil.hh:83
span< const uint8_t > mmap()
Map file in memory.
Definition: File.cc:103
Interface for getting lines from a video frame.
Definition: FrameSource.hh:15
const Pixel * getLinePtr(int line, unsigned width, Pixel *buf) const
Gets a pointer to the pixels of the given line number.
Definition: FrameSource.hh:91
void uploadBlock(unsigned srcStartY, unsigned srcEndY, unsigned lineWidth, FrameSource &paintFrame) override
Definition: GLHQScaler.cc:111
GLHQScaler(GLScaler &fallback)
Definition: GLHQScaler.cc:15
void scaleImage(gl::ColorTexture &src, gl::ColorTexture *superImpose, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth, unsigned logSrcHeight) override
Scales the image in the given area, which must consist of lines which are all equally wide.
Definition: GLHQScaler.cc:79
Abstract base class for OpenGL scalers.
Definition: GLScaler.hh:14
void setup(bool superImpose)
Definition: GLScaler.cc:40
void execute(gl::ColorTexture &src, gl::ColorTexture *superImpose, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, unsigned dstStartY, unsigned dstEndY, unsigned dstWidth, unsigned logSrcHeight, bool textureFromZero=false)
Helper method to draw a rectangle with multiple texture coordinates.
Definition: GLScaler.cc:46
virtual void scaleImage(gl::ColorTexture &src, gl::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.
gl::ShaderProgram program[2]
Definition: GLScaler.hh:78
constexpr pointer data() const noexcept
Definition: span.hh:323
std::unique_ptr< Context > context
Definition: GLContext.cc:9
void format(SectorAccessibleDisk &disk, bool dos1)
Format the given disk (= a single partition).
This file implemented 3 utility functions:
Definition: Autofire.cc:5
const FileContext & systemFileContext()
Definition: FileContext.cc:156
uint32_t Pixel
void calcEdgesGL(const uint32_t *curr, const uint32_t *next, Endian::L32 *edges2, EdgeOp edgeOp)
Definition: HQCommon.hh:106
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition: vla.hh:44
constexpr auto xrange(T e)
Definition: xrange.hh:155