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  edgeTexture.bind();
26  glTexImage2D(GL_TEXTURE_2D, // target
27  0, // level
28  GL_LUMINANCE16, // internal format
29  320, // width
30  240, // height
31  0, // border
32  GL_LUMINANCE, // format
33  GL_UNSIGNED_SHORT,// type
34  nullptr); // data
35  edgeBuffer.setImage(320, 240);
36 
37  auto context = systemFileContext();
38  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
39  string offsetName = "shaders/HQ_xLiteOffsets.dat";
40  for (int i = 0; i < 3; ++i) {
41  int n = i + 2;
42  offsetName[10] = char('0') + n;
43  File offsetFile(context.resolve(offsetName));
44  offsetTexture[i].bind();
45  glTexImage2D(GL_TEXTURE_2D, // target
46  0, // level
47  GL_LUMINANCE8_ALPHA8, // internal format
48  n * 64, // width
49  n * 64, // height
50  0, // border
51  GL_LUMINANCE_ALPHA, // format
52  GL_UNSIGNED_BYTE, // type
53  offsetFile.mmap().data());// data
54  }
55  glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // restore to default
56 }
57 
59  gl::ColorTexture& src, gl::ColorTexture* superImpose,
60  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
61  unsigned dstStartY, unsigned dstEndY, unsigned dstWidth,
62  unsigned logSrcHeight)
63 {
64  unsigned factorX = dstWidth / srcWidth; // 1 - 4
65  unsigned factorY = (dstEndY - dstStartY) / (srcEndY - srcStartY);
66 
67  if ((srcWidth == 320) && (factorX > 1) && (factorX == factorY)) {
68  setup(superImpose != nullptr);
69  src.setInterpolation(true);
70  glActiveTexture(GL_TEXTURE3);
71  offsetTexture[factorX - 2].bind();
72  glActiveTexture(GL_TEXTURE2);
73  edgeTexture.bind();
74  glActiveTexture(GL_TEXTURE0);
75  execute(src, superImpose,
76  srcStartY, srcEndY, srcWidth,
77  dstStartY, dstEndY, dstWidth,
78  logSrcHeight);
79  src.setInterpolation(false);
80  } else {
81  fallback.scaleImage(src, superImpose,
82  srcStartY, srcEndY, srcWidth,
83  dstStartY, dstEndY, dstWidth,
84  logSrcHeight);
85  }
86 }
87 
88 using Pixel = uint32_t;
90  unsigned srcStartY, unsigned srcEndY, unsigned lineWidth,
91  FrameSource& paintFrame)
92 {
93  if ((lineWidth != 320) || (srcEndY > 240)) return;
94 
95  uint32_t tmpBuf2[320 / 2]; // 2 x uint16_t
96  #ifndef NDEBUG
97  // Avoid UMR. In optimized mode we don't care.
98  memset(tmpBuf2, 0, sizeof(tmpBuf2));
99  #endif
100 
101  VLA_SSE_ALIGNED(Pixel, buf1_, lineWidth); auto* buf1 = buf1_;
102  VLA_SSE_ALIGNED(Pixel, buf2_, lineWidth); auto* buf2 = buf2_;
103  auto* curr = paintFrame.getLinePtr(srcStartY - 1, lineWidth, buf1);
104  auto* next = paintFrame.getLinePtr(srcStartY + 0, lineWidth, buf2);
105  calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
106 
107  edgeBuffer.bind();
108  if (auto* mapped = edgeBuffer.mapWrite()) {
109  for (unsigned y = srcStartY; y < srcEndY; ++y) {
110  curr = next;
111  std::swap(buf1, buf2);
112  next = paintFrame.getLinePtr(y + 1, lineWidth, buf2);
113  calcEdgesGL(curr, next, tmpBuf2, EdgeHQLite());
114  memcpy(mapped + 320 * y, tmpBuf2, 320 * sizeof(uint16_t));
115  }
116  edgeBuffer.unmap();
117 
118  edgeTexture.bind();
119  glTexSubImage2D(GL_TEXTURE_2D, // target
120  0, // level
121  0, // offset x
122  srcStartY, // offset y
123  lineWidth, // width
124  srcEndY - srcStartY, // height
125  GL_LUMINANCE, // format
126  GL_UNSIGNED_SHORT, // type
127  edgeBuffer.getOffset(0, srcStartY)); // data
128  }
129  edgeBuffer.unbind();
130 }
131 
132 } // namespace openmsx
T * mapWrite()
Maps the contents of this buffer into memory.
Definition: GLUtil.hh:315
void swap(optional< T > &x, optional< T > &y) noexcept(noexcept(x.swap(y)))
Definition: optional.hh:816
void setup(bool superImpose)
Definition: GLScaler.cc:39
FileContext systemFileContext()
Definition: FileContext.cc:148
uint32_t Pixel
Interface for getting lines from a video frame.
Definition: FrameSource.hh:14
void bind()
Makes this texture the active GL texture.
Definition: GLUtil.hh:77
void calcEdgesGL(const uint32_t *curr, const uint32_t *next, uint32_t *edges2, EdgeOp edgeOp)
Definition: HQCommon.hh:104
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
void unmap() const
Unmaps the contents of this buffer.
Definition: GLUtil.hh:326
std::unique_ptr< Context > context
Definition: GLContext.cc:9
GLHQLiteScaler(GLScaler &fallback)
void unbind() const
Unbind this buffer.
Definition: GLUtil.hh:294
void uploadBlock(unsigned srcStartY, unsigned srcEndY, unsigned lineWidth, FrameSource &paintFrame) override
void setImage(GLuint width, GLuint height)
Sets the image for this buffer.
Definition: GLUtil.hh:268
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
void setInterpolation(bool interpolation)
Enable/disable bilinear interpolation for this texture.
Definition: GLUtil.cc:54
Abstract base class for OpenGL scalers.
Definition: GLScaler.hh:13
void bind() const
Bind this PixelBuffer.
Definition: GLUtil.hh:286
gl::ShaderProgram program[2]
Definition: GLScaler.hh:77
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 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...
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...
T * getOffset(GLuint x, GLuint y)
Gets a pointer relative to the start of this buffer.
Definition: GLUtil.hh:302
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition: vla.hh:44