canvas3d.cpp 24.95 KiB
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCanvas3D module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
** $QT_END_LICENSE$
****************************************************************************/
#include "canvas3d_p.h"
#include "context3d_p.h"
#include "canvas3dcommon_p.h"
#include "canvasrendernode_p.h"
#include "teximage3d_p.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlContext>
#include <QtCore/QElapsedTimer>
QT_BEGIN_NAMESPACE
QT_CANVAS3D_BEGIN_NAMESPACE
/*!
 * \qmltype Canvas3D
 * \since QtCanvas3D 1.0
 * \ingroup qtcanvas3d-qml-types
 * \brief Canvas that provides a 3D rendering context.
 * The Canvas3D is a QML element that, when placed in your Qt Quick 2 scene, allows you to
 * get a 3D rendering context and call 3D rendering API calls through that context object.
 * Use of the rendering API requires knowledge of OpenGL like rendering APIs.
 * There are two functions that are called by the Canvas3D implementation:
 * \list
 * \li initGL is emitted before the first frame is rendered, and usually during that you get
 * the 3D context and initialize resources to be used later on during the rendering cycle.
 * \li renderGL is emitted for each frame to be rendered, and usually during that you
 * submit 3D rendering calls to draw whatever 3D content you want to be displayed.
 * \endlist
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
* * \sa Context3D, {QML Canvas 3D QML Types} */ /*! * \internal */ Canvas::Canvas(QQuickItem *parent): QQuickItem(parent), m_renderNodeReady(false), m_logAllCalls(false), m_logAllErrors(false), m_mainThread(QThread::currentThread()), m_contextThread(0), m_context3D(0), m_isFirstRender(true), m_glContext(0), m_glContextQt(0), m_contextWindow(0), m_fps(0), m_maxSamples(0), m_devicePixelRatio(1.0f), m_isOpenGLES2(false), m_isSoftwareRendered(false), m_isContextAttribsSet(false), m_antialiasFbo(0), m_renderFbo(0), m_displayFbo(0), m_offscreenSurface(0) { if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__; connect(this, &QQuickItem::windowChanged, this, &Canvas::handleWindowChanged); connect(this, &Canvas::needRender, this, &Canvas::renderNext, Qt::QueuedConnection); setAntialiasing(false); // Set contents to false in case we are in qml designer to make component look nice m_runningInDesigner = QGuiApplication::applicationDisplayName() == "Qml2Puppet"; setFlag(ItemHasContents, !m_runningInDesigner); #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) m_isSoftwareRendered = true; #endif } /*! * \qmlsignal void Canvas::initGL() * Emitted once when Canvas3D is ready and OpenGL state initialization can be done by the client. */ /*! * \qmlsignal void Canvas::renderGL() * Emitted each time a new frame should be drawn to Canvas3D. Driven by the QML scenegraph loop. */ /*! * \internal */ Canvas::~Canvas() { if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__; shutDown(); } /*! * \internal */ void Canvas::shutDown() { if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
if (!m_glContext) return; disconnect(m_contextWindow, 0, this, 0); disconnect(this, 0, this, 0); m_glContext->makeCurrent(m_offscreenSurface); delete m_renderFbo; delete m_displayFbo; delete m_antialiasFbo; delete m_context3D; m_glContext->doneCurrent(); if (m_logAllCalls) qDebug() << m_contextThread << m_mainThread; if (m_contextThread && m_contextThread != m_mainThread) { m_glContext->deleteLater(); m_offscreenSurface->deleteLater(); } else { delete m_glContext; delete m_offscreenSurface; } m_glContext = 0; m_glContextQt = 0; } /*! * \qmlproperty bool Canvas3D::logAllCalls * Specifies if all Canvas3D method calls (including internal ones) are logged to the console. * Defaults to \c{false}. */ void Canvas::setLogAllCalls(bool logCalls) { if (m_logAllCalls != logCalls) { m_logAllCalls = logCalls; emit logAllCallsChanged(logCalls); } } bool Canvas::logAllCalls() const { return m_logAllCalls; } /*! * \qmlproperty bool Canvas3D::logAllErrors * Specifies if all GL errors are checked and logged to the console. Defaults to \c{false}. * WARNING! Enabling this flag will have severe negative performance impact due to use of * \c{glGetError()} after each function call, so only enable it while debugging an issue during * development. */ void Canvas::setLogAllErrors(bool logErrors) { if (m_logAllErrors != logErrors) { m_logAllErrors = logErrors; emit logAllErrorsChanged(logErrors); } } bool Canvas::logAllErrors() const { return m_logAllErrors; } /*! * \qmlsignal Canvas3D::needRender() * This signal, if emitted, causes a re-rendering cycle to happen. Usually this is needed * if a value that affects the look of the 3D scene has changed, but no other mechanism * triggers the re-render cycle.