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], ¶m);
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