1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "GLcommon/ObjectNameSpace.h"
18
19 #include "base/Lock.h"
20 #include "base/Lookup.h"
21 #include "base/PathUtils.h"
22 #include "base/StreamSerializing.h"
23 #include "snapshot/TextureLoader.h"
24 #include "snapshot/TextureSaver.h"
25 #include "host-common/crash_reporter.h"
26 #include "GLcommon/GLEScontext.h"
27 #include "GLcommon/TranslatorIfaces.h"
28
29 #include <assert.h>
30
31 #define GL_LOG(...)
32
33 using android::snapshot::ITextureSaver;
34 using android::snapshot::ITextureLoader;
35 using android::snapshot::ITextureSaverPtr;
36 using android::snapshot::ITextureLoaderPtr;
37 using android::snapshot::ITextureLoaderWPtr;
38
NameSpace(NamedObjectType p_type,GlobalNameSpace * globalNameSpace,android::base::Stream * stream,const ObjectData::loadObject_t & loadObject)39 NameSpace::NameSpace(NamedObjectType p_type, GlobalNameSpace *globalNameSpace,
40 android::base::Stream* stream, const ObjectData::loadObject_t& loadObject) :
41 m_type(p_type),
42 m_globalNameSpace(globalNameSpace) {
43 if (!stream) return;
44 // When loading from a snapshot, we restores translator states here, but
45 // host GPU states are not touched until postLoadRestore is called.
46 // GlobalNames are not yet generated.
47 size_t objSize = stream->getBe32();
48 for (size_t obj = 0; obj < objSize; obj++) {
49 ObjectLocalName localName = stream->getBe64();
50 ObjectDataPtr data = loadObject((NamedObjectType)m_type,
51 localName, stream);
52 if (m_type == NamedObjectType::TEXTURE) {
53 // Texture data are managed differently
54 // They are loaded by GlobalNameSpace before loading
55 // share groups
56 TextureData* texData = (TextureData*)data.get();
57 if (!texData->getGlobalName()) {
58 GL_LOG("NameSpace::%s: %p: texture data %p is 0 texture\n",
59 __func__, this, texData);
60 continue;
61 }
62
63 SaveableTexturePtr saveableTexture =
64 globalNameSpace->getSaveableTextureFromLoad(
65 texData->getGlobalName());
66 texData->setSaveableTexture(std::move(saveableTexture));
67 texData->setGlobalName(0);
68 }
69 setObjectData(localName, std::move(data));
70 }
71 }
72
~NameSpace()73 NameSpace::~NameSpace() {
74 }
75
postLoad(const ObjectData::getObjDataPtr_t & getObjDataPtr)76 void NameSpace::postLoad(const ObjectData::getObjDataPtr_t& getObjDataPtr) {
77 for (const auto& objData : m_objectDataMap) {
78 GL_LOG("NameSpace::%s: %p: try to load object %llu\n", __func__, this, objData.first);
79 if (!objData.second) {
80 // bug: 130631787
81 // emugl::emugl_crash_reporter(
82 // "Fatal: null object data ptr on restore\n");
83 continue;
84 }
85 objData.second->postLoad(getObjDataPtr);
86 }
87 }
88
touchTextures()89 void NameSpace::touchTextures() {
90 assert(m_type == NamedObjectType::TEXTURE);
91 for (const auto& obj : m_objectDataMap) {
92 TextureData* texData = (TextureData*)obj.second.get();
93 if (!texData->needRestore()) {
94 GL_LOG("NameSpace::%s: %p: texture data %p does not need restore\n",
95 __func__, this, texData);
96 continue;
97 }
98 const SaveableTexturePtr& saveableTexture = texData->getSaveableTexture();
99 if (!saveableTexture.get()) {
100 GL_LOG("NameSpace::%s: %p: warning: no saveableTexture for texture data %p\n",
101 __func__, this, texData);
102 continue;
103 }
104
105 NamedObjectPtr texNamedObj = saveableTexture->getGlobalObject();
106 if (!texNamedObj) {
107 GL_LOG("NameSpace::%s: %p: fatal: global object null for texture data %p\n",
108 __func__, this, texData);
109 emugl_crash_reporter(
110 "fatal: null global texture object in "
111 "NameSpace::touchTextures");
112 }
113 setGlobalObject(obj.first, texNamedObj);
114 texData->setGlobalName(texNamedObj->getGlobalName());
115 texData->restore(0, nullptr);
116 }
117 }
118
postLoadRestore(const ObjectData::getGlobalName_t & getGlobalName)119 void NameSpace::postLoadRestore(const ObjectData::getGlobalName_t& getGlobalName) {
120 // Texture data are special, they got the global name from SaveableTexture
121 // This is because texture data can be shared across multiple share groups
122 if (m_type == NamedObjectType::TEXTURE) {
123 touchTextures();
124 return;
125 }
126 // 2 passes are needed for SHADER_OR_PROGRAM type, because (1) they
127 // live in the same namespace (2) shaders must be created before
128 // programs.
129 int numPasses = m_type == NamedObjectType::SHADER_OR_PROGRAM
130 ? 2 : 1;
131 for (int pass = 0; pass < numPasses; pass ++) {
132 for (const auto& obj : m_objectDataMap) {
133 assert(m_type == ObjectDataType2NamedObjectType(
134 obj.second->getDataType()));
135 // get global names
136 if ((obj.second->getDataType() == PROGRAM_DATA && pass == 0)
137 || (obj.second->getDataType() == SHADER_DATA &&
138 pass == 1)) {
139 continue;
140 }
141 genName(obj.second->getGenNameInfo(), obj.first, false);
142 obj.second->restore(obj.first, getGlobalName);
143 }
144 }
145 }
146
preSave(GlobalNameSpace * globalNameSpace)147 void NameSpace::preSave(GlobalNameSpace *globalNameSpace) {
148 if (m_type != NamedObjectType::TEXTURE) {
149 return;
150 }
151 // In case we loaded textures from a previous snapshot and have not yet
152 // restore them to GPU, we do the restoration here.
153 // TODO: skip restoration and write saveableTexture directly to the new
154 // snapshot
155 touchTextures();
156 for (const auto& obj : m_objectDataMap) {
157 globalNameSpace->preSaveAddTex((TextureData*)obj.second.get());
158 }
159 }
160
onSave(android::base::Stream * stream)161 void NameSpace::onSave(android::base::Stream* stream) {
162 stream->putBe32(m_objectDataMap.size());
163 for (const auto& obj : m_objectDataMap) {
164 stream->putBe64(obj.first);
165 obj.second->onSave(stream, getGlobalName(obj.first));
166 }
167 }
168
169 static ObjectDataPtr* nullObjectData = new ObjectDataPtr;
170 static NamedObjectPtr* nullNamedObject = new NamedObjectPtr;
171
172 ObjectLocalName
genName(GenNameInfo genNameInfo,ObjectLocalName p_localName,bool genLocal)173 NameSpace::genName(GenNameInfo genNameInfo, ObjectLocalName p_localName, bool genLocal)
174 {
175 assert(m_type == genNameInfo.m_type);
176 ObjectLocalName localName = p_localName;
177 if (genLocal) {
178 do {
179 localName = ++m_nextName;
180 } while(localName == 0 ||
181 nullptr != m_localToGlobalMap.getExceptZero_const(localName));
182 }
183
184 auto newObjPtr = NamedObjectPtr( new NamedObject(genNameInfo, m_globalNameSpace));
185 m_localToGlobalMap.add(localName, newObjPtr);
186
187 unsigned int globalName = newObjPtr->getGlobalName();
188 m_globalToLocalMap.add(globalName, localName);
189 return localName;
190 }
191
192
193 unsigned int
getGlobalName(ObjectLocalName p_localName,bool * found)194 NameSpace::getGlobalName(ObjectLocalName p_localName, bool* found)
195 {
196 auto objPtrPtr = m_localToGlobalMap.getExceptZero_const(p_localName);
197
198 if (!objPtrPtr) {
199 if (found) *found = false;
200 return 0;
201 }
202
203 if (found) *found = true;
204 auto res = (*objPtrPtr)->getGlobalName();
205 return res;
206 }
207
208 ObjectLocalName
getLocalName(unsigned int p_globalName)209 NameSpace::getLocalName(unsigned int p_globalName)
210 {
211 auto localPtr = m_globalToLocalMap.get_const(p_globalName);
212 if (!localPtr) return 0;
213 return *localPtr;
214 }
215
getNamedObject(ObjectLocalName p_localName)216 NamedObjectPtr NameSpace::getNamedObject(ObjectLocalName p_localName) {
217 auto objPtrPtr = m_localToGlobalMap.get_const(p_localName);
218 if (!objPtrPtr || !(*objPtrPtr)) return nullptr;
219 return *objPtrPtr;
220 }
221
222 void
deleteName(ObjectLocalName p_localName)223 NameSpace::deleteName(ObjectLocalName p_localName)
224 {
225 auto objPtrPtr = m_localToGlobalMap.getExceptZero(p_localName);
226 if (objPtrPtr) {
227 m_globalToLocalMap.remove((*objPtrPtr)->getGlobalName());
228 *objPtrPtr = *nullNamedObject;
229 m_localToGlobalMap.remove(p_localName);
230 }
231
232 m_objectDataMap.erase(p_localName);
233 m_boundMap.remove(p_localName);
234 }
235
236 bool
isObject(ObjectLocalName p_localName)237 NameSpace::isObject(ObjectLocalName p_localName)
238 {
239 auto objPtrPtr = m_localToGlobalMap.getExceptZero_const(p_localName);
240 return nullptr != objPtrPtr;
241 }
242
243 void
setGlobalObject(ObjectLocalName p_localName,NamedObjectPtr p_namedObject)244 NameSpace::setGlobalObject(ObjectLocalName p_localName,
245 NamedObjectPtr p_namedObject) {
246
247 auto objPtrPtr = m_localToGlobalMap.getExceptZero(p_localName);
248 if (objPtrPtr) {
249 m_globalToLocalMap.remove((*objPtrPtr)->getGlobalName());
250 *objPtrPtr = p_namedObject;
251 } else {
252 m_localToGlobalMap.add(p_localName, p_namedObject);
253 }
254
255 m_globalToLocalMap.add(p_namedObject->getGlobalName(), p_localName);
256 }
257
258 void
replaceGlobalObject(ObjectLocalName p_localName,NamedObjectPtr p_namedObject)259 NameSpace::replaceGlobalObject(ObjectLocalName p_localName,
260 NamedObjectPtr p_namedObject)
261 {
262 auto objPtrPtr = m_localToGlobalMap.getExceptZero(p_localName);
263 if (objPtrPtr) {
264 m_globalToLocalMap.remove((*objPtrPtr)->getGlobalName());
265 *objPtrPtr = p_namedObject;
266 m_globalToLocalMap.add(p_namedObject->getGlobalName(), p_localName);
267 }
268 }
269
270 // sets that the local name has been bound at least once, to save time later
setBoundAtLeastOnce(ObjectLocalName p_localName)271 void NameSpace::setBoundAtLeastOnce(ObjectLocalName p_localName) {
272 m_boundMap.add(p_localName, true);
273 }
274
275 // sets that the local name has been bound at least once, to save time later
everBound(ObjectLocalName p_localName) const276 bool NameSpace::everBound(ObjectLocalName p_localName) const {
277 const bool* boundPtr = m_boundMap.get_const(p_localName);
278 if (!boundPtr) return false;
279 return *boundPtr;
280 }
281
objDataMapBegin() const282 ObjectDataMap::const_iterator NameSpace::objDataMapBegin() const {
283 return m_objectDataMap.begin();
284 }
285
objDataMapEnd() const286 ObjectDataMap::const_iterator NameSpace::objDataMapEnd() const {
287 return m_objectDataMap.end();
288 }
289
getObjectDataPtr(ObjectLocalName p_localName)290 const ObjectDataPtr& NameSpace::getObjectDataPtr(
291 ObjectLocalName p_localName) {
292 const auto it = m_objectDataMap.find(p_localName);
293 if (it != m_objectDataMap.end()) {
294 return it->second;
295 }
296 return *nullObjectData;
297 }
298
setObjectData(ObjectLocalName p_localName,ObjectDataPtr data)299 void NameSpace::setObjectData(ObjectLocalName p_localName,
300 ObjectDataPtr data) {
301 m_objectDataMap[p_localName] = std::move(data);
302 }
303
preSaveAddEglImage(EglImage * eglImage)304 void GlobalNameSpace::preSaveAddEglImage(EglImage* eglImage) {
305 if (!eglImage->globalTexObj) {
306 GL_LOG("GlobalNameSpace::%s: %p: egl image %p with null texture object\n",
307 __func__, this, eglImage);
308 emugl_crash_reporter(
309 "Fatal: egl image with null texture object\n");
310 }
311 unsigned int globalName = eglImage->globalTexObj->getGlobalName();
312 android::base::AutoLock lock(m_lock);
313
314 if (!globalName) {
315 GL_LOG("GlobalNameSpace::%s: %p: egl image %p has 0 texture object\n",
316 __func__, this, eglImage);
317 return;
318 }
319
320 const auto& saveableTexIt = m_textureMap.find(globalName);
321 if (saveableTexIt == m_textureMap.end()) {
322 assert(eglImage->saveableTexture);
323 m_textureMap.emplace(globalName, eglImage->saveableTexture);
324 } else {
325 assert(m_textureMap[globalName] == eglImage->saveableTexture);
326 }
327 }
328
preSaveAddTex(TextureData * texture)329 void GlobalNameSpace::preSaveAddTex(TextureData* texture) {
330 android::base::AutoLock lock(m_lock);
331 const auto& saveableTexIt = m_textureMap.find(texture->getGlobalName());
332
333 if (!texture->getGlobalName()) {
334 GL_LOG("GlobalNameSpace::%s: %p: texture data %p is 0 texture\n",
335 __func__, this, texture);
336 return;
337 }
338
339 if (saveableTexIt == m_textureMap.end()) {
340 assert(texture->getSaveableTexture());
341 m_textureMap.emplace(texture->getGlobalName(),
342 texture->getSaveableTexture());
343 } else {
344 assert(m_textureMap[texture->getGlobalName()] ==
345 texture->getSaveableTexture());
346 }
347 }
348
onSave(android::base::Stream * stream,const ITextureSaverPtr & textureSaver,SaveableTexture::saver_t saver)349 void GlobalNameSpace::onSave(android::base::Stream* stream,
350 const ITextureSaverPtr& textureSaver,
351 SaveableTexture::saver_t saver) {
352 #if SNAPSHOT_PROFILE > 1
353 int cleanTexs = 0;
354 int dirtyTexs = 0;
355 #endif // SNAPSHOT_PROFILE > 1
356 saveCollection(
357 stream, m_textureMap,
358 [saver, &textureSaver
359 #if SNAPSHOT_PROFILE > 1
360 , &cleanTexs, &dirtyTexs
361 #endif // SNAPSHOT_PROFILE > 1
362 ](
363 android::base::Stream* stream,
364 const std::pair<const unsigned int, SaveableTexturePtr>&
365 tex) {
366 stream->putBe32(tex.first);
367 #if SNAPSHOT_PROFILE > 1
368 if (tex.second.get() && tex.second->isDirty()) {
369 dirtyTexs ++;
370 } else {
371 cleanTexs ++;
372 }
373 #endif // SNAPSHOT_PROFILE > 1
374 textureSaver->saveTexture(
375 tex.first,
376 [saver, &tex](android::base::Stream* stream,
377 ITextureSaver::Buffer* buffer) {
378 if (!tex.second.get()) return;
379 saver(tex.second.get(), stream, buffer);
380 });
381 });
382 clearTextureMap();
383 #if SNAPSHOT_PROFILE > 1
384 printf("Dirty texture saved %d, clean texture saved %d\n",
385 dirtyTexs, cleanTexs);
386 #endif // SNAPSHOT_PROFILE > 1
387 }
388
onLoad(android::base::Stream * stream,const ITextureLoaderWPtr & textureLoaderWPtr,SaveableTexture::creator_t creator)389 void GlobalNameSpace::onLoad(android::base::Stream* stream,
390 const ITextureLoaderWPtr& textureLoaderWPtr,
391 SaveableTexture::creator_t creator) {
392 const ITextureLoaderPtr textureLoader = textureLoaderWPtr.lock();
393 assert(m_textureMap.size() == 0);
394 if (!textureLoader->start()) {
395 fprintf(stderr,
396 "Error: texture file unsupported version or corrupted.\n");
397 emugl_crash_reporter(
398 "Error: texture file unsupported version or corrupted.\n");
399 return;
400 }
401 loadCollection(
402 stream, &m_textureMap,
403 [this, creator, textureLoaderWPtr](android::base::Stream* stream) {
404 unsigned int globalName = stream->getBe32();
405 // A lot of function wrapping happens here.
406 // When touched, saveableTexture triggers
407 // textureLoader->loadTexture, which sets up the file position
408 // and the mutex, and triggers saveableTexture->loadFromStream
409 // for the real loading.
410 SaveableTexture* saveableTexture = creator(
411 this, [globalName, textureLoaderWPtr](
412 SaveableTexture* saveableTexture) {
413 auto textureLoader = textureLoaderWPtr.lock();
414 if (!textureLoader) return;
415 textureLoader->loadTexture(
416 globalName,
417 [saveableTexture](
418 android::base::Stream* stream) {
419 saveableTexture->loadFromStream(stream);
420 });
421 });
422 return std::make_pair(globalName,
423 SaveableTexturePtr(saveableTexture));
424 });
425
426 m_backgroundLoader =
427 std::make_shared<GLBackgroundLoader>(
428 textureLoaderWPtr, *m_eglIface, *m_glesIface, m_textureMap);
429 textureLoader->acquireLoaderThread(m_backgroundLoader);
430 }
431
clearTextureMap()432 void GlobalNameSpace::clearTextureMap() {
433 decltype(m_textureMap)().swap(m_textureMap);
434 }
435
postLoad(android::base::Stream * stream)436 void GlobalNameSpace::postLoad(android::base::Stream* stream) {
437 m_backgroundLoader->start();
438 m_backgroundLoader.reset(); // leave it to TextureLoader
439 }
440
getSaveableTextureFromLoad(unsigned int oldGlobalName)441 const SaveableTexturePtr& GlobalNameSpace::getSaveableTextureFromLoad(
442 unsigned int oldGlobalName) {
443 assert(m_textureMap.count(oldGlobalName));
444 return m_textureMap[oldGlobalName];
445 }
446