blob: 359aa381fe01fe89899f6f93ee35fb3f8ec8a2e6 [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
Derek Sollenberger7a869872017-06-27 15:37:25 -04009
10#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
Stan Iliev7e910df2017-06-02 10:29:21 -040011#define GL_GLEXT_PROTOTYPES
12#define EGL_EGLEXT_PROTOTYPES
13#include "GrAHardwareBufferImageGenerator.h"
14
Derek Sollenberger7a869872017-06-27 15:37:25 -040015#include <android/hardware_buffer.h>
16
Stan Iliev7e910df2017-06-02 10:29:21 -040017#include "GrBackendSurface.h"
18#include "GrContext.h"
19#include "GrContextPriv.h"
Robert Phillipsadbe1322018-01-17 13:35:46 -050020#include "GrProxyProvider.h"
Stan Ilievdbba55d2017-06-28 13:24:41 -040021#include "GrResourceCache.h"
Robert Phillips00018282017-06-15 15:35:16 -040022#include "GrResourceProvider.h"
Robert Phillips847d4c52017-06-13 18:21:44 -040023#include "GrTexture.h"
Robert Phillipsade9f612017-06-16 07:32:43 -040024#include "GrTextureProxy.h"
Stan Ilievdbba55d2017-06-28 13:24:41 -040025#include "SkMessageBus.h"
Greg Danielf1251112018-08-27 09:55:03 -040026#include "gl/GrGLDefines.h"
27#include "gl/GrGLTypes.h"
Stan Iliev7e910df2017-06-02 10:29:21 -040028
29#include <EGL/egl.h>
30#include <EGL/eglext.h>
31#include <GLES/gl.h>
32#include <GLES/glext.h>
33
Stan Ilievc01b5c72018-08-28 10:18:19 -040034#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
35#define EGL_PROTECTED_CONTENT_EXT 0x32C0
36
37static bool can_import_protected_content_eglimpl() {
38 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
39 const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
40 size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
41 size_t extsLen = strlen(exts);
42 bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
43 bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen+1);
44 bool atEnd = (cropExtLen+1) < extsLen
45 && !strcmp(" " PROT_CONTENT_EXT_STR,
46 exts + extsLen - (cropExtLen+1));
47 bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
48 return equal || atStart || atEnd || inMiddle;
49}
50
51static bool can_import_protected_content(GrContext* context) {
52 if (kOpenGL_GrBackend == context->contextPriv().getBackend()) {
53 // Only compute whether the extension is present once the first time this
54 // function is called.
55 static bool hasIt = can_import_protected_content_eglimpl();
56 return hasIt;
57 }
58 return false;
59}
60
Stan Iliev7e910df2017-06-02 10:29:21 -040061std::unique_ptr<SkImageGenerator> GrAHardwareBufferImageGenerator::Make(
62 AHardwareBuffer* graphicBuffer, SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
63 AHardwareBuffer_Desc bufferDesc;
64 AHardwareBuffer_describe(graphicBuffer, &bufferDesc);
65 SkColorType colorType;
66 switch (bufferDesc.format) {
67 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
68 colorType = kRGBA_8888_SkColorType;
69 break;
70 case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
71 colorType = kRGBA_F16_SkColorType;
72 break;
73 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
74 colorType = kRGB_565_SkColorType;
75 break;
Stan Iliev114b0912018-08-31 14:02:55 -040076 case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
77 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
78 colorType = kRGB_888x_SkColorType;
79 break;
80 case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
81 colorType = kRGBA_1010102_SkColorType;
82 break;
Stan Iliev7e910df2017-06-02 10:29:21 -040083 default:
Stan Iliev114b0912018-08-31 14:02:55 -040084 // Given that we only use this texture as a source, colorType will not impact how Skia uses
85 // the texture. The only potential affect this is anticipated to have is that for some
86 // format types if we are not bound as an OES texture we may get invalid results for SKP
87 // capture if we read back the texture.
88 colorType = kRGBA_8888_SkColorType;
89 break;
Stan Iliev7e910df2017-06-02 10:29:21 -040090 }
91 SkImageInfo info = SkImageInfo::Make(bufferDesc.width, bufferDesc.height, colorType,
92 alphaType, std::move(colorSpace));
Stan Ilievc01b5c72018-08-28 10:18:19 -040093 bool createProtectedImage = 0 != (bufferDesc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
Stan Iliev7e910df2017-06-02 10:29:21 -040094 return std::unique_ptr<SkImageGenerator>(new GrAHardwareBufferImageGenerator(info, graphicBuffer,
Stan Iliev114b0912018-08-31 14:02:55 -040095 alphaType, createProtectedImage, bufferDesc.format));
Stan Iliev7e910df2017-06-02 10:29:21 -040096}
97
98GrAHardwareBufferImageGenerator::GrAHardwareBufferImageGenerator(const SkImageInfo& info,
Stan Iliev114b0912018-08-31 14:02:55 -040099 AHardwareBuffer* hardwareBuffer, SkAlphaType alphaType, bool isProtectedContent,
100 uint32_t bufferFormat)
Stan Iliev7e910df2017-06-02 10:29:21 -0400101 : INHERITED(info)
Stan Ilievc01b5c72018-08-28 10:18:19 -0400102 , fHardwareBuffer(hardwareBuffer)
Stan Iliev114b0912018-08-31 14:02:55 -0400103 , fBufferFormat(bufferFormat)
Stan Ilievc01b5c72018-08-28 10:18:19 -0400104 , fIsProtectedContent(isProtectedContent) {
Greg Danielf1251112018-08-27 09:55:03 -0400105 AHardwareBuffer_acquire(fHardwareBuffer);
106}
107
Stan Iliev7e910df2017-06-02 10:29:21 -0400108GrAHardwareBufferImageGenerator::~GrAHardwareBufferImageGenerator() {
Greg Danielf1251112018-08-27 09:55:03 -0400109 AHardwareBuffer_release(fHardwareBuffer);
Stan Iliev7e910df2017-06-02 10:29:21 -0400110}
111
Stan Iliev7e910df2017-06-02 10:29:21 -0400112///////////////////////////////////////////////////////////////////////////////////////////////////
113
Greg Daniel3860cfd2018-09-07 09:13:54 -0400114class GLCleanupHelper {
Greg Daniel9af948d2018-08-27 09:53:51 -0400115public:
Greg Daniel3860cfd2018-09-07 09:13:54 -0400116 GLCleanupHelper(GrGLuint texID, EGLImageKHR image, EGLDisplay display)
117 : fTexID(texID)
118 , fImage(image)
Greg Daniel9af948d2018-08-27 09:53:51 -0400119 , fDisplay(display) { }
Greg Daniel3860cfd2018-09-07 09:13:54 -0400120 ~GLCleanupHelper() {
121 glDeleteTextures(1, &fTexID);
Greg Danielf1251112018-08-27 09:55:03 -0400122 // eglDestroyImageKHR will remove a ref from the AHardwareBuffer
Greg Daniel9af948d2018-08-27 09:53:51 -0400123 eglDestroyImageKHR(fDisplay, fImage);
124 }
125private:
Greg Daniel3860cfd2018-09-07 09:13:54 -0400126 GrGLuint fTexID;
Greg Daniel9af948d2018-08-27 09:53:51 -0400127 EGLImageKHR fImage;
Greg Daniel3860cfd2018-09-07 09:13:54 -0400128 EGLDisplay fDisplay;
Greg Daniel9af948d2018-08-27 09:53:51 -0400129};
130
131
Greg Daniel3860cfd2018-09-07 09:13:54 -0400132void GrAHardwareBufferImageGenerator::DeleteGLTexture(void* context) {
133 GLCleanupHelper* cleanupHelper = static_cast<GLCleanupHelper*>(context);
Greg Daniel9af948d2018-08-27 09:53:51 -0400134 delete cleanupHelper;
135}
136
137static GrBackendTexture make_gl_backend_texture(
138 GrContext* context, AHardwareBuffer* hardwareBuffer,
Greg Danielf1251112018-08-27 09:55:03 -0400139 int width, int height, GrPixelConfig config,
Greg Daniel9af948d2018-08-27 09:53:51 -0400140 GrAHardwareBufferImageGenerator::DeleteImageProc* deleteProc,
Stan Ilievc01b5c72018-08-28 10:18:19 -0400141 GrAHardwareBufferImageGenerator::DeleteImageCtx* deleteCtx,
Stan Iliev114b0912018-08-31 14:02:55 -0400142 bool isProtectedContent,
143 const GrBackendFormat& backendFormat) {
Greg Daniel9af948d2018-08-27 09:53:51 -0400144 while (GL_NO_ERROR != glGetError()) {} //clear GL errors
145
Stan Ilievc01b5c72018-08-28 10:18:19 -0400146 EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer);
Greg Daniel9af948d2018-08-27 09:53:51 -0400147 EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
Stan Ilievc01b5c72018-08-28 10:18:19 -0400148 isProtectedContent ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
149 isProtectedContent ? EGL_TRUE : EGL_NONE,
Greg Daniel9af948d2018-08-27 09:53:51 -0400150 EGL_NONE };
151 EGLDisplay display = eglGetCurrentDisplay();
Greg Danielf1251112018-08-27 09:55:03 -0400152 // eglCreateImageKHR will add a ref to the AHardwareBuffer
Greg Daniel9af948d2018-08-27 09:53:51 -0400153 EGLImageKHR image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
154 clientBuffer, attribs);
155 if (EGL_NO_IMAGE_KHR == image) {
156 SkDebugf("Could not create EGL image, err = (%#x)", (int) eglGetError() );
157 return GrBackendTexture();
158 }
159
160 GrGLuint texID;
161 glGenTextures(1, &texID);
162 if (!texID) {
163 eglDestroyImageKHR(display, image);
164 return GrBackendTexture();
165 }
166 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texID);
167 GLenum status = GL_NO_ERROR;
168 if ((status = glGetError()) != GL_NO_ERROR) {
169 SkDebugf("glBindTexture failed (%#x)", (int) status);
170 glDeleteTextures(1, &texID);
171 eglDestroyImageKHR(display, image);
172 return GrBackendTexture();
173 }
174 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
175 if ((status = glGetError()) != GL_NO_ERROR) {
176 SkDebugf("glEGLImageTargetTexture2DOES failed (%#x)", (int) status);
177 glDeleteTextures(1, &texID);
178 eglDestroyImageKHR(display, image);
179 return GrBackendTexture();
180 }
181 context->resetContext(kTextureBinding_GrGLBackendState);
182
183 GrGLTextureInfo textureInfo;
Greg Daniel9af948d2018-08-27 09:53:51 -0400184 textureInfo.fID = texID;
Stan Iliev114b0912018-08-31 14:02:55 -0400185 SkASSERT(backendFormat.isValid());
186 textureInfo.fTarget = *backendFormat.getGLTarget();
187 textureInfo.fFormat = *backendFormat.getGLFormat();
Greg Daniel9af948d2018-08-27 09:53:51 -0400188
Greg Daniel3860cfd2018-09-07 09:13:54 -0400189 *deleteProc = GrAHardwareBufferImageGenerator::DeleteGLTexture;
190 *deleteCtx = new GLCleanupHelper(texID, image, display);
Greg Daniel9af948d2018-08-27 09:53:51 -0400191
192 return GrBackendTexture(width, height, GrMipMapped::kNo, textureInfo);
193}
194
195static GrBackendTexture make_backend_texture(
196 GrContext* context, AHardwareBuffer* hardwareBuffer,
Greg Danielf1251112018-08-27 09:55:03 -0400197 int width, int height, GrPixelConfig config,
Greg Daniel9af948d2018-08-27 09:53:51 -0400198 GrAHardwareBufferImageGenerator::DeleteImageProc* deleteProc,
Stan Ilievc01b5c72018-08-28 10:18:19 -0400199 GrAHardwareBufferImageGenerator::DeleteImageCtx* deleteCtx,
Stan Iliev114b0912018-08-31 14:02:55 -0400200 bool isProtectedContent,
201 const GrBackendFormat& backendFormat) {
Greg Daniel9af948d2018-08-27 09:53:51 -0400202 if (context->abandoned() || kOpenGL_GrBackend != context->contextPriv().getBackend()) {
203 // Check if GrContext is not abandoned and the backend is GL.
204 return GrBackendTexture();
205 }
Stan Ilievc01b5c72018-08-28 10:18:19 -0400206 bool createProtectedImage = isProtectedContent && can_import_protected_content(context);
Greg Danielf1251112018-08-27 09:55:03 -0400207 return make_gl_backend_texture(context, hardwareBuffer, width, height, config, deleteProc,
Stan Iliev114b0912018-08-31 14:02:55 -0400208 deleteCtx, createProtectedImage, backendFormat);
Greg Daniel9af948d2018-08-27 09:53:51 -0400209}
210
Stan Iliev114b0912018-08-31 14:02:55 -0400211GrBackendFormat get_backend_format(GrBackend backend, uint32_t bufferFormat) {
212 if (backend == kOpenGL_GrBackend) {
213 switch (bufferFormat) {
214 //TODO: find out if we can detect, which graphic buffers support GR_GL_TEXTURE_2D
215 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
216 return GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
217 case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
218 return GrBackendFormat::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_EXTERNAL);
219 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
220 return GrBackendFormat::MakeGL(GR_GL_RGB565, GR_GL_TEXTURE_EXTERNAL);
221 case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
222 return GrBackendFormat::MakeGL(GR_GL_RGB10_A2, GR_GL_TEXTURE_EXTERNAL);
223 case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
224 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
225 return GrBackendFormat::MakeGL(GR_GL_RGB8, GR_GL_TEXTURE_EXTERNAL);
226 default:
227 return GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
228 }
229 }
230 return GrBackendFormat();
231}
232
Greg Daniel3860cfd2018-09-07 09:13:54 -0400233sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::makeProxy(GrContext* context) {
Khushalc421ca12018-06-26 14:38:34 -0700234 if (context->abandoned() || kOpenGL_GrBackend != context->contextPriv().getBackend()) {
Stan Iliev7e910df2017-06-02 10:29:21 -0400235 // Check if GrContext is not abandoned and the backend is GL.
Greg Daniel3860cfd2018-09-07 09:13:54 -0400236 return nullptr;
Stan Iliev7e910df2017-06-02 10:29:21 -0400237 }
238
Stan Iliev7e910df2017-06-02 10:29:21 -0400239 GrPixelConfig pixelConfig;
Stan Iliev114b0912018-08-31 14:02:55 -0400240 GrBackendFormat backendFormat = get_backend_format(context->contextPriv().getBackend(),
241 fBufferFormat);
242 if (!context->contextPriv().caps()->getConfigFromBackendFormat(
243 backendFormat, this->getInfo().colorType(), &pixelConfig)) {
Greg Daniel3860cfd2018-09-07 09:13:54 -0400244 return nullptr;
Stan Iliev7e910df2017-06-02 10:29:21 -0400245 }
246
Greg Danielf1251112018-08-27 09:55:03 -0400247 int width = this->getInfo().width();
248 int height = this->getInfo().height();
Greg Daniel9af948d2018-08-27 09:53:51 -0400249
Greg Danielf1251112018-08-27 09:55:03 -0400250 GrSurfaceDesc desc;
251 desc.fWidth = width;
252 desc.fHeight = height;
253 desc.fConfig = pixelConfig;
Greg Daniel9af948d2018-08-27 09:53:51 -0400254
Greg Danielf1251112018-08-27 09:55:03 -0400255 GrTextureType textureType = GrTextureType::k2D;
256 if (context->contextPriv().getBackend() == kOpenGL_GrBackend) {
257 textureType = GrTextureType::kExternal;
Stan Iliev7e910df2017-06-02 10:29:21 -0400258 }
Greg Daniel6a0176b2018-01-30 09:28:44 -0500259
Greg Danielf1251112018-08-27 09:55:03 -0400260 auto proxyProvider = context->contextPriv().proxyProvider();
261
262 AHardwareBuffer* hardwareBuffer = fHardwareBuffer;
263 AHardwareBuffer_acquire(hardwareBuffer);
264
Stan Ilievc01b5c72018-08-28 10:18:19 -0400265 const bool isProtectedContent = fIsProtectedContent;
Greg Danielf1251112018-08-27 09:55:03 -0400266
Greg Daniel3860cfd2018-09-07 09:13:54 -0400267 sk_sp<GrTextureProxy> texProxy = proxyProvider->createLazyProxy(
268 [context, hardwareBuffer, width, height, pixelConfig, isProtectedContent, backendFormat]
Greg Danielf1251112018-08-27 09:55:03 -0400269 (GrResourceProvider* resourceProvider) {
270 if (!resourceProvider) {
271 AHardwareBuffer_release(hardwareBuffer);
272 return sk_sp<GrTexture>();
273 }
274
Greg Danielf1251112018-08-27 09:55:03 -0400275 DeleteImageProc deleteImageProc = nullptr;
276 DeleteImageCtx deleteImageCtx = nullptr;
277
278 GrBackendTexture backendTex = make_backend_texture(context, hardwareBuffer,
279 width, height, pixelConfig,
280 &deleteImageProc,
Stan Ilievc01b5c72018-08-28 10:18:19 -0400281 &deleteImageCtx,
Stan Iliev114b0912018-08-31 14:02:55 -0400282 isProtectedContent,
283 backendFormat);
Greg Danielf1251112018-08-27 09:55:03 -0400284 if (!backendTex.isValid()) {
285 return sk_sp<GrTexture>();
286 }
287 SkASSERT(deleteImageProc && deleteImageCtx);
288
289 backendTex.fConfig = pixelConfig;
Greg Daniel3860cfd2018-09-07 09:13:54 -0400290 sk_sp<GrTexture> tex = resourceProvider->wrapBackendTexture(backendTex);
Greg Danielf1251112018-08-27 09:55:03 -0400291 if (!tex) {
Greg Danielf1251112018-08-27 09:55:03 -0400292 deleteImageProc(deleteImageCtx);
293 return sk_sp<GrTexture>();
294 }
295
296 sk_sp<GrReleaseProcHelper> releaseProcHelper(
Greg Daniel9af948d2018-08-27 09:53:51 -0400297 new GrReleaseProcHelper(deleteImageProc, deleteImageCtx));
Greg Danielf1251112018-08-27 09:55:03 -0400298 tex->setRelease(releaseProcHelper);
Stan Iliev7e910df2017-06-02 10:29:21 -0400299
Greg Danielf1251112018-08-27 09:55:03 -0400300 return tex;
301 },
302 desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, textureType, SkBackingFit::kExact,
303 SkBudgeted::kNo);
304
Greg Daniel3860cfd2018-09-07 09:13:54 -0400305 if (!texProxy) {
Greg Danielf1251112018-08-27 09:55:03 -0400306 AHardwareBuffer_release(hardwareBuffer);
Greg Danielf1251112018-08-27 09:55:03 -0400307 }
Greg Daniel3860cfd2018-09-07 09:13:54 -0400308 return texProxy;
309}
310
311sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::onGenerateTexture(
312 GrContext* context, const SkImageInfo& info, const SkIPoint& origin, bool willNeedMipMaps) {
313 sk_sp<GrTextureProxy> texProxy = this->makeProxy(context);
314 if (!texProxy) {
315 return nullptr;
316 }
317
318 if (0 == origin.fX && 0 == origin.fY &&
319 info.width() == this->getInfo().width() && info.height() == this->getInfo().height()) {
320 // If the caller wants the full texture we're done. The caller will handle making a copy for
321 // mip maps if that is required.
322 return texProxy;
323 }
324 // Otherwise, make a copy for the requested subset.
325 SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(), info.height());
326
327 GrMipMapped mipMapped = willNeedMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo;
328
329 return GrSurfaceProxy::Copy(context, texProxy.get(), mipMapped, subset, SkBudgeted::kYes);
Stan Iliev7e910df2017-06-02 10:29:21 -0400330}
Stan Iliev7e910df2017-06-02 10:29:21 -0400331
332bool GrAHardwareBufferImageGenerator::onIsValid(GrContext* context) const {
333 if (nullptr == context) {
334 return false; //CPU backend is not supported, because hardware buffer can be swizzled
335 }
336 // TODO: add Vulkan support
337 return kOpenGL_GrBackend == context->contextPriv().getBackend();
338}
339
340#endif //SK_BUILD_FOR_ANDROID_FRAMEWORK