Esempio n. 1
0
GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &image, BindOptions options)
{
    if (image.isNull())
        return 0;
    QMutexLocker locker(&m_mutex);
    qint64 key = image.cacheKey();

    // A QPainter is active on the image - take the safe route and replace the texture.
    if (!image.paintingActive()) {
        QOpenGLCachedTexture *entry = m_cache.object(key);
        if (entry && entry->options() == options) {
            context->functions()->glBindTexture(GL_TEXTURE_2D, entry->id());
            return entry->id();
        }
    }

    QImage img = image;
    if (!context->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures)) {
        // Scale the pixmap if needed. GL textures needs to have the
        // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL
        // 2.0 or use the GL_TEXTURE_RECTANGLE texture target
        int tx_w = qNextPowerOfTwo(image.width() - 1);
        int tx_h = qNextPowerOfTwo(image.height() - 1);
        if (tx_w != image.width() || tx_h != image.height()) {
            img = img.scaled(tx_w, tx_h);
        }
    }

    GLuint id = bindTexture(context, key, img, options);
    if (id > 0)
        QImagePixmapCleanupHooks::enableCleanupHooks(image);

    return id;
}
Esempio n. 2
0
void QTextureGlyphCache::fillInPendingGlyphs()
{
    if (!hasPendingGlyphs())
        return;

    int requiredHeight = m_h;
    int requiredWidth = m_w; // Use a minimum size to avoid a lot of initial reallocations
    {
        QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
        while (iter != m_pendingGlyphs.end()) {
            Coord c = iter.value();
            requiredHeight = qMax(requiredHeight, c.y + c.h);
            requiredWidth = qMax(requiredWidth, c.x + c.w);
            ++iter;
        }
    }

    if (isNull() || requiredHeight > m_h || requiredWidth > m_w) {
        if (isNull())
            createCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
        else
            resizeCache(qNextPowerOfTwo(requiredWidth - 1), qNextPowerOfTwo(requiredHeight - 1));
    }

    {
        QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
        while (iter != m_pendingGlyphs.end()) {
            GlyphAndSubPixelPosition key = iter.key();
            fillTexture(iter.value(), key.glyph, key.subPixelPosition);

            ++iter;
        }
    }

    m_pendingGlyphs.clear();
}
Esempio n. 3
0
void MainWindow::roundSBToPowerOfTwo(int value)
{
    QSpinBox *sb = (QSpinBox *)sender();
    sb->blockSignals(true);

    int prevValue = (sb == ui->rangeMinSB) ? rangeMinSBPrevValue : rangeMaxSBPrevValue;
    int nextValue = value;

    if (prevValue < value)
        nextValue = qNextPowerOfTwo(value);
    else if(prevValue > value)
        nextValue = qNextPowerOfTwo(value) >> 1;

    if (sb == ui->rangeMinSB)
        rangeMinSBPrevValue = nextValue;
    else
        rangeMaxSBPrevValue = nextValue;

    sb->setValue(nextValue);
    sb->blockSignals(false);
}
Esempio n. 4
0
bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
                                                const QFixedPoint *positions)
{
#ifdef CACHE_DEBUG
    printf("Populating with %d glyphs\n", numGlyphs);
    qDebug() << " -> current transformation: " << m_transform;
#endif

    m_current_fontengine = fontEngine;
    const int padding = glyphPadding();
    const int paddingDoubled = padding * 2;

    bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions();
    if (fontEngine->m_subPixelPositionCount == 0) {
        if (!supportsSubPixelPositions) {
            fontEngine->m_subPixelPositionCount = 1;
        } else {
            int i = 0;
            while (fontEngine->m_subPixelPositionCount == 0 && i < numGlyphs)
                fontEngine->m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]);
        }
    }

    if (m_cx == 0 && m_cy == 0) {
        m_cx = padding;
        m_cy = padding;
    }

    QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates;
    int rowHeight = 0;

    // check each glyph for its metrics and get the required rowHeight.
    for (int i=0; i < numGlyphs; ++i) {
        const glyph_t glyph = glyphs[i];

        QFixed subPixelPosition;
        if (supportsSubPixelPositions) {
            QFixed x = positions != 0 ? positions[i].x : QFixed();
            subPixelPosition = fontEngine->subPixelPositionForX(x);
        }

        if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
            continue;
        if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
            continue;

        glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, m_format);

#ifdef CACHE_DEBUG
        printf("(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
               glyph,
               metrics.width.toReal(),
               metrics.height.toReal(),
               metrics.xoff.toReal(),
               metrics.yoff.toReal(),
               metrics.x.toReal(),
               metrics.y.toReal());
#endif
        GlyphAndSubPixelPosition key(glyph, subPixelPosition);
        int glyph_width = metrics.width.ceil().toInt();
        int glyph_height = metrics.height.ceil().toInt();
        if (glyph_height == 0 || glyph_width == 0) {
            // Avoid multiple calls to boundingBox() for non-printable characters
            Coord c = { 0, 0, 0, 0, 0, 0 };
            coords.insert(key, c);
            continue;
        }
        // align to 8-bit boundary
        if (m_format == QFontEngine::Format_Mono)
            glyph_width = (glyph_width+7)&~7;

        Coord c = { 0, 0, // will be filled in later
                    glyph_width,
                    glyph_height, // texture coords
                    metrics.x.truncate(),
                    -metrics.y.truncate() }; // baseline for horizontal scripts

        listItemCoordinates.insert(key, c);
        rowHeight = qMax(rowHeight, glyph_height);
    }
    if (listItemCoordinates.isEmpty())
        return true;

    rowHeight += paddingDoubled;

    if (m_w == 0) {
        if (fontEngine->maxCharWidth() <= QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH)
            m_w = QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH;
        else
            m_w = qNextPowerOfTwo(qCeil(fontEngine->maxCharWidth()) - 1);
    }

    // now actually use the coords and paint the wanted glyps into cache.
    QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = listItemCoordinates.begin();
    int requiredWidth = m_w;
    while (iter != listItemCoordinates.end()) {
        Coord c = iter.value();

        m_currentRowHeight = qMax(m_currentRowHeight, c.h);

        if (m_cx + c.w + padding > requiredWidth) {
            int new_width = requiredWidth*2;
            while (new_width < m_cx + c.w + padding)
                new_width *= 2;
            if (new_width <= maxTextureWidth()) {
                requiredWidth = new_width;
            } else {
                // no room on the current line, start new glyph strip
                m_cx = padding;
                m_cy += m_currentRowHeight + paddingDoubled;
                m_currentRowHeight = c.h; // New row
            }
        }

        if (maxTextureHeight() > 0 && m_cy + c.h + padding > maxTextureHeight()) {
            // We can't make a cache of the required size, so we bail out
            return false;
        }

        c.x = m_cx;
        c.y = m_cy;

        coords.insert(iter.key(), c);
        m_pendingGlyphs.insert(iter.key(), c);

        m_cx += c.w + paddingDoubled;
        ++iter;
    }
    return true;

}
Esempio n. 5
0
void MainWindow::startBench()
{
    int rangeMin = ui->rangeMinSB->value();
    int rangeMax = ui->rangeMaxSB->value();

    Q_ASSERT(IS_POWER_OF_TWO(rangeMin));
    Q_ASSERT(IS_POWER_OF_TWO(rangeMax));

    int sizeCount = (int)(log2(rangeMax) - log2(rangeMin) + 1);
    if (sizeCount <= 0)
        return;

    int iterations = ui->benchIterRB->value();
    float fourierCount = iterations * (sizeCount + 2);
    float progressStep = 100.0 / fourierCount;
    float progressCounter;

    FT::FTType algorithm = (FT::FTType)ui->benchFtCombo->currentIndex();

    QString input = ui->benchInputLine->text();
    Q_ASSERT(FImage::isRectCode(input));

    ui->benchResultView->clear();
    progressCounter = 0.0;
    m_progress->setValue(progressCounter);

    for (int size = rangeMin; size <= rangeMax; size = qNextPowerOfTwo(size)) {
        QVector<int> results;
        FImage rectangle = FImage::rectangle(input, QSize(size, size));

        FT *fourierWarmUp = FT::createFT(algorithm, &rectangle);
        fourierWarmUp->bench();
        delete fourierWarmUp;
        progressCounter += progressStep;
        m_progress->setValue(progressCounter);

        for (int i = 0; i < iterations; ++i) {
            FT *fourier = FT::createFT(algorithm, &rectangle);
            results.append(fourier->bench());
            delete fourier;

            progressCounter += progressStep;
            m_progress->setValue(progressCounter);
        }

        int result = 0;
        if (ui->benchMinRB->isChecked())
            result = *std::min_element(results.begin(), results.end());
        else if (ui->benchMaxRB->isChecked())
            result = *std::max_element(results.begin(), results.end());
        else if (ui->benchMeanRB->isChecked()) {
            float sum = 0.0;
            Q_FOREACH (int r, results)
                sum += (float)r;

            result = qRound(sum / (float)results.count());
        }

        QStringList benchSum;
        benchSum.append(QStringLiteral("%1").arg(rectangle.id()).leftJustified(28, ' '));
        benchSum.append(QString::number(size).rightJustified(4, ' '));
        benchSum.append(QStringLiteral("%1 ms").arg(QString::number(result).rightJustified(4, ' ')));

        QStringList resultList;
        Q_FOREACH (int r, results)
            resultList.append(QString::number(r).rightJustified(4, ' '));

        ui->benchResultView->append(QStringLiteral("%1\t%2").arg(benchSum.join(" ")).arg(resultList.join(" ")));

        progressCounter += progressStep;
        m_progress->setValue(progressCounter);
    }