1 //
2 // Copyright 2020 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "pxr/imaging/hgiGL/garbageCollector.h"
25 #include "pxr/imaging/hgiGL/hgi.h"
26 
27 #include "pxr/base/arch/hints.h"
28 #include "pxr/base/tf/diagnostic.h"
29 
30 
31 PXR_NAMESPACE_OPEN_SCOPE
32 
33 std::vector<HgiBufferHandleVector*>
34     HgiGLGarbageCollector::_bufferList;
35 std::vector<HgiTextureHandleVector*>
36     HgiGLGarbageCollector::_textureList;
37 std::vector<HgiSamplerHandleVector*>
38     HgiGLGarbageCollector::_samplerList;
39 std::vector<HgiShaderFunctionHandleVector*>
40     HgiGLGarbageCollector::_shaderFunctionList;
41 std::vector<HgiShaderProgramHandleVector*>
42     HgiGLGarbageCollector::_shaderProgramList;
43 std::vector<HgiResourceBindingsHandleVector*>
44     HgiGLGarbageCollector::_resourceBindingsList;
45 std::vector<HgiGraphicsPipelineHandleVector*>
46     HgiGLGarbageCollector::_graphicsPipelineList;
47 std::vector<HgiComputePipelineHandleVector*>
48     HgiGLGarbageCollector::_computePipelineList;
49 
50 
51 template<class T>
_EmptyTrash(std::vector<std::vector<HgiHandle<T>> * > * list)52 static void _EmptyTrash(std::vector<std::vector<HgiHandle<T>>*>* list) {
53     for (auto vec : *list) {
54         for (auto objectHandle : *vec) {
55             delete objectHandle.Get();
56         }
57         vec->clear();
58         vec->shrink_to_fit();
59     }
60 }
61 
HgiGLGarbageCollector(HgiGL * hgi)62 HgiGLGarbageCollector::HgiGLGarbageCollector(HgiGL* hgi)
63     : _hgi(hgi)
64     , _isDestroying(false)
65 {
66 }
67 
~HgiGLGarbageCollector()68 HgiGLGarbageCollector::~HgiGLGarbageCollector()
69 {
70     PerformGarbageCollection();
71 }
72 
73 /* Multi threaded */
74 HgiBufferHandleVector*
GetBufferList()75 HgiGLGarbageCollector::GetBufferList()
76 {
77     return _GetThreadLocalStorageList(&_bufferList);
78 }
79 
80 /* Multi threaded */
81 HgiTextureHandleVector*
GetTextureList()82 HgiGLGarbageCollector::GetTextureList()
83 {
84     return _GetThreadLocalStorageList(&_textureList);
85 }
86 
87 /* Multi threaded */
88 HgiSamplerHandleVector*
GetSamplerList()89 HgiGLGarbageCollector::GetSamplerList()
90 {
91     return _GetThreadLocalStorageList(&_samplerList);
92 }
93 
94 /* Multi threaded */
95 HgiShaderFunctionHandleVector*
GetShaderFunctionList()96 HgiGLGarbageCollector::GetShaderFunctionList()
97 {
98     return _GetThreadLocalStorageList(&_shaderFunctionList);
99 }
100 
101 /* Multi threaded */
102 HgiShaderProgramHandleVector*
GetShaderProgramList()103 HgiGLGarbageCollector::GetShaderProgramList()
104 {
105     return _GetThreadLocalStorageList(&_shaderProgramList);
106 }
107 
108 /* Multi threaded */
109 HgiResourceBindingsHandleVector*
GetResourceBindingsList()110 HgiGLGarbageCollector::GetResourceBindingsList()
111 {
112     return _GetThreadLocalStorageList(&_resourceBindingsList);
113 }
114 
115 /* Multi threaded */
116 HgiGraphicsPipelineHandleVector*
GetGraphicsPipelineList()117 HgiGLGarbageCollector::GetGraphicsPipelineList()
118 {
119     return _GetThreadLocalStorageList(&_graphicsPipelineList);
120 }
121 
122 /* Multi threaded */
123 HgiComputePipelineHandleVector*
GetComputePipelineList()124 HgiGLGarbageCollector::GetComputePipelineList()
125 {
126     return _GetThreadLocalStorageList(&_computePipelineList);
127 }
128 
129 /* Single threaded */
130 void
PerformGarbageCollection()131 HgiGLGarbageCollector::PerformGarbageCollection()
132 {
133     _isDestroying = true;
134 
135     _EmptyTrash(&_bufferList);
136     _EmptyTrash(&_textureList);
137     _EmptyTrash(&_samplerList);
138     _EmptyTrash(&_shaderFunctionList);
139     _EmptyTrash(&_shaderProgramList);
140     _EmptyTrash(&_resourceBindingsList);
141     _EmptyTrash(&_graphicsPipelineList);
142     _EmptyTrash(&_computePipelineList);
143 
144     _isDestroying = false;
145 }
146 
147 template<class T>
_GetThreadLocalStorageList(std::vector<T * > * collector)148 T* HgiGLGarbageCollector::_GetThreadLocalStorageList(std::vector<T*>* collector)
149 {
150     if (ARCH_UNLIKELY(_isDestroying)) {
151         TF_CODING_ERROR("Cannot destroy object during garbage collection ");
152         while(_isDestroying);
153     }
154 
155     // Only lock and create a new garbage vector if we dont have one in TLS.
156     // Using TLS means this we store per type T, not per T and Hgi instance.
157     // So if you call garbage collect on one Hgi, it destroys objects across
158     // all Hgi's. This should be ok since we only call the destructor of the
159     // garbage object.
160     thread_local T* _tls = nullptr;
161     static std::mutex garbageMutex;
162 
163     if (!_tls) {
164         _tls = new T();
165         std::lock_guard<std::mutex> guard(garbageMutex);
166         collector->push_back(_tls);
167     }
168     return _tls;
169 }
170 
171 
172 PXR_NAMESPACE_CLOSE_SCOPE
173