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