xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // PBufferSurfaceCGL.cpp: an implementation of PBuffers created from IOSurfaces using
8 //                        EGL_ANGLE_iosurface_client_buffer
9 
10 #include "libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h"
11 
12 #include <IOSurface/IOSurface.h>
13 #include <OpenGL/CGLIOSurface.h>
14 #include <OpenGL/OpenGL.h>
15 
16 #include "common/debug.h"
17 #include "common/gl/cgl/FunctionsCGL.h"
18 #include "libANGLE/AttributeMap.h"
19 #include "libANGLE/renderer/gl/BlitGL.h"
20 #include "libANGLE/renderer/gl/FramebufferGL.h"
21 #include "libANGLE/renderer/gl/FunctionsGL.h"
22 #include "libANGLE/renderer/gl/RendererGL.h"
23 #include "libANGLE/renderer/gl/StateManagerGL.h"
24 #include "libANGLE/renderer/gl/TextureGL.h"
25 #include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
26 
27 namespace rx
28 {
29 
30 namespace
31 {
32 
33 struct IOSurfaceFormatInfo
34 {
35     GLenum internalFormat;
36     GLenum type;
37 
38     size_t componentBytes;
39 
40     GLenum nativeInternalFormat;
41     GLenum nativeFormat;
42     GLenum nativeType;
43 };
44 
45 // clang-format off
46 static const IOSurfaceFormatInfo kIOSurfaceFormats[] = {
47     {GL_RED,      GL_UNSIGNED_BYTE,                1, GL_RED,  GL_RED,  GL_UNSIGNED_BYTE              },
48     {GL_RED,      GL_UNSIGNED_SHORT,               2, GL_RED,  GL_RED,  GL_UNSIGNED_SHORT             },
49     {GL_RG,       GL_UNSIGNED_BYTE,                2, GL_RG,   GL_RG,   GL_UNSIGNED_BYTE              },
50     {GL_RG,       GL_UNSIGNED_SHORT,               4, GL_RG,   GL_RG,   GL_UNSIGNED_SHORT             },
51     {GL_RGB,      GL_UNSIGNED_BYTE,                4, GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV   },
52     {GL_BGRA_EXT, GL_UNSIGNED_BYTE,                4, GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV   },
53     {GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV,  4, GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV},
54     {GL_RGBA,     GL_HALF_FLOAT,                   8, GL_RGBA, GL_RGBA, GL_HALF_FLOAT                 },
55 };
56 // clang-format on
57 
FindIOSurfaceFormatIndex(GLenum internalFormat,GLenum type)58 int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
59 {
60     for (int i = 0; i < static_cast<int>(ArraySize(kIOSurfaceFormats)); ++i)
61     {
62         const auto &formatInfo = kIOSurfaceFormats[i];
63         if (formatInfo.internalFormat == internalFormat && formatInfo.type == type)
64         {
65             return i;
66         }
67     }
68     return -1;
69 }
70 
71 }  // anonymous namespace
72 
IOSurfaceSurfaceCGL(const egl::SurfaceState & state,RendererGL * renderer,CGLContextObj cglContext,EGLClientBuffer buffer,const egl::AttributeMap & attribs)73 IOSurfaceSurfaceCGL::IOSurfaceSurfaceCGL(const egl::SurfaceState &state,
74                                          RendererGL *renderer,
75                                          CGLContextObj cglContext,
76                                          EGLClientBuffer buffer,
77                                          const egl::AttributeMap &attribs)
78     : SurfaceGL(state),
79       mFunctions(renderer->getFunctions()),
80       mStateManager(renderer->getStateManager()),
81       mCGLContext(cglContext),
82       mIOSurface(nullptr),
83       mWidth(0),
84       mHeight(0),
85       mPlane(0),
86       mFormatIndex(-1),
87       mAlphaInitialized(false),
88       mTextureID(0),
89       mFramebufferID(0)
90 {
91     // Keep reference to the IOSurface so it doesn't get deleted while the pbuffer exists.
92     mIOSurface = reinterpret_cast<IOSurfaceRef>(buffer);
93     CFRetain(mIOSurface);
94 
95     // Extract attribs useful for the call to CGLTexImageIOSurface2D
96     mWidth  = static_cast<int>(attribs.get(EGL_WIDTH));
97     mHeight = static_cast<int>(attribs.get(EGL_HEIGHT));
98     mPlane  = static_cast<int>(attribs.get(EGL_IOSURFACE_PLANE_ANGLE));
99 
100     EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
101     EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
102     mFormatIndex =
103         FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
104     ASSERT(mFormatIndex >= 0);
105 
106     mAlphaInitialized = !hasEmulatedAlphaChannel();
107 }
108 
~IOSurfaceSurfaceCGL()109 IOSurfaceSurfaceCGL::~IOSurfaceSurfaceCGL()
110 {
111     if (mFramebufferID != 0)
112     {
113         mStateManager->deleteFramebuffer(mFramebufferID);
114         mFramebufferID = 0;
115         mStateManager->deleteTexture(mTextureID);
116         mTextureID = 0;
117     }
118 
119     if (mIOSurface != nullptr)
120     {
121         CFRelease(mIOSurface);
122         mIOSurface = nullptr;
123     }
124 }
125 
initialize(const egl::Display * display)126 egl::Error IOSurfaceSurfaceCGL::initialize(const egl::Display *display)
127 {
128     return egl::NoError();
129 }
130 
makeCurrent(const gl::Context * context)131 egl::Error IOSurfaceSurfaceCGL::makeCurrent(const gl::Context *context)
132 {
133     return egl::NoError();
134 }
135 
unMakeCurrent(const gl::Context * context)136 egl::Error IOSurfaceSurfaceCGL::unMakeCurrent(const gl::Context *context)
137 {
138     GetFunctionsGL(context)->flush();
139     return egl::NoError();
140 }
141 
swap(const gl::Context * context)142 egl::Error IOSurfaceSurfaceCGL::swap(const gl::Context *context)
143 {
144     return egl::NoError();
145 }
146 
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)147 egl::Error IOSurfaceSurfaceCGL::postSubBuffer(const gl::Context *context,
148                                               EGLint x,
149                                               EGLint y,
150                                               EGLint width,
151                                               EGLint height)
152 {
153     UNREACHABLE();
154     return egl::NoError();
155 }
156 
querySurfacePointerANGLE(EGLint attribute,void ** value)157 egl::Error IOSurfaceSurfaceCGL::querySurfacePointerANGLE(EGLint attribute, void **value)
158 {
159     UNREACHABLE();
160     return egl::NoError();
161 }
162 
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)163 egl::Error IOSurfaceSurfaceCGL::bindTexImage(const gl::Context *context,
164                                              gl::Texture *texture,
165                                              EGLint buffer)
166 {
167     StateManagerGL *stateManager = GetStateManagerGL(context);
168 
169     const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
170     GLuint textureID           = textureGL->getTextureID();
171     stateManager->bindTexture(gl::TextureType::Rectangle, textureID);
172 
173     const auto &format = kIOSurfaceFormats[mFormatIndex];
174     CGLError error     = CGLTexImageIOSurface2D(
175         mCGLContext, GL_TEXTURE_RECTANGLE, format.nativeInternalFormat, mWidth, mHeight,
176         format.nativeFormat, format.nativeType, mIOSurface, mPlane);
177 
178     if (error != kCGLNoError)
179     {
180         return egl::EglContextLost() << "CGLTexImageIOSurface2D failed: " << CGLErrorString(error);
181     }
182 
183     if (IsError(initializeAlphaChannel(context, textureID)))
184     {
185         return egl::EglContextLost() << "Failed to initialize IOSurface alpha channel.";
186     }
187 
188     return egl::NoError();
189 }
190 
releaseTexImage(const gl::Context * context,EGLint buffer)191 egl::Error IOSurfaceSurfaceCGL::releaseTexImage(const gl::Context *context, EGLint buffer)
192 {
193     const FunctionsGL *functions = GetFunctionsGL(context);
194     functions->flush();
195     return egl::NoError();
196 }
197 
setSwapInterval(const egl::Display * display,EGLint interval)198 void IOSurfaceSurfaceCGL::setSwapInterval(const egl::Display *display, EGLint interval)
199 {
200     UNREACHABLE();
201 }
202 
getWidth() const203 EGLint IOSurfaceSurfaceCGL::getWidth() const
204 {
205     return mWidth;
206 }
207 
getHeight() const208 EGLint IOSurfaceSurfaceCGL::getHeight() const
209 {
210     return mHeight;
211 }
212 
isPostSubBufferSupported() const213 EGLint IOSurfaceSurfaceCGL::isPostSubBufferSupported() const
214 {
215     UNREACHABLE();
216     return EGL_FALSE;
217 }
218 
getSwapBehavior() const219 EGLint IOSurfaceSurfaceCGL::getSwapBehavior() const
220 {
221     // N/A because you can't MakeCurrent an IOSurface, return any valid value.
222     return EGL_BUFFER_PRESERVED;
223 }
224 
225 // static
validateAttributes(EGLClientBuffer buffer,const egl::AttributeMap & attribs)226 bool IOSurfaceSurfaceCGL::validateAttributes(EGLClientBuffer buffer,
227                                              const egl::AttributeMap &attribs)
228 {
229     IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(buffer);
230 
231     // The plane must exist for this IOSurface. IOSurfaceGetPlaneCount can return 0 for non-planar
232     // ioSurfaces but we will treat non-planar like it is a single plane.
233     size_t surfacePlaneCount = std::max(size_t(1), IOSurfaceGetPlaneCount(ioSurface));
234     EGLAttrib plane          = attribs.get(EGL_IOSURFACE_PLANE_ANGLE);
235     if (plane < 0 || static_cast<size_t>(plane) >= surfacePlaneCount)
236     {
237         return false;
238     }
239 
240     // The width height specified must be at least (1, 1) and at most the plane size
241     EGLAttrib width  = attribs.get(EGL_WIDTH);
242     EGLAttrib height = attribs.get(EGL_HEIGHT);
243     if (width <= 0 || static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) ||
244         height <= 0 || static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, plane))
245     {
246         return false;
247     }
248 
249     // Find this IOSurface format
250     EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
251     EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
252 
253     int formatIndex =
254         FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
255 
256     if (formatIndex < 0)
257     {
258         return false;
259     }
260 
261     // FIXME: Check that the format matches this IOSurface plane for pixel formats that we know of.
262     // We could map IOSurfaceGetPixelFormat to expected type plane and format type.
263     // However, the caller might supply us non-public pixel format, which makes exhaustive checks
264     // problematic.
265     if (IOSurfaceGetBytesPerElementOfPlane(ioSurface, plane) !=
266         kIOSurfaceFormats[formatIndex].componentBytes)
267     {
268         WARN() << "IOSurface bytes per elements does not match the pbuffer internal format.";
269     }
270 
271     return true;
272 }
273 
initializeAlphaChannel(const gl::Context * context,GLuint texture)274 angle::Result IOSurfaceSurfaceCGL::initializeAlphaChannel(const gl::Context *context,
275                                                           GLuint texture)
276 {
277     if (mAlphaInitialized)
278     {
279         return angle::Result::Continue;
280     }
281 
282     BlitGL *blitter = GetBlitGL(context);
283     ANGLE_TRY(blitter->clearRenderableTextureAlphaToOne(context, texture,
284                                                         gl::TextureTarget::Rectangle, 0));
285     mAlphaInitialized = true;
286     return angle::Result::Continue;
287 }
288 
hasEmulatedAlphaChannel() const289 bool IOSurfaceSurfaceCGL::hasEmulatedAlphaChannel() const
290 {
291     const auto &format = kIOSurfaceFormats[mFormatIndex];
292     return format.internalFormat == GL_RGB;
293 }
294 
attachToFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)295 egl::Error IOSurfaceSurfaceCGL::attachToFramebuffer(const gl::Context *context,
296                                                     gl::Framebuffer *framebuffer)
297 {
298     FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
299     ASSERT(framebufferGL->getFramebufferID() == 0);
300     if (mFramebufferID == 0)
301     {
302         GLuint textureID = 0;
303         mFunctions->genTextures(1, &textureID);
304         const auto &format = kIOSurfaceFormats[mFormatIndex];
305         mStateManager->bindTexture(gl::TextureType::Rectangle, textureID);
306         CGLError error = CGLTexImageIOSurface2D(
307             mCGLContext, GL_TEXTURE_RECTANGLE, format.nativeInternalFormat, mWidth, mHeight,
308             format.nativeFormat, format.nativeType, mIOSurface, mPlane);
309         if (error != kCGLNoError)
310         {
311             return egl::EglContextLost()
312                    << "CGLTexImageIOSurface2D failed: " << CGLErrorString(error);
313         }
314         ASSERT(error == kCGLNoError);
315 
316         // TODO: pass context
317         if (IsError(initializeAlphaChannel(context, textureID)))
318         {
319             return egl::EglContextLost() << "Failed to initialize IOSurface alpha channel.";
320         }
321 
322         GLuint framebufferID = 0;
323         mFunctions->genFramebuffers(1, &framebufferID);
324         mStateManager->bindFramebuffer(GL_FRAMEBUFFER, framebufferID);
325         mStateManager->bindTexture(gl::TextureType::Rectangle, textureID);
326         mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE,
327                                          textureID, 0);
328         mTextureID     = textureID;
329         mFramebufferID = framebufferID;
330     }
331 
332     framebufferGL->setFramebufferID(mFramebufferID);
333     return egl::NoError();
334 }
335 
detachFromFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)336 egl::Error IOSurfaceSurfaceCGL::detachFromFramebuffer(const gl::Context *context,
337                                                       gl::Framebuffer *framebuffer)
338 {
339     FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
340     ASSERT(framebufferGL->getFramebufferID() == mFramebufferID);
341 
342     framebufferGL->setFramebufferID(0);
343     return egl::NoError();
344 }
345 
346 }  // namespace rx
347