📄 qpaintengine_opengl.cpp
字号:
public: QGLOffscreen() : QObject(), offscreen(0), ctx(0), mask_dim(0), activated(false), bound(false) { connect(QGLProxy::signalProxy(), SIGNAL(aboutToDestroyContext(const QGLContext *)), SLOT(cleanupGLContextRefs(const QGLContext *))); } inline void setDevice(QPaintDevice *pdev); void begin(); void end(); inline void bind(); inline void release(); inline bool isBound() const; inline QSize drawableSize() const; inline QSize offscreenSize() const; inline GLuint offscreenTexture() const; QGLContext *context() const; static bool isSupported(); inline void initialize(); inline bool isValid() const;public Q_SLOTS: void cleanupGLContextRefs(const QGLContext *context) { if (context == ctx) ctx = 0; }private: QGLDrawable drawable; QGLFramebufferObject *offscreen; QGLContext *ctx; // dimensions of mask texture (square) int mask_dim; QSize last_failed_size; bool drawable_fbo; bool activated; bool initialized; bool bound;};inline void QGLOffscreen::setDevice(QPaintDevice *pdev){ drawable.setDevice(pdev); drawable_fbo = (pdev->devType() == QInternal::FramebufferObject);}void QGLOffscreen::begin(){#ifndef Q_WS_QWS initialized = false; if (activated) initialize();#endif}void QGLOffscreen::initialize(){#ifndef Q_WS_QWS if (initialized) return; activated = true; initialized = true; int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(drawable.size().width(), drawable.size().height())))); bool shared_context = qgl_share_reg()->checkSharing(drawable.context(), ctx); bool would_fail = last_failed_size.isValid() && (drawable.size().width() >= last_failed_size.width() || drawable.size().height() >= last_failed_size.height()); bool needs_refresh = dim > mask_dim || !shared_context; if (needs_refresh && !would_fail) { DEBUG_ONCE qDebug() << "QGLOffscreen::initialize(): creating offscreen of size" << dim; delete offscreen; offscreen = new QGLFramebufferObject(dim, dim); mask_dim = dim; if (!offscreen->isValid()) { qWarning("QGLOffscreen: Invalid offscreen fbo (size %dx%d)", mask_dim, mask_dim); delete offscreen; offscreen = 0; mask_dim = 0; last_failed_size = drawable.size(); } } qt_mask_texture_cache()->setOffscreenSize(offscreenSize()); qt_mask_texture_cache()->setDrawableSize(drawable.size()); ctx = drawable.context();#endif}inline bool QGLOffscreen::isValid() const{ return offscreen;}void QGLOffscreen::end(){ if (bound) release();#ifdef DEBUG_DISPLAY_MASK_TEXTURE glDisable(GL_FRAGMENT_PROGRAM_ARB); glReadBuffer(GL_BACK); glDrawBuffer(GL_BACK); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor4f(1, 1, 1, 1); glDisable(GL_DEPTH_TEST); glBlendFunc(GL_ONE, GL_ZERO); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, offscreen->texture()); glBegin(GL_QUADS); glTexCoord2f(0.0, 1.0); glVertex2f(0.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex2f(drawable.size().width(), 0.0); glTexCoord2f(1.0, 0.0); glVertex2f(drawable.size().width(), drawable.size().height()); glTexCoord2f(0.0, 0.0); glVertex2f(0.0, drawable.size().height()); glEnd(); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D);#endif}inline void QGLOffscreen::bind(){#ifndef Q_WS_QWS Q_ASSERT(initialized); if (!offscreen || bound) return; DEBUG_ONCE qDebug() << "QGLOffscreen: binding offscreen"; offscreen->bind(); bound = true; glViewport(0, 0, offscreenSize().width(), offscreenSize().height()); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, offscreenSize().width(), offscreenSize().height(), 0, -999999, 999999); glMatrixMode(GL_MODELVIEW);#endif}inline void QGLOffscreen::release(){#ifndef Q_WS_QWS if (!offscreen || !bound) return;#ifdef Q_WS_X11 // workaround for bug in nvidia driver versions 9x.xx if (QGLExtensions::nvidiaFboNeedsFinish) glFinish();#endif DEBUG_ONCE_STR("QGLOffscreen: releasing offscreen"); if (drawable_fbo) drawable.makeCurrent(); else offscreen->release(); QSize sz(drawable.size()); glViewport(0, 0, sz.width(), sz.height()); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); glMatrixMode(GL_MODELVIEW); bound = false;#endif}inline bool QGLOffscreen::isBound() const{ return bound;}inline QSize QGLOffscreen::drawableSize() const{ return drawable.size();}inline QSize QGLOffscreen::offscreenSize() const{ return QSize(mask_dim, mask_dim);}inline GLuint QGLOffscreen::offscreenTexture() const{ return offscreen ? offscreen->texture() : 0;}inline QGLContext *QGLOffscreen::context() const{ return ctx;}bool QGLOffscreen::isSupported(){ return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject) // for fbo && (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0); // non-power-of-two textures}struct QDrawQueueItem{ QDrawQueueItem(qreal _opacity, QBrush _brush, const QPointF &_brush_origion, QPainter::CompositionMode _composition_mode, const QTransform &_matrix, QGLMaskTextureCache::CacheLocation _location) : opacity(_opacity), brush(_brush), brush_origin(_brush_origion), composition_mode(_composition_mode), matrix(_matrix), location(_location) {} qreal opacity; QBrush brush; QPointF brush_origin; QPainter::CompositionMode composition_mode; QTransform matrix; QGLMaskTextureCache::CacheLocation location;};class QOpenGLPaintEnginePrivate;class QGLPrivateCleanup : public QObject{ Q_OBJECTpublic: QGLPrivateCleanup(QOpenGLPaintEnginePrivate *priv) : p(priv) { connect(QGLProxy::signalProxy(), SIGNAL(aboutToDestroyContext(const QGLContext *)), SLOT(cleanupGLContextRefs(const QGLContext *))); }public Q_SLOTS: void cleanupGLContextRefs(const QGLContext *context);private: QOpenGLPaintEnginePrivate *p;};class QOpenGLPaintEnginePrivate : public QPaintEnginePrivate{ Q_DECLARE_PUBLIC(QOpenGLPaintEngine)public: QOpenGLPaintEnginePrivate() : opacity(1) , composition_mode(QPainter::CompositionMode_SourceOver) , has_fast_pen(false) , txop(QTransform::TxNone) , inverseScale(1) , moveToCount(0) , shader_ctx(0) , grad_palette(0) , use_stencil_method(false) , has_stencil_face_ext(false) , use_fragment_programs(false) , high_quality_antialiasing(false) , drawable_texture(0) , ref_cleaner(this) {} inline void setGLPen(const QColor &c) { uint alpha = qRound(c.alpha() * opacity); pen_color[0] = (c.red() * alpha + 128) >> 8; pen_color[1] = (c.green() * alpha + 128) >> 8; pen_color[2] = (c.blue() * alpha + 128) >> 8; pen_color[3] = alpha; } inline void setGLBrush(const QColor &c) { uint alpha = qRound(c.alpha() * opacity); brush_color[0] = (c.red() * alpha + 128) >> 8; brush_color[1] = (c.green() * alpha + 128) >> 8; brush_color[2] = (c.blue() * alpha + 128) >> 8; brush_color[3] = alpha; } inline void setGradientOps(const QBrush &brush, const QRectF &bounds); void createGradientPaletteTexture(const QGradient& g); void updateGradient(const QBrush &brush, const QRectF &bounds); inline void lineToStencil(qreal x, qreal y); inline void curveToStencil(const QPointF &cp1, const QPointF &cp2, const QPointF &ep); void pathToVertexArrays(const QPainterPath &path); void fillVertexArray(Qt::FillRule fillRule); void drawVertexArrays(); void fillPath(const QPainterPath &path); void fillPolygon_dev(const QPointF *polygonPoints, int pointCount, Qt::FillRule fill); void drawFastRect(const QRectF &rect); void strokePath(const QPainterPath &path, bool use_cache); void strokePathFastPen(const QPainterPath &path, bool needsResolving); void strokeLines(const QPainterPath &path); void cleanupGLContextRefs(const QGLContext *context) { if (context == shader_ctx) shader_ctx = 0; } QPen cpen; QBrush cbrush; QRegion crgn; Qt::BrushStyle brush_style; QPointF brush_origin; Qt::BrushStyle pen_brush_style; qreal opacity; QPainter::CompositionMode composition_mode; Qt::BrushStyle current_style; uint has_clipping : 1; uint has_pen : 1; uint has_brush : 1; uint has_fast_pen : 1; QTransform matrix; GLubyte pen_color[4]; GLubyte brush_color[4]; QTransform::TransformationType txop; QGLDrawable drawable; QGLOffscreen offscreen; qreal inverseScale; int moveToCount; QPointF path_start; bool isFastRect(const QRectF &r); void drawImageAsPath(const QRectF &r, const QImage &img, const QRectF &sr); void drawTiledImageAsPath(const QRectF &r, const QImage &img); void drawOffscreenPath(const QPainterPath &path); void composite(const QRectF &rect, const QPoint &maskOffset = QPoint()); void composite(GLuint primitive, const float *vertexArray, int vertexCount, const QPoint &maskOffset = QPoint()); bool createFragmentPrograms(); void deleteFragmentPrograms(); void updateFragmentProgramData(int locations[]); void cacheItemErased(int channel, const QRect &rect); void addItem(const QGLMaskTextureCache::CacheLocation &location); void drawItem(const QDrawQueueItem &item); void flushDrawQueue(); void copyDrawable(const QRectF &rect); QGLContext *shader_ctx; GLuint grad_palette; GLuint painter_fragment_programs[num_fragment_brushes][num_fragment_composition_modes]; GLuint mask_fragment_programs[num_fragment_masks]; bool use_stencil_method; bool has_stencil_face_ext; bool use_fragment_programs; bool high_quality_antialiasing; float inv_matrix_data[3][4]; float fmp_data[4]; float fmp2_m_radius2_data[4]; float angle_data[4]; float linear_data[4]; float porterduff_ab_data[4]; float porterduff_xyz_data[4]; float mask_offset_data[4]; float mask_channel_data[4]; FragmentBrushType fragment_brush; FragmentCompositionModeType fragment_composition_mode; bool has_fast_composition_mode; void setPorterDuffData(float a, float b, float x, float y, float z); void setInvMatrixData(const QTransform &inv_matrix); qreal max_x; qreal max_y; qreal min_x;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -