diff options
| author | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-12-16 08:27:57 +0100 |
|---|---|---|
| committer | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-12-16 08:27:57 +0100 |
| commit | 0c117eb94ebbc39fd6a8d6be25db86f349d05e20 (patch) | |
| tree | 61c9ead27377f5ca1e634ebbd946d132ec20e71a | |
| parent | 6bdfa1a7529a9f4dd379b3eca4dec1cb4ce7364d (diff) | |
some more autotests for texturemanager
| -rw-r--r-- | TODO | 31 | ||||
| -rw-r--r-- | src/scenegraph/coreapi/qsgtexturemanager.cpp | 51 | ||||
| -rw-r--r-- | src/scenegraph/coreapi/qsgtexturemanager.h | 2 | ||||
| -rw-r--r-- | tests/auto/texturemanager/tst_texturemanagertest.cpp | 69 |
4 files changed, 150 insertions, 3 deletions
@@ -12,7 +12,6 @@ declarative/ canvas/ view - animation driver items/ all the qxitems scenegraph/ @@ -34,6 +33,9 @@ adaptation interfaces default implementations qmlrenderer + animation driver + + - Make QxImage push normalized source coords into TextureNode so we don't have to renormalize for every geometry change. It also makes a lot more sense, now that TextureNode doesn't know the @@ -48,3 +50,30 @@ does a texture memcpy for the first glDrawElements() that uses the texture in the UI thread. I guess that only leaves PBO uploads, but that won't remedy the problem, I recon... EDIT: CLIENT_STORAGE + TEXTURE_STORAGE as SHARED + seems to kill ALL performance problems + + +- Scene Graph + - Product Finalization: + - API Review and proper d-ptr implementations where required + - Documentation for all public classes + - Autotests for all public classes + - NodeInterfaces, Scene Graph structure, QSGContext, Texture classes, Renderer + - Solve the texture problem. Convenient base class, asynchronous uploads (threading?), atlasses? + - Multimedia, through Qt Mobility or directly to native API's like gstreamer + - We have phonon, but it doesn't work for devices + - Gstreamer, would work on meego / linux + - Lacking solution on symbian + - Upgrade to proper QML Items + - Examples for most common usecases usecases + - Solve the text problem + - Investigate mipmapping + - Investigate distance field + - Investigate curve rendering on gpu + - Scalable unhinted text layout + - text as geometry over a physical size + - Optimal backends for SGX, CTS79 and Mali 400. + - Pluggable vsync animation + - Wayland based + - eglSwapBuffers based + - signal based? + diff --git a/src/scenegraph/coreapi/qsgtexturemanager.cpp b/src/scenegraph/coreapi/qsgtexturemanager.cpp index d8c08f8..6b072cc 100644 --- a/src/scenegraph/coreapi/qsgtexturemanager.cpp +++ b/src/scenegraph/coreapi/qsgtexturemanager.cpp @@ -120,13 +120,29 @@ public: int uploadTimer; QTime lastUpload; + + int maxTextureSize; }; +/*! + The QSGTextureManager class is responsible for converting QImages into texture ids + inside the QML scene graph. + The QSGTextureManager is created by the QSGContext class after a GL context is + available, so the QSGTextureManager and subclasses can safely assume that a + GL context is bound and make GL calls. + */ QSGTextureManager::QSGTextureManager() : d(new QSGTextureManagerPrivate) { + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &d->maxTextureSize); +} + + +int QSGTextureManager::maxTextureSize() const +{ + return d->maxTextureSize; } @@ -186,6 +202,9 @@ QSGTextureRef QSGTextureManager::upload(const QImage &image) if (texture) return QSGTextureRef(texture); + while (glGetError() != GL_NO_ERROR) {} + + GLuint id; glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); @@ -198,6 +217,16 @@ QSGTextureRef QSGTextureManager::upload(const QImage &image) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, image.constBits()); #endif + // Gracefully fail in case of an error... + GLuint error = glGetError(); + if (error != GL_NO_ERROR) { + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &id); + if (error != GL_OUT_OF_MEMORY) + qWarning("QSGTextureManager::upload failed, OpenGL error code: %x", error); + return QSGTextureRef(); + } + texture = new QSGTexture; texture->setTextureId(id); texture->setTextureSize(image.size()); @@ -220,7 +249,9 @@ QSGTextureRef QSGTextureManager::requestUpload(const QImage &image, Q_ASSERT(!image.isNull()); QSGTexture *t = new QSGTexture(); - connect(t, SIGNAL(statusChanged(int)), listener, slot); + t->setStatus(QSGTexture::Loading); + if (listener && slot) + connect(t, SIGNAL(statusChanged(int)), listener, slot); connect(t, SIGNAL(destroyed(QObject*)), this, SLOT(textureDestroyed(QObject*))); QSGTextureAsyncUpload work; @@ -282,14 +313,30 @@ void QSGTextureManager::processAsyncTextures() // Create or bind the texture... if (upload.texture->textureId() == 0) { + while (glGetError() != GL_NO_ERROR) {} GLuint id; glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + + // Clean up + // Gracefully fail in case of an error... + GLuint error = glGetError(); + if (error != GL_NO_ERROR) { + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &id); + if (error != GL_OUT_OF_MEMORY) { + qWarning("QSGTextureManager::async upload failed, OpenGL error code: %x", error); + t->setStatus(QSGTexture::Error); + } else { + t->setStatus(QSGTexture::Null); + } + return; + } + t->setTextureId(id); t->setTextureSize(QSize(w, h)); t->setAlphaChannel(upload.image.hasAlphaChannel()); - t->setStatus(QSGTexture::Loading); // printf("ASYNC: created texture %p with id=%d\n", t, id); } else { glBindTexture(GL_TEXTURE_2D, t->textureId()); diff --git a/src/scenegraph/coreapi/qsgtexturemanager.h b/src/scenegraph/coreapi/qsgtexturemanager.h index 6eb25ad..2b065f3 100644 --- a/src/scenegraph/coreapi/qsgtexturemanager.h +++ b/src/scenegraph/coreapi/qsgtexturemanager.h @@ -177,6 +177,8 @@ public: static void swizzleBGRAToRGBA(QImage *image); + int maxTextureSize() const; + protected: void timerEvent(QTimerEvent *); diff --git a/tests/auto/texturemanager/tst_texturemanagertest.cpp b/tests/auto/texturemanager/tst_texturemanagertest.cpp index 853d527..3ddda9e 100644 --- a/tests/auto/texturemanager/tst_texturemanagertest.cpp +++ b/tests/auto/texturemanager/tst_texturemanagertest.cpp @@ -19,6 +19,13 @@ private Q_SLOTS: void upload(); void uploadSameImageTwice(); + void requestUpload(); + + void gracefullyRunOutOfMemory(); + void gracefullyFailOnTooLarge(); + + void maxTextureSize(); + private: QSGContext *context; QGLWidget *glWidget; @@ -80,10 +87,72 @@ void TextureManagerTest::uploadSameImageTwice() QImage shallowCopy = image; QSGTextureRef t2 = tm->upload(shallowCopy); QCOMPARE(t.texture(), t2.texture()); +} + + +void TextureManagerTest::requestUpload() +{ + QImage image(100, 100, QImage::Format_ARGB32_Premultiplied); + QSGTextureRef t = tm->requestUpload(image, 0, 0); + QVERIFY(t->status() == QSGTexture::Ready || t->status() == QSGTexture::Loading); + + int maxWait = 1000; + while (t->status() == QSGTexture::Loading) { + QTest::qWait(50); + QApplication::processEvents(); + } + + QVERIFY(t->status() == QSGTexture::Ready); + QVERIFY(t->textureId() > 0); + QVERIFY(t->textureSize().width() >= image.width()); + QVERIFY(t->textureSize().height() >= image.height()); } +/*! + Test that we don't fail horribly when allocating large amounts of + texture memory. Since some drivers page graphics memory out to disk + and thus never run out, cap the test at 128Mb to not run forever + */ +void TextureManagerTest::gracefullyRunOutOfMemory() +{ + QImage image(512, 512, QImage::Format_ARGB32_Premultiplied); + QList<QSGTextureRef> refs; + + int i = 128; + while (--i) { + QSGTextureRef t = tm->upload(image); + refs << t; + if (t.isNull()) + break; + } + + QVERIFY(true); +} + + +void TextureManagerTest::gracefullyFailOnTooLarge() +{ + QImage image(32000, 2, QImage::Format_ARGB32_Premultiplied); + QSGTextureRef t = tm->upload(image); + QVERIFY(t.isNull()); +} + + +void TextureManagerTest::maxTextureSize() +{ + int size = tm->maxTextureSize(); + + if (size < 1024) { + qWarning("Texture limit is only %d", size); + } + + // 64 is the lowest allowed by the spec... + // Any lower number would indicate an error + QVERIFY(size >=64); } + + QTEST_MAIN(TextureManagerTest); #include "tst_texturemanagertest.moc" |
