Beispiel #1
0
void PtexReader::readFaceData(FilePos pos, FaceDataHeader fdh, Res res, int levelid,
                              FaceData*& face)
{
    // keep new face local until fully initialized
    FaceData* volatile newface = 0;

    seek(pos);
    switch (fdh.encoding()) {
    case enc_constant:
    {
        ConstantFace* pf = new ConstantFace((void**)&face, _cache, _pixelsize);
        readBlock(pf->data(), _pixelsize);
        if (levelid==0 && _premultiply && _header.hasAlpha())
            PtexUtils::multalpha(pf->data(), 1, _header.datatype,
                                 _header.nchannels, _header.alphachan);
        newface = pf;
    }
    break;
    case enc_tiled:
    {
        Res tileres;
        readBlock(&tileres, sizeof(tileres));
        uint32_t tileheadersize;
        readBlock(&tileheadersize, sizeof(tileheadersize));
        TiledFace* tf = new TiledFace((void**)&face, _cache, res, tileres, levelid, this);
        readZipBlock(&tf->_fdh[0], tileheadersize, FaceDataHeaderSize * tf->_ntiles);
        computeOffsets(tell(), tf->_ntiles, &tf->_fdh[0], &tf->_offsets[0]);
        newface = tf;
    }
    break;
    case enc_zipped:
    case enc_diffzipped:
    {
        int uw = res.u(), vw = res.v();
        int npixels = uw * vw;
        int unpackedSize = _pixelsize * npixels;
        PackedFace* pf = new PackedFace((void**)&face, _cache,
                                        res, _pixelsize, unpackedSize);
        bool useMalloc = unpackedSize > AllocaMax;
        void* tmp = useMalloc ? malloc(unpackedSize) : alloca(unpackedSize);
        readZipBlock(tmp, fdh.blocksize(), unpackedSize);
        if (fdh.encoding() == enc_diffzipped)
            PtexUtils::decodeDifference(tmp, unpackedSize, _header.datatype);
        PtexUtils::interleave(tmp, uw * DataSize(_header.datatype), uw, vw,
                              pf->data(), uw * _pixelsize,
                              _header.datatype, _header.nchannels);
        if (levelid==0 && _premultiply && _header.hasAlpha())
            PtexUtils::multalpha(pf->data(), npixels, _header.datatype,
                                 _header.nchannels, _header.alphachan);
        newface = pf;
        if (useMalloc) free(tmp);
    }
    break;
    }

    face = newface;
}
Beispiel #2
0
void PtexReader::readFace(int levelid, Level* level, int faceid)
{
    // temporarily release cache lock so other threads can proceed
    _cache->cachelock.unlock();

    // get read lock and make sure we still need to read
    FaceData*& face = level->faces[faceid];
    AutoMutex locker(readlock);

    if (face) {
        // another thread must have read it while we were waiting
        _cache->cachelock.lock();
        // make sure it's still there now that we have the lock
        if (face) {
            face->ref();
            return;
        }
        _cache->cachelock.unlock();
    }

    // Go ahead and read the face, and read nearby faces if
    // possible. The goal is to coalesce small faces into single
    // runs of consecutive reads to minimize seeking and take
    // advantage of read-ahead buffering.

    // Try to read as many faces as will fit in BlockSize.  Use the
    // in-memory size rather than the on-disk size to prevent flooding
    // the memory cache.  And don't coalesce w/ tiled faces as these
    // are meant to be read individually.

    // scan both backwards and forwards looking for unread faces
    int first = faceid, last = faceid;
    int totalsize = 0;

    FaceDataHeader fdh = level->fdh[faceid];
    if (fdh.encoding() != enc_tiled) {
        totalsize += unpackedSize(fdh, levelid, faceid);

        int nfaces = int(level->fdh.size());
        while (1) {
            int f = first-1;
            if (f < 0 || level->faces[f]) break;
            fdh = level->fdh[f];
            if (fdh.encoding() == enc_tiled) break;
            int size = totalsize + unpackedSize(fdh, levelid, f);
            if (size > BlockSize) break;
            first = f;
            totalsize = size;
        }
        while (1) {
            int f = last+1;
            if (f >= nfaces || level->faces[f]) break;
            fdh = level->fdh[f];
            if (fdh.encoding() == enc_tiled) break;
            int size = totalsize + unpackedSize(fdh, levelid, f);
            if (size > BlockSize) break;
            last = f;
            totalsize = size;
        }
    }

    // read all faces in range
    // keep track of extra faces we read so we can add them to the cache later
    std::vector<FaceData*> extraFaces;
    extraFaces.reserve(last-first);

    for (int i = first; i <= last; i++) {
        fdh = level->fdh[i];
        // skip faces with zero size (which is true for level-0 constant faces)
        if (fdh.blocksize()) {
            FaceData*& face = level->faces[i];
            readFaceData(level->offsets[i], fdh, getRes(levelid, i), levelid, face);
            if (i != faceid) extraFaces.push_back(face);
        }
    }

    // reacquire cache lock, then unref extra faces to add them to the cache
    _cache->cachelock.lock();
    for (size_t i = 0, size = extraFaces.size(); i < size; i++)
        extraFaces[i]->unref();
}