• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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/SaveableTexture.h"
18 
19 #include "aemu/base/ArraySize.h"
20 #include "aemu/base/containers/SmallVector.h"
21 #include "aemu/base/files/StreamSerializing.h"
22 #include "aemu/base/system/System.h"
23 
24 #include "GLcommon/GLEScontext.h"
25 #include "GLcommon/GLutils.h"
26 #include "GLcommon/TextureUtils.h"
27 
28 #include "host-common/crash_reporter.h"
29 #include "host-common/logging.h"
30 
31 #include <algorithm>
32 
33 #define SAVEABLE_TEXTURE_DEBUG 0
34 
35 #if SAVEABLE_TEXTURE_DEBUG
36 #define D(fmt,...) printf("%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
37 #else
38 #define D(fmt,...)
39 #endif
40 
41 // using android::base::ScopedMemoryProfiler;
42 // using android::base::LazyInstance;
43 // using android::base::MemoryProfiler;
44 // using android::base::StringView;
45 
46 static const GLenum kTexParam[] = {
47     GL_TEXTURE_MIN_FILTER,
48     GL_TEXTURE_MAG_FILTER,
49     GL_TEXTURE_WRAP_S,
50     GL_TEXTURE_WRAP_T,
51 };
52 
53 static const GLenum kTexParamGles3[] = {
54     GL_TEXTURE_BASE_LEVEL,
55     GL_TEXTURE_COMPARE_FUNC,
56     GL_TEXTURE_COMPARE_MODE,
57     GL_TEXTURE_MIN_LOD,
58     GL_TEXTURE_MAX_LOD,
59     GL_TEXTURE_MAX_LEVEL,
60     GL_TEXTURE_SWIZZLE_R,
61     GL_TEXTURE_SWIZZLE_G,
62     GL_TEXTURE_SWIZZLE_B,
63     GL_TEXTURE_SWIZZLE_A,
64     GL_TEXTURE_WRAP_R,
65 };
66 
s_texAlign(uint32_t v,uint32_t align)67 static uint32_t s_texAlign(uint32_t v, uint32_t align) {
68     uint32_t rem = v % align;
69     return rem ? (v + (align - rem)) : v;
70 }
71 
72 // s_computePixelSize is both in the host and the guest. Consider moving it to
73 // android-emugl/shared
74 
s_computePixelSize(GLenum format,GLenum type)75 static int s_computePixelSize(GLenum format, GLenum type) {
76 #define FORMAT_ERROR(format, type)                                         \
77     fprintf(stderr, "%s:%d unknown format/type 0x%x 0x%x\n", __FUNCTION__, \
78             __LINE__, format, type);
79 
80     switch (type) {
81         case GL_BYTE:
82             switch (format) {
83                 case GL_R8:
84                 case GL_R8I:
85                 case GL_R8_SNORM:
86                 case GL_RED:
87                     return 1;
88                 case GL_RED_INTEGER:
89                     return 1;
90                 case GL_RG8:
91                 case GL_RG8I:
92                 case GL_RG8_SNORM:
93                 case GL_RG:
94                     return 1 * 2;
95                 case GL_RG_INTEGER:
96                     return 1 * 2;
97                 case GL_RGB8:
98                 case GL_RGB8I:
99                 case GL_RGB8_SNORM:
100                 case GL_RGB:
101                     return 1 * 3;
102                 case GL_RGB_INTEGER:
103                     return 1 * 3;
104                 case GL_RGBA8:
105                 case GL_RGBA8I:
106                 case GL_RGBA8_SNORM:
107                 case GL_RGBA:
108                     return 1 * 4;
109                 case GL_RGBA_INTEGER:
110                     return 1 * 4;
111                 default:
112                     FORMAT_ERROR(format, type);
113             }
114             break;
115         case GL_UNSIGNED_BYTE:
116             switch (format) {
117                 case GL_R8:
118                 case GL_R8UI:
119                 case GL_RED:
120                     return 1;
121                 case GL_RED_INTEGER:
122                     return 1;
123                 case GL_ALPHA8_EXT:
124                 case GL_ALPHA:
125                     return 1;
126                 case GL_LUMINANCE8_EXT:
127                 case GL_LUMINANCE:
128                     return 1;
129                 case GL_LUMINANCE8_ALPHA8_EXT:
130                 case GL_LUMINANCE_ALPHA:
131                     return 1 * 2;
132                 case GL_RG8:
133                 case GL_RG8UI:
134                 case GL_RG:
135                     return 1 * 2;
136                 case GL_RG_INTEGER:
137                     return 1 * 2;
138                 case GL_RGB8:
139                 case GL_RGB8UI:
140                 case GL_SRGB8:
141                 case GL_RGB:
142                     return 1 * 3;
143                 case GL_RGB_INTEGER:
144                     return 1 * 3;
145                 case GL_RGBA8:
146                 case GL_RGBA8UI:
147                 case GL_SRGB8_ALPHA8:
148                 case GL_RGBA:
149                     return 1 * 4;
150                 case GL_RGBA_INTEGER:
151                     return 1 * 4;
152                 case GL_BGRA_EXT:
153                 case GL_BGRA8_EXT:
154                     return 1 * 4;
155                 default:
156                     FORMAT_ERROR(format, type);
157             }
158             break;
159         case GL_SHORT:
160             switch (format) {
161                 case GL_R16I:
162                 case GL_RED_INTEGER:
163                     return 2;
164                 case GL_RG16I:
165                 case GL_RG_INTEGER:
166                     return 2 * 2;
167                 case GL_RGB16I:
168                 case GL_RGB_INTEGER:
169                     return 2 * 3;
170                 case GL_RGBA16I:
171                 case GL_RGBA_INTEGER:
172                     return 2 * 4;
173                 default:
174                     FORMAT_ERROR(format, type);
175             }
176             break;
177         case GL_UNSIGNED_SHORT:
178             switch (format) {
179                 case GL_DEPTH_COMPONENT16:
180                 case GL_DEPTH_COMPONENT:
181                     return 2;
182                 case GL_R16UI:
183                 case GL_RED_INTEGER:
184                     return 2;
185                 case GL_RG16UI:
186                 case GL_RG_INTEGER:
187                     return 2 * 2;
188                 case GL_RGB16UI:
189                 case GL_RGB_INTEGER:
190                     return 2 * 3;
191                 case GL_RGBA16UI:
192                 case GL_RGBA_INTEGER:
193                     return 2 * 4;
194                 default:
195                     FORMAT_ERROR(format, type);
196             }
197             break;
198         case GL_INT:
199             switch (format) {
200                 case GL_R32I:
201                 case GL_RED_INTEGER:
202                     return 4;
203                 case GL_RG32I:
204                 case GL_RG_INTEGER:
205                     return 4 * 2;
206                 case GL_RGB32I:
207                 case GL_RGB_INTEGER:
208                     return 4 * 3;
209                 case GL_RGBA32I:
210                 case GL_RGBA_INTEGER:
211                     return 4 * 4;
212                 default:
213                     FORMAT_ERROR(format, type);
214             }
215             break;
216         case GL_UNSIGNED_INT:
217             switch (format) {
218                 case GL_DEPTH_COMPONENT16:
219                 case GL_DEPTH_COMPONENT24:
220                 case GL_DEPTH_COMPONENT32_OES:
221                 case GL_DEPTH_COMPONENT:
222                     return 4;
223                 case GL_R32UI:
224                 case GL_RED_INTEGER:
225                     return 4;
226                 case GL_RG32UI:
227                 case GL_RG_INTEGER:
228                     return 4 * 2;
229                 case GL_RGB32UI:
230                 case GL_RGB_INTEGER:
231                     return 4 * 3;
232                 case GL_RGBA32UI:
233                 case GL_RGBA_INTEGER:
234                     return 4 * 4;
235                 default:
236                     FORMAT_ERROR(format, type);
237             }
238             break;
239         case GL_UNSIGNED_SHORT_4_4_4_4:
240         case GL_UNSIGNED_SHORT_5_5_5_1:
241         case GL_UNSIGNED_SHORT_5_6_5:
242         case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
243         case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
244             return 2;
245         case GL_UNSIGNED_INT_10F_11F_11F_REV:
246         case GL_UNSIGNED_INT_5_9_9_9_REV:
247         case GL_UNSIGNED_INT_2_10_10_10_REV:
248         case GL_UNSIGNED_INT_24_8_OES:
249             return 4;
250         case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
251             return 4 + 4;
252         case GL_FLOAT:
253             switch (format) {
254                 case GL_DEPTH_COMPONENT32F:
255                 case GL_DEPTH_COMPONENT:
256                     return 4;
257                 case GL_ALPHA32F_EXT:
258                 case GL_ALPHA:
259                     return 4;
260                 case GL_LUMINANCE32F_EXT:
261                 case GL_LUMINANCE:
262                     return 4;
263                 case GL_LUMINANCE_ALPHA32F_EXT:
264                 case GL_LUMINANCE_ALPHA:
265                     return 4 * 2;
266                 case GL_RED:
267                     return 4;
268                 case GL_R32F:
269                     return 4;
270                 case GL_RG:
271                     return 4 * 2;
272                 case GL_RG32F:
273                     return 4 * 2;
274                 case GL_RGB:
275                     return 4 * 3;
276                 case GL_RGB32F:
277                     return 4 * 3;
278                 case GL_RGBA:
279                     return 4 * 4;
280                 case GL_RGBA32F:
281                     return 4 * 4;
282                 default:
283                     FORMAT_ERROR(format, type);
284             }
285             break;
286         case GL_HALF_FLOAT:
287         case GL_HALF_FLOAT_OES:
288             switch (format) {
289                 case GL_ALPHA16F_EXT:
290                 case GL_ALPHA:
291                     return 2;
292                 case GL_LUMINANCE16F_EXT:
293                 case GL_LUMINANCE:
294                     return 2;
295                 case GL_LUMINANCE_ALPHA16F_EXT:
296                 case GL_LUMINANCE_ALPHA:
297                     return 2 * 2;
298                 case GL_RED:
299                     return 2;
300                 case GL_R16F:
301                     return 2;
302                 case GL_RG:
303                     return 2 * 2;
304                 case GL_RG16F:
305                     return 2 * 2;
306                 case GL_RGB:
307                     return 2 * 3;
308                 case GL_RGB16F:
309                     return 2 * 3;
310                 case GL_RGBA:
311                     return 2 * 4;
312                 case GL_RGBA16F:
313                     return 2 * 4;
314                 default:
315                     FORMAT_ERROR(format, type);
316             }
317             break;
318         default:
319             FORMAT_ERROR(format, type);
320     }
321 
322     return 0;
323 }
324 
s_texImageSize(GLenum internalformat,GLenum type,int unpackAlignment,GLsizei width,GLsizei height)325 static uint32_t s_texImageSize(GLenum internalformat,
326                                GLenum type,
327                                int unpackAlignment,
328                                GLsizei width,
329                                GLsizei height) {
330     uint32_t alignedWidth = s_texAlign(width, unpackAlignment);
331     uint32_t pixelSize = s_computePixelSize(internalformat, type);
332     uint32_t totalSize = pixelSize * alignedWidth * height;
333 
334     return totalSize;
335 }
336 
337 struct TextureDataReader {
338     GLESVersion glesVersion = GLES_2_0;
339     GLenum fbTarget = GL_FRAMEBUFFER;
340     GLint prevViewport[4] = { 0, 0, 0, 0 };
341     GLuint fbo = 0;
342     GLuint prevFbo = 0;
343 
setupFboTextureDataReader344     void setupFbo() {
345         GLenum fbBindingTarget;
346         auto gl = GLEScontext::dispatcher();
347 
348         glesVersion = gl.getGLESVersion();
349         if (glesVersion >= GLES_3_0) {
350             fbTarget = GL_READ_FRAMEBUFFER;
351             fbBindingTarget = GL_READ_FRAMEBUFFER_BINDING;
352         } else {
353             fbTarget = GL_FRAMEBUFFER;
354             fbBindingTarget = GL_FRAMEBUFFER_BINDING;
355         }
356         gl.glGetIntegerv(GL_VIEWPORT, prevViewport);
357         gl.glGenFramebuffers(1, &fbo);
358         gl.glGetIntegerv(fbBindingTarget, (GLint*)&prevFbo);
359         gl.glBindFramebuffer(fbTarget, fbo);
360     }
361 
teardownFboTextureDataReader362     void teardownFbo() {
363         if (!fbo) return;
364         auto gl = GLEScontext::dispatcher();
365 
366         gl.glBindFramebuffer(fbTarget, prevFbo);
367         gl.glDeleteFramebuffers(1, &fbo);
368         gl.glViewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3]);
369 
370         *this = {};
371     }
372 
shouldUseReadPixelsTextureDataReader373     bool shouldUseReadPixels(
374         GLenum target, GLenum level, GLenum format, GLenum type) {
375 
376         auto gl = GLEScontext::dispatcher();
377         if (!gl.glGetTexImage) return true;
378 
379         // TODO: if (isGles2Gles()) return true
380 
381         // TODO: Query extensions for support for these kinds of things
382         if (target != GL_TEXTURE_2D || level != 0) return false;
383 
384 #define KNOWN_GOOD_READ_PIXELS_COMBINATION(goodFormat, goodType) \
385         if (format == goodFormat && type == goodType) return true;
386 
387         KNOWN_GOOD_READ_PIXELS_COMBINATION(GL_RGB, GL_UNSIGNED_BYTE)
388         KNOWN_GOOD_READ_PIXELS_COMBINATION(GL_RGBA, GL_UNSIGNED_BYTE)
389 
390         return false;
391     }
392 
getTexImageTextureDataReader393     void getTexImage(
394         GLuint globalName, GLenum target, GLenum level, GLenum format, GLenum type,
395         GLint width, GLint height, GLint depth, uint8_t* data) {
396 
397         D("Reading: %u 0x%x %u 0x%x 0x%x %d x %d x %d...",
398           globalName, target, level, format, type, width, height, depth);
399 
400         auto gl = GLEScontext::dispatcher();
401 
402         if (!shouldUseReadPixels(target, level, format, type)) {
403             D("with underlying glGetTexImage");
404             gl.glGetTexImage(target, level, format, type, data);
405             return;
406         }
407 
408 
409         GLenum attachment = GL_COLOR_ATTACHMENT0;
410 
411         switch (format) {
412             case GL_DEPTH_COMPONENT:
413                 attachment = GL_DEPTH_ATTACHMENT;
414                 break;
415             case GL_DEPTH_STENCIL:
416                 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
417                 break;
418         }
419 
420         gl.glViewport(0, 0, width, height);
421 
422         switch (target) {
423             case GL_TEXTURE_2D:
424             case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
425             case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
426             case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
427             case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
428             case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
429             case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
430                 D("with glFramebufferTexture2D + glReadPixels");
431                 gl.glFramebufferTexture2D(
432                         fbTarget, attachment, target,
433                         globalName, level);
434                 gl.glReadPixels(0, 0, width, height,
435                         format, type,
436                         data);
437                 gl.glFramebufferTexture2D(
438                         fbTarget, attachment, target,
439                         0, level);
440                 break;
441             case GL_TEXTURE_3D: {
442                 D("with glFramebufferTexture3DOES + glReadPixels");
443                 unsigned int layerImgSize = s_texImageSize(
444                         format, type, 1, width, height);
445                 for (unsigned int d = 0; d < depth; d++) {
446                     gl.glFramebufferTexture3DOES(
447                             fbTarget, attachment, target,
448                             globalName, level, d);
449                     gl.glReadPixels(0, 0, width,
450                             height, format,
451                             type, data +
452                             layerImgSize * d);
453                     gl.glFramebufferTexture3DOES(
454                             fbTarget, attachment, target,
455                             0, level, d);
456                 }
457                 break;
458             }
459             case GL_TEXTURE_2D_ARRAY: {
460                 D("with glFramebufferTextureLayer + glReadPixels");
461                 unsigned int layerImgSize = s_texImageSize(
462                         format, type, 1, width, height);
463                 for (unsigned int d = 0; d < depth; d++) {
464                     gl.glFramebufferTextureLayer(
465                             fbTarget, attachment,
466                             globalName, level, d);
467                     gl.glReadPixels(0, 0, width,
468                             height, format,
469                             type, data +
470                             layerImgSize * d);
471                     gl.glFramebufferTextureLayer(
472                             fbTarget, attachment,
473                             0, level, d);
474                 }
475                 break;
476             }
477         }
478     }
479 
preSaveTextureDataReader480     void preSave() {
481         setupFbo();
482     }
483 
postSaveTextureDataReader484     void postSave() {
485         teardownFbo();
486     }
487 };
488 
sTextureDataReader()489 static TextureDataReader* sTextureDataReader() {
490     static TextureDataReader* r = new TextureDataReader;
491     return r;
492 }
493 
preSave()494 void SaveableTexture::preSave() {
495     sTextureDataReader()->preSave();
496 }
497 
postSave()498 void SaveableTexture::postSave() {
499     sTextureDataReader()->postSave();
500 }
501 
SaveableTexture(const TextureData & texture)502 SaveableTexture::SaveableTexture(const TextureData& texture)
503     : m_target(texture.target),
504       m_width(texture.width),
505       m_height(texture.height),
506       m_depth(texture.depth),
507       m_format(texture.format),
508       m_internalFormat(texture.internalFormat),
509       m_type(texture.type),
510       m_border(texture.border),
511       m_texStorageLevels(texture.texStorageLevels),
512       m_globalName(texture.getGlobalName()),
513       m_isDirty(true) {}
514 
SaveableTexture(GlobalNameSpace * globalNameSpace,loader_t && loader)515 SaveableTexture::SaveableTexture(GlobalNameSpace* globalNameSpace,
516                                  loader_t&& loader)
517     : m_loader(std::move(loader)),
518       m_globalNamespace(globalNameSpace),
519       m_isDirty(false) {
520     mNeedRestore = true;
521 }
522 
loadFromStream(android::base::Stream * stream)523 void SaveableTexture::loadFromStream(android::base::Stream* stream) {
524     m_target = stream->getBe32();
525     m_width = stream->getBe32();
526     m_height = stream->getBe32();
527     m_depth = stream->getBe32();
528     m_format = stream->getBe32();
529     m_internalFormat = stream->getBe32();
530     m_type = stream->getBe32();
531     m_border = stream->getBe32();
532     m_texStorageLevels = stream->getBe32();
533     m_maxMipmapLevel = stream->getBe32();
534     // TODO: handle other texture targets
535     if (m_target == GL_TEXTURE_2D || m_target == GL_TEXTURE_CUBE_MAP ||
536         m_target == GL_TEXTURE_3D || m_target == GL_TEXTURE_2D_ARRAY) {
537         unsigned int numLevels = m_texStorageLevels ? m_texStorageLevels :
538                 m_maxMipmapLevel + 1;
539         auto loadTex = [stream, numLevels](
540                                std::unique_ptr<LevelImageData[]>& levelData,
541                                bool isDepth) {
542             levelData.reset(new LevelImageData[numLevels]);
543             for (unsigned int level = 0; level < numLevels; level++) {
544                 levelData[level].m_width = stream->getBe32();
545                 levelData[level].m_height = stream->getBe32();
546                 if (isDepth) {
547                     levelData[level].m_depth = stream->getBe32();
548                 }
549                 loadBuffer(stream, &levelData[level].m_data);
550             }
551         };
552         switch (m_target) {
553             case GL_TEXTURE_2D:
554                 loadTex(m_levelData[0], false);
555                 break;
556             case GL_TEXTURE_CUBE_MAP:
557                 for (int i = 0; i < 6; i++) {
558                     loadTex(m_levelData[i], false);
559                 }
560                 break;
561             case GL_TEXTURE_3D:
562             case GL_TEXTURE_2D_ARRAY:
563                 loadTex(m_levelData[0], true);
564                 break;
565             default:
566                 break;
567         }
568         // Load tex param
569         loadCollection(stream, &m_texParam,
570                 [](android::base::Stream* stream)
571                     -> std::unordered_map<GLenum, GLint>::value_type {
572                     GLenum pname = stream->getBe32();
573                     GLint value = stream->getBe32();
574                     return std::make_pair(pname, value);
575                 });
576     } else if (m_target != 0) {
577         GL_LOG("SaveableTexture::%s: warning: texture target 0x%x not "
578                "supported\n",
579                __func__, m_target);
580         fprintf(stderr, "Warning: texture target %d not supported\n", m_target);
581     }
582     m_loadedFromStream.store(true);
583 }
584 
onSave(android::base::Stream * stream)585 void SaveableTexture::onSave(
586         android::base::Stream* stream) {
587     stream->putBe32(m_target);
588     stream->putBe32(m_width);
589     stream->putBe32(m_height);
590     stream->putBe32(m_depth);
591     stream->putBe32(m_format);
592     stream->putBe32(m_internalFormat);
593     stream->putBe32(m_type);
594     stream->putBe32(m_border);
595     stream->putBe32(m_texStorageLevels);
596     stream->putBe32(m_maxMipmapLevel);
597     // TODO: handle other texture targets
598     if (m_target == GL_TEXTURE_2D || m_target == GL_TEXTURE_CUBE_MAP ||
599         m_target == GL_TEXTURE_3D || m_target == GL_TEXTURE_2D_ARRAY) {
600         static constexpr GLenum pixelStoreIndexes[] = {
601                 GL_PACK_ROW_LENGTH, GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_ROWS,
602                 GL_PACK_ALIGNMENT,
603         };
604         static constexpr GLint pixelStoreDesired[] = {0, 0, 0, 1};
605         GLint pixelStorePrev[android::base::arraySize(pixelStoreIndexes)];
606 
607         GLint prevTex = 0;
608         GLDispatch& dispatcher = GLEScontext::dispatcher();
609         assert(dispatcher.glGetIntegerv);
610         for (int i = 0; i != android::base::arraySize(pixelStoreIndexes); ++i) {
611             if (isGles2Gles() && pixelStoreIndexes[i] != GL_PACK_ALIGNMENT &&
612                 pixelStoreIndexes[i] != GL_UNPACK_ALIGNMENT) {
613                 continue;
614             }
615             dispatcher.glGetIntegerv(pixelStoreIndexes[i], &pixelStorePrev[i]);
616             if (pixelStorePrev[i] != pixelStoreDesired[i]) {
617                 dispatcher.glPixelStorei(pixelStoreIndexes[i],
618                                          pixelStoreDesired[i]);
619             }
620         }
621         switch (m_target) {
622             case GL_TEXTURE_2D:
623                 dispatcher.glGetIntegerv(GL_TEXTURE_BINDING_2D, &prevTex);
624                 break;
625             case GL_TEXTURE_CUBE_MAP:
626                 dispatcher.glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &prevTex);
627                 break;
628             case GL_TEXTURE_3D:
629                 dispatcher.glGetIntegerv(GL_TEXTURE_BINDING_3D, &prevTex);
630                 break;
631             case GL_TEXTURE_2D_ARRAY:
632                 dispatcher.glGetIntegerv(GL_TEXTURE_BINDING_2D_ARRAY, &prevTex);
633                 break;
634             default:
635                 break;
636         }
637 
638         dispatcher.glBindTexture(m_target, getGlobalName());
639         // Get the number of mipmap levels.
640         unsigned int numLevels = m_texStorageLevels ? m_texStorageLevels :
641                 m_maxMipmapLevel + 1;
642 
643         // bug: 112749908
644         // Texture saving causes hundreds of megabytes of memory ballooning.
645         // This could be behind nullptr dereferences in crash reports if
646         // the user ran out of commit charge on Windows, which is not measured
647         // in android::base::System::isUnderMemoryPressure.
648         //
649         // To debug this issue, avoid keeping the imgData buffers around,
650         // and log the memory usage.
651         //
652         // bool isLowMem = android::base::System::isUnderMemoryPressure();
653         bool isLowMem = true;
654 
655         auto saveTex = [this, stream, numLevels, &dispatcher, isLowMem](
656                                 GLenum target, bool isDepth,
657                                 std::unique_ptr<LevelImageData[]>& imgData) {
658 
659             if (m_isDirty) {
660                 imgData.reset(new LevelImageData[numLevels]);
661                 for (unsigned int level = 0; level < numLevels; level++) {
662                     unsigned int& width = imgData.get()[level].m_width;
663                     unsigned int& height = imgData.get()[level].m_height;
664                     unsigned int& depth = imgData.get()[level].m_depth;
665                     width = level == 0 ? m_width :
666                         std::max<unsigned int>(
667                             imgData.get()[level - 1].m_width / 2, 1);
668                     height = level == 0 ? m_height :
669                         std::max<unsigned int>(
670                             imgData.get()[level - 1].m_height / 2, 1);
671                     depth = level == 0 ? m_depth :
672                         std::max<unsigned int>(
673                             imgData.get()[level - 1].m_depth / 2, 1);
674 
675                     // ScopedMemoryProfiler::Callback memoryProfilerCallback =
676                     //     [this, level, width, height, depth]
677                     //     (StringView tag, StringView stage,
678                     //      MemoryProfiler::MemoryUsageBytes currentResident,
679                     //      MemoryProfiler::MemoryUsageBytes change) {
680 
681                     //     double megabyte = 1024.0 * 1024.0;
682 
683                     //     GL_LOG("%s %s: %f mb current. change: %f mb. texture:"
684                     //            "format 0x%x type 0x%x level 0x%x dims (%u, %u, %u)\n",
685                     //            c_str(tag).get(),
686                     //            c_str(stage).get(),
687                     //            (double)currentResident / megabyte,
688                     //            (double)change / megabyte,
689                     //            m_format,
690                     //            m_type,
691                     //            level,
692                     //            width, height, depth);
693                     // };
694 
695                     // ScopedMemoryProfiler mem("saveTexture", memoryProfilerCallback);
696 
697                     android::base::SmallFixedVector<unsigned char, 16>& buffer
698                         = imgData.get()[level].m_data;
699                     if (!isGles2Gles()) {
700                         GLint glWidth;
701                         GLint glHeight;
702                         dispatcher.glGetTexLevelParameteriv(target, level,
703                                 GL_TEXTURE_WIDTH, &glWidth);
704                         dispatcher.glGetTexLevelParameteriv(target, level,
705                                 GL_TEXTURE_HEIGHT, &glHeight);
706                         width = static_cast<unsigned int>(glWidth);
707                         height = static_cast<unsigned int>(glHeight);
708                     }
709                     if (isDepth) {
710                         if (!isGles2Gles()) {
711                             GLint glDepth;
712                             dispatcher.glGetTexLevelParameteriv(target, level,
713                                     GL_TEXTURE_DEPTH, &glDepth);
714                             depth = static_cast<unsigned int>(std::max(glDepth,
715                                     1));
716                         }
717                     } else {
718                         depth = 1;
719                     }
720                     // Snapshot texture data
721                     buffer.clear();
722                     buffer.resize_noinit(
723                             s_texImageSize(m_format, m_type, 1, width, height) *
724                             depth);
725                     if (!buffer.empty()) {
726                         GLenum neededBufferFormat = m_format;
727                         if (isCoreProfile()) {
728                             neededBufferFormat =
729                                 getCoreProfileEmulatedFormat(m_format);
730                         }
731                         sTextureDataReader()->getTexImage(
732                             m_globalName, target, level, neededBufferFormat, m_type, width, height, depth, buffer.data());
733                     }
734                 }
735             }
736             for (unsigned int level = 0; level < numLevels; level++) {
737                 stream->putBe32(imgData.get()[level].m_width);
738                 stream->putBe32(imgData.get()[level].m_height);
739                 if (isDepth) {
740                     stream->putBe32(imgData.get()[level].m_depth);
741                 }
742                 saveBuffer(stream, imgData.get()[level].m_data);
743             }
744 
745             // If under memory pressure, delete this intermediate buffer.
746             if (isLowMem) {
747                 imgData.reset();
748             }
749         };
750         switch (m_target) {
751             case GL_TEXTURE_2D:
752                 saveTex(GL_TEXTURE_2D, false, m_levelData[0]);
753                 break;
754             case GL_TEXTURE_CUBE_MAP:
755                 saveTex(GL_TEXTURE_CUBE_MAP_POSITIVE_X, false, m_levelData[0]);
756                 saveTex(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, false, m_levelData[1]);
757                 saveTex(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, false, m_levelData[2]);
758                 saveTex(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, false, m_levelData[3]);
759                 saveTex(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, false, m_levelData[4]);
760                 saveTex(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, false, m_levelData[5]);
761                 break;
762             case GL_TEXTURE_3D:
763                 saveTex(GL_TEXTURE_3D, true, m_levelData[0]);
764                 break;
765             case GL_TEXTURE_2D_ARRAY:
766                 saveTex(GL_TEXTURE_2D_ARRAY, true, m_levelData[0]);
767                 break;
768             default:
769                 break;
770         }
771         // Snapshot texture param
772         TextureSwizzle emulatedBaseSwizzle;
773         if (isCoreProfile()) {
774             emulatedBaseSwizzle = getSwizzleForEmulatedFormat(m_format);
775         }
776         std::unordered_map<GLenum, GLint> texParam;
777         auto saveParam = [this, &texParam, &dispatcher,
778                 emulatedBaseSwizzle](
779                 const GLenum* plist, size_t plistSize) {
780             GLint param;
781             for (size_t i = 0; i < plistSize; i++) {
782                 dispatcher.glGetTexParameteriv(m_target, plist[i], &param);
783                 if (isSwizzleParam(plist[i]) && param != GL_ZERO &&
784                         param != GL_ONE) {
785                     if (param == emulatedBaseSwizzle.toRed) {
786                         param = GL_RED;
787                     } else if (param == emulatedBaseSwizzle.toGreen) {
788                         param = GL_GREEN;
789                     } else if (param == emulatedBaseSwizzle.toBlue) {
790                         param = GL_BLUE;
791                     } else if (param == emulatedBaseSwizzle.toAlpha) {
792                         param = GL_ALPHA;
793                     }
794                 }
795                 texParam.emplace(plist[i], param);
796             }
797         };
798         saveParam(kTexParam, sizeof(kTexParam) / sizeof(kTexParam[0]));
799         if (dispatcher.getGLESVersion() >= GLES_3_0) {
800             saveParam(kTexParamGles3,
801                     sizeof(kTexParamGles3) / sizeof(kTexParamGles3[0]));
802         }
803         saveCollection(stream, texParam,
804                 [](android::base::Stream* s,
805                     const std::unordered_map<GLenum, GLint>::value_type& pair) {
806                     s->putBe32(pair.first);
807                     s->putBe32(pair.second);
808                 });
809         // Restore environment
810         for (int i = 0; i != android::base::arraySize(pixelStoreIndexes); ++i) {
811             if (isGles2Gles() && pixelStoreIndexes[i] != GL_PACK_ALIGNMENT &&
812                 pixelStoreIndexes[i] != GL_UNPACK_ALIGNMENT) {
813                 continue;
814             }
815             if (pixelStorePrev[i] != pixelStoreDesired[i]) {
816                 dispatcher.glPixelStorei(pixelStoreIndexes[i],
817                                          pixelStorePrev[i]);
818             }
819         }
820         dispatcher.glBindTexture(m_target, prevTex);
821 
822         // If we were under memory pressure, we deleted the intermediate
823         // buffer, so we need to maintain the invariant that m_isDirty = false
824         // textures requires that the intermediate buffer is still around.
825         // Therefore, mark as dirty if we were under memory pressure.
826         //
827         // TODO: Don't keep those around in memory regardless of memory
828         // pressure
829 
830         m_isDirty = false || isLowMem;
831     } else if (m_target != 0) {
832         // SaveableTexture is uninitialized iff a texture hasn't been bound,
833         // which will give m_target==0
834         GL_LOG("SaveableTexture::onSave: warning: texture target 0x%x not supported\n", m_target);
835         fprintf(stderr, "Warning: texture target 0x%x not supported\n", m_target);
836     }
837 }
838 
restore()839 void SaveableTexture::restore() {
840     assert(m_loader);
841     m_loader(this);
842 
843     if (!m_loadedFromStream.load()) {
844         return;
845     }
846 
847     m_globalTexObj.reset(new NamedObject(
848             GenNameInfo(NamedObjectType::TEXTURE), m_globalNamespace));
849     if (!m_globalTexObj) {
850         GL_LOG("SaveableTexture::%s: %p: could not allocate NamedObject for texture\n", __func__, this);
851         emugl::emugl_crash_reporter(
852                 "Fatal: could not allocate SaveableTexture m_globalTexObj\n");
853     }
854 
855     m_globalName = m_globalTexObj->getGlobalName();
856     if (m_target == GL_TEXTURE_2D || m_target == GL_TEXTURE_CUBE_MAP ||
857         m_target == GL_TEXTURE_3D || m_target == GL_TEXTURE_2D_ARRAY) {
858         // restore the texture
859         GLDispatch& dispatcher = GLEScontext::dispatcher();
860         // Make sure we are using the right dispatcher
861         assert(dispatcher.glGetIntegerv);
862 
863         static constexpr GLenum pixelStoreIndexes[] = {
864                 GL_UNPACK_ROW_LENGTH,  GL_UNPACK_IMAGE_HEIGHT,
865                 GL_UNPACK_SKIP_PIXELS, GL_UNPACK_SKIP_ROWS,
866                 GL_UNPACK_SKIP_IMAGES, GL_UNPACK_ALIGNMENT,
867         };
868 
869         static constexpr GLint pixelStoreDesired[] = {0, 0, 0, 0, 0, 1};
870 
871         GLint pixelStorePrev[android::base::arraySize(pixelStoreIndexes)];
872         for (int i = 0; i != android::base::arraySize(pixelStoreIndexes); ++i) {
873             if (isGles2Gles() && pixelStoreIndexes[i] != GL_PACK_ALIGNMENT &&
874                 pixelStoreIndexes[i] != GL_UNPACK_ALIGNMENT) {
875                 continue;
876             }
877             dispatcher.glGetIntegerv(pixelStoreIndexes[i], &pixelStorePrev[i]);
878             if (pixelStorePrev[i] != pixelStoreDesired[i]) {
879                 dispatcher.glPixelStorei(pixelStoreIndexes[i],
880                                          pixelStoreDesired[i]);
881             }
882         }
883 
884         GLint prevTex = 0;
885         switch (m_target) {
886             case GL_TEXTURE_2D:
887                 dispatcher.glGetIntegerv(GL_TEXTURE_BINDING_2D, &prevTex);
888                 break;
889             case GL_TEXTURE_CUBE_MAP:
890                 dispatcher.glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &prevTex);
891                 break;
892             case GL_TEXTURE_3D:
893                 dispatcher.glGetIntegerv(GL_TEXTURE_BINDING_3D, &prevTex);
894                 break;
895             case GL_TEXTURE_2D_ARRAY:
896                 dispatcher.glGetIntegerv(GL_TEXTURE_BINDING_2D_ARRAY, &prevTex);
897                 break;
898             default:
899                 break;
900         }
901         dispatcher.glBindTexture(m_target, getGlobalName());
902         // Restore texture data
903         dispatcher.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
904         // Get the number of mipmap levels.
905         unsigned int numLevels = m_texStorageLevels ? m_texStorageLevels :
906                 m_maxMipmapLevel + 1;
907         GLint resultInternalFormat = m_internalFormat;
908         GLenum resultFormat = m_format;
909         // Desktop OpenGL doesn't support GL_BGRA_EXT as internal format.
910         if (!isGles2Gles() && m_type == GL_UNSIGNED_BYTE && m_format == GL_BGRA_EXT &&
911             resultInternalFormat == GL_BGRA_EXT) {
912             resultInternalFormat = GL_RGBA;
913         } else if (isCoreProfile() && isCoreProfileEmulatedFormat(m_format)) {
914             resultInternalFormat = getCoreProfileEmulatedInternalFormat(
915                     m_format, m_type);
916             resultFormat = getCoreProfileEmulatedFormat(m_format);
917         }
918         if (m_texStorageLevels) {
919             switch (m_target) {
920                 case GL_TEXTURE_2D:
921                 case GL_TEXTURE_CUBE_MAP:
922                     dispatcher.glTexStorage2D(m_target, m_texStorageLevels,
923                             m_internalFormat,
924                             m_levelData[0].get()[0].m_width,
925                             m_levelData[0].get()[0].m_height);
926                     break;
927                 case GL_TEXTURE_3D:
928                 case GL_TEXTURE_2D_ARRAY:
929                     dispatcher.glTexStorage3D(m_target, m_texStorageLevels,
930                             m_internalFormat,
931                             m_levelData[0].get()[0].m_width,
932                             m_levelData[0].get()[0].m_height,
933                             m_levelData[0].get()[0].m_depth);
934                     break;
935             }
936         }
937 
938         auto restoreTex2D =
939                 [this, numLevels, resultInternalFormat,
940                 resultFormat, &dispatcher](
941                         GLenum target,
942                         std::unique_ptr<LevelImageData[]>& levelData) {
943                     for (unsigned int level = 0; level < numLevels; level++) {
944                         const void* pixels =
945                                 levelData[level].m_data.empty()
946                                         ? nullptr
947                                         : levelData[level].m_data.data();
948                         if (!level || pixels) {
949                             if (m_texStorageLevels) {
950                                 dispatcher.glTexSubImage2D(
951                                         target, level, 0, 0,
952                                         levelData[level].m_width,
953                                         levelData[level].m_height,
954                                         resultFormat, m_type, pixels);
955                             } else {
956                                 dispatcher.glTexImage2D(
957                                         target, level, resultInternalFormat,
958                                         levelData[level].m_width,
959                                         levelData[level].m_height,
960                                         m_border, resultFormat, m_type, pixels);
961                             }
962                         }
963                     }
964                 };
965         auto restoreTex3D =
966                 [this, numLevels, resultFormat, &dispatcher](
967                         GLenum target,
968                         std::unique_ptr<LevelImageData[]>& levelData) {
969                     for (unsigned int level = 0; level < numLevels; level++) {
970                         const void* pixels =
971                                 levelData[level].m_data.empty()
972                                         ? nullptr
973                                         : levelData[level].m_data.data();
974                         if (!level || pixels) {
975                             if (m_texStorageLevels) {
976                                 dispatcher.glTexSubImage3D(
977                                         target, level, 0, 0, 0,
978                                         levelData[level].m_width,
979                                         levelData[level].m_height,
980                                         levelData[level].m_depth,
981                                         resultFormat, m_type, pixels);
982                             } else {
983                                 dispatcher.glTexImage3D(
984                                         target, level, m_internalFormat,
985                                         levelData[level].m_width,
986                                         levelData[level].m_height,
987                                         levelData[level].m_depth, m_border,
988                                         resultFormat, m_type, pixels);
989                             }
990                         }
991                     }
992                 };
993         switch (m_target) {
994             case GL_TEXTURE_2D:
995                 restoreTex2D(GL_TEXTURE_2D, m_levelData[0]);
996                 break;
997             case GL_TEXTURE_CUBE_MAP:
998                 restoreTex2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, m_levelData[0]);
999                 restoreTex2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, m_levelData[1]);
1000                 restoreTex2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, m_levelData[2]);
1001                 restoreTex2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, m_levelData[3]);
1002                 restoreTex2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, m_levelData[4]);
1003                 restoreTex2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, m_levelData[5]);
1004                 break;
1005             case GL_TEXTURE_3D:
1006             case GL_TEXTURE_2D_ARRAY:
1007                 restoreTex3D(m_target, m_levelData[0]);
1008                 break;
1009             default:
1010                 break;
1011         }
1012         // Restore tex param
1013         TextureSwizzle emulatedBaseSwizzle;
1014         if (isCoreProfile()) {
1015             emulatedBaseSwizzle = getSwizzleForEmulatedFormat(m_format);
1016         }
1017         for (const auto& param : m_texParam) {
1018             if (isSwizzleParam(param.first)) {
1019                 GLenum hostEquivalentSwizzle =
1020                     swizzleComponentOf(emulatedBaseSwizzle, param.second);
1021                 dispatcher.glTexParameteri(m_target, param.first,
1022                         hostEquivalentSwizzle);
1023             } else {
1024                 dispatcher.glTexParameteri(m_target, param.first, param.second);
1025             }
1026         }
1027         m_texParam.clear();
1028         // Restore environment
1029         for (int i = 0; i != android::base::arraySize(pixelStoreIndexes); ++i) {
1030             if (isGles2Gles() && pixelStoreIndexes[i] != GL_PACK_ALIGNMENT &&
1031                 pixelStoreIndexes[i] != GL_UNPACK_ALIGNMENT) {
1032                 continue;
1033             }
1034             if (pixelStorePrev[i] != pixelStoreDesired[i]) {
1035                 dispatcher.glPixelStorei(pixelStoreIndexes[i],
1036                                          pixelStorePrev[i]);
1037             }
1038         }
1039         dispatcher.glBindTexture(m_target, prevTex);
1040     }
1041 }
1042 
getGlobalObject()1043 const NamedObjectPtr& SaveableTexture::getGlobalObject() {
1044     touch();
1045     return m_globalTexObj;
1046 }
1047 
fillEglImage(EglImage * eglImage)1048 void SaveableTexture::fillEglImage(EglImage* eglImage) {
1049     touch();
1050     eglImage->border = m_border;
1051     eglImage->format = m_format;
1052     eglImage->height = m_height;
1053     eglImage->globalTexObj = m_globalTexObj;
1054     eglImage->internalFormat = m_internalFormat;
1055     eglImage->type = m_type;
1056     eglImage->width = m_width;
1057     eglImage->texStorageLevels = m_texStorageLevels;
1058     eglImage->sync = nullptr;
1059     if (!eglImage->globalTexObj) {
1060         GL_LOG("%s: EGL image %p has no global texture object!\n",
1061                __func__, eglImage);
1062     }
1063 }
1064 
makeDirty()1065 void SaveableTexture::makeDirty() {
1066     m_isDirty = true;
1067 }
1068 
isDirty() const1069 bool SaveableTexture::isDirty() const {
1070     return m_isDirty;
1071 }
1072 
setTarget(GLenum target)1073 void SaveableTexture::setTarget(GLenum target) {
1074     m_target = target;
1075 }
1076 
setMipmapLevelAtLeast(unsigned int level)1077 void SaveableTexture::setMipmapLevelAtLeast(unsigned int level) {
1078     m_maxMipmapLevel = std::max(level, m_maxMipmapLevel);
1079 }
1080 
getGlobalName()1081 unsigned int SaveableTexture::getGlobalName() {
1082     if (m_globalTexObj) {
1083         return m_globalTexObj->getGlobalName();
1084     }
1085     return m_globalName;
1086 }
1087