xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/ImageMtl.mm (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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::EglBadAttribute();
74    }
75
76    if (texture.textureType != MTLTextureType2D && texture.textureType != MTLTextureTypeCube &&
77        texture.textureType != MTLTextureType2DArray)
78    {
79        return egl::EglBadAttribute();
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::EglBadAttribute() << "Unrecognized format";
87    }
88
89    if (format.metalFormat != texture.pixelFormat)
90    {
91        return egl::EglBadAttribute() << "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::EglBadAttribute() << "Invalid texture type for non-zero texture array slice";
99    }
100    if (textureArraySlice >= texture.arrayLength)
101    {
102        return egl::EglBadAttribute() << "Invalid texture array slice: " << textureArraySlice;
103    }
104
105    return egl::NoError();
106}
107
108egl::Error TextureImageSiblingMtl::initialize(const egl::Display *display)
109{
110    DisplayMtl *displayMtl = mtl::GetImpl(display);
111    if (initImpl(displayMtl) != angle::Result::Continue)
112    {
113        return egl::EglBadParameter();
114    }
115
116    return egl::NoError();
117}
118
119angle::Result TextureImageSiblingMtl::initImpl(DisplayMtl *displayMtl)
120{
121    mNativeTexture = mtl::Texture::MakeFromMetal((__bridge id<MTLTexture>)(mBuffer));
122
123    if (mNativeTexture->textureType() == MTLTextureType2DArray)
124    {
125        mtl::TextureRef baseTexture = std::move(mNativeTexture);
126        unsigned textureArraySlice =
127            static_cast<unsigned>(mAttribs.getAsInt(EGL_METAL_TEXTURE_ARRAY_SLICE_ANGLE, 0));
128        mNativeTexture =
129            baseTexture->createSliceMipView(textureArraySlice, mtl::kZeroNativeMipLevel);
130    }
131
132    angle::FormatID angleFormatId = intendedFormatForMTLTexture(mNativeTexture->get(), mAttribs);
133    mFormat                       = displayMtl->getPixelFormat(angleFormatId);
134
135    if (mNativeTexture)
136    {
137        size_t resourceSize = EstimateTextureSizeInBytes(
138            mFormat, mNativeTexture->widthAt0(), mNativeTexture->heightAt0(),
139            mNativeTexture->depthAt0(), mNativeTexture->samples(), mNativeTexture->mipmapLevels());
140        mNativeTexture->setEstimatedByteSize(resourceSize);
141    }
142
143    mGLFormat = gl::Format(mFormat.intendedAngleFormat().glInternalFormat);
144
145    mRenderable = mFormat.getCaps().depthRenderable || mFormat.getCaps().colorRenderable;
146
147    // Some formats are not filterable but renderable such as integer formats. In this case, treat
148    // them as texturable as well.
149    mTextureable = mFormat.getCaps().filterable || mRenderable;
150
151    return angle::Result::Continue;
152}
153
154void TextureImageSiblingMtl::onDestroy(const egl::Display *display)
155{
156    mNativeTexture = nullptr;
157}
158
159gl::Format TextureImageSiblingMtl::getFormat() const
160{
161    return mGLFormat;
162}
163
164bool TextureImageSiblingMtl::isRenderable(const gl::Context *context) const
165{
166    return mRenderable;
167}
168
169bool TextureImageSiblingMtl::isTexturable(const gl::Context *context) const
170{
171    return mTextureable;
172}
173
174gl::Extents TextureImageSiblingMtl::getSize() const
175{
176    return mNativeTexture ? mNativeTexture->sizeAt0() : gl::Extents(0, 0, 0);
177}
178
179size_t TextureImageSiblingMtl::getSamples() const
180{
181    uint32_t samples = mNativeTexture ? mNativeTexture->samples() : 0;
182    return samples > 1 ? samples : 0;
183}
184
185bool TextureImageSiblingMtl::isYUV() const
186{
187    // NOTE(hqle): not supporting YUV image yet.
188    return false;
189}
190
191bool TextureImageSiblingMtl::hasProtectedContent() const
192{
193    return false;
194}
195
196// ImageMtl implementation
197ImageMtl::ImageMtl(const egl::ImageState &state, const gl::Context *context) : ImageImpl(state) {}
198
199ImageMtl::~ImageMtl() {}
200
201void ImageMtl::onDestroy(const egl::Display *display)
202{
203    mNativeTexture = nullptr;
204}
205
206egl::Error ImageMtl::initialize(const egl::Display *display)
207{
208    if (mState.target == EGL_METAL_TEXTURE_ANGLE)
209    {
210        const TextureImageSiblingMtl *externalImageSibling =
211            GetImplAs<TextureImageSiblingMtl>(GetAs<egl::ExternalImageSibling>(mState.source));
212
213        mNativeTexture = externalImageSibling->getTexture();
214
215        switch (mNativeTexture->textureType())
216        {
217            case MTLTextureType2D:
218            case MTLTextureType2DArray:
219                mImageTextureType = gl::TextureType::_2D;
220                break;
221            case MTLTextureTypeCube:
222                mImageTextureType = gl::TextureType::CubeMap;
223                break;
224            default:
225                UNREACHABLE();
226        }
227
228        mImageLevel = 0;
229        mImageLayer = 0;
230    }
231    else
232    {
233        UNREACHABLE();
234        return egl::EglBadAccess();
235    }
236
237    return egl::NoError();
238}
239
240angle::Result ImageMtl::orphan(const gl::Context *context, egl::ImageSibling *sibling)
241{
242    if (sibling == mState.source)
243    {
244        mNativeTexture = nullptr;
245    }
246
247    return angle::Result::Continue;
248}
249
250}  // namespace rx
251