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