Load image data on main thread

QQuickPixmap use should be done on the main thread, if not it can lead
to an exception when creating the file loading thread (owned by the
engine).

Change-Id: Id59cec4312ecdee537dcba85778bd90ea4433b2e
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
This commit is contained in:
Alan Alpert 2013-09-13 16:34:07 -07:00 committed by The Qt Project
parent 639553f024
commit 2c750b4570
2 changed files with 37 additions and 28 deletions

View File

@ -846,7 +846,7 @@ QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
, m_lastLevel(Unknown)
, m_debugMode(false)
, m_entryEffect(Fade)
, m_buildingNodes(false)
, m_startedImageLoading(0)
{
setFlag(ItemHasContents);
}
@ -1293,39 +1293,47 @@ bool QQuickImageParticle::loadingSomething()
|| (m_spriteEngine && m_spriteEngine->isLoading());
}
void QQuickImageParticle::buildParticleNodes()//Starts async parts, like loading images.
void QQuickImageParticle::mainThreadFetchImageData()
{
if (m_image) {//ImageData created on setSource
m_image->pix.clear(this);
m_image->pix.load(qmlEngine(this), m_image->source);
}
if (m_spriteEngine)
m_spriteEngine->startAssemblingImage();
if (m_colorTable)
m_colorTable->pix.load(qmlEngine(this), m_colorTable->source);
if (m_sizeTable)
m_sizeTable->pix.load(qmlEngine(this), m_sizeTable->source);
if (m_opacityTable)
m_opacityTable->pix.load(qmlEngine(this), m_opacityTable->source);
m_startedImageLoading = 2;
}
void QQuickImageParticle::buildParticleNodes()
{
// Starts async parts, like loading images, on gui thread
// Not on individual properties, because we delay until system is running
if (m_rootNode || loadingSomething())
return;
if (!m_buildingNodes) {
if (m_image) {//ImageData created on setSource
m_image->pix.clear(this);
m_image->pix.load(qmlEngine(this), m_image->source);
}
if (m_spriteEngine)
m_spriteEngine->startAssemblingImage();
if (m_colorTable)
m_colorTable->pix.load(qmlEngine(this), m_colorTable->source);
if (m_sizeTable)
m_sizeTable->pix.load(qmlEngine(this), m_sizeTable->source);
if (m_opacityTable)
m_opacityTable->pix.load(qmlEngine(this), m_opacityTable->source);
m_buildingNodes = true;
if (loadingSomething())
return;
if (m_startedImageLoading == 0) {
m_startedImageLoading = 1;
QQuickImageParticle::staticMetaObject.invokeMethod(this, "mainThreadFetchImageData", Qt::QueuedConnection);
} else if (m_startedImageLoading == 2) { //stage 1 is in gui thread
finishBuildParticleNodes(); //rest happens in render thread
}
finishBuildParticleNodes();
//No mutex, because it's slow and a compare that fails due to a race condition means just a dropped frame
}
void QQuickImageParticle::finishBuildParticleNodes()
{
m_buildingNodes = false;
#ifdef QT_OPENGL_ES_2
if (m_count * 4 > 0xffff) {
printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
@ -1574,7 +1582,7 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
m_material = 0;
m_pleaseReset = false;
m_buildingNodes = false;//Cancel a part-way build
m_startedImageLoading = 0;//Cancel a part-way build (may still have a pending load)
}
if (m_system && m_system->isRunning() && !m_system->isPaused()){
@ -1583,7 +1591,7 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
update();
foreach (QSGGeometryNode* node, m_nodes)
node->markDirty(QSGNode::DirtyGeometry);
} else if (m_buildingNodes) {
} else if (m_startedImageLoading < 2) {
update();//To call prepareNextFrame() again from the renderThread
}
}

View File

@ -353,6 +353,7 @@ private Q_SLOTS:
void spriteAdvance(int spriteIndex);
void spritesUpdate(qreal time = 0 );
void mainThreadFetchImageData();
void finishBuildParticleNodes();
private:
struct ImageData {
@ -436,7 +437,7 @@ private:
}
EntryEffect m_entryEffect;
Status m_status;
bool m_buildingNodes;
int m_startedImageLoading;
};
QT_END_NAMESPACE