summaryrefslogtreecommitdiffstats
path: root/src/opengl/gl2paintengineex
diff options
context:
space:
mode:
authorSamuel Rødal <sroedal@trolltech.com>2009-06-02 13:25:07 (GMT)
committerSamuel Rødal <sroedal@trolltech.com>2009-06-03 07:10:42 (GMT)
commitfa95af38594b09718b9eb9048b75b9628dc9a0da (patch)
tree81e0817af46beaaf9684127f32a3462faaa79c89 /src/opengl/gl2paintengineex
parentd37de8e085bdc3ee5d0185b403879bac485ef834 (diff)
downloadQt-fa95af38594b09718b9eb9048b75b9628dc9a0da.zip
Qt-fa95af38594b09718b9eb9048b75b9628dc9a0da.tar.gz
Qt-fa95af38594b09718b9eb9048b75b9628dc9a0da.tar.bz2
Implemented QGLTextureGlyphCache to avoid wasting glyph cache memory.
Now there's only a copy of the texture glyph cache in graphics memory, avoiding the system memory copy that we used earlier. In addition the texture will use the GL_ALPHA texture format when possible, making it consume less graphics memory as well. Reviewed-by: Tom
Diffstat (limited to 'src/opengl/gl2paintengineex')
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp29
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h4
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadersource_p.h9
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp198
4 files changed, 211 insertions, 29 deletions
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index f64af85..3159cbb 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -64,6 +64,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
maskType(NoMask),
useTextureCoords(false),
compositionMode(QPainter::CompositionMode_SourceOver),
+ blitShaderProg(0),
simpleShaderProg(0),
currentShaderProg(0)
{
@@ -83,6 +84,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
code[MainVertexShader] = qglslMainVertexShader;
code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader;
+ code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader;
code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader;
code[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader;
code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader;
@@ -160,6 +162,24 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
qCritical() << "Errors linking simple shader:"
<< simpleShaderProg->log();
}
+
+ // Compile the blit shader:
+ blitShaderProg = new QGLShaderProgram(ctx, this);
+ compileNamedShader(MainWithTexCoordsVertexShader, QGLShader::PartialVertexShader);
+ compileNamedShader(UntransformedPositionVertexShader, QGLShader::PartialVertexShader);
+ compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader);
+ compileNamedShader(ImageSrcFragmentShader, QGLShader::PartialFragmentShader);
+ blitShaderProg->addShader(compiledShaders[MainWithTexCoordsVertexShader]);
+ blitShaderProg->addShader(compiledShaders[UntransformedPositionVertexShader]);
+ blitShaderProg->addShader(compiledShaders[MainFragmentShader]);
+ blitShaderProg->addShader(compiledShaders[ImageSrcFragmentShader]);
+ blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+ blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ blitShaderProg->link();
+ if (!blitShaderProg->isLinked()) {
+ qCritical() << "Errors linking blit shader:"
+ << blitShaderProg->log();
+ }
}
QGLEngineShaderManager::~QGLEngineShaderManager()
@@ -176,6 +196,11 @@ void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform &transfo
Q_UNUSED(transform); // Currently ignored
}
+void QGLEngineShaderManager::setDirty()
+{
+ shaderProgNeedsChanging = true;
+}
+
void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style)
{
srcPixelType = style;
@@ -222,6 +247,10 @@ QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
return simpleShaderProg;
}
+QGLShaderProgram* QGLEngineShaderManager::blitProgram()
+{
+ return blitShaderProg;
+}
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index b8b2745..9bc81ef 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -279,15 +279,18 @@ public:
void setMaskType(MaskType);
void setCompositionMode(QPainter::CompositionMode);
+ void setDirty(); // someone has manually changed the current shader program
bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
+ QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
enum ShaderName {
MainVertexShader,
MainWithTexCoordsVertexShader,
+ UntransformedPositionVertexShader,
PositionOnlyVertexShader,
PositionWithPatternBrushVertexShader,
PositionWithLinearGradientBrushVertexShader,
@@ -365,6 +368,7 @@ private:
bool useTextureCoords;
QPainter::CompositionMode compositionMode;
+ QGLShaderProgram* blitShaderProg;
QGLShaderProgram* simpleShaderProg;
QGLShaderProgram* currentShaderProg;
diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
index fdbba72..920d0bc 100644
--- a/src/opengl/gl2paintengineex/qglengineshadersource_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
@@ -89,6 +89,12 @@ static const char* const qglslPositionOnlyVertexShader = "\
gl_Position = pmvMatrix * vertexCoordsArray;\
}";
+static const char* const qglslUntransformedPositionVertexShader = "\
+ attribute highp vec4 vertexCoordsArray;\
+ void setPosition(void)\
+ {\
+ gl_Position = vertexCoordsArray;\
+ }";
// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125
static const char* const qglslPositionWithPatternBrushVertexShader = "\
@@ -354,7 +360,7 @@ static const char* const qglslMaskFragmentShader = "\
lowp vec4 applyMask(lowp vec4 src) \
{\
lowp vec4 mask = texture2D(maskTexture, textureCoords); \
- return src * mask.r; \
+ return src * mask.a; \
}";
/*
@@ -375,7 +381,6 @@ static const char* const qglslMaskFragmentShader = "\
ExclusionCompositionModeFragmentShader,
*/
-
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 40f3a8d..868adcf 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -79,18 +79,165 @@
#include "qglengineshadermanager_p.h"
#include "qgl2pexvertexarray_p.h"
-
#include <QDebug>
QT_BEGIN_NAMESPACE
-extern QImage qt_imageForBrush(int brushStyle, bool invert);
-
static const GLuint QT_BRUSH_TEXTURE_UNIT = 0;
static const GLuint QT_IMAGE_TEXTURE_UNIT = 0; //Can be the same as brush texture unit
static const GLuint QT_MASK_TEXTURE_UNIT = 1;
static const GLuint QT_BACKGROUND_TEXTURE_UNIT = 2;
+class QGLTextureGlyphCache : public QTextureGlyphCache
+{
+public:
+ QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
+ ~QGLTextureGlyphCache();
+
+ virtual void createTextureData(int width, int height);
+ virtual void resizeTextureData(int width, int height);
+ virtual void fillTexture(const Coord &c, glyph_t glyph);
+
+ inline GLuint texture() const { return m_texture; }
+
+ inline int width() const { return m_width; }
+ inline int height() const { return m_height; }
+
+ inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
+
+private:
+ QGLContext *ctx;
+
+ QGL2PaintEngineExPrivate *pex;
+
+ GLuint m_texture;
+ GLuint m_fbo;
+
+ int m_width;
+ int m_height;
+
+ QGLShaderProgram *m_program;
+};
+
+QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
+ : QTextureGlyphCache(type, matrix)
+ , ctx(context)
+ , m_width(0)
+ , m_height(0)
+{
+ glGenFramebuffers(1, &m_fbo);
+}
+
+QGLTextureGlyphCache::~QGLTextureGlyphCache()
+{
+ glDeleteFramebuffers(1, &m_fbo);
+
+ if (m_width || m_height)
+ glDeleteTextures(1, &m_texture);
+}
+
+void QGLTextureGlyphCache::createTextureData(int width, int height)
+{
+ glGenTextures(1, &m_texture);
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+
+ m_width = width;
+ m_height = height;
+
+ QVarLengthArray<uchar> data(width * height);
+ for (int i = 0; i < width * height; ++i)
+ data[i] = 0;
+
+ if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
+ else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+}
+
+void QGLTextureGlyphCache::resizeTextureData(int width, int height)
+{
+ // ### the QTextureGlyphCache API needs to be reworked to allow
+ // ### resizeTextureData to fail
+
+ int oldWidth = m_width;
+ int oldHeight = m_height;
+
+ GLuint oldTexture = m_texture;
+ createTextureData(width, height);
+
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
+
+ GLuint colorBuffer;
+ glGenRenderbuffers(1, &colorBuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER_EXT, colorBuffer);
+ glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA, oldWidth, oldHeight);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, colorBuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
+
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, oldTexture);
+
+ pex->transferMode(BrushDrawingMode);
+
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_DEPTH_TEST);
+
+ glViewport(0, 0, oldWidth, oldHeight);
+
+ float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 };
+ float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
+
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
+
+ pex->shaderManager->blitProgram()->enable();
+ pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
+ pex->shaderManager->setDirty();
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, 0);
+ glDeleteRenderbuffers(1, &colorBuffer);
+ glDeleteTextures(1, &oldTexture);
+
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
+
+ glViewport(0, 0, pex->width, pex->height);
+ pex->updateDepthClip();
+}
+
+void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
+{
+ QImage mask = textureMapForGlyph(glyph);
+
+ const uint maskWidth = mask.width();
+ const uint maskHeight = mask.height();
+
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ if (mask.format() == QImage::Format_RGB32) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, m_height - c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
+ } else {
+ mask = mask.convertToFormat(QImage::Format_Indexed8);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
+ }
+}
+
+extern QImage qt_imageForBrush(int brushStyle, bool invert);
+
////////////////////////////////// Private Methods //////////////////////////////////////////
QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
@@ -141,6 +288,7 @@ void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush)
void QGL2PaintEngineExPrivate::useSimpleShader()
{
shaderManager->simpleProgram()->enable();
+ shaderManager->setDirty();
if (matrixDirty)
updateMatrix();
@@ -905,8 +1053,6 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem
void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)
{
- transferMode(TextDrawingMode);
-
Q_Q(QGL2PaintEngineEx);
QOpenGL2PaintEngineState *s = q->state();
@@ -921,34 +1067,32 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte
? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
: QFontEngineGlyphCache::Raster_A8;
- GLenum maskFormat = GL_RGBA;
- if (glyphType == QFontEngineGlyphCache::Raster_A8) {
- shaderManager->setMaskType(QGLEngineShaderManager::PixelMask);
-// maskFormat = GL_ALPHA;
+ QGLTextureGlyphCache *cache =
+ (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, s->matrix);
+ if (!cache) {
+ cache = new QGLTextureGlyphCache(ctx, glyphType, s->matrix);
+ ti.fontEngine->setGlyphCache(ctx, cache);
}
+
+ cache->setPaintEnginePrivate(this);
+ cache->populate(ti, glyphs, positions);
+
+ if (cache->width() == 0 || cache->height() == 0)
+ return;
+
+ transferMode(TextDrawingMode);
+
+ if (glyphType == QFontEngineGlyphCache::Raster_A8)
+ shaderManager->setMaskType(QGLEngineShaderManager::PixelMask);
else if (glyphType == QFontEngineGlyphCache::Raster_RGBMask)
shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMask);
//### TODO: Gamma correction
shaderManager->setTextureCoordsEnabled(true);
-
- QImageTextureGlyphCache *cache =
- (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix);
- if (!cache) {
- cache = new QImageTextureGlyphCache(glyphType, s->matrix);
- ti.fontEngine->setGlyphCache(glyphType, cache);
- }
-
- cache->populate(ti, glyphs, positions);
-
- const QImage &image = cache->image();
int margin = cache->glyphMargin();
- if (image.isNull())
- return;
-
- GLfloat dx = 1.0 / image.width();
- GLfloat dy = 1.0 / image.height();
+ GLfloat dx = 1.0 / cache->width();
+ GLfloat dy = 1.0 / cache->height();
QGLPoint *oldVertexCoordinateDataPtr = vertexCoordinateArray.data();
QGLPoint *oldTextureCoordinateDataPtr = textureCoordinateArray.data();
@@ -962,11 +1106,11 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte
int y = positions[i].y.toInt() - c.baseLineY - margin;
vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
- textureCoordinateArray.addRect(QRectF(c.x*dx, 1 - c.y*dy, c.w * dx, -c.h * dy));
+ textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
}
glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
- ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
+ glBindTexture(GL_TEXTURE_2D, cache->texture());
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
QBrush pensBrush = q->state()->pen.brush();