diff --git a/toonz/sources/common/tfx/trenderer.cpp b/toonz/sources/common/tfx/trenderer.cpp index 1e1c9b6..638e310 100644 --- a/toonz/sources/common/tfx/trenderer.cpp +++ b/toonz/sources/common/tfx/trenderer.cpp @@ -36,6 +36,12 @@ #include #include +#include +#include +#include +#include +#include + using namespace TThread; std::vector calculateSortedFxs(TRasterFxP rootFx); @@ -1411,6 +1417,18 @@ void TRendererImp::startRendering( alias = alias + renderData.m_fxRoot.m_frameB->getAlias(frame, renderData.m_info); + // If the render contains offscreen render, then prepare the + // QOffscreenSurface + // in main (GUI) thread. For now it is used only in the plasticDeformerFx. + if (alias.find("plasticDeformerFx") != std::string::npos && + QThread::currentThread() == qGuiApp->thread()) { + rs.m_offScreenSurface.reset(new QOffscreenSurface()); + rs.m_offScreenSurface->setFormat(QSurfaceFormat::defaultFormat()); + rs.m_offScreenSurface->setScreen( + QOpenGLContext::globalShareContext()->screen()); + rs.m_offScreenSurface->create(); + } + // Search the alias among stored clusters - and store the frame jt = clusters.find(alias); diff --git a/toonz/sources/include/toonz/imagepainter.h b/toonz/sources/include/toonz/imagepainter.h index 6bb78d5..cc864a0 100644 --- a/toonz/sources/include/toonz/imagepainter.h +++ b/toonz/sources/include/toonz/imagepainter.h @@ -66,6 +66,7 @@ public: bool m_recomputeIfNeeded; bool m_drawBlankFrame; bool m_useChecks; //!< whether to consider paint check and ink check + bool m_forSceneIcon = false; // whether it is redered for the scene icons public: VisualSettings(); diff --git a/toonz/sources/include/trasterfx.h b/toonz/sources/include/trasterfx.h index fa588e4..c1dab56 100644 --- a/toonz/sources/include/trasterfx.h +++ b/toonz/sources/include/trasterfx.h @@ -9,6 +9,7 @@ // TnzBase includes #include "tfx.h" #include "trasterfxrenderdata.h" +#include #undef DVAPI #undef DVVAR @@ -151,6 +152,12 @@ public: /*-- 途中でPreview計算がキャンセルされたときのフラグ --*/ int *m_isCanceled; + // pointer to QOffscreenSurface which is created on + // TRendererImp::startRendering() + // for offscreen rendering to be done in non-GUI thread. + // For now it is used only in the plasticDeformerFx. + std::shared_ptr m_offScreenSurface; + public: TRenderSettings(); ~TRenderSettings(); diff --git a/toonz/sources/tcomposer/tcomposer.cpp b/toonz/sources/tcomposer/tcomposer.cpp index 42ac0cd..5c0bf88 100644 --- a/toonz/sources/tcomposer/tcomposer.cpp +++ b/toonz/sources/tcomposer/tcomposer.cpp @@ -403,7 +403,7 @@ static std::pair generateMovie(ToonzScene *scene, const TFilePath &fp, r0 = r0 - 1; r1 = r1 - 1; - if (r0 < 0) r0 = 0; + if (r0 < 0) r0 = 0; if (r1 < 0 || r1 >= scene->getFrameCount()) r1 = scene->getFrameCount() - 1; string msg; assert(r1 >= r0); @@ -564,6 +564,7 @@ static std::pair generateMovie(ToonzScene *scene, const TFilePath &fp, DV_IMPORT_API void initStdFx(); DV_IMPORT_API void initColorFx(); int main(int argc, char *argv[]) { + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); QApplication app(argc, argv); // Create a QObject destroyed just before app - see Tnz6's main.cpp for @@ -661,8 +662,8 @@ int main(int argc, char *argv[]) { TVectorBrushStyle::setRootDir(libraryFolder); TPalette::setRootDir(libraryFolder); TImageStyle::setLibraryDir(libraryFolder); - TFilePath cacheRoot = ToonzFolder::getCacheRootFolder(); - if (cacheRoot.isEmpty()) cacheRoot= TEnv::getStuffDir() + "cache"; + TFilePath cacheRoot = ToonzFolder::getCacheRootFolder(); + if (cacheRoot.isEmpty()) cacheRoot = TEnv::getStuffDir() + "cache"; TImageCache::instance()->setRootDir(cacheRoot); // #endif @@ -947,8 +948,8 @@ int main(int argc, char *argv[]) { DVGui::info(QString::fromStdString(msg)); TImageCache::instance()->clear(true); } catch (TException &e) { - msg = "Untrapped exception: " + ::to_string(e.getMessage()), - cout << msg << endl; + msg = "Untrapped exception: " + ::to_string(e.getMessage()), cout << msg + << endl; m_userLog->error(msg); TImageCache::instance()->clear(true); } catch (...) { diff --git a/toonz/sources/tnzext/meshtexturizer.cpp b/toonz/sources/tnzext/meshtexturizer.cpp index 2a00f53..799bded 100644 --- a/toonz/sources/tnzext/meshtexturizer.cpp +++ b/toonz/sources/tnzext/meshtexturizer.cpp @@ -29,6 +29,17 @@ TCG_STATIC_ASSERT(TRANSP_BORDER > 0); // Due to GL_CLAMP beyond tile limits TCG_STATIC_ASSERT(NONPREM_BORDER <= TRANSP_BORDER); // The nonpremultiplied border is transparent +namespace { +int getMaxTextureTileSize() { + static int maxTexSize = -1; + if (maxTexSize == -1) { + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); + maxTexSize = std::min(maxTexSize, 1 << 11); + } + return maxTexSize; +} +}; + //****************************************************************************************** // MeshTexturizer::Imp definition //****************************************************************************************** @@ -58,8 +69,16 @@ public: //--------------------------------------------------------------------------------- bool MeshTexturizer::Imp::testTextureAlloc(int lx, int ly) { + GLuint texName; + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &texName); + glBindTexture(GL_TEXTURE_2D, texName); + lx += TOTAL_BORDER_2, ly += TOTAL_BORDER_2; // Add border + int max_texture_size; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); + glTexImage2D(GL_PROXY_TEXTURE_2D, 0, // one level only GL_RGBA, // number of pixel channels @@ -73,6 +92,8 @@ bool MeshTexturizer::Imp::testTextureAlloc(int lx, int ly) { int outLx; glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &outLx); + glDeleteTextures(1, &texName); + assert(glGetError() == GL_NO_ERROR); return (lx == outLx); } @@ -155,6 +176,7 @@ GLuint MeshTexturizer::Imp::textureAlloc(const TRaster32P &ras, TGL_FMT, // pixel format GL_UNSIGNED_BYTE, // pixel data type (GLvoid *)tex->getRawData()); + assert(glGetError() == GL_NO_ERROR); return texId; } @@ -183,6 +205,7 @@ void MeshTexturizer::Imp::allocateTextures(int groupIdx, const TRaster32P &ras, TextureData::TileData td = {texId, tileGeom}; data->m_tileDatas.push_back(td); + assert(glGetError() == GL_NO_ERROR); return; } @@ -246,9 +269,10 @@ int MeshTexturizer::bindTexture(const TRaster32P &ras, const TRectD &geom, int textureLy = tcg::numeric_ops::GE_2Power((unsigned int)ras->getLy() + TOTAL_BORDER_2); - // We'll assume a strict granularity max of 512 x 512 textures - textureLx = std::min(textureLx, 1 << 9); - textureLy = std::min(textureLy, 1 << 9); + // We'll assume a strict granularity max of 2048 x 2048 textures, if it is + // possible. + textureLx = std::min(textureLx, getMaxTextureTileSize()); + textureLy = std::min(textureLy, getMaxTextureTileSize()); // Allocate a suitable texture raster. The texture will include a transparent // 1-pix border diff --git a/toonz/sources/toonzlib/imagebuilders.cpp b/toonz/sources/toonzlib/imagebuilders.cpp index 767637a..5d48b7d 100644 --- a/toonz/sources/toonzlib/imagebuilders.cpp +++ b/toonz/sources/toonzlib/imagebuilders.cpp @@ -291,7 +291,6 @@ TImageP ImageRasterizer::build(int imFlags, void *extData) { new QOpenGLFramebufferObject(d.lx, d.ly)); fb->bind(); - assert(glGetError() == 0); glViewport(0, 0, d.lx, d.ly); glClearColor(0, 0, 0, 0); @@ -305,13 +304,9 @@ TImageP ImageRasterizer::build(int imFlags, void *extData) { glLoadIdentity(); glTranslatef(0.375, 0.375, 0.0); - assert(glGetError() == 0); tglDraw(rd, vi.getPointer()); - assert(glGetError() == 0); - assert(glGetError() == 0); glFlush(); - assert(glGetError() == 0); QImage img = fb->toImage().scaled(QSize(d.lx, d.ly), Qt::IgnoreAspectRatio, @@ -335,6 +330,8 @@ TImageP ImageRasterizer::build(int imFlags, void *extData) { TRasterImageP ri = TRasterImageP(ras); ri->setOffset(off + ras->getCenter()); + assert(glGetError() == 0); + return ri; } } diff --git a/toonz/sources/toonzlib/plasticdeformerfx.cpp b/toonz/sources/toonzlib/plasticdeformerfx.cpp index bda75e2..0134510 100644 --- a/toonz/sources/toonzlib/plasticdeformerfx.cpp +++ b/toonz/sources/toonzlib/plasticdeformerfx.cpp @@ -28,6 +28,12 @@ #include "tconvert.h" #include "trop.h" +#include +#include +#include +#include +#include + FX_IDENTIFIER_IS_HIDDEN(PlasticDeformerFx, "plasticDeformerFx") //*************************************************************************************************** @@ -345,7 +351,7 @@ void PlasticDeformerFx::doCompute(TTile &tile, double frame, TTile inTile; m_port->allocateAndCompute(inTile, bbox.getP00(), tileSize, TRasterP(), frame, texInfo); - + QOpenGLContext *context; // Draw the textured mesh { // Prepare texture @@ -356,16 +362,32 @@ void PlasticDeformerFx::doCompute(TTile &tile, double frame, const std::string &texId = "render_tex " + std::to_string(++var); // Prepare an OpenGL context - std::unique_ptr context( - new TOfflineGL(tile.getRaster()->getSize())); - context->makeCurrent(); + context = new QOpenGLContext(); + context->setShareContext(QOpenGLContext::globalShareContext()); + context->setFormat(QSurfaceFormat::defaultFormat()); + context->create(); + context->makeCurrent(info.m_offScreenSurface.get()); + + TDimension d = tile.getRaster()->getSize(); + QOpenGLFramebufferObject fb(d.lx, d.ly); + + fb.bind(); // Load texture into the context TTexturesStorage *ts = TTexturesStorage::instance(); const DrawableTextureDataP &texData = ts->loadTexture(texId, tex, bbox); // Draw - glPushMatrix(); + glViewport(0, 0, d.lx, d.ly); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0, d.lx, 0, d.ly); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); tglMultMatrix(TTranslation(-tile.m_pos) * info.m_affine * meshToWorldMeshAff); @@ -375,16 +397,32 @@ void PlasticDeformerFx::doCompute(TTile &tile, double frame, tglDraw(*mi, *texData, meshToTextureAff, *dataGroup); // Retrieve drawing and copy to output tile - context->getRaster(tile.getRaster()); + QImage img = fb.toImage().scaled(QSize(d.lx, d.ly), Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + int wrap = tile.getRaster()->getLx() * sizeof(TPixel32); + uchar *srcPix = img.bits(); + uchar *dstPix = tile.getRaster()->getRawData() + wrap * (d.ly - 1); + for (int y = 0; y < d.ly; y++) { + memcpy(dstPix, srcPix, wrap); + dstPix -= wrap; + srcPix += wrap; + } + fb.release(); + + // context->getRaster(tile.getRaster()); + glFlush(); + glFinish(); // Cleanup // No need to disable stuff - the context dies here // ts->unloadTexture(texId); // Auto-released // due to display list destruction - context->doneCurrent(); + context->deleteLater(); + // context->doneCurrent(); } + assert(glGetError() == GL_NO_ERROR); } //----------------------------------------------------------------------------------- diff --git a/toonz/sources/toonzlib/stagevisitor.cpp b/toonz/sources/toonzlib/stagevisitor.cpp index bc2909e..eaf3b4d 100644 --- a/toonz/sources/toonzlib/stagevisitor.cpp +++ b/toonz/sources/toonzlib/stagevisitor.cpp @@ -749,9 +749,12 @@ void RasterPainter::onImage(const Stage::Player &player) { // QOffscreenSurface is created outside the gui thread. // As a quick workaround, ignore the deformation if this is called from // non-gui thread (i.e. icon generator thread) + // 12/1/2018 Now the scene icon is rendered without deformation either + // since it causes unknown error with opengl contexts.. TStageObject *obj = ::plasticDeformedObj(player, m_vs.m_plasticVisualSettings); - if (obj && QThread::currentThread() == qGuiApp->thread()) { + if (obj && QThread::currentThread() == qGuiApp->thread() && + !m_vs.m_forSceneIcon) { flushRasterImages(); ::onPlasticDeformedImage(obj, player, m_vs, m_viewAff); } else { @@ -1540,6 +1543,7 @@ void onPlasticDeformedImage(TStageObject *playerObj, glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); + assert(glGetError() == GL_NO_ERROR); } } // namespace diff --git a/toonz/sources/toonzlib/toonzscene.cpp b/toonz/sources/toonzlib/toonzscene.cpp index 129d339..7946239 100644 --- a/toonz/sources/toonzlib/toonzscene.cpp +++ b/toonz/sources/toonzlib/toonzscene.cpp @@ -741,6 +741,7 @@ void ToonzScene::renderFrame(const TRaster32P &ras, int row, const TXsheet *xsh, ImagePainter::VisualSettings vs; vs.m_plasticVisualSettings.m_drawMeshesWireframe = false; + vs.m_forSceneIcon = true; Stage::RasterPainter painter(ras->getSize(), viewAff, clipRect, vs, checkFlags);