xref: /aosp_15_r20/external/skia/src/gpu/ganesh/gl/AHardwareBufferGL.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2023 Google LLC
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 
8 #include "include/android/GrAHardwareBufferUtils.h"
9 
10 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
11 #define GL_GLEXT_PROTOTYPES
12 #define EGL_EGLEXT_PROTOTYPES
13 
14 #include "include/gpu/ganesh/GrBackendSurface.h"
15 #include "include/gpu/ganesh/GrDirectContext.h"
16 #include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
17 #include "include/gpu/ganesh/gl/GrGLTypes.h"
18 #include "src/gpu/ganesh/GrDirectContextPriv.h"
19 #include "src/gpu/ganesh/gl/GrGLDefines.h"
20 #include "src/gpu/ganesh/gl/GrGLUtil.h"
21 
22 #include <android/hardware_buffer.h>
23 #include <EGL/egl.h>
24 #include <EGL/eglext.h>
25 #include <GLES/gl.h>
26 #include <GLES/glext.h>
27 
28 #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
29 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
30 
31 namespace GrAHardwareBufferUtils {
32 
GetGLBackendFormat(GrDirectContext * dContext,uint32_t bufferFormat,bool requireKnownFormat)33 GrBackendFormat GetGLBackendFormat(GrDirectContext* dContext,
34                                    uint32_t bufferFormat, bool requireKnownFormat) {
35     GrBackendApi backend = dContext->backend();
36     if (backend != GrBackendApi::kOpenGL) {
37         return GrBackendFormat();
38     }
39     switch (bufferFormat) {
40         //TODO: find out if we can detect, which graphic buffers support GR_GL_TEXTURE_2D
41         case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
42         case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
43             return GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
44         case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
45             return GrBackendFormats::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_EXTERNAL);
46         case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
47             return GrBackendFormats::MakeGL(GR_GL_RGB565, GR_GL_TEXTURE_EXTERNAL);
48         case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
49             return GrBackendFormats::MakeGL(GR_GL_RGB10_A2, GR_GL_TEXTURE_EXTERNAL);
50         case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
51             return GrBackendFormats::MakeGL(GR_GL_RGB8, GR_GL_TEXTURE_EXTERNAL);
52 #if __ANDROID_API__ >= 33
53         case AHARDWAREBUFFER_FORMAT_R8_UNORM:
54             return GrBackendFormats::MakeGL(GR_GL_R8, GR_GL_TEXTURE_EXTERNAL);
55 #endif
56         default:
57             if (requireKnownFormat) {
58                 return GrBackendFormat();
59             } else {
60                 return GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
61             }
62     }
63     SkUNREACHABLE;
64 }
65 
66 class GLTextureHelper {
67 public:
GLTextureHelper(GrGLuint texID,EGLImageKHR image,EGLDisplay display,GrGLuint texTarget)68     GLTextureHelper(GrGLuint texID, EGLImageKHR image, EGLDisplay display, GrGLuint texTarget)
69         : fTexID(texID)
70         , fImage(image)
71         , fDisplay(display)
72         , fTexTarget(texTarget) { }
~GLTextureHelper()73     ~GLTextureHelper() {
74         glDeleteTextures(1, &fTexID);
75         // eglDestroyImageKHR will remove a ref from the AHardwareBuffer
76         eglDestroyImageKHR(fDisplay, fImage);
77     }
78     void rebind(GrDirectContext*);
79 
80 private:
81     GrGLuint    fTexID;
82     EGLImageKHR fImage;
83     EGLDisplay  fDisplay;
84     GrGLuint    fTexTarget;
85 };
86 
rebind(GrDirectContext * dContext)87 void GLTextureHelper::rebind(GrDirectContext* dContext) {
88     glBindTexture(fTexTarget, fTexID);
89     GLenum status = GL_NO_ERROR;
90     if ((status = glGetError()) != GL_NO_ERROR) {
91         SkDebugf("glBindTexture(%#x, %d) failed (%#x)", (int) fTexTarget,
92             (int) fTexID, (int) status);
93         return;
94     }
95     glEGLImageTargetTexture2DOES(fTexTarget, fImage);
96     if ((status = glGetError()) != GL_NO_ERROR) {
97         SkDebugf("glEGLImageTargetTexture2DOES failed (%#x)", (int) status);
98         return;
99     }
100     dContext->resetContext(kTextureBinding_GrGLBackendState);
101 }
102 
delete_gl_texture(void * context)103 void delete_gl_texture(void* context) {
104     GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context);
105     delete cleanupHelper;
106 }
107 
update_gl_texture(void * context,GrDirectContext * dContext)108 void update_gl_texture(void* context, GrDirectContext* dContext) {
109     GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context);
110     cleanupHelper->rebind(dContext);
111 }
112 
make_gl_backend_texture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & backendFormat,bool isRenderable)113 static GrBackendTexture make_gl_backend_texture(
114         GrDirectContext* dContext,
115         AHardwareBuffer* hardwareBuffer,
116         int width, int height,
117         DeleteImageProc* deleteProc,
118         UpdateImageProc* updateProc,
119         TexImageCtx* imageCtx,
120         bool isProtectedContent,
121         const GrBackendFormat& backendFormat,
122         bool isRenderable) {
123     while (GL_NO_ERROR != glGetError()) {} //clear GL errors
124 
125     EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer);
126     EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
127                          isProtectedContent ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
128                          isProtectedContent ? EGL_TRUE : EGL_NONE,
129                          EGL_NONE };
130     EGLDisplay display = eglGetCurrentDisplay();
131     // eglCreateImageKHR will add a ref to the AHardwareBuffer
132     EGLImageKHR image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
133                                           clientBuffer, attribs);
134     if (EGL_NO_IMAGE_KHR == image) {
135         SkDebugf("Could not create EGL image, err = (%#x)", (int) eglGetError() );
136         return GrBackendTexture();
137     }
138 
139     GrGLuint texID;
140     glGenTextures(1, &texID);
141     if (!texID) {
142         eglDestroyImageKHR(display, image);
143         return GrBackendTexture();
144     }
145 
146     GrGLuint target = isRenderable ? GR_GL_TEXTURE_2D : GR_GL_TEXTURE_EXTERNAL;
147 
148     glBindTexture(target, texID);
149     GLenum status = GL_NO_ERROR;
150     if ((status = glGetError()) != GL_NO_ERROR) {
151         SkDebugf("glBindTexture failed (%#x)", (int) status);
152         glDeleteTextures(1, &texID);
153         eglDestroyImageKHR(display, image);
154         return GrBackendTexture();
155     }
156     glEGLImageTargetTexture2DOES(target, image);
157     if ((status = glGetError()) != GL_NO_ERROR) {
158         SkDebugf("glEGLImageTargetTexture2DOES failed (%#x)", (int) status);
159         glDeleteTextures(1, &texID);
160         eglDestroyImageKHR(display, image);
161         return GrBackendTexture();
162     }
163     dContext->resetContext(kTextureBinding_GrGLBackendState);
164 
165     GrGLTextureInfo textureInfo;
166     textureInfo.fID = texID;
167     SkASSERT(backendFormat.isValid());
168     textureInfo.fTarget = target;
169     textureInfo.fFormat = GrBackendFormats::AsGLFormatEnum(backendFormat);
170     textureInfo.fProtected = skgpu::Protected(isProtectedContent);
171 
172     *deleteProc = delete_gl_texture;
173     *updateProc = update_gl_texture;
174     *imageCtx = new GLTextureHelper(texID, image, display, target);
175 
176     return GrBackendTextures::MakeGL(width, height, skgpu::Mipmapped::kNo, textureInfo);
177 }
178 
can_import_protected_content_eglimpl()179 static bool can_import_protected_content_eglimpl() {
180     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
181     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
182     size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
183     size_t extsLen = strlen(exts);
184     bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
185     bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen+1);
186     bool atEnd = (cropExtLen+1) < extsLen
187                   && !strcmp(" " PROT_CONTENT_EXT_STR,
188                   exts + extsLen - (cropExtLen+1));
189     bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
190     return equal || atStart || atEnd || inMiddle;
191 }
192 
can_import_protected_content(GrDirectContext * dContext)193 static bool can_import_protected_content(GrDirectContext* dContext) {
194     SkASSERT(GrBackendApi::kOpenGL == dContext->backend());
195     // Only compute whether the extension is present once the first time this
196     // function is called.
197     static bool hasIt = can_import_protected_content_eglimpl();
198     return hasIt;
199 }
200 
MakeGLBackendTexture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & backendFormat,bool isRenderable)201 GrBackendTexture MakeGLBackendTexture(GrDirectContext* dContext,
202                                       AHardwareBuffer* hardwareBuffer,
203                                       int width, int height,
204                                       DeleteImageProc* deleteProc,
205                                       UpdateImageProc* updateProc,
206                                       TexImageCtx* imageCtx,
207                                       bool isProtectedContent,
208                                       const GrBackendFormat& backendFormat,
209                                       bool isRenderable) {
210     SkASSERT(dContext);
211     if (!dContext || dContext->abandoned()) {
212         return GrBackendTexture();
213     }
214 
215     if (GrBackendApi::kOpenGL != dContext->backend()) {
216         return GrBackendTexture();
217     }
218 
219     if (isProtectedContent && !can_import_protected_content(dContext)) {
220         return GrBackendTexture();
221     }
222 
223     return make_gl_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
224                                    updateProc, imageCtx, isProtectedContent, backendFormat,
225                                    isRenderable);
226 }
227 
228 }  // namespace GrAHardwareBufferUtils
229 
230 #endif
231