• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// Copyright 2021 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// ImageMtl.cpp:
7//    Implements the class methods for ImageMtl.
8//
9
10#include "libANGLE/renderer/metal/ImageMtl.h"
11
12#include "common/debug.h"
13#include "libANGLE/Context.h"
14#include "libANGLE/Display.h"
15#include "libANGLE/renderer/metal/ContextMtl.h"
16#include "libANGLE/renderer/metal/DisplayMtl.h"
17#include "libANGLE/renderer/metal/RenderBufferMtl.h"
18#include "libANGLE/renderer/metal/TextureMtl.h"
19
20namespace rx
21{
22
23namespace
24{
25angle::FormatID intendedFormatForMTLTexture(id<MTLTexture> texture,
26                                            const egl::AttributeMap &attribs)
27{
28    angle::FormatID angleFormatId = mtl::Format::MetalToAngleFormatID(texture.pixelFormat);
29    if (angleFormatId == angle::FormatID::NONE)
30    {
31        return angle::FormatID::NONE;
32    }
33
34    const angle::Format *textureAngleFormat = &angle::Format::Get(angleFormatId);
35    ASSERT(textureAngleFormat);
36
37    GLenum sizedInternalFormat = textureAngleFormat->glInternalFormat;
38
39    if (attribs.contains(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE))
40    {
41        const GLenum internalFormat =
42            static_cast<GLenum>(attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE));
43        GLenum type       = gl::GetSizedInternalFormatInfo(sizedInternalFormat).type;
44        const auto format = gl::Format(internalFormat, type);
45        if (!format.valid())
46        {
47            return angle::FormatID::NONE;
48        }
49
50        sizedInternalFormat = format.info->sizedInternalFormat;
51    }
52
53    return angle::Format::InternalFormatToID(sizedInternalFormat);
54}
55}  // anonymous namespace
56
57// TextureImageSiblingMtl implementation
58TextureImageSiblingMtl::TextureImageSiblingMtl(EGLClientBuffer buffer,
59                                               const egl::AttributeMap &attribs)
60    : mBuffer(buffer), mAttribs(attribs), mGLFormat(GL_NONE)
61{}
62
63TextureImageSiblingMtl::~TextureImageSiblingMtl() {}
64
65// Static
66egl::Error TextureImageSiblingMtl::ValidateClientBuffer(const DisplayMtl *display,
67                                                        EGLClientBuffer buffer,
68                                                        const egl::AttributeMap &attribs)
69{
70    id<MTLTexture> texture = (__bridge id<MTLTexture>)(buffer);
71    if (!texture || texture.device != display->getMetalDevice())
72    {
73        return egl::Error(EGL_BAD_ATTRIBUTE);
74    }
75
76    if (texture.textureType != MTLTextureType2D && texture.textureType != MTLTextureTypeCube &&
77        texture.textureType != MTLTextureType2DArray)
78    {
79        return egl::Error(EGL_BAD_ATTRIBUTE);
80    }
81
82    angle::FormatID angleFormatId = intendedFormatForMTLTexture(texture, attribs);
83    const mtl::Format &format     = display->getPixelFormat(angleFormatId);
84    if (!format.valid())
85    {
86        return egl::Error(EGL_BAD_ATTRIBUTE, "Unrecognized format");
87    }
88
89    if (format.metalFormat != texture.pixelFormat)
90    {
91        return egl::Error(EGL_BAD_ATTRIBUTE, "Incompatible format");
92    }
93
94    unsigned textureArraySlice =
95        static_cast<unsigned>(attribs.getAsInt(EGL_METAL_TEXTURE_ARRAY_SLICE_ANGLE, 0));
96    if (texture.textureType != MTLTextureType2DArray && textureArraySlice > 0)
97    {
98        return egl::Error(EGL_BAD_ATTRIBUTE,
99                          "Invalid texture type for non-zero texture array slice");
100    }
101    if (textureArraySlice >= texture.arrayLength)
102    {
103        std::ostringstream err;
104        err << "Invalid texture array slice: " << textureArraySlice;
105        return egl::Error(EGL_BAD_ATTRIBUTE, err.str());
106    }
107
108    return egl::NoError();
109}
110
111egl::Error TextureImageSiblingMtl::initialize(const egl::Display *display)
112{
113    DisplayMtl *displayMtl = mtl::GetImpl(display);
114    if (initImpl(displayMtl) != angle::Result::Continue)
115    {
116        return egl::Error(EGL_BAD_PARAMETER);
117    }
118
119    return egl::NoError();
120}
121
122angle::Result TextureImageSiblingMtl::initImpl(DisplayMtl *displayMtl)
123{
124    mNativeTexture = mtl::Texture::MakeFromMetal((__bridge id<MTLTexture>)(mBuffer));
125
126    if (mNativeTexture->textureType() == MTLTextureType2DArray)
127    {
128        mtl::TextureRef baseTexture = std::move(mNativeTexture);
129        unsigned textureArraySlice =
130            static_cast<unsigned>(mAttribs.getAsInt(EGL_METAL_TEXTURE_ARRAY_SLICE_ANGLE, 0));
131        mNativeTexture =
132            baseTexture->createSliceMipView(textureArraySlice, mtl::kZeroNativeMipLevel);
133    }
134
135    angle::FormatID angleFormatId = intendedFormatForMTLTexture(mNativeTexture->get(), mAttribs);
136    mFormat                       = displayMtl->getPixelFormat(angleFormatId);
137
138    if (mNativeTexture)
139    {
140        size_t resourceSize = EstimateTextureSizeInBytes(
141            mFormat, mNativeTexture->widthAt0(), mNativeTexture->heightAt0(),
142            mNativeTexture->depthAt0(), mNativeTexture->samples(), mNativeTexture->mipmapLevels());
143        mNativeTexture->setEstimatedByteSize(resourceSize);
144    }
145
146    mGLFormat = gl::Format(mFormat.intendedAngleFormat().glInternalFormat);
147
148    mRenderable = mFormat.getCaps().depthRenderable || mFormat.getCaps().colorRenderable;
149
150    // Some formats are not filterable but renderable such as integer formats. In this case, treat
151    // them as texturable as well.
152    mTextureable = mFormat.getCaps().filterable || mRenderable;
153
154    return angle::Result::Continue;
155}
156
157void TextureImageSiblingMtl::onDestroy(const egl::Display *display)
158{
159    mNativeTexture = nullptr;
160}
161
162gl::Format TextureImageSiblingMtl::getFormat() const
163{
164    return mGLFormat;
165}
166
167bool TextureImageSiblingMtl::isRenderable(const gl::Context *context) const
168{
169    return mRenderable;
170}
171
172bool TextureImageSiblingMtl::isTexturable(const gl::Context *context) const
173{
174    return mTextureable;
175}
176
177gl::Extents TextureImageSiblingMtl::getSize() const
178{
179    return mNativeTexture ? mNativeTexture->sizeAt0() : gl::Extents(0, 0, 0);
180}
181
182size_t TextureImageSiblingMtl::getSamples() const
183{
184    uint32_t samples = mNativeTexture ? mNativeTexture->samples() : 0;
185    return samples > 1 ? samples : 0;
186}
187
188bool TextureImageSiblingMtl::isYUV() const
189{
190    // NOTE(hqle): not supporting YUV image yet.
191    return false;
192}
193
194bool TextureImageSiblingMtl::hasProtectedContent() const
195{
196    return false;
197}
198
199// ImageMtl implementation
200ImageMtl::ImageMtl(const egl::ImageState &state, const gl::Context *context) : ImageImpl(state) {}
201
202ImageMtl::~ImageMtl() {}
203
204void ImageMtl::onDestroy(const egl::Display *display)
205{
206    mNativeTexture = nullptr;
207}
208
209egl::Error ImageMtl::initialize(const egl::Display *display)
210{
211    if (mState.target == EGL_METAL_TEXTURE_ANGLE)
212    {
213        const TextureImageSiblingMtl *externalImageSibling =
214            GetImplAs<TextureImageSiblingMtl>(GetAs<egl::ExternalImageSibling>(mState.source));
215
216        mNativeTexture = externalImageSibling->getTexture();
217
218        switch (mNativeTexture->textureType())
219        {
220            case MTLTextureType2D:
221            case MTLTextureType2DArray:
222                mImageTextureType = gl::TextureType::_2D;
223                break;
224            case MTLTextureTypeCube:
225                mImageTextureType = gl::TextureType::CubeMap;
226                break;
227            default:
228                UNREACHABLE();
229        }
230
231        mImageLevel = 0;
232        mImageLayer = 0;
233    }
234    else
235    {
236        UNREACHABLE();
237        return egl::Error(EGL_BAD_ACCESS);
238    }
239
240    return egl::NoError();
241}
242
243angle::Result ImageMtl::orphan(const gl::Context *context, egl::ImageSibling *sibling)
244{
245    if (sibling == mState.source)
246    {
247        mNativeTexture = nullptr;
248    }
249
250    return angle::Result::Continue;
251}
252
253}  // namespace rx
254