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