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