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