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