From 0bb760260eb055f813247bf9ef06e372cac219d3 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 18 Jul 2018 16:42:11 +0200 Subject: Fix tiling of NPOT textures on GL/ES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The emulation was not working since the vertices are clamped before getting to the fragment shader. So instead just resize the brush if not supported. Change-Id: I856e47890cd3021874b77d869a6ff7162cadde10 Reviewed-by: Tor Arne Vestbø Reviewed-by: Laszlo Agocs --- src/gui/opengl/qopenglengineshadermanager.cpp | 7 ++----- src/gui/opengl/qopenglengineshadersource_p.h | 14 ++------------ src/gui/opengl/qopenglpaintengine.cpp | 24 ++++++++++++++++-------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp index f66193cb01..b7bac2728a 100644 --- a/src/gui/opengl/qopenglengineshadermanager.cpp +++ b/src/gui/opengl/qopenglengineshadermanager.cpp @@ -167,7 +167,7 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader_core; // Calls "customShader", which must be appended code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader_core; - code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop_core; + code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_core; code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader_core; code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader_core; code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader_core; @@ -212,10 +212,7 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader; code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader; - if (context->isOpenGLES()) - code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_ES; - else - code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop; + code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader; code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader; code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader; code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader; diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h index 5d9ee8110b..3ac599b6c2 100644 --- a/src/gui/opengl/qopenglengineshadersource_p.h +++ b/src/gui/opengl/qopenglengineshadersource_p.h @@ -303,17 +303,7 @@ static const char* const qopenglslPositionWithTextureBrushVertexShader = "\n\ static const char* const qopenglslAffinePositionWithTextureBrushVertexShader = qopenglslPositionWithTextureBrushVertexShader; -// OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead, -// we emulate GL_REPEAT by only taking the fractional part of the texture coords. -// TODO: Special case POT textures which don't need this emulation -static const char* const qopenglslTextureBrushSrcFragmentShader_ES = "\n\ - varying highp vec2 brushTextureCoords; \n\ - uniform sampler2D brushTexture; \n\ - lowp vec4 srcPixel() { \n\ - return texture2D(brushTexture, fract(brushTextureCoords)); \n\ - }\n"; - -static const char* const qopenglslTextureBrushSrcFragmentShader_desktop = "\n\ +static const char* const qopenglslTextureBrushSrcFragmentShader = "\n\ varying highp vec2 brushTextureCoords; \n\ uniform sampler2D brushTexture; \n\ lowp vec4 srcPixel() \n\ @@ -795,7 +785,7 @@ static const char* const qopenglslPositionWithTextureBrushVertexShader_core = "\ static const char* const qopenglslAffinePositionWithTextureBrushVertexShader_core = qopenglslPositionWithTextureBrushVertexShader_core; -static const char* const qopenglslTextureBrushSrcFragmentShader_desktop_core = "\n\ +static const char* const qopenglslTextureBrushSrcFragmentShader_core = "\n\ in vec2 brushTextureCoords; \n\ uniform sampler2D brushTexture; \n\ vec4 srcPixel() \n\ diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 5902713faa..aca57d664a 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -272,6 +272,12 @@ GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const ImageWithBindOptions &ima return QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, imageWithOptions.image, imageWithOptions.options); } +inline static bool isPowerOfTwo(int x) +{ + // Assumption: x >= 1 + return x == (x & -x); +} + void QOpenGL2PaintEngineExPrivate::updateBrushTexture() { Q_Q(QOpenGL2PaintEngineEx); @@ -304,16 +310,18 @@ void QOpenGL2PaintEngineExPrivate::updateBrushTexture() currentBrushImage = currentBrush.textureImage(); int max_texture_size = ctx->d_func()->maxTextureSize(); - if (currentBrushImage.width() > max_texture_size || currentBrushImage.height() > max_texture_size) - currentBrushImage = currentBrushImage.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); + QSize newSize = currentBrushImage.size(); + newSize = newSize.boundedTo(QSize(max_texture_size, max_texture_size)); + if (!QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat)) { + if (!isPowerOfTwo(newSize.width()) || !isPowerOfTwo(newSize.height())) { + newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1)); + newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1)); + } + } + if (currentBrushImage.size() != newSize) + currentBrushImage = currentBrushImage.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); GLuint wrapMode = GL_REPEAT; - if (QOpenGLContext::currentContext()->isOpenGLES()) { - // OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead, - // we emulate GL_REPEAT by only taking the fractional part of the texture coords - // in the qopenglslTextureBrushSrcFragmentShader program. - wrapMode = GL_CLAMP_TO_EDGE; - } updateTexture(QT_BRUSH_TEXTURE_UNIT, currentBrushImage, wrapMode, filterMode, ForceUpdate); } -- cgit v1.2.3