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