openMSX
GLHQLiteScaler.cc
Go to the documentation of this file.
1 #include "GLHQLiteScaler.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("hqlite")
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  }
22 
23  // GL_LUMINANCE_ALPHA is no longer supported in newer openGL versions
24  auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
25  edgeTexture.bind();
26  glTexImage2D(GL_TEXTURE_2D, // target
27  0, // level
28  format, // internal format
29  320, // width
30  240, // height
31  0, // border
32  format, // format
33  GL_UNSIGNED_BYTE, // type
34  nullptr); // data
35 #if OPENGL_VERSION >= OPENGL_3_3
36  GLint swizzleMask1[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
37  glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask1);
38 #endif
39  edgeBuffer.setImage(320, 240);
40 
41  auto context = systemFileContext();
42  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
43  std::string offsetName = "shaders/HQ_xLiteOffsets.dat";
44  for (auto i : xrange(3)) {
45  int n = i + 2;
46  offsetName[10] = char('0') + n;
47  File offsetFile(context.resolve(offsetName));
48  offsetTexture[i].bind();
49  glTexImage2D(GL_TEXTURE_2D, // target
50  0, // level
51  format, // internal format
52  n * 64, // width
53  n * 64, // height
54  0, // border
55  format, // format
56  GL_UNSIGNED_BYTE, // type
57  offsetFile.mmap().data());// data
58 #if OPENGL_VERSION >= OPENGL_3_3
59  GLint swizzleMask2[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
60  glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask2);
61 #endif
62  }
63  glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
64 }
65 
67  gl::ColorTexture& src, gl::ColorTexture* superImpose,
68  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
69  unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
70  unsigned logSrcHeight)
71 {
72  unsigned factorX = dstWidth / srcWidth; // 1 - 4
73  unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY);
74 
75  if ((srcWidth == 320) && (factorX > 1) && (factorX == factorY)) {
76  setup(superImpose != nullptr);
77  src.setInterpolation(true);
78  glActiveTexture(GL_TEXTURE3);
79  offsetTexture[factorX - 2].bind();
80  glActiveTexture(GL_TEXTURE2);
81  edgeTexture.bind();
82  glActiveTexture(GL_TEXTURE0);
83  execute(src, superImpose,
84  srcStartY, srcEndY, srcWidth,
85  dstStartY, dstEndY, dstWidth,
86  logSrcHeight);
87  src.setInterpolation(false);
88  } else {
89  fallback.scaleImage(src, superImpose,
90  srcStartY, srcEndY, srcWidth,
91  dstStartY, dstEndY, dstWidth,
92  logSrcHeight);
93  }
94 }
95 
96 using Pixel = uint32_t;
98  unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
99  FrameSource& paintFrame)
100 {
101  if ((lineWidth != 320) || (srcEndY > 240)) return;
102 
103  Endian::L32 tmpBuf2[320 / 2]; // 2 x uint16_t
104  #ifndef NDEBUG
105  // Avoid UMR. In optimized mode we don't care.
106  memset(tmpBuf2, 0, sizeof(tmpBuf2));
107  #endif
108 
109  VLA_SSE_ALIGNED(Pixel, buf1_, lineWidth); auto* buf1 = buf1_;
110  VLA_SSE_ALIGNED(Pixel, buf2_, lineWidth); auto* buf2 = buf2_;
111  const auto* curr = paintFrame.getLinePtr(srcStartY - 1, lineWidth, buf1);
112  const auto* next = paintFrame.getLinePtr(srcStartY + 0, lineWidth, buf2);
113  calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
114 
115  edgeBuffer.bind();
116  if (auto* mapped = edgeBuffer.mapWrite()) {
117  for (auto y : xrange(srcStartY, srcEndY)) {
118  curr = next;
119  std::swap(buf1, buf2);
120  next = paintFrame.getLinePtr(y + 1, lineWidth, buf2);
121  calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
122  memcpy(mapped + 320 * y, tmpBuf2, 320 * sizeof(uint16_t));
123  }
124  edgeBuffer.unmap();
125 
126  auto format = (OPENGL_VERSION >= OPENGL_3_3) ? GL_RG : GL_LUMINANCE_ALPHA;
127  edgeTexture.bind();
128  glTexSubImage2D(GL_TEXTURE_2D, // target
129  0, // level
130  0, // offset x
131  srcStartY, // offset y
132  lineWidth, // width
133  srcEndY - srcStartY, // height
134  format, // format
135  GL_UNSIGNED_BYTE, // type
136  edgeBuffer.getOffset(0, srcStartY)); // data
137  }
138  edgeBuffer.unbind();
139 }
140 
141 } // namespace openmsx
#define OPENGL_3_3
Definition: GLUtil.hh:25
#define OPENGL_VERSION
Definition: GLUtil.hh:26
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 setInterpolation(bool interpolation)
Enable/disable bilinear interpolation for this texture.
Definition: GLUtil.cc:47
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
GLHQLiteScaler(GLScaler &fallback)
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.
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