• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// Copyright 2020 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// IOSurfaceSurfaceVkMac.mm:
7//    Implements methods from IOSurfaceSurfaceVkMac.
8//
9
10#include "libANGLE/renderer/vulkan/mac/IOSurfaceSurfaceVkMac.h"
11#include "libANGLE/Context.h"
12#include "libANGLE/Display.h"
13#include "libANGLE/Surface.h"
14#include "libANGLE/renderer/vulkan/ContextVk.h"
15#include "libANGLE/renderer/vulkan/DisplayVk.h"
16#include "libANGLE/renderer/vulkan/FramebufferVk.h"
17#include "libANGLE/renderer/vulkan/TextureVk.h"
18
19#include <IOSurface/IOSurface.h>
20
21namespace rx
22{
23
24namespace
25{
26
27struct IOSurfaceFormatInfo
28{
29    GLenum internalFormat;
30    GLenum type;
31
32    size_t componentBytes;
33
34    GLenum nativeSizedInternalFormat;
35};
36
37// clang-format off
38constexpr std::array<IOSurfaceFormatInfo, 6> kIOSurfaceFormats = {{
39    {GL_RED,      GL_UNSIGNED_BYTE,  1, GL_R8   },
40    {GL_R16UI,    GL_UNSIGNED_SHORT, 2, GL_R16UI  },
41    {GL_RG,       GL_UNSIGNED_BYTE,  2, GL_RG8 },
42    {GL_RGB,      GL_UNSIGNED_BYTE,  4, GL_BGRA8_EXT},
43    {GL_BGRA_EXT, GL_UNSIGNED_BYTE,  4, GL_BGRA8_EXT },
44    {GL_RGBA,     GL_HALF_FLOAT,     8, GL_RGBA16F },
45}};
46// clang-format on
47
48int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
49{
50    for (int i = 0; i < static_cast<int>(kIOSurfaceFormats.size()); ++i)
51    {
52        const auto &formatInfo = kIOSurfaceFormats[i];
53        if (formatInfo.internalFormat == internalFormat && formatInfo.type == type)
54        {
55            return i;
56        }
57    }
58    return -1;
59}
60
61}  // anonymous namespace
62
63IOSurfaceSurfaceVkMac::IOSurfaceSurfaceVkMac(const egl::SurfaceState &state,
64                                             EGLClientBuffer buffer,
65                                             const egl::AttributeMap &attribs)
66    : OffscreenSurfaceVk(state), mIOSurface(nullptr), mPlane(0), mFormatIndex(-1)
67{
68    // Keep reference to the IOSurface so it doesn't get deleted while the pbuffer exists.
69    mIOSurface = reinterpret_cast<IOSurfaceRef>(buffer);
70    CFRetain(mIOSurface);
71
72    // Extract attribs useful for the call to CGLTexImageIOSurface2D
73    mWidth  = static_cast<int>(attribs.get(EGL_WIDTH));
74    mHeight = static_cast<int>(attribs.get(EGL_HEIGHT));
75    mPlane  = static_cast<int>(attribs.get(EGL_IOSURFACE_PLANE_ANGLE));
76
77    EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
78    EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
79    mFormatIndex =
80        FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
81    ASSERT(mFormatIndex >= 0);
82}
83
84IOSurfaceSurfaceVkMac::~IOSurfaceSurfaceVkMac()
85{
86    if (mIOSurface != nullptr)
87    {
88        CFRelease(mIOSurface);
89        mIOSurface = nullptr;
90    }
91}
92
93egl::Error IOSurfaceSurfaceVkMac::initialize(const egl::Display *display)
94{
95    DisplayVk *displayVk = vk::GetImpl(display);
96    angle::Result result = initializeImpl(displayVk);
97    return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
98}
99
100angle::Result IOSurfaceSurfaceVkMac::initializeImpl(DisplayVk *displayVk)
101{
102    RendererVk *renderer      = displayVk->getRenderer();
103    const egl::Config *config = mState.config;
104
105    GLint samples = 1;
106    if (config->sampleBuffers && config->samples > 1)
107    {
108        samples = config->samples;
109    }
110    ANGLE_VK_CHECK(displayVk, samples > 0, VK_ERROR_INITIALIZATION_FAILED);
111
112    // Swiftshader will use the raw pointer to the buffer referenced by the IOSurfaceRef
113    ANGLE_TRY(mColorAttachment.initializeWithExternalMemory(
114        displayVk, mWidth, mHeight,
115        renderer->getFormat(kIOSurfaceFormats[mFormatIndex].nativeSizedInternalFormat), samples,
116        IOSurfaceGetBaseAddressOfPlane(mIOSurface, mPlane)));
117    mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, 0, 0);
118
119    return angle::Result::Continue;
120}
121
122egl::Error IOSurfaceSurfaceVkMac::unMakeCurrent(const gl::Context *context)
123{
124    ASSERT(context != nullptr);
125    ContextVk *contextVk = vk::GetImpl(context);
126    DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
127    angle::Result result = contextVk->flushImpl(nullptr);
128    return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
129}
130
131egl::Error IOSurfaceSurfaceVkMac::bindTexImage(const gl::Context *context,
132                                               gl::Texture *texture,
133                                               EGLint buffer)
134{
135    IOSurfaceLock(mIOSurface, 0, nullptr);
136
137    return egl::NoError();
138}
139
140egl::Error IOSurfaceSurfaceVkMac::releaseTexImage(const gl::Context *context, EGLint buffer)
141{
142    ASSERT(context != nullptr);
143    ContextVk *contextVk = vk::GetImpl(context);
144    DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
145    angle::Result result = contextVk->finishImpl();
146
147    IOSurfaceUnlock(mIOSurface, 0, nullptr);
148
149    return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
150}
151
152// static
153bool IOSurfaceSurfaceVkMac::ValidateAttributes(const DisplayVk *displayVk,
154                                               EGLClientBuffer buffer,
155                                               const egl::AttributeMap &attribs)
156{
157    ASSERT(displayVk != nullptr);
158    RendererVk *renderer = displayVk->getRenderer();
159
160    IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(buffer);
161
162    // The plane must exist for this IOSurface. IOSurfaceGetPlaneCount can return 0 for non-planar
163    // ioSurfaces but we will treat non-planar like it is a single plane.
164    size_t surfacePlaneCount = std::max(size_t(1), IOSurfaceGetPlaneCount(ioSurface));
165    EGLAttrib plane          = attribs.get(EGL_IOSURFACE_PLANE_ANGLE);
166    if (plane < 0 || static_cast<size_t>(plane) >= surfacePlaneCount)
167    {
168        return false;
169    }
170
171    // The width height specified must be at least (1, 1) and at most the plane size
172    EGLAttrib width  = attribs.get(EGL_WIDTH);
173    EGLAttrib height = attribs.get(EGL_HEIGHT);
174    if (width <= 0 || static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) ||
175        height <= 0 || static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, plane))
176    {
177        return false;
178    }
179
180    // Find this IOSurface format
181    EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
182    EGLAttrib type           = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
183
184    int formatIndex =
185        FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
186
187    if (formatIndex < 0)
188    {
189        return false;
190    }
191
192    // Check that the format matches this IOSurface plane
193    if (IOSurfaceGetBytesPerElementOfPlane(ioSurface, plane) !=
194        kIOSurfaceFormats[formatIndex].componentBytes)
195    {
196        return false;
197    }
198
199    void *pointer = IOSurfaceGetBaseAddressOfPlane(ioSurface, plane);
200    VkMemoryHostPointerPropertiesEXT memoryHostPointerProperties = {};
201    memoryHostPointerProperties.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT;
202    vkGetMemoryHostPointerPropertiesEXT(
203        renderer->getDevice(), VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT,
204        pointer, &memoryHostPointerProperties);
205
206    bool hostVisible =
207        memoryHostPointerProperties.memoryTypeBits & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
208    if (!hostVisible)
209    {
210        return false;
211    }
212
213    VkDeviceSize alignment = renderer->getMinImportedHostPointerAlignment();
214    if (reinterpret_cast<size_t>(pointer) % alignment != 0)
215    {
216        return false;
217    }
218
219    return true;
220}
221
222}  // namespace rx
223