// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #include "pxr/pxr.h" #include "pxr/usd/pcp/layerPrefetchRequest.h" #include "pxr/usd/pcp/layerStackRegistry.h" #include "pxr/usd/sdf/layerUtils.h" #include "pxr/base/work/arenaDispatcher.h" #include "pxr/base/work/threadLimits.h" #include PXR_NAMESPACE_OPEN_SCOPE namespace { struct _Opener { explicit _Opener(const Pcp_MutedLayers& mutedLayers, std::set *retainedLayers) : _mutedLayers(mutedLayers) , _retainedLayers(retainedLayers) {} ~_Opener() { _dispatcher.Wait(); } void OpenSublayers(const SdfLayerRefPtr &layer, const SdfLayer::FileFormatArguments &layerArgs) { TF_FOR_ALL(path, layer->GetSubLayerPaths()) { _dispatcher.Run( &_Opener::_OpenSublayer, this, *path, layer, layerArgs); } } private: void _OpenSublayer(std::string path, const SdfLayerRefPtr &anchorLayer, const SdfLayer::FileFormatArguments &layerArgs) { if (_mutedLayers.IsLayerMuted(anchorLayer, path)) { return; } // Open this specific sublayer path. // The call to SdfFindOrOpenRelativeToLayer() may take some time, // potentially multiple seconds. if (SdfLayerRefPtr sublayer = SdfFindOrOpenRelativeToLayer(anchorLayer, &path, layerArgs)) { // Retain this sublayer. bool didInsert; { tbb::spin_mutex::scoped_lock lock(_retainedLayersMutex); didInsert = _retainedLayers->insert(sublayer).second; } // Open the nested sublayers. Only do this if we haven't seen this // layer before, i.e. didInsert is true. if (didInsert) OpenSublayers(sublayer, layerArgs); } } WorkArenaDispatcher _dispatcher; const Pcp_MutedLayers& _mutedLayers; std::set *_retainedLayers; mutable tbb::spin_mutex _retainedLayersMutex; }; } // anon void PcpLayerPrefetchRequest::RequestSublayerStack( const SdfLayerRefPtr &layer, const SdfLayer::FileFormatArguments &args) { _sublayerRequests.insert(std::make_pair(layer, args)); } void PcpLayerPrefetchRequest::Run(const Pcp_MutedLayers& mutedLayers) { if (WorkGetConcurrencyLimit() <= 1) { // Do not bother pre-fetching if we do not have extra threads // available. return; } // Release the GIL so we don't deadlock when Sd tries to get a path // resolver (which does ref-counting on the resolver, which requires // the GIL to manage TfRefBase identity-uniqueness). TF_PY_ALLOW_THREADS_IN_SCOPE(); std::set<_Request> requests; requests.swap(_sublayerRequests); // Open all the sublayers in the request. _Opener opener(mutedLayers, &_retainedLayers); TF_FOR_ALL(req, requests) opener.OpenSublayers(req->first, req->second); } PXR_NAMESPACE_CLOSE_SCOPE