Example #1
0
size_t
HdPerfLog::GetCacheMisses(TfToken const& name)
{
    _Lock lock(_mutex);
    if (HdPerfLog::_CacheEntry* value = TfMapLookupPtr(_cacheMap, name))
        return value->GetMisses();
    return 0;
}
Example #2
0
double
HdPerfLog::GetCacheHitRatio(TfToken const& name)
{
    _Lock lock(_mutex);
    if (HdPerfLog::_CacheEntry* value = TfMapLookupPtr(_cacheMap, name)) {
        return value->GetHitRatio();
    }
    return 0.0;
}
Example #3
0
/*virtual*/
VtValue
UsdMayaGLBatchRenderer::TaskDelegate::Get(
    SdfPath const& id,
    TfToken const &key)
{
    _ValueCache *vcache = TfMapLookupPtr(_valueCacheMap, id);
    VtValue ret;
    if( vcache && TfMapLookup(*vcache, key, &ret) )
        return ret;

    TF_CODING_ERROR("%s:%s doesn't exist in the value cache\n",
                    id.GetText(), key.GetText());
    return VtValue();
}
Example #4
0
void
HdRenderIndex::InsertRprim(TfToken const& typeId,
                 HdSceneDelegate* sceneDelegate,
                 SdfPath const& rprimId,
                 SdfPath const& instancerId /*= SdfPath()*/)
{
    HD_TRACE_FUNCTION();
    HF_MALLOC_TAG_FUNCTION();

    if (ARCH_UNLIKELY(TfMapLookupPtr(_rprimMap, rprimId))) {
        return;
    }

    SdfPath const &sceneDelegateId = sceneDelegate->GetDelegateID();
    if (!rprimId.HasPrefix(sceneDelegateId)) {
        TF_CODING_ERROR("Scene Delegate Id (%s) must prefix prim Id (%s)",
                        sceneDelegateId.GetText(), rprimId.GetText());
        return;
    }


    HdRprim *rprim = _renderDelegate->CreateRprim(typeId,
                                                  rprimId,
                                                  instancerId);
    if (rprim == nullptr) {
        return;
    }

    _rprimIds.Insert(rprimId);


    _tracker.RprimInserted(rprimId, rprim->GetInitialDirtyBitsMask());
    _AllocatePrimId(rprim);

    _RprimInfo info = {
      sceneDelegate,
      rprim
    };
    _rprimMap[rprimId] = std::move(info);

    SdfPath instanceId = rprim->GetInstancerId();

    if (!instanceId.IsEmpty()) {
        _tracker.InstancerRPrimInserted(instanceId, rprimId);
    }
}
Example #5
0
PXR_NAMESPACE_OPEN_SCOPE

// ---------------------------------------------------------------------------
// Delegate implementation.

/* virtual */
VtValue
HdStreamTaskController::_Delegate::Get(SdfPath const& id, TfToken const& key)
{
    _ValueCache *vcache = TfMapLookupPtr(_valueCacheMap, id);
    VtValue ret;
    if (vcache && TfMapLookup(*vcache, key, &ret)) {
        return ret;
    }
    TF_CODING_ERROR("%s:%s doesn't exist in the value cache\n",
            id.GetText(), key.GetText());
    return VtValue();
}
Example #6
0
/*virtual*/
bool
HdxSelectionTracker::GetBuffers(HdRenderIndex const* index,
                         VtIntArray* offsets) const
{
    TRACE_FUNCTION();
    TfAutoMallocTag2 tag("Hdx", "HdxSelection::GetBuffers");

    // XXX: Set minimum size for UBO/SSBO requirements. Seems like this should
    // be handled by Hydra. Update all uses of minSize below when resolved.
    const int minSize = 8;
    size_t numPrims = _selection ? _selection->selectedPrims.size() : 0;
    if (numPrims == 0) {
        TF_DEBUG(HDX_SELECTION_SETUP).Msg("No selected prims\n");
        offsets->resize(minSize);
        return false;
    }

    // Note that numeric_limits<float>::min for is surprising, so using lowest()
    // here instead. Doing this for <int> here to avoid copy and paste bugs.
    int min = std::numeric_limits<int>::max(),
        max = std::numeric_limits<int>::lowest();

    std::vector<int> ids;
    ids.resize(numPrims);

    size_t const N = 1000;
    int const INVALID = -1;
    WorkParallelForN(numPrims/N + 1,
       [&ids, &index, this](size_t begin, size_t end) mutable {
        end = std::min(end*N, ids.size());
        begin = begin*N;
        for (size_t i = begin; i < end; i++) {
            if (auto const& rprim = index->GetRprim(_selection->selectedPrims[i])) {
                ids[i] = rprim->GetPrimId();
            } else {
                // silently ignore non-existing prim
                ids[i] = INVALID;
            }
        }
    });

    for (int id : ids) {
        if (id == INVALID) continue;
        min = std::min(id, min);
        max = std::max(id, max);
    }

    if (max < min) {
        offsets->resize(minSize);
        return false;
    }

    // ---------------------------------------------------------------------- //
    // Buffer Layout
    // ---------------------------------------------------------------------- //
    // In the folowing code, we want to build up a buffer that is capable of
    // driving selection highlighting. To do this, we leverage the fact that all
    // shaders have access to the drawing coord, namely the ObjectID,
    // InstanceID, FaceID, VertexID, etc. The idea is to take one such ID and
    // compare it against a range of known selected values within a given range.
    //
    // For example, imaging the ObjectID is 6, then we can know this object is
    // selected if ID 6 is in the range of selected objects. We then
    // hierarchically re-apply this scheme for instances and faces. The buffer
    // layout is as follows:
    //
    // Object: [ start index | end index | (offset to next level per object) ]
    //
    // So to test if a given object ID is selected, we check if the ID is in the
    // range [start,end), if so, the object's offset in the buffer is ID-start.
    // 
    // The value for an object is one of three cases:
    //
    //  0 - indicates the object is not selected
    //  1 - indicates the object is fully selected
    //  N - an offset to the next level of the hierarchy
    //
    // The structure described above for objects is also applied for each level
    // of instancing as well as for faces. All data is aggregated into a single
    // buffer with the following layout:
    //
    // [ object | element | instance level-N | ... | level 0 ]
    //  
    //  Each section above is prefixed with [start,end) ranges and the values of
    //  each range follow the three cases outlined.
    //
    //  To see these values built incrementally, enable the TF_DEBUG flag
    //  HDX_SELECTION_SETUP.
    // ---------------------------------------------------------------------- //

    // Start with individual arrays. Splice arrays once finished.
    int const SELECT_ALL = 1;
    int const SELECT_NONE = 0;

    _DebugPrintArray("ids", ids);

    std::vector<int> output;
    output.insert(output.end(), 2+1+max-min, SELECT_NONE);
    output[0] = min;
    output[1] = max+1;

    // XXX: currently, _selectedPrims may have duplicated entries
    // (e.g. to instances and to faces) for an objPath.
    // this would cause unreferenced offset buffer allocated in the
    // result buffer.

    _DebugPrintArray("objects", output);

    for (size_t primIndex = 0; primIndex < ids.size(); primIndex++) {
        // TODO: store ID and path in "ids" vector
        SdfPath const& objPath = _selection->selectedPrims[primIndex];
        int id = ids[primIndex];
        if (id == INVALID) continue;

        TF_DEBUG(HDX_SELECTION_SETUP).Msg("Processing: %d - %s\n",
                id, objPath.GetText());

        // ------------------------------------------------------------------ //
        // Elements
        // ------------------------------------------------------------------ //
        // Find element sizes, for this object.
        int elemOffset = output.size();
        if (VtIntArray const *faceIndices
            = TfMapLookupPtr(_selection->selectedFaces, objPath)) {
            if (faceIndices->size()) {
                int minElem = std::numeric_limits<int>::max();
                int maxElem = std::numeric_limits<int>::lowest();

                for (int const& elemId : *faceIndices) {
                    minElem = std::min(minElem, elemId);
                    maxElem = std::max(maxElem, elemId);
                }

                // Grow the element array to hold elements for this object.
                output.insert(output.end(), maxElem-minElem+1+2, SELECT_NONE);
                output[elemOffset+0] = minElem;
                output[elemOffset+1] = maxElem+1;

                for (int elemId : *faceIndices) {
                    // TODO: Add support for edge and point selection.
                    output[2+elemOffset+ (elemId-minElem)] = SELECT_ALL;
                }
                _DebugPrintArray("elements", output);
            } else {
                // Entire object/instance is selected
                elemOffset = SELECT_ALL;
            }
        } else {
            // Entire object/instance is selected
            elemOffset = SELECT_ALL;
        }

        // ------------------------------------------------------------------ //
        // Instances
        // ------------------------------------------------------------------ //
        // Initialize prevLevel to elemOffset which removes a special case in
        // the loops below.
        int prevLevelOffset = elemOffset;
        if (std::vector<VtIntArray> const * a =
            TfMapLookupPtr(_selection->selectedInstances, objPath)) {
            // Different instances can have different number of levels.
            int numLevels = std::numeric_limits<int>::max();
            size_t numInst= a->size();
            if (numInst == 0) {
                numLevels = 0;
            } else {
                for (size_t instNum = 0; instNum < numInst; ++instNum) {
                    size_t levelsForInst = a->at(instNum).size();
                    numLevels = std::min(numLevels,
                                         static_cast<int>(levelsForInst));
                }
            }

            TF_DEBUG(HDX_SELECTION_SETUP).Msg("NumLevels: %d\n", numLevels);
            if (numLevels == 0) {
                output[id-min+2] = elemOffset;
            }
            for (int level = 0; level < numLevels; ++level) {
                // Find the required size of the instance vectors.
                int levelMin = std::numeric_limits<int>::max();
                int levelMax = std::numeric_limits<int>::lowest();
                for (VtIntArray const &instVec : *a) {
                    _DebugPrintArray("\tinstVec", instVec, false);
                    int instId = instVec[level];
                    levelMin = std::min(levelMin, instId);
                    levelMax = std::max(levelMax, instId);
                }

                TF_DEBUG(HDX_SELECTION_SETUP).Msg(
                    "level-%d: min(%d) max(%d)\n",
                    level, levelMin, levelMax);

                int objLevelSize = levelMax - levelMin +2+1;
                int levelOffset = output.size();
                output.insert(output.end(), objLevelSize, SELECT_NONE);
                output[levelOffset + 0] = levelMin;
                output[levelOffset + 1] = levelMax + 1;
                for (VtIntArray const& instVec : *a) {
                    int instId = instVec[level] - levelMin+2;
                    output[levelOffset+instId] = prevLevelOffset; 
                }

                if (level == numLevels-1) {
                    output[id-min+2] = levelOffset;
                }

                if (ARCH_UNLIKELY(TfDebug::IsEnabled(HDX_SELECTION_SETUP))){
                    std::stringstream name;
                    name << "level[" << level << "]";
                    _DebugPrintArray(name.str(), output);
                }
                prevLevelOffset = levelOffset;
            }
        } else {
            output[id-min+2] = elemOffset;
        }
    }
    _DebugPrintArray("final output", output);
    offsets->resize(output.size());
    for (size_t i = 0; i < output.size(); i++) {
        (*offsets)[i] = output[i];
    }
    _DebugPrintArray("final output", *offsets);

    return true;
}
Example #7
0
const HdxIntersector::Hit * 
UsdMayaGLBatchRenderer::_GetHitInfo(
    M3dView& view,
    unsigned int pickResolution,
    bool singleSelection,
    const SdfPath& sharedId,
    const GfMatrix4d &localToWorldSpace)
{
    // Guard against user clicking in viewer before renderer is setup
    if( !_renderIndex )
        return NULL;

    // Selection only occurs once per display refresh, with all usd objects
    // simulataneously. If the selectQueue is not empty, that means that
    // a refresh has occurred, and we need to perform a new selection operation.
    
    if( !_selectQueue.empty() )
    {
        TF_DEBUG(PXRUSDMAYAGL_QUEUE_INFO).Msg(
            "____________ SELECTION STAGE START ______________ (singleSelect = %d)\n",
            singleSelection );

        GfMatrix4d viewMatrix;
        GfMatrix4d projectionMatrix;
        px_LegacyViewportUtils::GetViewSelectionMatrices(view,
                                                         &viewMatrix,
                                                         &projectionMatrix);

        // As Maya doesn't support batched selection, intersection testing is
        // actually performed in the first selection query that happens after a
        // render. This query occurs in the local space of SOME object, but
        // we need results in world space so that we have results for every
        // node available. worldToLocalSpace removes the local space we
        // happen to be in for the initial query.
        GfMatrix4d worldToLocalSpace(localToWorldSpace.GetInverse());

        _intersector->SetResolution(GfVec2i(pickResolution, pickResolution));
        
        HdxIntersector::Params qparams;
        qparams.viewMatrix = worldToLocalSpace * viewMatrix;
        qparams.projectionMatrix = projectionMatrix;
        qparams.alphaThreshold = 0.1;
        
        _selectResults.clear();

        for( const auto &renderSetIter : _selectQueue )
        {
            const RenderParams &renderParams = renderSetIter.second.first;
            const _SdfPathSet &renderPaths = renderSetIter.second.second;
            SdfPathVector roots(renderPaths.begin(), renderPaths.end());
            
            TF_DEBUG(PXRUSDMAYAGL_QUEUE_INFO).Msg(
                    "--- pickQueue, batch %zx, size %zu\n",
                    renderSetIter.first, renderPaths.size());
            
            TfToken colName = renderParams.geometryCol;
            HdRprimCollection rprims(colName, renderParams.drawRepr);
            rprims.SetRootPaths(roots);
            rprims.SetRenderTags(renderParams.renderTags);

            qparams.cullStyle = renderParams.cullStyle;
            qparams.renderTags = renderParams.renderTags;

            HdxIntersector::Result result;
            HdxIntersector::HitVector hits;

            glPushAttrib(GL_VIEWPORT_BIT |
                         GL_ENABLE_BIT |
                         GL_COLOR_BUFFER_BIT |
                         GL_DEPTH_BUFFER_BIT |
                         GL_STENCIL_BUFFER_BIT |
                         GL_TEXTURE_BIT |
                         GL_POLYGON_BIT);
            bool r = _intersector->Query(qparams, rprims, &_hdEngine, &result);
            glPopAttrib();
            if( !r ) {
                continue;
            }
            
            if( singleSelection )
            {
                hits.resize(1);
                if( !result.ResolveNearest(&hits.front()) )
                    continue;
            }
            else if( !result.ResolveAll(&hits) )
            {
                continue;
            }

            for (const HdxIntersector::Hit& hit : hits) {
                auto itIfExists =
                    _selectResults.insert(
                        std::pair<SdfPath, HdxIntersector::Hit>(hit.delegateId, hit));
                
                const bool &inserted = itIfExists.second;
                if( inserted )
                    continue;
                                
                HdxIntersector::Hit& existingHit = itIfExists.first->second;
                if( hit.ndcDepth < existingHit.ndcDepth )
                    existingHit = hit;
            }
        }
        
        if( singleSelection && _selectResults.size()>1 )
        {
            TF_DEBUG(PXRUSDMAYAGL_QUEUE_INFO).Msg(
                    "!!! multiple singleSel hits found: %zu\n",
                    _selectResults.size());
            
            auto minIt=_selectResults.begin();
            for( auto curIt=minIt; curIt!=_selectResults.end(); curIt++ )
            {
                const HdxIntersector::Hit& curHit = curIt->second;
                const HdxIntersector::Hit& minHit = minIt->second;
                if( curHit.ndcDepth < minHit.ndcDepth )
                    minIt = curIt;
            }
            
            if( minIt!=_selectResults.begin() )
                _selectResults.erase(_selectResults.begin(),minIt);
            minIt++;
            if( minIt!=_selectResults.end() )
                _selectResults.erase(minIt,_selectResults.end());
        }
        
        if( TfDebug::IsEnabled(PXRUSDMAYAGL_QUEUE_INFO) )
        {
            for ( const auto &selectPair : _selectResults)
            {
                const SdfPath& path = selectPair.first;
                const HdxIntersector::Hit& hit = selectPair.second;
                cout << "NEW HIT: " << path << endl;
                cout << "\tdelegateId: " << hit.delegateId << endl;
                cout << "\tobjectId: " << hit.objectId << endl;
                cout << "\tndcDepth: " << hit.ndcDepth << endl;
            }
        }
        
        // As we've cached the results in pickBatches, we
        // can clear out the selection queue.
        _selectQueue.clear();

        // Selection can happen after a refresh but before a draw call, so
        // clear out the render queue as well
        _renderQueue.clear();

        // If nothing was selected, the view does not refresh, but this
        // means _selectQueue will not get processed again even if the
        // user attempts another selection. We fix the renderer state by
        // scheduling another refresh when the view is next idle.
        
        if( _selectResults.empty() )
            view.scheduleRefresh();
        
        TF_DEBUG(PXRUSDMAYAGL_QUEUE_INFO).Msg(
            "^^^^^^^^^^^^ SELECTION STAGE FINISH ^^^^^^^^^^^^^\n");
    }
    
    return TfMapLookupPtr( _selectResults, sharedId );
}