blob: 50ef50e92331eadfa8eef63c9a9349e208afa9fb [file] [log] [blame]
Stan Iliev7e910df2017-06-02 10:29:21 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include "SkTypes.h"
8
9//TODO: This define is temporary and we will compile with NDK after
10//TODO: Skia bug 6672 is resolved.
11#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
12#define GL_GLEXT_PROTOTYPES
13#define EGL_EGLEXT_PROTOTYPES
14#include "GrAHardwareBufferImageGenerator.h"
15
16#include "GrBackendSurface.h"
17#include "GrContext.h"
18#include "GrContextPriv.h"
Robert Phillips00018282017-06-15 15:35:16 -040019#include "GrResourceProvider.h"
Robert Phillips847d4c52017-06-13 18:21:44 -040020#include "GrTexture.h"
Robert Phillipsade9f612017-06-16 07:32:43 -040021#include "GrTextureProxy.h"
Stan Iliev7e910df2017-06-02 10:29:21 -040022
23#include <EGL/egl.h>
24#include <EGL/eglext.h>
25#include <GLES/gl.h>
26#include <GLES/glext.h>
27
28class BufferCleanupHelper {
29public:
30 BufferCleanupHelper(EGLImageKHR image, EGLDisplay display)
31 : fImage(image)
32 , fDisplay(display) { }
33 ~BufferCleanupHelper() {
34 eglDestroyImageKHR(fDisplay, fImage);
35 }
36private:
37 EGLImageKHR fImage;
38 EGLDisplay fDisplay;
39};
40
41std::unique_ptr<SkImageGenerator> GrAHardwareBufferImageGenerator::Make(
42 AHardwareBuffer* graphicBuffer, SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
43 AHardwareBuffer_Desc bufferDesc;
44 AHardwareBuffer_describe(graphicBuffer, &bufferDesc);
45 SkColorType colorType;
46 switch (bufferDesc.format) {
47 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
48 colorType = kRGBA_8888_SkColorType;
49 break;
50 case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
51 colorType = kRGBA_F16_SkColorType;
52 break;
53 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
54 colorType = kRGB_565_SkColorType;
55 break;
56 default:
57 return nullptr;
58 }
59 SkImageInfo info = SkImageInfo::Make(bufferDesc.width, bufferDesc.height, colorType,
60 alphaType, std::move(colorSpace));
61 return std::unique_ptr<SkImageGenerator>(new GrAHardwareBufferImageGenerator(info, graphicBuffer,
62 alphaType));
63}
64
65GrAHardwareBufferImageGenerator::GrAHardwareBufferImageGenerator(const SkImageInfo& info,
66 AHardwareBuffer* graphicBuffer, SkAlphaType alphaType)
67 : INHERITED(info)
68 , fGraphicBuffer(graphicBuffer)
69 , fAlphaType(alphaType) {
70 AHardwareBuffer_acquire(fGraphicBuffer);
71}
72
73GrAHardwareBufferImageGenerator::~GrAHardwareBufferImageGenerator() {
74 AHardwareBuffer_release(fGraphicBuffer);
75}
76
77void GrAHardwareBufferImageGenerator::deleteImageTexture(void* context) {
78 BufferCleanupHelper* cleanupHelper = static_cast<BufferCleanupHelper*>(context);
79 delete cleanupHelper;
80}
81
82///////////////////////////////////////////////////////////////////////////////////////////////////
83
84#if SK_SUPPORT_GPU
85
86
87sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::onGenerateTexture(
88 GrContext* context, const SkImageInfo& info, const SkIPoint& origin) {
89 // TODO: return a cached GrTextureProxy if invoked with the same context
90 // TODO: if we cache GrTextureProxy, then deleteImageTexture may be invoked on the wrong thread
91
92 if (!context->getGpu() || kOpenGL_GrBackend != context->contextPriv().getBackend()) {
93 // Check if GrContext is not abandoned and the backend is GL.
94 return nullptr;
95 }
96
97 while (GL_NO_ERROR != glGetError()) {} //clear GL errors
98
99 EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(fGraphicBuffer);
100 EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
101 EGL_NONE };
102 EGLDisplay display = eglGetCurrentDisplay();
103 EGLImageKHR image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
104 clientBuffer, attribs);
105 if (EGL_NO_IMAGE_KHR == image) {
106 SkDebugf("Could not create EGL image, err = (%#x)", (int) eglGetError() );
107 return nullptr;
108 }
109 GrGLuint texID;
110 glGenTextures(1, &texID);
111 if (!texID) {
112 eglDestroyImageKHR(display, image);
113 return nullptr;
114 }
115 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texID);
116 GLenum status = GL_NO_ERROR;
117 if ((status = glGetError()) != GL_NO_ERROR) {
118 SkDebugf("glBindTexture failed (%#x)", (int) status);
119 glDeleteTextures(1, &texID);
120 eglDestroyImageKHR(display, image);
121 return nullptr;
122 }
123 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
124 if ((status = glGetError()) != GL_NO_ERROR) {
125 SkDebugf("glEGLImageTargetTexture2DOES failed (%#x)", (int) status);
126 glDeleteTextures(1, &texID);
127 eglDestroyImageKHR(display, image);
128 return nullptr;
129 }
130 context->resetContext(kTextureBinding_GrGLBackendState);
131
132 GrGLTextureInfo textureInfo;
133 textureInfo.fTarget = GL_TEXTURE_EXTERNAL_OES;
134 textureInfo.fID = texID;
135
136 GrPixelConfig pixelConfig;
137 switch (getInfo().colorType()) {
138 case kRGBA_8888_SkColorType:
139 pixelConfig = kRGBA_8888_GrPixelConfig;
140 break;
141 case kRGBA_F16_SkColorType:
142 pixelConfig = kRGBA_half_GrPixelConfig;
143 break;
144 case kRGB_565_SkColorType:
145 pixelConfig = kRGB_565_GrPixelConfig;
146 break;
147 default:
148 glDeleteTextures(1, &texID);
149 eglDestroyImageKHR(display, image);
150 return nullptr;
151 }
152
153 GrBackendTexture backendTex(getInfo().width(), getInfo().height(), pixelConfig, textureInfo);
154 if (backendTex.width() <= 0 || backendTex.height() <= 0) {
155 glDeleteTextures(1, &texID);
156 eglDestroyImageKHR(display, image);
157 return nullptr;
158 }
159 GrBackendTextureFlags flags = kNone_GrBackendTextureFlag;
160 sk_sp<GrTexture> tex = context->resourceProvider()->wrapBackendTexture(backendTex,
161 kTopLeft_GrSurfaceOrigin,
162 flags,
163 0,
164 kAdopt_GrWrapOwnership);
165 if (!tex) {
166 glDeleteTextures(1, &texID);
167 eglDestroyImageKHR(display, image);
168 return nullptr;
169 }
170 tex->setRelease(deleteImageTexture, new BufferCleanupHelper(image, display));
171 sk_sp<GrTextureProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(tex)));
172
173 if (0 == origin.fX && 0 == origin.fY &&
174 info.width() == backendTex.width() && info.height() == backendTex.height()) {
175 // If the caller wants the entire texture, we're done
176 return proxy;
177 } else {
178 // Otherwise, make a copy of the requested subset.
179 GrSurfaceDesc desc;
180 desc.fConfig = proxy->config();
181 desc.fWidth = info.width();
182 desc.fHeight = info.height();
183 desc.fOrigin = proxy->origin();
184 desc.fIsMipMapped = proxy->isMipMapped();
185
186 sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeDeferredSurfaceContext(
187 desc, SkBackingFit::kExact, SkBudgeted::kYes));
188 if (!sContext) {
189 return nullptr;
190 }
191
192 SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(), info.height());
193 if (!sContext->copy(proxy.get(), subset, SkIPoint::Make(0, 0))) {
194 return nullptr;
195 }
196
197 return sContext->asTextureProxyRef();
198 }
199}
200#endif
201
202bool GrAHardwareBufferImageGenerator::onIsValid(GrContext* context) const {
203 if (nullptr == context) {
204 return false; //CPU backend is not supported, because hardware buffer can be swizzled
205 }
206 // TODO: add Vulkan support
207 return kOpenGL_GrBackend == context->contextPriv().getBackend();
208}
209
210#endif //SK_BUILD_FOR_ANDROID_FRAMEWORK