blob: 65becf88b93039d7d2da5f117c6aa9c11078d690 [file] [log] [blame]
John Reck44627c22018-04-12 13:55:38 -07001/*
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 "EglReadback.h"
18
19#include "renderthread/EglManager.h"
20
21#include <gui/Surface.h>
22#include <ui/Fence.h>
23#include <ui/GraphicBuffer.h>
24
25namespace android {
26namespace uirenderer {
27
John Recke170fb62018-05-07 08:12:07 -070028CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) {
John Reck44627c22018-04-12 13:55:38 -070029 ATRACE_CALL();
30 // Setup the source
31 sp<GraphicBuffer> sourceBuffer;
32 sp<Fence> sourceFence;
33 Matrix4 texTransform;
34 status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
35 texTransform.invalidateType();
36 if (err != NO_ERROR) {
37 ALOGW("Failed to get last queued buffer, error = %d", err);
38 return CopyResult::UnknownError;
39 }
40 if (!sourceBuffer.get()) {
41 ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
42 return CopyResult::SourceEmpty;
43 }
44 if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
45 ALOGW("Surface is protected, unable to copy from it");
46 return CopyResult::SourceInvalid;
47 }
48 err = sourceFence->wait(500 /* ms */);
49 if (err != NO_ERROR) {
50 ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
51 return CopyResult::Timeout;
52 }
53
54 return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap);
55}
56
John Recke170fb62018-05-07 08:12:07 -070057CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
58 const Rect& srcRect, SkBitmap* bitmap) {
John Reck1e510712018-04-23 08:15:03 -070059 mRenderThread.requireGlContext();
John Reck44627c22018-04-12 13:55:38 -070060 // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
61 // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
62 // to be able to properly sample from the buffer.
63
64 // Create the EGLImage object that maps the GraphicBuffer
65 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
66 EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
67 EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
68
69 EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
70 clientBuffer, attrs);
71
72 if (sourceImage == EGL_NO_IMAGE_KHR) {
73 ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
74 return CopyResult::UnknownError;
75 }
76
77 uint32_t width = graphicBuffer->getWidth();
78 uint32_t height = graphicBuffer->getHeight();
79 CopyResult copyResult =
80 copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap);
81
82 eglDestroyImageKHR(display, sourceImage);
83 return copyResult;
84}
85
86CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) {
87 Rect srcRect;
88 Matrix4 transform;
89 transform.loadScale(1, -1, 1);
90 transform.translate(0, -1);
91 return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap);
92}
93
94} // namespace uirenderer
95} // namespace android