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