diff options
Diffstat (limited to 'libs/hwui/OpenGLReadback.cpp')
-rw-r--r-- | libs/hwui/OpenGLReadback.cpp | 287 |
1 files changed, 0 insertions, 287 deletions
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp deleted file mode 100644 index 11432d629650..000000000000 --- a/libs/hwui/OpenGLReadback.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "OpenGLReadback.h" - -#include "Caches.h" -#include "GlLayer.h" -#include "GlopBuilder.h" -#include "Image.h" -#include "renderstate/RenderState.h" -#include "renderthread/EglManager.h" -#include "utils/GLUtils.h" - -#include <GLES2/gl2.h> -#include <gui/Surface.h> -#include <ui/Fence.h> -#include <ui/GraphicBuffer.h> - -namespace android { -namespace uirenderer { - -CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, - SkBitmap* bitmap) { - ATRACE_CALL(); - // Setup the source - sp<GraphicBuffer> sourceBuffer; - sp<Fence> sourceFence; - Matrix4 texTransform; - status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data); - texTransform.invalidateType(); - if (err != NO_ERROR) { - ALOGW("Failed to get last queued buffer, error = %d", err); - return CopyResult::UnknownError; - } - if (!sourceBuffer.get()) { - ALOGW("Surface doesn't have any previously queued frames, nothing to readback from"); - return CopyResult::SourceEmpty; - } - if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) { - ALOGW("Surface is protected, unable to copy from it"); - return CopyResult::SourceInvalid; - } - err = sourceFence->wait(500 /* ms */); - if (err != NO_ERROR) { - ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt"); - return CopyResult::Timeout; - } - - return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap); -} - -CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, - Matrix4& texTransform, const Rect& srcRect, - SkBitmap* bitmap) { - mRenderThread.eglManager().initialize(); - // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via - // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES - // to be able to properly sample from the buffer. - - // Create the EGLImage object that maps the GraphicBuffer - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); - EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; - - EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - clientBuffer, attrs); - - if (sourceImage == EGL_NO_IMAGE_KHR) { - ALOGW("eglCreateImageKHR failed (%#x)", eglGetError()); - return CopyResult::UnknownError; - } - - uint32_t width = graphicBuffer->getWidth(); - uint32_t height = graphicBuffer->getHeight(); - CopyResult copyResult = - copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap); - - // All we're flushing & finishing is the deletion of the texture since - // copyImageInto already did a major flush & finish as an implicit - // part of glReadPixels, so this shouldn't pose any major stalls. - glFinish(); - eglDestroyImageKHR(display, sourceImage); - return copyResult; -} - -CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) { - Rect srcRect; - Matrix4 transform; - transform.loadScale(1, -1, 1); - transform.translate(0, -1); - return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap); -} - -static float sFlipVInit[16] = { - 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, -}; - -static const Matrix4 sFlipV(sFlipVInit); - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, Texture& sourceTexture, - const Matrix4& texTransform, const Rect& srcRect, - SkBitmap* bitmap) { - int destWidth = bitmap->width(); - int destHeight = bitmap->height(); - if (destWidth > caches.maxTextureSize || destHeight > caches.maxTextureSize) { - ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d", destWidth, - destHeight, caches.maxTextureSize); - return CopyResult::DestinationInvalid; - } - - if (bitmap->colorType() == kRGBA_F16_SkColorType && - !caches.extensions().hasRenderableFloatTextures()) { - ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); - return CopyResult::DestinationInvalid; - } - - GLuint fbo = renderState.createFramebuffer(); - if (!fbo) { - ALOGW("Could not obtain an FBO"); - return CopyResult::UnknownError; - } - - GLuint texture; - - GLenum format; - GLenum internalFormat; - GLenum type; - - switch (bitmap->colorType()) { - case kAlpha_8_SkColorType: - format = GL_ALPHA; - internalFormat = GL_ALPHA; - type = GL_UNSIGNED_BYTE; - break; - case kRGB_565_SkColorType: - format = GL_RGB; - internalFormat = GL_RGB; - type = GL_UNSIGNED_SHORT_5_6_5; - break; - case kARGB_4444_SkColorType: - format = GL_RGBA; - internalFormat = GL_RGBA; - type = GL_UNSIGNED_SHORT_4_4_4_4; - break; - case kRGBA_F16_SkColorType: - format = GL_RGBA; - internalFormat = GL_RGBA16F; - type = GL_HALF_FLOAT; - break; - case kN32_SkColorType: - default: - format = GL_RGBA; - internalFormat = GL_RGBA; - type = GL_UNSIGNED_BYTE; - break; - } - - renderState.bindFramebuffer(fbo); - - // TODO: Use layerPool or something to get this maybe? But since we - // need explicit format control we can't currently. - - // Setup the rendertarget - glGenTextures(1, &texture); - caches.textureState().activateTexture(0); - caches.textureState().bindTexture(texture); - glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight, 0, format, type, nullptr); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); - - { - bool requiresFilter; - // Draw & readback - renderState.setViewport(destWidth, destHeight); - renderState.scissor().setEnabled(false); - renderState.blend().syncEnabled(); - renderState.stencil().disable(); - - Matrix4 croppedTexTransform(texTransform); - if (!srcRect.isEmpty()) { - // We flipV to convert to 0,0 top-left for the srcRect - // coordinates then flip back to 0,0 bottom-left for - // GLES coordinates. - croppedTexTransform.multiply(sFlipV); - croppedTexTransform.translate(srcRect.left / sourceTexture.width(), - srcRect.top / sourceTexture.height(), 0); - croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(), - srcRect.getHeight() / sourceTexture.height(), 1); - croppedTexTransform.multiply(sFlipV); - requiresFilter = srcRect.getWidth() != (float)destWidth || - srcRect.getHeight() != (float)destHeight; - } else { - requiresFilter = sourceTexture.width() != (uint32_t)destWidth || - sourceTexture.height() != (uint32_t)destHeight; - } - Glop glop; - GlopBuilder(renderState, caches, &glop) - .setRoundRectClipState(nullptr) - .setMeshTexturedUnitQuad(nullptr) - .setFillExternalTexture(sourceTexture, croppedTexTransform, requiresFilter) - .setTransform(Matrix4::identity(), TransformFlags::None) - .setModelViewMapUnitToRect(Rect(destWidth, destHeight)) - .build(); - Matrix4 ortho; - ortho.loadOrtho(destWidth, destHeight); - renderState.render(glop, ortho, false); - - // TODO: We should convert to linear space when the target is RGBA16F - glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels()); - bitmap->notifyPixelsChanged(); - } - - // Cleanup - caches.textureState().deleteTexture(texture); - renderState.deleteFramebuffer(fbo); - - GL_CHECKPOINT(MODERATE); - - return CopyResult::Success; -} - -CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, - int imgWidth, int imgHeight, const Rect& srcRect, - SkBitmap* bitmap) { - // If this is a 90 or 270 degree rotation we need to swap width/height - // This is a fuzzy way of checking that. - if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) { - std::swap(imgWidth, imgHeight); - } - - Caches& caches = Caches::getInstance(); - GLuint sourceTexId; - // Create a 2D texture to sample from the EGLImage - glGenTextures(1, &sourceTexId); - caches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId); - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage); - - GLenum status = GL_NO_ERROR; - while ((status = glGetError()) != GL_NO_ERROR) { - ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status); - return CopyResult::UnknownError; - } - - Texture sourceTexture(caches); - sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */, - GL_TEXTURE_EXTERNAL_OES); - - CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), sourceTexture, - imgTransform, srcRect, bitmap); - sourceTexture.deleteTexture(); - return copyResult; -} - -bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer, - SkBitmap* bitmap) { - if (!layer.isRenderable()) { - // layer has never been updated by DeferredLayerUpdater, abort copy - return false; - } - - return CopyResult::Success == copyTextureInto(Caches::getInstance(), renderThread.renderState(), - layer.getTexture(), layer.getTexTransform(), - Rect(), bitmap); -} - -} // namespace uirenderer -} // namespace android |