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