1*8975f5c5SAndroid Build Coastguard Worker 2*8975f5c5SAndroid Build Coastguard Worker// 3*8975f5c5SAndroid Build Coastguard Worker// Copyright 2019 The ANGLE Project Authors. All rights reserved. 4*8975f5c5SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be 5*8975f5c5SAndroid Build Coastguard Worker// found in the LICENSE file. 6*8975f5c5SAndroid Build Coastguard Worker// 7*8975f5c5SAndroid Build Coastguard Worker// TextureMtl.mm: 8*8975f5c5SAndroid Build Coastguard Worker// Implements the class methods for TextureMtl. 9*8975f5c5SAndroid Build Coastguard Worker// 10*8975f5c5SAndroid Build Coastguard Worker 11*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/TextureMtl.h" 12*8975f5c5SAndroid Build Coastguard Worker 13*8975f5c5SAndroid Build Coastguard Worker#include <algorithm> 14*8975f5c5SAndroid Build Coastguard Worker#include <initializer_list> 15*8975f5c5SAndroid Build Coastguard Worker 16*8975f5c5SAndroid Build Coastguard Worker#include "common/Color.h" 17*8975f5c5SAndroid Build Coastguard Worker#include "common/MemoryBuffer.h" 18*8975f5c5SAndroid Build Coastguard Worker#include "common/debug.h" 19*8975f5c5SAndroid Build Coastguard Worker#include "common/mathutil.h" 20*8975f5c5SAndroid Build Coastguard Worker#include "image_util/imageformats.h" 21*8975f5c5SAndroid Build Coastguard Worker#include "image_util/loadimage.h" 22*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/Surface.h" 23*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/Format.h" 24*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/BufferMtl.h" 25*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/ContextMtl.h" 26*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/DisplayMtl.h" 27*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/FrameBufferMtl.h" 28*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/ImageMtl.h" 29*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/SamplerMtl.h" 30*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/SurfaceMtl.h" 31*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/mtl_common.h" 32*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/mtl_format_utils.h" 33*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/mtl_utils.h" 34*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/renderer_utils.h" 35*8975f5c5SAndroid Build Coastguard Worker 36*8975f5c5SAndroid Build Coastguard Workernamespace rx 37*8975f5c5SAndroid Build Coastguard Worker{ 38*8975f5c5SAndroid Build Coastguard Worker 39*8975f5c5SAndroid Build Coastguard Workernamespace 40*8975f5c5SAndroid Build Coastguard Worker{ 41*8975f5c5SAndroid Build Coastguard Worker 42*8975f5c5SAndroid Build Coastguard Workergl::ImageIndex GetZeroLevelIndex(const mtl::TextureRef &image) 43*8975f5c5SAndroid Build Coastguard Worker{ 44*8975f5c5SAndroid Build Coastguard Worker switch (image->textureType()) 45*8975f5c5SAndroid Build Coastguard Worker { 46*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType2D: 47*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make2D(0); 48*8975f5c5SAndroid Build Coastguard Worker case MTLTextureTypeCube: 49*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::MakeFromType(gl::TextureType::CubeMap, 0); 50*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType2DArray: 51*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make2DArray(0 /** entire layers */); 52*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType2DMultisample: 53*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make2DMultisample(); 54*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType3D: 55*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make3D(0 /** entire layers */); 56*8975f5c5SAndroid Build Coastguard Worker default: 57*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 58*8975f5c5SAndroid Build Coastguard Worker break; 59*8975f5c5SAndroid Build Coastguard Worker } 60*8975f5c5SAndroid Build Coastguard Worker 61*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex(); 62*8975f5c5SAndroid Build Coastguard Worker} 63*8975f5c5SAndroid Build Coastguard Worker 64*8975f5c5SAndroid Build Coastguard Worker// Slice is ignored if texture type is not Cube or 2D array 65*8975f5c5SAndroid Build Coastguard Workergl::ImageIndex GetCubeOrArraySliceMipIndex(const mtl::TextureRef &image, 66*8975f5c5SAndroid Build Coastguard Worker uint32_t slice, 67*8975f5c5SAndroid Build Coastguard Worker uint32_t level) 68*8975f5c5SAndroid Build Coastguard Worker{ 69*8975f5c5SAndroid Build Coastguard Worker switch (image->textureType()) 70*8975f5c5SAndroid Build Coastguard Worker { 71*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType2D: 72*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make2D(level); 73*8975f5c5SAndroid Build Coastguard Worker case MTLTextureTypeCube: 74*8975f5c5SAndroid Build Coastguard Worker { 75*8975f5c5SAndroid Build Coastguard Worker auto cubeFace = static_cast<gl::TextureTarget>( 76*8975f5c5SAndroid Build Coastguard Worker static_cast<int>(gl::TextureTarget::CubeMapPositiveX) + slice); 77*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::MakeCubeMapFace(cubeFace, level); 78*8975f5c5SAndroid Build Coastguard Worker } 79*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType2DArray: 80*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make2DArray(level, slice); 81*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType2DMultisample: 82*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make2DMultisample(); 83*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType3D: 84*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make3D(level); 85*8975f5c5SAndroid Build Coastguard Worker default: 86*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 87*8975f5c5SAndroid Build Coastguard Worker break; 88*8975f5c5SAndroid Build Coastguard Worker } 89*8975f5c5SAndroid Build Coastguard Worker 90*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex(); 91*8975f5c5SAndroid Build Coastguard Worker} 92*8975f5c5SAndroid Build Coastguard Worker 93*8975f5c5SAndroid Build Coastguard Worker// layer is ignored if texture type is not Cube or 2D array or 3D 94*8975f5c5SAndroid Build Coastguard Workergl::ImageIndex GetLayerMipIndex(const mtl::TextureRef &image, uint32_t layer, uint32_t level) 95*8975f5c5SAndroid Build Coastguard Worker{ 96*8975f5c5SAndroid Build Coastguard Worker switch (image->textureType()) 97*8975f5c5SAndroid Build Coastguard Worker { 98*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType2D: 99*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make2D(level); 100*8975f5c5SAndroid Build Coastguard Worker case MTLTextureTypeCube: 101*8975f5c5SAndroid Build Coastguard Worker { 102*8975f5c5SAndroid Build Coastguard Worker auto cubeFace = static_cast<gl::TextureTarget>( 103*8975f5c5SAndroid Build Coastguard Worker static_cast<int>(gl::TextureTarget::CubeMapPositiveX) + layer); 104*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::MakeCubeMapFace(cubeFace, level); 105*8975f5c5SAndroid Build Coastguard Worker } 106*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType2DArray: 107*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make2DArray(level, layer); 108*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType2DMultisample: 109*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make2DMultisample(); 110*8975f5c5SAndroid Build Coastguard Worker case MTLTextureType3D: 111*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex::Make3D(level, layer); 112*8975f5c5SAndroid Build Coastguard Worker default: 113*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 114*8975f5c5SAndroid Build Coastguard Worker break; 115*8975f5c5SAndroid Build Coastguard Worker } 116*8975f5c5SAndroid Build Coastguard Worker 117*8975f5c5SAndroid Build Coastguard Worker return gl::ImageIndex(); 118*8975f5c5SAndroid Build Coastguard Worker} 119*8975f5c5SAndroid Build Coastguard Worker 120*8975f5c5SAndroid Build Coastguard WorkerGLuint GetImageLayerIndexFrom(const gl::ImageIndex &index) 121*8975f5c5SAndroid Build Coastguard Worker{ 122*8975f5c5SAndroid Build Coastguard Worker switch (index.getType()) 123*8975f5c5SAndroid Build Coastguard Worker { 124*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2D: 125*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2DMultisample: 126*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::Rectangle: 127*8975f5c5SAndroid Build Coastguard Worker return 0; 128*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::CubeMap: 129*8975f5c5SAndroid Build Coastguard Worker return index.cubeMapFaceIndex(); 130*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2DArray: 131*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_3D: 132*8975f5c5SAndroid Build Coastguard Worker return index.getLayerIndex(); 133*8975f5c5SAndroid Build Coastguard Worker default: 134*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 135*8975f5c5SAndroid Build Coastguard Worker } 136*8975f5c5SAndroid Build Coastguard Worker 137*8975f5c5SAndroid Build Coastguard Worker return 0; 138*8975f5c5SAndroid Build Coastguard Worker} 139*8975f5c5SAndroid Build Coastguard Worker 140*8975f5c5SAndroid Build Coastguard WorkerGLuint GetImageCubeFaceIndexOrZeroFrom(const gl::ImageIndex &index) 141*8975f5c5SAndroid Build Coastguard Worker{ 142*8975f5c5SAndroid Build Coastguard Worker switch (index.getType()) 143*8975f5c5SAndroid Build Coastguard Worker { 144*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::CubeMap: 145*8975f5c5SAndroid Build Coastguard Worker return index.cubeMapFaceIndex(); 146*8975f5c5SAndroid Build Coastguard Worker default: 147*8975f5c5SAndroid Build Coastguard Worker break; 148*8975f5c5SAndroid Build Coastguard Worker } 149*8975f5c5SAndroid Build Coastguard Worker 150*8975f5c5SAndroid Build Coastguard Worker return 0; 151*8975f5c5SAndroid Build Coastguard Worker} 152*8975f5c5SAndroid Build Coastguard Worker 153*8975f5c5SAndroid Build Coastguard Worker// Given texture type, get texture type of one image for a glTexImage call. 154*8975f5c5SAndroid Build Coastguard Worker// For example, for texture 2d, one image is also texture 2d. 155*8975f5c5SAndroid Build Coastguard Worker// for texture cube, one image is texture 2d. 156*8975f5c5SAndroid Build Coastguard Workergl::TextureType GetTextureImageType(gl::TextureType texType) 157*8975f5c5SAndroid Build Coastguard Worker{ 158*8975f5c5SAndroid Build Coastguard Worker switch (texType) 159*8975f5c5SAndroid Build Coastguard Worker { 160*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::CubeMap: 161*8975f5c5SAndroid Build Coastguard Worker return gl::TextureType::_2D; 162*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2D: 163*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2DArray: 164*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2DMultisample: 165*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_3D: 166*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::Rectangle: 167*8975f5c5SAndroid Build Coastguard Worker return texType; 168*8975f5c5SAndroid Build Coastguard Worker default: 169*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 170*8975f5c5SAndroid Build Coastguard Worker return gl::TextureType::InvalidEnum; 171*8975f5c5SAndroid Build Coastguard Worker } 172*8975f5c5SAndroid Build Coastguard Worker} 173*8975f5c5SAndroid Build Coastguard Worker 174*8975f5c5SAndroid Build Coastguard Worker// D24X8 by default writes depth data to high 24 bits of 32 bit integers. However, Metal separate 175*8975f5c5SAndroid Build Coastguard Worker// depth stencil blitting expects depth data to be in low 24 bits of the data. 176*8975f5c5SAndroid Build Coastguard Workervoid WriteDepthStencilToDepth24(const uint8_t *srcPtr, uint8_t *dstPtr) 177*8975f5c5SAndroid Build Coastguard Worker{ 178*8975f5c5SAndroid Build Coastguard Worker auto src = reinterpret_cast<const angle::DepthStencil *>(srcPtr); 179*8975f5c5SAndroid Build Coastguard Worker auto dst = reinterpret_cast<uint32_t *>(dstPtr); 180*8975f5c5SAndroid Build Coastguard Worker *dst = gl::floatToNormalized<24, uint32_t>(static_cast<float>(src->depth)); 181*8975f5c5SAndroid Build Coastguard Worker} 182*8975f5c5SAndroid Build Coastguard Worker 183*8975f5c5SAndroid Build Coastguard Workervoid CopyTextureData(const MTLSize ®ionSize, 184*8975f5c5SAndroid Build Coastguard Worker size_t srcRowPitch, 185*8975f5c5SAndroid Build Coastguard Worker size_t src2DImageSize, 186*8975f5c5SAndroid Build Coastguard Worker const uint8_t *psrc, 187*8975f5c5SAndroid Build Coastguard Worker size_t destRowPitch, 188*8975f5c5SAndroid Build Coastguard Worker size_t dest2DImageSize, 189*8975f5c5SAndroid Build Coastguard Worker uint8_t *pdst) 190*8975f5c5SAndroid Build Coastguard Worker{ 191*8975f5c5SAndroid Build Coastguard Worker { 192*8975f5c5SAndroid Build Coastguard Worker size_t rowCopySize = std::min(srcRowPitch, destRowPitch); 193*8975f5c5SAndroid Build Coastguard Worker for (NSUInteger d = 0; d < regionSize.depth; ++d) 194*8975f5c5SAndroid Build Coastguard Worker { 195*8975f5c5SAndroid Build Coastguard Worker for (NSUInteger r = 0; r < regionSize.height; ++r) 196*8975f5c5SAndroid Build Coastguard Worker { 197*8975f5c5SAndroid Build Coastguard Worker const uint8_t *pCopySrc = psrc + d * src2DImageSize + r * srcRowPitch; 198*8975f5c5SAndroid Build Coastguard Worker uint8_t *pCopyDst = pdst + d * dest2DImageSize + r * destRowPitch; 199*8975f5c5SAndroid Build Coastguard Worker memcpy(pCopyDst, pCopySrc, rowCopySize); 200*8975f5c5SAndroid Build Coastguard Worker } 201*8975f5c5SAndroid Build Coastguard Worker } 202*8975f5c5SAndroid Build Coastguard Worker } 203*8975f5c5SAndroid Build Coastguard Worker} 204*8975f5c5SAndroid Build Coastguard Worker 205*8975f5c5SAndroid Build Coastguard Workervoid ConvertDepthStencilData(const MTLSize ®ionSize, 206*8975f5c5SAndroid Build Coastguard Worker const angle::Format &srcAngleFormat, 207*8975f5c5SAndroid Build Coastguard Worker size_t srcRowPitch, 208*8975f5c5SAndroid Build Coastguard Worker size_t src2DImageSize, 209*8975f5c5SAndroid Build Coastguard Worker const uint8_t *psrc, 210*8975f5c5SAndroid Build Coastguard Worker const angle::Format &dstAngleFormat, 211*8975f5c5SAndroid Build Coastguard Worker rx::PixelWriteFunction pixelWriteFunctionOverride, 212*8975f5c5SAndroid Build Coastguard Worker size_t destRowPitch, 213*8975f5c5SAndroid Build Coastguard Worker size_t dest2DImageSize, 214*8975f5c5SAndroid Build Coastguard Worker uint8_t *pdst) 215*8975f5c5SAndroid Build Coastguard Worker{ 216*8975f5c5SAndroid Build Coastguard Worker if (srcAngleFormat.id == dstAngleFormat.id) 217*8975f5c5SAndroid Build Coastguard Worker { 218*8975f5c5SAndroid Build Coastguard Worker size_t rowCopySize = std::min(srcRowPitch, destRowPitch); 219*8975f5c5SAndroid Build Coastguard Worker for (NSUInteger d = 0; d < regionSize.depth; ++d) 220*8975f5c5SAndroid Build Coastguard Worker { 221*8975f5c5SAndroid Build Coastguard Worker for (NSUInteger r = 0; r < regionSize.height; ++r) 222*8975f5c5SAndroid Build Coastguard Worker { 223*8975f5c5SAndroid Build Coastguard Worker const uint8_t *pCopySrc = psrc + d * src2DImageSize + r * srcRowPitch; 224*8975f5c5SAndroid Build Coastguard Worker uint8_t *pCopyDst = pdst + d * dest2DImageSize + r * destRowPitch; 225*8975f5c5SAndroid Build Coastguard Worker memcpy(pCopyDst, pCopySrc, rowCopySize); 226*8975f5c5SAndroid Build Coastguard Worker } 227*8975f5c5SAndroid Build Coastguard Worker } 228*8975f5c5SAndroid Build Coastguard Worker } 229*8975f5c5SAndroid Build Coastguard Worker else 230*8975f5c5SAndroid Build Coastguard Worker { 231*8975f5c5SAndroid Build Coastguard Worker rx::PixelWriteFunction pixelWriteFunction = pixelWriteFunctionOverride 232*8975f5c5SAndroid Build Coastguard Worker ? pixelWriteFunctionOverride 233*8975f5c5SAndroid Build Coastguard Worker : dstAngleFormat.pixelWriteFunction; 234*8975f5c5SAndroid Build Coastguard Worker // This is only for depth & stencil case. 235*8975f5c5SAndroid Build Coastguard Worker ASSERT(srcAngleFormat.depthBits || srcAngleFormat.stencilBits); 236*8975f5c5SAndroid Build Coastguard Worker ASSERT(srcAngleFormat.pixelReadFunction && pixelWriteFunction); 237*8975f5c5SAndroid Build Coastguard Worker 238*8975f5c5SAndroid Build Coastguard Worker // cache to store read result of source pixel 239*8975f5c5SAndroid Build Coastguard Worker angle::DepthStencil depthStencilData; 240*8975f5c5SAndroid Build Coastguard Worker auto sourcePixelReadData = reinterpret_cast<uint8_t *>(&depthStencilData); 241*8975f5c5SAndroid Build Coastguard Worker ASSERT(srcAngleFormat.pixelBytes <= sizeof(depthStencilData)); 242*8975f5c5SAndroid Build Coastguard Worker 243*8975f5c5SAndroid Build Coastguard Worker for (NSUInteger d = 0; d < regionSize.depth; ++d) 244*8975f5c5SAndroid Build Coastguard Worker { 245*8975f5c5SAndroid Build Coastguard Worker for (NSUInteger r = 0; r < regionSize.height; ++r) 246*8975f5c5SAndroid Build Coastguard Worker { 247*8975f5c5SAndroid Build Coastguard Worker for (NSUInteger c = 0; c < regionSize.width; ++c) 248*8975f5c5SAndroid Build Coastguard Worker { 249*8975f5c5SAndroid Build Coastguard Worker const uint8_t *sourcePixelData = 250*8975f5c5SAndroid Build Coastguard Worker psrc + d * src2DImageSize + r * srcRowPitch + c * srcAngleFormat.pixelBytes; 251*8975f5c5SAndroid Build Coastguard Worker 252*8975f5c5SAndroid Build Coastguard Worker uint8_t *destPixelData = pdst + d * dest2DImageSize + r * destRowPitch + 253*8975f5c5SAndroid Build Coastguard Worker c * dstAngleFormat.pixelBytes; 254*8975f5c5SAndroid Build Coastguard Worker 255*8975f5c5SAndroid Build Coastguard Worker srcAngleFormat.pixelReadFunction(sourcePixelData, sourcePixelReadData); 256*8975f5c5SAndroid Build Coastguard Worker pixelWriteFunction(sourcePixelReadData, destPixelData); 257*8975f5c5SAndroid Build Coastguard Worker } 258*8975f5c5SAndroid Build Coastguard Worker } 259*8975f5c5SAndroid Build Coastguard Worker } 260*8975f5c5SAndroid Build Coastguard Worker } 261*8975f5c5SAndroid Build Coastguard Worker} 262*8975f5c5SAndroid Build Coastguard Worker 263*8975f5c5SAndroid Build Coastguard Workermtl::BlitCommandEncoder *GetBlitCommandEncoderForResources( 264*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl, 265*8975f5c5SAndroid Build Coastguard Worker const std::initializer_list<const mtl::Resource *> &resources) 266*8975f5c5SAndroid Build Coastguard Worker{ 267*8975f5c5SAndroid Build Coastguard Worker if (std::none_of(resources.begin(), resources.end(), [contextMtl](const mtl::Resource *res) { 268*8975f5c5SAndroid Build Coastguard Worker return res->hasPendingRenderWorks(contextMtl); 269*8975f5c5SAndroid Build Coastguard Worker })) 270*8975f5c5SAndroid Build Coastguard Worker { 271*8975f5c5SAndroid Build Coastguard Worker // If no resource has pending render works waiting to be submitted, then it's safe to 272*8975f5c5SAndroid Build Coastguard Worker // create a blit encoder without ending current render pass. The blit commands 273*8975f5c5SAndroid Build Coastguard Worker // will run before any pending render commands. 274*8975f5c5SAndroid Build Coastguard Worker return contextMtl->getBlitCommandEncoderWithoutEndingRenderEncoder(); 275*8975f5c5SAndroid Build Coastguard Worker } 276*8975f5c5SAndroid Build Coastguard Worker return contextMtl->getBlitCommandEncoder(); 277*8975f5c5SAndroid Build Coastguard Worker} 278*8975f5c5SAndroid Build Coastguard Worker 279*8975f5c5SAndroid Build Coastguard Workerangle::Result CopyDepthStencilTextureContentsToStagingBuffer( 280*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl, 281*8975f5c5SAndroid Build Coastguard Worker const angle::Format &textureAngleFormat, 282*8975f5c5SAndroid Build Coastguard Worker const angle::Format &stagingAngleFormat, 283*8975f5c5SAndroid Build Coastguard Worker rx::PixelWriteFunction pixelWriteFunctionOverride, 284*8975f5c5SAndroid Build Coastguard Worker const MTLSize ®ionSize, 285*8975f5c5SAndroid Build Coastguard Worker const uint8_t *data, 286*8975f5c5SAndroid Build Coastguard Worker size_t bytesPerRow, 287*8975f5c5SAndroid Build Coastguard Worker size_t bytesPer2DImage, 288*8975f5c5SAndroid Build Coastguard Worker size_t *bufferRowPitchOut, 289*8975f5c5SAndroid Build Coastguard Worker size_t *buffer2DImageSizeOut, 290*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef *bufferOut) 291*8975f5c5SAndroid Build Coastguard Worker{ 292*8975f5c5SAndroid Build Coastguard Worker size_t stagingBufferRowPitch = regionSize.width * stagingAngleFormat.pixelBytes; 293*8975f5c5SAndroid Build Coastguard Worker size_t stagingBuffer2DImageSize = stagingBufferRowPitch * regionSize.height; 294*8975f5c5SAndroid Build Coastguard Worker size_t stagingBufferSize = stagingBuffer2DImageSize * regionSize.depth; 295*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef stagingBuffer; 296*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, stagingBufferSize, nullptr, &stagingBuffer)); 297*8975f5c5SAndroid Build Coastguard Worker 298*8975f5c5SAndroid Build Coastguard Worker uint8_t *pdst = stagingBuffer->map(contextMtl); 299*8975f5c5SAndroid Build Coastguard Worker 300*8975f5c5SAndroid Build Coastguard Worker ConvertDepthStencilData(regionSize, textureAngleFormat, bytesPerRow, bytesPer2DImage, data, 301*8975f5c5SAndroid Build Coastguard Worker stagingAngleFormat, pixelWriteFunctionOverride, stagingBufferRowPitch, 302*8975f5c5SAndroid Build Coastguard Worker stagingBuffer2DImageSize, pdst); 303*8975f5c5SAndroid Build Coastguard Worker 304*8975f5c5SAndroid Build Coastguard Worker stagingBuffer->unmap(contextMtl); 305*8975f5c5SAndroid Build Coastguard Worker 306*8975f5c5SAndroid Build Coastguard Worker *bufferOut = stagingBuffer; 307*8975f5c5SAndroid Build Coastguard Worker *bufferRowPitchOut = stagingBufferRowPitch; 308*8975f5c5SAndroid Build Coastguard Worker *buffer2DImageSizeOut = stagingBuffer2DImageSize; 309*8975f5c5SAndroid Build Coastguard Worker 310*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 311*8975f5c5SAndroid Build Coastguard Worker} 312*8975f5c5SAndroid Build Coastguard Worker 313*8975f5c5SAndroid Build Coastguard Workerangle::Result CopyTextureContentsToStagingBuffer(ContextMtl *contextMtl, 314*8975f5c5SAndroid Build Coastguard Worker const angle::Format &textureAngleFormat, 315*8975f5c5SAndroid Build Coastguard Worker const MTLSize ®ionSize, 316*8975f5c5SAndroid Build Coastguard Worker const uint8_t *data, 317*8975f5c5SAndroid Build Coastguard Worker size_t bytesPerRow, 318*8975f5c5SAndroid Build Coastguard Worker size_t bytesPer2DImage, 319*8975f5c5SAndroid Build Coastguard Worker size_t *bufferRowPitchOut, 320*8975f5c5SAndroid Build Coastguard Worker size_t *buffer2DImageSizeOut, 321*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef *bufferOut) 322*8975f5c5SAndroid Build Coastguard Worker{ 323*8975f5c5SAndroid Build Coastguard Worker size_t stagingBufferRowPitch = regionSize.width * textureAngleFormat.pixelBytes; 324*8975f5c5SAndroid Build Coastguard Worker size_t stagingBuffer2DImageSize = stagingBufferRowPitch * regionSize.height; 325*8975f5c5SAndroid Build Coastguard Worker size_t stagingBufferSize = stagingBuffer2DImageSize * regionSize.depth; 326*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef stagingBuffer; 327*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, stagingBufferSize, nullptr, &stagingBuffer)); 328*8975f5c5SAndroid Build Coastguard Worker 329*8975f5c5SAndroid Build Coastguard Worker uint8_t *pdst = stagingBuffer->map(contextMtl); 330*8975f5c5SAndroid Build Coastguard Worker CopyTextureData(regionSize, bytesPerRow, bytesPer2DImage, data, stagingBufferRowPitch, 331*8975f5c5SAndroid Build Coastguard Worker stagingBuffer2DImageSize, pdst); 332*8975f5c5SAndroid Build Coastguard Worker 333*8975f5c5SAndroid Build Coastguard Worker stagingBuffer->unmap(contextMtl); 334*8975f5c5SAndroid Build Coastguard Worker 335*8975f5c5SAndroid Build Coastguard Worker *bufferOut = stagingBuffer; 336*8975f5c5SAndroid Build Coastguard Worker *bufferRowPitchOut = stagingBufferRowPitch; 337*8975f5c5SAndroid Build Coastguard Worker *buffer2DImageSizeOut = stagingBuffer2DImageSize; 338*8975f5c5SAndroid Build Coastguard Worker 339*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 340*8975f5c5SAndroid Build Coastguard Worker} 341*8975f5c5SAndroid Build Coastguard Worker 342*8975f5c5SAndroid Build Coastguard Workerangle::Result CopyCompressedTextureContentsToStagingBuffer(ContextMtl *contextMtl, 343*8975f5c5SAndroid Build Coastguard Worker const angle::Format &textureAngleFormat, 344*8975f5c5SAndroid Build Coastguard Worker const MTLSize ®ionSizeInBlocks, 345*8975f5c5SAndroid Build Coastguard Worker const uint8_t *data, 346*8975f5c5SAndroid Build Coastguard Worker size_t bytesPerBlockRow, 347*8975f5c5SAndroid Build Coastguard Worker size_t bytesPer2DImage, 348*8975f5c5SAndroid Build Coastguard Worker size_t *bufferRowPitchOut, 349*8975f5c5SAndroid Build Coastguard Worker size_t *buffer2DImageSizeOut, 350*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef *bufferOut) 351*8975f5c5SAndroid Build Coastguard Worker{ 352*8975f5c5SAndroid Build Coastguard Worker size_t stagingBufferRowPitch = bytesPerBlockRow; 353*8975f5c5SAndroid Build Coastguard Worker size_t stagingBuffer2DImageSize = bytesPer2DImage; 354*8975f5c5SAndroid Build Coastguard Worker size_t stagingBufferSize = stagingBuffer2DImageSize * regionSizeInBlocks.depth; 355*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef stagingBuffer; 356*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, stagingBufferSize, nullptr, &stagingBuffer)); 357*8975f5c5SAndroid Build Coastguard Worker 358*8975f5c5SAndroid Build Coastguard Worker uint8_t *pdst = stagingBuffer->map(contextMtl); 359*8975f5c5SAndroid Build Coastguard Worker CopyTextureData(regionSizeInBlocks, bytesPerBlockRow, bytesPer2DImage, data, 360*8975f5c5SAndroid Build Coastguard Worker stagingBufferRowPitch, stagingBuffer2DImageSize, pdst); 361*8975f5c5SAndroid Build Coastguard Worker 362*8975f5c5SAndroid Build Coastguard Worker stagingBuffer->unmap(contextMtl); 363*8975f5c5SAndroid Build Coastguard Worker 364*8975f5c5SAndroid Build Coastguard Worker *bufferOut = stagingBuffer; 365*8975f5c5SAndroid Build Coastguard Worker *bufferRowPitchOut = stagingBufferRowPitch; 366*8975f5c5SAndroid Build Coastguard Worker *buffer2DImageSizeOut = stagingBuffer2DImageSize; 367*8975f5c5SAndroid Build Coastguard Worker 368*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 369*8975f5c5SAndroid Build Coastguard Worker} 370*8975f5c5SAndroid Build Coastguard Worker 371*8975f5c5SAndroid Build Coastguard Workerangle::Result SaturateDepth(ContextMtl *contextMtl, 372*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef srcBuffer, 373*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef dstBuffer, 374*8975f5c5SAndroid Build Coastguard Worker uint32_t srcBufferOffset, 375*8975f5c5SAndroid Build Coastguard Worker uint32_t srcPitch, 376*8975f5c5SAndroid Build Coastguard Worker MTLSize size) 377*8975f5c5SAndroid Build Coastguard Worker{ 378*8975f5c5SAndroid Build Coastguard Worker static_assert(gl::IMPLEMENTATION_MAX_2D_TEXTURE_SIZE <= UINT_MAX); 379*8975f5c5SAndroid Build Coastguard Worker mtl::DepthSaturationParams params; 380*8975f5c5SAndroid Build Coastguard Worker params.srcBuffer = srcBuffer; 381*8975f5c5SAndroid Build Coastguard Worker params.dstBuffer = dstBuffer; 382*8975f5c5SAndroid Build Coastguard Worker params.srcBufferOffset = srcBufferOffset; 383*8975f5c5SAndroid Build Coastguard Worker params.dstWidth = static_cast<uint32_t>(size.width); 384*8975f5c5SAndroid Build Coastguard Worker params.dstHeight = static_cast<uint32_t>(size.height); 385*8975f5c5SAndroid Build Coastguard Worker params.srcPitch = srcPitch; 386*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(contextMtl->getDisplay()->getUtils().saturateDepth(contextMtl, params)); 387*8975f5c5SAndroid Build Coastguard Worker 388*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 389*8975f5c5SAndroid Build Coastguard Worker} 390*8975f5c5SAndroid Build Coastguard Worker 391*8975f5c5SAndroid Build Coastguard Worker// This will copy a buffer to: 392*8975f5c5SAndroid Build Coastguard Worker// - the respective level & slice of an original texture if the "dst" texture is a view. 393*8975f5c5SAndroid Build Coastguard Worker// - the "dst" texture if it is not a view. 394*8975f5c5SAndroid Build Coastguard Worker// Notes: 395*8975f5c5SAndroid Build Coastguard Worker// - dstSlice is a slice in the "dst" texture not original texture. 396*8975f5c5SAndroid Build Coastguard Worker// - dstLevel is a level in the "dst" texture not original texture. 397*8975f5c5SAndroid Build Coastguard Worker// This function is needed because some GPUs such as the ones having AMD Bronze driver 398*8975f5c5SAndroid Build Coastguard Worker// have a bug when copying a buffer to a view of a 3D texture. 399*8975f5c5SAndroid Build Coastguard Workervoid CopyBufferToOriginalTextureIfDstIsAView(ContextMtl *contextMtl, 400*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *blitEncoder, 401*8975f5c5SAndroid Build Coastguard Worker const mtl::BufferRef &src, 402*8975f5c5SAndroid Build Coastguard Worker size_t srcOffset, 403*8975f5c5SAndroid Build Coastguard Worker size_t srcBytesPerRow, 404*8975f5c5SAndroid Build Coastguard Worker size_t srcBytesPerImage, 405*8975f5c5SAndroid Build Coastguard Worker MTLSize srcSize, 406*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &dst, 407*8975f5c5SAndroid Build Coastguard Worker const uint32_t dstSlice, 408*8975f5c5SAndroid Build Coastguard Worker const mtl::MipmapNativeLevel &dstLevel, 409*8975f5c5SAndroid Build Coastguard Worker MTLOrigin dstOrigin, 410*8975f5c5SAndroid Build Coastguard Worker MTLBlitOption blitOption) 411*8975f5c5SAndroid Build Coastguard Worker{ 412*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef correctedTexture = dst; 413*8975f5c5SAndroid Build Coastguard Worker mtl::MipmapNativeLevel correctedLevel = dstLevel; 414*8975f5c5SAndroid Build Coastguard Worker uint32_t correctedSlice = dstSlice; 415*8975f5c5SAndroid Build Coastguard Worker // TODO(b/343734719): Simulator has bug in parentRelativeSlice() so skip this step 416*8975f5c5SAndroid Build Coastguard Worker // on simulator. 417*8975f5c5SAndroid Build Coastguard Worker if (!contextMtl->getDisplay()->isSimulator() && correctedTexture->parentTexture()) 418*8975f5c5SAndroid Build Coastguard Worker { 419*8975f5c5SAndroid Build Coastguard Worker correctedLevel = correctedLevel + correctedTexture->parentRelativeLevel().get(); 420*8975f5c5SAndroid Build Coastguard Worker correctedSlice += correctedTexture->parentRelativeSlice(); 421*8975f5c5SAndroid Build Coastguard Worker correctedTexture = correctedTexture->parentTexture(); 422*8975f5c5SAndroid Build Coastguard Worker } 423*8975f5c5SAndroid Build Coastguard Worker 424*8975f5c5SAndroid Build Coastguard Worker blitEncoder->copyBufferToTexture(src, srcOffset, srcBytesPerRow, srcBytesPerImage, srcSize, 425*8975f5c5SAndroid Build Coastguard Worker correctedTexture, correctedSlice, correctedLevel, dstOrigin, 426*8975f5c5SAndroid Build Coastguard Worker blitOption); 427*8975f5c5SAndroid Build Coastguard Worker} 428*8975f5c5SAndroid Build Coastguard Worker 429*8975f5c5SAndroid Build Coastguard Workerangle::Result UploadDepthStencilTextureContentsWithStagingBuffer( 430*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl, 431*8975f5c5SAndroid Build Coastguard Worker const angle::Format &textureAngleFormat, 432*8975f5c5SAndroid Build Coastguard Worker MTLRegion region, 433*8975f5c5SAndroid Build Coastguard Worker const mtl::MipmapNativeLevel &mipmapLevel, 434*8975f5c5SAndroid Build Coastguard Worker uint32_t slice, 435*8975f5c5SAndroid Build Coastguard Worker const uint8_t *data, 436*8975f5c5SAndroid Build Coastguard Worker size_t bytesPerRow, 437*8975f5c5SAndroid Build Coastguard Worker size_t bytesPer2DImage, 438*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &texture) 439*8975f5c5SAndroid Build Coastguard Worker{ 440*8975f5c5SAndroid Build Coastguard Worker ASSERT(texture && texture->valid()); 441*8975f5c5SAndroid Build Coastguard Worker 442*8975f5c5SAndroid Build Coastguard Worker ASSERT(!texture->isCPUAccessible()); 443*8975f5c5SAndroid Build Coastguard Worker 444*8975f5c5SAndroid Build Coastguard Worker ASSERT(!textureAngleFormat.depthBits || !textureAngleFormat.stencilBits); 445*8975f5c5SAndroid Build Coastguard Worker 446*8975f5c5SAndroid Build Coastguard Worker // Depth and stencil textures cannot be of 3D type; 447*8975f5c5SAndroid Build Coastguard Worker // arrays and cube maps must be uploaded per-slice. 448*8975f5c5SAndroid Build Coastguard Worker ASSERT(region.size.depth == 1); 449*8975f5c5SAndroid Build Coastguard Worker 450*8975f5c5SAndroid Build Coastguard Worker // Copy data to staging buffer 451*8975f5c5SAndroid Build Coastguard Worker size_t stagingBufferRowPitch; 452*8975f5c5SAndroid Build Coastguard Worker size_t stagingBuffer2DImageSize; 453*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef stagingBuffer; 454*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(CopyDepthStencilTextureContentsToStagingBuffer( 455*8975f5c5SAndroid Build Coastguard Worker contextMtl, textureAngleFormat, textureAngleFormat, textureAngleFormat.pixelWriteFunction, 456*8975f5c5SAndroid Build Coastguard Worker region.size, data, bytesPerRow, bytesPer2DImage, &stagingBufferRowPitch, 457*8975f5c5SAndroid Build Coastguard Worker &stagingBuffer2DImageSize, &stagingBuffer)); 458*8975f5c5SAndroid Build Coastguard Worker 459*8975f5c5SAndroid Build Coastguard Worker if (textureAngleFormat.id == angle::FormatID::D32_FLOAT) 460*8975f5c5SAndroid Build Coastguard Worker { 461*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(SaturateDepth(contextMtl, stagingBuffer, stagingBuffer, 0, 462*8975f5c5SAndroid Build Coastguard Worker static_cast<uint32_t>(region.size.width), region.size)); 463*8975f5c5SAndroid Build Coastguard Worker } 464*8975f5c5SAndroid Build Coastguard Worker 465*8975f5c5SAndroid Build Coastguard Worker // Copy staging buffer to texture. 466*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *encoder = 467*8975f5c5SAndroid Build Coastguard Worker GetBlitCommandEncoderForResources(contextMtl, {stagingBuffer.get(), texture.get()}); 468*8975f5c5SAndroid Build Coastguard Worker 469*8975f5c5SAndroid Build Coastguard Worker CopyBufferToOriginalTextureIfDstIsAView( 470*8975f5c5SAndroid Build Coastguard Worker contextMtl, encoder, stagingBuffer, 0, stagingBufferRowPitch, stagingBuffer2DImageSize, 471*8975f5c5SAndroid Build Coastguard Worker region.size, texture, slice, mipmapLevel, region.origin, MTLBlitOptionNone); 472*8975f5c5SAndroid Build Coastguard Worker 473*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 474*8975f5c5SAndroid Build Coastguard Worker} 475*8975f5c5SAndroid Build Coastguard Worker 476*8975f5c5SAndroid Build Coastguard Worker// Packed depth stencil upload using staging buffer 477*8975f5c5SAndroid Build Coastguard Workerangle::Result UploadPackedDepthStencilTextureContentsWithStagingBuffer( 478*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl, 479*8975f5c5SAndroid Build Coastguard Worker const angle::Format &textureAngleFormat, 480*8975f5c5SAndroid Build Coastguard Worker MTLRegion region, 481*8975f5c5SAndroid Build Coastguard Worker const mtl::MipmapNativeLevel &mipmapLevel, 482*8975f5c5SAndroid Build Coastguard Worker uint32_t slice, 483*8975f5c5SAndroid Build Coastguard Worker const uint8_t *data, 484*8975f5c5SAndroid Build Coastguard Worker size_t bytesPerRow, 485*8975f5c5SAndroid Build Coastguard Worker size_t bytesPer2DImage, 486*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &texture) 487*8975f5c5SAndroid Build Coastguard Worker{ 488*8975f5c5SAndroid Build Coastguard Worker ASSERT(texture && texture->valid()); 489*8975f5c5SAndroid Build Coastguard Worker 490*8975f5c5SAndroid Build Coastguard Worker ASSERT(!texture->isCPUAccessible()); 491*8975f5c5SAndroid Build Coastguard Worker 492*8975f5c5SAndroid Build Coastguard Worker ASSERT(textureAngleFormat.depthBits && textureAngleFormat.stencilBits); 493*8975f5c5SAndroid Build Coastguard Worker 494*8975f5c5SAndroid Build Coastguard Worker // Depth and stencil textures cannot be of 3D type; 495*8975f5c5SAndroid Build Coastguard Worker // arrays and cube maps must be uploaded per-slice. 496*8975f5c5SAndroid Build Coastguard Worker ASSERT(region.size.depth == 1); 497*8975f5c5SAndroid Build Coastguard Worker 498*8975f5c5SAndroid Build Coastguard Worker // We have to split the depth & stencil data into 2 buffers. 499*8975f5c5SAndroid Build Coastguard Worker angle::FormatID stagingDepthBufferFormatId; 500*8975f5c5SAndroid Build Coastguard Worker angle::FormatID stagingStencilBufferFormatId; 501*8975f5c5SAndroid Build Coastguard Worker // Custom depth write function. We cannot use those in imageformats.cpp since Metal has some 502*8975f5c5SAndroid Build Coastguard Worker // special cases. 503*8975f5c5SAndroid Build Coastguard Worker rx::PixelWriteFunction stagingDepthBufferWriteFunctionOverride = nullptr; 504*8975f5c5SAndroid Build Coastguard Worker 505*8975f5c5SAndroid Build Coastguard Worker switch (textureAngleFormat.id) 506*8975f5c5SAndroid Build Coastguard Worker { 507*8975f5c5SAndroid Build Coastguard Worker case angle::FormatID::D24_UNORM_S8_UINT: 508*8975f5c5SAndroid Build Coastguard Worker // D24_UNORM_X8_UINT writes depth data to high 24 bits. But Metal expects depth data to 509*8975f5c5SAndroid Build Coastguard Worker // be in low 24 bits. 510*8975f5c5SAndroid Build Coastguard Worker stagingDepthBufferFormatId = angle::FormatID::D24_UNORM_X8_UINT; 511*8975f5c5SAndroid Build Coastguard Worker stagingDepthBufferWriteFunctionOverride = WriteDepthStencilToDepth24; 512*8975f5c5SAndroid Build Coastguard Worker stagingStencilBufferFormatId = angle::FormatID::S8_UINT; 513*8975f5c5SAndroid Build Coastguard Worker break; 514*8975f5c5SAndroid Build Coastguard Worker case angle::FormatID::D32_FLOAT_S8X24_UINT: 515*8975f5c5SAndroid Build Coastguard Worker stagingDepthBufferFormatId = angle::FormatID::D32_FLOAT; 516*8975f5c5SAndroid Build Coastguard Worker stagingStencilBufferFormatId = angle::FormatID::S8_UINT; 517*8975f5c5SAndroid Build Coastguard Worker break; 518*8975f5c5SAndroid Build Coastguard Worker default: 519*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_UNREACHABLE(contextMtl); 520*8975f5c5SAndroid Build Coastguard Worker } 521*8975f5c5SAndroid Build Coastguard Worker 522*8975f5c5SAndroid Build Coastguard Worker const angle::Format &angleStagingDepthFormat = angle::Format::Get(stagingDepthBufferFormatId); 523*8975f5c5SAndroid Build Coastguard Worker const angle::Format &angleStagingStencilFormat = 524*8975f5c5SAndroid Build Coastguard Worker angle::Format::Get(stagingStencilBufferFormatId); 525*8975f5c5SAndroid Build Coastguard Worker 526*8975f5c5SAndroid Build Coastguard Worker size_t stagingDepthBufferRowPitch, stagingStencilBufferRowPitch; 527*8975f5c5SAndroid Build Coastguard Worker size_t stagingDepthBuffer2DImageSize, stagingStencilBuffer2DImageSize; 528*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef stagingDepthBuffer, stagingStencilBuffer; 529*8975f5c5SAndroid Build Coastguard Worker 530*8975f5c5SAndroid Build Coastguard Worker // Copy depth data to staging depth buffer 531*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(CopyDepthStencilTextureContentsToStagingBuffer( 532*8975f5c5SAndroid Build Coastguard Worker contextMtl, textureAngleFormat, angleStagingDepthFormat, 533*8975f5c5SAndroid Build Coastguard Worker stagingDepthBufferWriteFunctionOverride, region.size, data, bytesPerRow, bytesPer2DImage, 534*8975f5c5SAndroid Build Coastguard Worker &stagingDepthBufferRowPitch, &stagingDepthBuffer2DImageSize, &stagingDepthBuffer)); 535*8975f5c5SAndroid Build Coastguard Worker 536*8975f5c5SAndroid Build Coastguard Worker // Copy stencil data to staging stencil buffer 537*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(CopyDepthStencilTextureContentsToStagingBuffer( 538*8975f5c5SAndroid Build Coastguard Worker contextMtl, textureAngleFormat, angleStagingStencilFormat, nullptr, region.size, data, 539*8975f5c5SAndroid Build Coastguard Worker bytesPerRow, bytesPer2DImage, &stagingStencilBufferRowPitch, 540*8975f5c5SAndroid Build Coastguard Worker &stagingStencilBuffer2DImageSize, &stagingStencilBuffer)); 541*8975f5c5SAndroid Build Coastguard Worker 542*8975f5c5SAndroid Build Coastguard Worker if (angleStagingDepthFormat.id == angle::FormatID::D32_FLOAT) 543*8975f5c5SAndroid Build Coastguard Worker { 544*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(SaturateDepth(contextMtl, stagingDepthBuffer, stagingDepthBuffer, 0, 545*8975f5c5SAndroid Build Coastguard Worker static_cast<uint32_t>(region.size.width), region.size)); 546*8975f5c5SAndroid Build Coastguard Worker } 547*8975f5c5SAndroid Build Coastguard Worker 548*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *encoder = GetBlitCommandEncoderForResources( 549*8975f5c5SAndroid Build Coastguard Worker contextMtl, {stagingDepthBuffer.get(), stagingStencilBuffer.get(), texture.get()}); 550*8975f5c5SAndroid Build Coastguard Worker 551*8975f5c5SAndroid Build Coastguard Worker CopyBufferToOriginalTextureIfDstIsAView( 552*8975f5c5SAndroid Build Coastguard Worker contextMtl, encoder, stagingDepthBuffer, 0, stagingDepthBufferRowPitch, 553*8975f5c5SAndroid Build Coastguard Worker stagingDepthBuffer2DImageSize, region.size, texture, slice, mipmapLevel, region.origin, 554*8975f5c5SAndroid Build Coastguard Worker MTLBlitOptionDepthFromDepthStencil); 555*8975f5c5SAndroid Build Coastguard Worker CopyBufferToOriginalTextureIfDstIsAView( 556*8975f5c5SAndroid Build Coastguard Worker contextMtl, encoder, stagingStencilBuffer, 0, stagingStencilBufferRowPitch, 557*8975f5c5SAndroid Build Coastguard Worker stagingStencilBuffer2DImageSize, region.size, texture, slice, mipmapLevel, region.origin, 558*8975f5c5SAndroid Build Coastguard Worker MTLBlitOptionStencilFromDepthStencil); 559*8975f5c5SAndroid Build Coastguard Worker 560*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 561*8975f5c5SAndroid Build Coastguard Worker} 562*8975f5c5SAndroid Build Coastguard Worker 563*8975f5c5SAndroid Build Coastguard Workerangle::Result UploadTextureContentsWithStagingBuffer(ContextMtl *contextMtl, 564*8975f5c5SAndroid Build Coastguard Worker const angle::Format &textureAngleFormat, 565*8975f5c5SAndroid Build Coastguard Worker MTLRegion region, 566*8975f5c5SAndroid Build Coastguard Worker const mtl::MipmapNativeLevel &mipmapLevel, 567*8975f5c5SAndroid Build Coastguard Worker uint32_t slice, 568*8975f5c5SAndroid Build Coastguard Worker const uint8_t *data, 569*8975f5c5SAndroid Build Coastguard Worker size_t bytesPerRow, 570*8975f5c5SAndroid Build Coastguard Worker size_t bytesPer2DImage, 571*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &texture) 572*8975f5c5SAndroid Build Coastguard Worker{ 573*8975f5c5SAndroid Build Coastguard Worker ASSERT(texture && texture->valid()); 574*8975f5c5SAndroid Build Coastguard Worker 575*8975f5c5SAndroid Build Coastguard Worker angle::FormatID stagingBufferFormatID = textureAngleFormat.id; 576*8975f5c5SAndroid Build Coastguard Worker const angle::Format &angleStagingFormat = angle::Format::Get(stagingBufferFormatID); 577*8975f5c5SAndroid Build Coastguard Worker 578*8975f5c5SAndroid Build Coastguard Worker size_t stagingBufferRowPitch; 579*8975f5c5SAndroid Build Coastguard Worker size_t stagingBuffer2DImageSize; 580*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef stagingBuffer; 581*8975f5c5SAndroid Build Coastguard Worker 582*8975f5c5SAndroid Build Coastguard Worker // Block-compressed formats need a bit of massaging for copy. 583*8975f5c5SAndroid Build Coastguard Worker if (textureAngleFormat.isBlock) 584*8975f5c5SAndroid Build Coastguard Worker { 585*8975f5c5SAndroid Build Coastguard Worker GLenum internalFormat = textureAngleFormat.glInternalFormat; 586*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &fmt = gl::GetSizedInternalFormatInfo(internalFormat); 587*8975f5c5SAndroid Build Coastguard Worker MTLRegion newRegion = region; 588*8975f5c5SAndroid Build Coastguard Worker bytesPerRow = 589*8975f5c5SAndroid Build Coastguard Worker (region.size.width + fmt.compressedBlockWidth - 1) / fmt.compressedBlockWidth * 16; 590*8975f5c5SAndroid Build Coastguard Worker bytesPer2DImage = (region.size.height + fmt.compressedBlockHeight - 1) / 591*8975f5c5SAndroid Build Coastguard Worker fmt.compressedBlockHeight * bytesPerRow; 592*8975f5c5SAndroid Build Coastguard Worker newRegion.size.width = 593*8975f5c5SAndroid Build Coastguard Worker (region.size.width + fmt.compressedBlockWidth - 1) / fmt.compressedBlockWidth; 594*8975f5c5SAndroid Build Coastguard Worker newRegion.size.height = 595*8975f5c5SAndroid Build Coastguard Worker (region.size.height + fmt.compressedBlockHeight - 1) / fmt.compressedBlockHeight; 596*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(CopyCompressedTextureContentsToStagingBuffer( 597*8975f5c5SAndroid Build Coastguard Worker contextMtl, angleStagingFormat, newRegion.size, data, bytesPerRow, bytesPer2DImage, 598*8975f5c5SAndroid Build Coastguard Worker &stagingBufferRowPitch, &stagingBuffer2DImageSize, &stagingBuffer)); 599*8975f5c5SAndroid Build Coastguard Worker } 600*8975f5c5SAndroid Build Coastguard Worker // Copy to staging buffer before uploading to texture. 601*8975f5c5SAndroid Build Coastguard Worker else 602*8975f5c5SAndroid Build Coastguard Worker { 603*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(CopyTextureContentsToStagingBuffer( 604*8975f5c5SAndroid Build Coastguard Worker contextMtl, angleStagingFormat, region.size, data, bytesPerRow, bytesPer2DImage, 605*8975f5c5SAndroid Build Coastguard Worker &stagingBufferRowPitch, &stagingBuffer2DImageSize, &stagingBuffer)); 606*8975f5c5SAndroid Build Coastguard Worker } 607*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *encoder = 608*8975f5c5SAndroid Build Coastguard Worker GetBlitCommandEncoderForResources(contextMtl, {stagingBuffer.get(), texture.get()}); 609*8975f5c5SAndroid Build Coastguard Worker 610*8975f5c5SAndroid Build Coastguard Worker CopyBufferToOriginalTextureIfDstIsAView( 611*8975f5c5SAndroid Build Coastguard Worker contextMtl, encoder, stagingBuffer, 0, stagingBufferRowPitch, stagingBuffer2DImageSize, 612*8975f5c5SAndroid Build Coastguard Worker region.size, texture, slice, mipmapLevel, region.origin, 0); 613*8975f5c5SAndroid Build Coastguard Worker 614*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 615*8975f5c5SAndroid Build Coastguard Worker} 616*8975f5c5SAndroid Build Coastguard Worker 617*8975f5c5SAndroid Build Coastguard Workerangle::Result UploadTextureContents(const gl::Context *context, 618*8975f5c5SAndroid Build Coastguard Worker const angle::Format &textureAngleFormat, 619*8975f5c5SAndroid Build Coastguard Worker const MTLRegion ®ion, 620*8975f5c5SAndroid Build Coastguard Worker const mtl::MipmapNativeLevel &mipmapLevel, 621*8975f5c5SAndroid Build Coastguard Worker uint32_t slice, 622*8975f5c5SAndroid Build Coastguard Worker const uint8_t *data, 623*8975f5c5SAndroid Build Coastguard Worker size_t bytesPerRow, 624*8975f5c5SAndroid Build Coastguard Worker size_t bytesPer2DImage, 625*8975f5c5SAndroid Build Coastguard Worker bool avoidStagingBuffers, 626*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &texture) 627*8975f5c5SAndroid Build Coastguard Worker 628*8975f5c5SAndroid Build Coastguard Worker{ 629*8975f5c5SAndroid Build Coastguard Worker ASSERT(texture && texture->valid()); 630*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 631*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &mtlFormat = contextMtl->getPixelFormat(textureAngleFormat.id); 632*8975f5c5SAndroid Build Coastguard Worker 633*8975f5c5SAndroid Build Coastguard Worker bool preferGPUInitialization = 634*8975f5c5SAndroid Build Coastguard Worker !avoidStagingBuffers && 635*8975f5c5SAndroid Build Coastguard Worker PreferStagedTextureUploads(context, texture, mtlFormat, mtl::StagingPurpose::Upload); 636*8975f5c5SAndroid Build Coastguard Worker if (texture->isCPUAccessible() && !preferGPUInitialization) 637*8975f5c5SAndroid Build Coastguard Worker { 638*8975f5c5SAndroid Build Coastguard Worker if (mtlFormat.isPVRTC()) 639*8975f5c5SAndroid Build Coastguard Worker { 640*8975f5c5SAndroid Build Coastguard Worker // Replace Region Validation: rowBytes must be 0 641*8975f5c5SAndroid Build Coastguard Worker bytesPerRow = 0; 642*8975f5c5SAndroid Build Coastguard Worker } 643*8975f5c5SAndroid Build Coastguard Worker 644*8975f5c5SAndroid Build Coastguard Worker // If texture is CPU accessible, just call replaceRegion() directly. 645*8975f5c5SAndroid Build Coastguard Worker texture->replaceRegion(contextMtl, region, mipmapLevel, slice, data, bytesPerRow, 646*8975f5c5SAndroid Build Coastguard Worker bytesPer2DImage); 647*8975f5c5SAndroid Build Coastguard Worker 648*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 649*8975f5c5SAndroid Build Coastguard Worker } 650*8975f5c5SAndroid Build Coastguard Worker 651*8975f5c5SAndroid Build Coastguard Worker // Texture is not CPU accessible or staging is forced due to a workaround 652*8975f5c5SAndroid Build Coastguard Worker if (!textureAngleFormat.depthBits && !textureAngleFormat.stencilBits) 653*8975f5c5SAndroid Build Coastguard Worker { 654*8975f5c5SAndroid Build Coastguard Worker // Upload color data 655*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadTextureContentsWithStagingBuffer(contextMtl, textureAngleFormat, region, 656*8975f5c5SAndroid Build Coastguard Worker mipmapLevel, slice, data, bytesPerRow, 657*8975f5c5SAndroid Build Coastguard Worker bytesPer2DImage, texture)); 658*8975f5c5SAndroid Build Coastguard Worker } 659*8975f5c5SAndroid Build Coastguard Worker else if (textureAngleFormat.depthBits && textureAngleFormat.stencilBits) 660*8975f5c5SAndroid Build Coastguard Worker { 661*8975f5c5SAndroid Build Coastguard Worker // Packed depth-stencil 662*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadPackedDepthStencilTextureContentsWithStagingBuffer( 663*8975f5c5SAndroid Build Coastguard Worker contextMtl, textureAngleFormat, region, mipmapLevel, slice, data, bytesPerRow, 664*8975f5c5SAndroid Build Coastguard Worker bytesPer2DImage, texture)); 665*8975f5c5SAndroid Build Coastguard Worker } 666*8975f5c5SAndroid Build Coastguard Worker else 667*8975f5c5SAndroid Build Coastguard Worker { 668*8975f5c5SAndroid Build Coastguard Worker // Depth or stencil 669*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadDepthStencilTextureContentsWithStagingBuffer( 670*8975f5c5SAndroid Build Coastguard Worker contextMtl, textureAngleFormat, region, mipmapLevel, slice, data, bytesPerRow, 671*8975f5c5SAndroid Build Coastguard Worker bytesPer2DImage, texture)); 672*8975f5c5SAndroid Build Coastguard Worker } 673*8975f5c5SAndroid Build Coastguard Worker 674*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 675*8975f5c5SAndroid Build Coastguard Worker} 676*8975f5c5SAndroid Build Coastguard Worker 677*8975f5c5SAndroid Build Coastguard Worker// This might be unused on platform not supporting swizzle. 678*8975f5c5SAndroid Build Coastguard WorkerANGLE_APPLE_UNUSED 679*8975f5c5SAndroid Build Coastguard WorkerGLenum OverrideSwizzleValue(const gl::Context *context, 680*8975f5c5SAndroid Build Coastguard Worker GLenum swizzle, 681*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &format, 682*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &glInternalFormat) 683*8975f5c5SAndroid Build Coastguard Worker{ 684*8975f5c5SAndroid Build Coastguard Worker if (format.actualAngleFormat().hasDepthOrStencilBits()) 685*8975f5c5SAndroid Build Coastguard Worker { 686*8975f5c5SAndroid Build Coastguard Worker ASSERT(!format.swizzled); 687*8975f5c5SAndroid Build Coastguard Worker if (context->getState().getClientMajorVersion() >= 3 && glInternalFormat.sized) 688*8975f5c5SAndroid Build Coastguard Worker { 689*8975f5c5SAndroid Build Coastguard Worker // ES 3.1 spec: treat depth and stencil textures as red textures during sampling. 690*8975f5c5SAndroid Build Coastguard Worker if (swizzle == GL_GREEN || swizzle == GL_BLUE) 691*8975f5c5SAndroid Build Coastguard Worker { 692*8975f5c5SAndroid Build Coastguard Worker return GL_NONE; 693*8975f5c5SAndroid Build Coastguard Worker } 694*8975f5c5SAndroid Build Coastguard Worker else if (swizzle == GL_ALPHA) 695*8975f5c5SAndroid Build Coastguard Worker { 696*8975f5c5SAndroid Build Coastguard Worker return GL_ONE; 697*8975f5c5SAndroid Build Coastguard Worker } 698*8975f5c5SAndroid Build Coastguard Worker } 699*8975f5c5SAndroid Build Coastguard Worker else 700*8975f5c5SAndroid Build Coastguard Worker { 701*8975f5c5SAndroid Build Coastguard Worker // https://www.khronos.org/registry/OpenGL/extensions/OES/OES_depth_texture.txt 702*8975f5c5SAndroid Build Coastguard Worker // Treat depth texture as luminance texture during sampling. 703*8975f5c5SAndroid Build Coastguard Worker if (swizzle == GL_GREEN || swizzle == GL_BLUE) 704*8975f5c5SAndroid Build Coastguard Worker { 705*8975f5c5SAndroid Build Coastguard Worker return GL_RED; 706*8975f5c5SAndroid Build Coastguard Worker } 707*8975f5c5SAndroid Build Coastguard Worker else if (swizzle == GL_ALPHA) 708*8975f5c5SAndroid Build Coastguard Worker { 709*8975f5c5SAndroid Build Coastguard Worker return GL_ONE; 710*8975f5c5SAndroid Build Coastguard Worker } 711*8975f5c5SAndroid Build Coastguard Worker } 712*8975f5c5SAndroid Build Coastguard Worker } 713*8975f5c5SAndroid Build Coastguard Worker else if (format.swizzled) 714*8975f5c5SAndroid Build Coastguard Worker { 715*8975f5c5SAndroid Build Coastguard Worker // Combine the swizzles 716*8975f5c5SAndroid Build Coastguard Worker switch (swizzle) 717*8975f5c5SAndroid Build Coastguard Worker { 718*8975f5c5SAndroid Build Coastguard Worker case GL_RED: 719*8975f5c5SAndroid Build Coastguard Worker return format.swizzle[0]; 720*8975f5c5SAndroid Build Coastguard Worker case GL_GREEN: 721*8975f5c5SAndroid Build Coastguard Worker return format.swizzle[1]; 722*8975f5c5SAndroid Build Coastguard Worker case GL_BLUE: 723*8975f5c5SAndroid Build Coastguard Worker return format.swizzle[2]; 724*8975f5c5SAndroid Build Coastguard Worker case GL_ALPHA: 725*8975f5c5SAndroid Build Coastguard Worker return format.swizzle[3]; 726*8975f5c5SAndroid Build Coastguard Worker default: 727*8975f5c5SAndroid Build Coastguard Worker break; 728*8975f5c5SAndroid Build Coastguard Worker } 729*8975f5c5SAndroid Build Coastguard Worker } 730*8975f5c5SAndroid Build Coastguard Worker 731*8975f5c5SAndroid Build Coastguard Worker return swizzle; 732*8975f5c5SAndroid Build Coastguard Worker} 733*8975f5c5SAndroid Build Coastguard Worker 734*8975f5c5SAndroid Build Coastguard Workermtl::TextureRef &GetLayerLevelTextureView( 735*8975f5c5SAndroid Build Coastguard Worker TextureMtl::LayerLevelTextureViewVector *layerLevelTextureViews, 736*8975f5c5SAndroid Build Coastguard Worker uint32_t layer, 737*8975f5c5SAndroid Build Coastguard Worker uint32_t level, 738*8975f5c5SAndroid Build Coastguard Worker uint32_t layerCount, 739*8975f5c5SAndroid Build Coastguard Worker uint32_t levelCount) 740*8975f5c5SAndroid Build Coastguard Worker{ 741*8975f5c5SAndroid Build Coastguard Worker // Lazily allocate the full layer and level count to not trigger any std::vector reallocations. 742*8975f5c5SAndroid Build Coastguard Worker if (layerLevelTextureViews->empty()) 743*8975f5c5SAndroid Build Coastguard Worker { 744*8975f5c5SAndroid Build Coastguard Worker layerLevelTextureViews->resize(layerCount); 745*8975f5c5SAndroid Build Coastguard Worker } 746*8975f5c5SAndroid Build Coastguard Worker ASSERT(layerLevelTextureViews->size() > layer); 747*8975f5c5SAndroid Build Coastguard Worker 748*8975f5c5SAndroid Build Coastguard Worker TextureMtl::TextureViewVector &levelTextureViews = (*layerLevelTextureViews)[layer]; 749*8975f5c5SAndroid Build Coastguard Worker 750*8975f5c5SAndroid Build Coastguard Worker if (levelTextureViews.empty()) 751*8975f5c5SAndroid Build Coastguard Worker { 752*8975f5c5SAndroid Build Coastguard Worker levelTextureViews.resize(levelCount); 753*8975f5c5SAndroid Build Coastguard Worker } 754*8975f5c5SAndroid Build Coastguard Worker ASSERT(levelTextureViews.size() > level); 755*8975f5c5SAndroid Build Coastguard Worker 756*8975f5c5SAndroid Build Coastguard Worker return levelTextureViews[level]; 757*8975f5c5SAndroid Build Coastguard Worker} 758*8975f5c5SAndroid Build Coastguard Worker 759*8975f5c5SAndroid Build Coastguard Worker} // namespace 760*8975f5c5SAndroid Build Coastguard Worker 761*8975f5c5SAndroid Build Coastguard Worker// TextureMtl::NativeTextureWrapper implementation. 762*8975f5c5SAndroid Build Coastguard Worker// This class uses GL level instead of mtl::MipmapNativeLevel. 763*8975f5c5SAndroid Build Coastguard Worker// It seamlessly translates GL level to native level based on the base GL information passed in the 764*8975f5c5SAndroid Build Coastguard Worker// constructor. The base GL level is unchanged thoughout the lifetime of this object. 765*8975f5c5SAndroid Build Coastguard Worker// Note that NativeTextureWrapper's base GL level doesn't necessarily mean it's the same as a GL 766*8975f5c5SAndroid Build Coastguard Worker// texture's real base level. 767*8975f5c5SAndroid Build Coastguard Worker// - If NativeTextureWrapper holds a native storage of a non-immutable texture, 768*8975f5c5SAndroid Build Coastguard Worker// its base GL level is indeed equal to the GL texture's base level. 769*8975f5c5SAndroid Build Coastguard Worker// - If NativeTextureWrapper holds a native storage of an immutable texture, 770*8975f5c5SAndroid Build Coastguard Worker// it base GL level is actually 0. 771*8975f5c5SAndroid Build Coastguard Worker// - If NativeTextureWrapper holds a view from base level to max level of a GL texture, 772*8975f5c5SAndroid Build Coastguard Worker// then its base GL level is equal to the GL texture's base level. 773*8975f5c5SAndroid Build Coastguard Workerclass TextureMtl::NativeTextureWrapper : angle::NonCopyable 774*8975f5c5SAndroid Build Coastguard Worker{ 775*8975f5c5SAndroid Build Coastguard Worker public: 776*8975f5c5SAndroid Build Coastguard Worker NativeTextureWrapper(mtl::TextureRef texture, GLuint baseGLLevel) 777*8975f5c5SAndroid Build Coastguard Worker : mNativeTexture(std::move(texture)), mBaseGLLevel(baseGLLevel) 778*8975f5c5SAndroid Build Coastguard Worker { 779*8975f5c5SAndroid Build Coastguard Worker ASSERT(mNativeTexture && mNativeTexture->valid()); 780*8975f5c5SAndroid Build Coastguard Worker } 781*8975f5c5SAndroid Build Coastguard Worker 782*8975f5c5SAndroid Build Coastguard Worker operator const mtl::TextureRef &() const { return mNativeTexture; } 783*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &getNativeTexture() const { return mNativeTexture; } 784*8975f5c5SAndroid Build Coastguard Worker 785*8975f5c5SAndroid Build Coastguard Worker void replaceRegion(ContextMtl *context, 786*8975f5c5SAndroid Build Coastguard Worker const MTLRegion ®ion, 787*8975f5c5SAndroid Build Coastguard Worker GLuint glLevel, 788*8975f5c5SAndroid Build Coastguard Worker uint32_t slice, 789*8975f5c5SAndroid Build Coastguard Worker const uint8_t *data, 790*8975f5c5SAndroid Build Coastguard Worker size_t bytesPerRow, 791*8975f5c5SAndroid Build Coastguard Worker size_t bytesPer2DImage) 792*8975f5c5SAndroid Build Coastguard Worker { 793*8975f5c5SAndroid Build Coastguard Worker mNativeTexture->replaceRegion(context, region, getNativeLevel(glLevel), slice, data, 794*8975f5c5SAndroid Build Coastguard Worker bytesPerRow, bytesPer2DImage); 795*8975f5c5SAndroid Build Coastguard Worker } 796*8975f5c5SAndroid Build Coastguard Worker 797*8975f5c5SAndroid Build Coastguard Worker void getBytes(ContextMtl *context, 798*8975f5c5SAndroid Build Coastguard Worker size_t bytesPerRow, 799*8975f5c5SAndroid Build Coastguard Worker size_t bytesPer2DInage, 800*8975f5c5SAndroid Build Coastguard Worker const MTLRegion ®ion, 801*8975f5c5SAndroid Build Coastguard Worker GLuint glLevel, 802*8975f5c5SAndroid Build Coastguard Worker uint32_t slice, 803*8975f5c5SAndroid Build Coastguard Worker uint8_t *dataOut) 804*8975f5c5SAndroid Build Coastguard Worker { 805*8975f5c5SAndroid Build Coastguard Worker mNativeTexture->getBytes(context, bytesPerRow, bytesPer2DInage, region, 806*8975f5c5SAndroid Build Coastguard Worker getNativeLevel(glLevel), slice, dataOut); 807*8975f5c5SAndroid Build Coastguard Worker } 808*8975f5c5SAndroid Build Coastguard Worker 809*8975f5c5SAndroid Build Coastguard Worker GLuint getBaseGLLevel() const { return mBaseGLLevel; } 810*8975f5c5SAndroid Build Coastguard Worker // Get max addressable GL level that this texture supports. 811*8975f5c5SAndroid Build Coastguard Worker GLuint getMaxSupportedGLLevel() const { return mBaseGLLevel + mipmapLevels() - 1; } 812*8975f5c5SAndroid Build Coastguard Worker // Check whether a GL level refers to a valid mip in this texture. 813*8975f5c5SAndroid Build Coastguard Worker bool isGLLevelSupported(GLuint glLevel) 814*8975f5c5SAndroid Build Coastguard Worker { 815*8975f5c5SAndroid Build Coastguard Worker return glLevel >= mBaseGLLevel && glLevel <= getMaxSupportedGLLevel(); 816*8975f5c5SAndroid Build Coastguard Worker } 817*8975f5c5SAndroid Build Coastguard Worker mtl::MipmapNativeLevel getNativeLevel(GLuint glLevel) const 818*8975f5c5SAndroid Build Coastguard Worker { 819*8975f5c5SAndroid Build Coastguard Worker return mtl::GetNativeMipLevel(glLevel, mBaseGLLevel); 820*8975f5c5SAndroid Build Coastguard Worker } 821*8975f5c5SAndroid Build Coastguard Worker GLuint getGLLevel(const mtl::MipmapNativeLevel &nativeLevel) const 822*8975f5c5SAndroid Build Coastguard Worker { 823*8975f5c5SAndroid Build Coastguard Worker return mtl::GetGLMipLevel(nativeLevel, mBaseGLLevel); 824*8975f5c5SAndroid Build Coastguard Worker } 825*8975f5c5SAndroid Build Coastguard Worker 826*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef getStencilView() { return mNativeTexture->getStencilView(); } 827*8975f5c5SAndroid Build Coastguard Worker 828*8975f5c5SAndroid Build Coastguard Worker MTLTextureType textureType() const { return mNativeTexture->textureType(); } 829*8975f5c5SAndroid Build Coastguard Worker MTLPixelFormat pixelFormat() const { return mNativeTexture->pixelFormat(); } 830*8975f5c5SAndroid Build Coastguard Worker 831*8975f5c5SAndroid Build Coastguard Worker uint32_t mipmapLevels() const { return mNativeTexture->mipmapLevels(); } 832*8975f5c5SAndroid Build Coastguard Worker uint32_t arrayLength() const { return mNativeTexture->arrayLength(); } 833*8975f5c5SAndroid Build Coastguard Worker uint32_t cubeFaces() const { return mNativeTexture->cubeFaces(); } 834*8975f5c5SAndroid Build Coastguard Worker uint32_t cubeFacesOrArrayLength() const { return mNativeTexture->cubeFacesOrArrayLength(); } 835*8975f5c5SAndroid Build Coastguard Worker 836*8975f5c5SAndroid Build Coastguard Worker uint32_t width(GLuint glLevel) const { return mNativeTexture->width(getNativeLevel(glLevel)); } 837*8975f5c5SAndroid Build Coastguard Worker uint32_t height(GLuint glLevel) const 838*8975f5c5SAndroid Build Coastguard Worker { 839*8975f5c5SAndroid Build Coastguard Worker return mNativeTexture->height(getNativeLevel(glLevel)); 840*8975f5c5SAndroid Build Coastguard Worker } 841*8975f5c5SAndroid Build Coastguard Worker uint32_t depth(GLuint glLevel) const { return mNativeTexture->depth(getNativeLevel(glLevel)); } 842*8975f5c5SAndroid Build Coastguard Worker 843*8975f5c5SAndroid Build Coastguard Worker gl::Extents size(GLuint glLevel) const { return mNativeTexture->size(getNativeLevel(glLevel)); } 844*8975f5c5SAndroid Build Coastguard Worker 845*8975f5c5SAndroid Build Coastguard Worker // Get width, height, depth, size at base level. 846*8975f5c5SAndroid Build Coastguard Worker uint32_t widthAt0() const { return width(mBaseGLLevel); } 847*8975f5c5SAndroid Build Coastguard Worker uint32_t heightAt0() const { return height(mBaseGLLevel); } 848*8975f5c5SAndroid Build Coastguard Worker uint32_t depthAt0() const { return depth(mBaseGLLevel); } 849*8975f5c5SAndroid Build Coastguard Worker gl::Extents sizeAt0() const { return size(mBaseGLLevel); } 850*8975f5c5SAndroid Build Coastguard Worker 851*8975f5c5SAndroid Build Coastguard Worker protected: 852*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef mNativeTexture; 853*8975f5c5SAndroid Build Coastguard Worker const GLuint mBaseGLLevel; 854*8975f5c5SAndroid Build Coastguard Worker}; 855*8975f5c5SAndroid Build Coastguard Worker 856*8975f5c5SAndroid Build Coastguard Worker// This class extends NativeTextureWrapper with support for view creation 857*8975f5c5SAndroid Build Coastguard Workerclass TextureMtl::NativeTextureWrapperWithViewSupport : public NativeTextureWrapper 858*8975f5c5SAndroid Build Coastguard Worker{ 859*8975f5c5SAndroid Build Coastguard Worker public: 860*8975f5c5SAndroid Build Coastguard Worker NativeTextureWrapperWithViewSupport(mtl::TextureRef texture, GLuint baseGLLevel) 861*8975f5c5SAndroid Build Coastguard Worker : NativeTextureWrapper(std::move(texture), baseGLLevel) 862*8975f5c5SAndroid Build Coastguard Worker {} 863*8975f5c5SAndroid Build Coastguard Worker 864*8975f5c5SAndroid Build Coastguard Worker // Create a view of one slice at a level. 865*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef createSliceMipView(uint32_t slice, GLuint glLevel) 866*8975f5c5SAndroid Build Coastguard Worker { 867*8975f5c5SAndroid Build Coastguard Worker return mNativeTexture->createSliceMipView(slice, getNativeLevel(glLevel)); 868*8975f5c5SAndroid Build Coastguard Worker } 869*8975f5c5SAndroid Build Coastguard Worker // Create a levels range view 870*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef createMipsView(GLuint glLevel, uint32_t levels) 871*8975f5c5SAndroid Build Coastguard Worker { 872*8975f5c5SAndroid Build Coastguard Worker return mNativeTexture->createMipsView(getNativeLevel(glLevel), levels); 873*8975f5c5SAndroid Build Coastguard Worker } 874*8975f5c5SAndroid Build Coastguard Worker // Create a view of a level. 875*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef createMipView(GLuint glLevel) 876*8975f5c5SAndroid Build Coastguard Worker { 877*8975f5c5SAndroid Build Coastguard Worker return mNativeTexture->createMipView(getNativeLevel(glLevel)); 878*8975f5c5SAndroid Build Coastguard Worker } 879*8975f5c5SAndroid Build Coastguard Worker // Create a view for a shader image binding. 880*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef createShaderImageView2D(GLuint glLevel, int layer, MTLPixelFormat format) 881*8975f5c5SAndroid Build Coastguard Worker { 882*8975f5c5SAndroid Build Coastguard Worker return mNativeTexture->createShaderImageView2D(getNativeLevel(glLevel), layer, format); 883*8975f5c5SAndroid Build Coastguard Worker } 884*8975f5c5SAndroid Build Coastguard Worker 885*8975f5c5SAndroid Build Coastguard Worker // Create a swizzled view 886*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef createMipsSwizzleView(GLuint glLevel, 887*8975f5c5SAndroid Build Coastguard Worker uint32_t levels, 888*8975f5c5SAndroid Build Coastguard Worker MTLPixelFormat format, 889*8975f5c5SAndroid Build Coastguard Worker const MTLTextureSwizzleChannels &swizzle) 890*8975f5c5SAndroid Build Coastguard Worker { 891*8975f5c5SAndroid Build Coastguard Worker return mNativeTexture->createMipsSwizzleView(getNativeLevel(glLevel), levels, format, 892*8975f5c5SAndroid Build Coastguard Worker swizzle); 893*8975f5c5SAndroid Build Coastguard Worker } 894*8975f5c5SAndroid Build Coastguard Worker}; 895*8975f5c5SAndroid Build Coastguard Worker 896*8975f5c5SAndroid Build Coastguard Worker// TextureMtl implementation 897*8975f5c5SAndroid Build Coastguard WorkerTextureMtl::TextureMtl(const gl::TextureState &state) : TextureImpl(state) {} 898*8975f5c5SAndroid Build Coastguard Worker 899*8975f5c5SAndroid Build Coastguard WorkerTextureMtl::~TextureMtl() = default; 900*8975f5c5SAndroid Build Coastguard Worker 901*8975f5c5SAndroid Build Coastguard Workervoid TextureMtl::onDestroy(const gl::Context *context) 902*8975f5c5SAndroid Build Coastguard Worker{ 903*8975f5c5SAndroid Build Coastguard Worker deallocateNativeStorage(/*keepImages=*/false); 904*8975f5c5SAndroid Build Coastguard Worker mBoundSurface = nullptr; 905*8975f5c5SAndroid Build Coastguard Worker} 906*8975f5c5SAndroid Build Coastguard Worker 907*8975f5c5SAndroid Build Coastguard Workervoid TextureMtl::deallocateNativeStorage(bool keepImages, bool keepSamplerStateAndFormat) 908*8975f5c5SAndroid Build Coastguard Worker{ 909*8975f5c5SAndroid Build Coastguard Worker 910*8975f5c5SAndroid Build Coastguard Worker if (!keepImages) 911*8975f5c5SAndroid Build Coastguard Worker { 912*8975f5c5SAndroid Build Coastguard Worker mTexImageDefs.clear(); 913*8975f5c5SAndroid Build Coastguard Worker mShaderImageViews.clear(); 914*8975f5c5SAndroid Build Coastguard Worker } 915*8975f5c5SAndroid Build Coastguard Worker else if (mNativeTextureStorage) 916*8975f5c5SAndroid Build Coastguard Worker { 917*8975f5c5SAndroid Build Coastguard Worker // Release native texture but keep its image definitions. 918*8975f5c5SAndroid Build Coastguard Worker retainImageDefinitions(); 919*8975f5c5SAndroid Build Coastguard Worker } 920*8975f5c5SAndroid Build Coastguard Worker 921*8975f5c5SAndroid Build Coastguard Worker mNativeTextureStorage = nullptr; 922*8975f5c5SAndroid Build Coastguard Worker mViewFromBaseToMaxLevel = nullptr; 923*8975f5c5SAndroid Build Coastguard Worker mSwizzleStencilSamplingView = nullptr; 924*8975f5c5SAndroid Build Coastguard Worker 925*8975f5c5SAndroid Build Coastguard Worker // Clear render target cache for each texture's image. We don't erase them because they 926*8975f5c5SAndroid Build Coastguard Worker // might still be referenced by a framebuffer. 927*8975f5c5SAndroid Build Coastguard Worker for (auto &samplesMapRenderTargets : mRenderTargets) 928*8975f5c5SAndroid Build Coastguard Worker { 929*8975f5c5SAndroid Build Coastguard Worker for (RenderTargetMtl &perSampleCountRenderTarget : samplesMapRenderTargets.second) 930*8975f5c5SAndroid Build Coastguard Worker { 931*8975f5c5SAndroid Build Coastguard Worker perSampleCountRenderTarget.reset(); 932*8975f5c5SAndroid Build Coastguard Worker } 933*8975f5c5SAndroid Build Coastguard Worker } 934*8975f5c5SAndroid Build Coastguard Worker 935*8975f5c5SAndroid Build Coastguard Worker for (auto &samplesMapMSTextures : mImplicitMSTextures) 936*8975f5c5SAndroid Build Coastguard Worker { 937*8975f5c5SAndroid Build Coastguard Worker for (mtl::TextureRef &perSampleCountMSTexture : samplesMapMSTextures.second) 938*8975f5c5SAndroid Build Coastguard Worker { 939*8975f5c5SAndroid Build Coastguard Worker perSampleCountMSTexture.reset(); 940*8975f5c5SAndroid Build Coastguard Worker } 941*8975f5c5SAndroid Build Coastguard Worker } 942*8975f5c5SAndroid Build Coastguard Worker 943*8975f5c5SAndroid Build Coastguard Worker for (mtl::TextureRef &view : mLevelViewsWithinBaseMax) 944*8975f5c5SAndroid Build Coastguard Worker { 945*8975f5c5SAndroid Build Coastguard Worker view.reset(); 946*8975f5c5SAndroid Build Coastguard Worker } 947*8975f5c5SAndroid Build Coastguard Worker 948*8975f5c5SAndroid Build Coastguard Worker if (!keepSamplerStateAndFormat) 949*8975f5c5SAndroid Build Coastguard Worker { 950*8975f5c5SAndroid Build Coastguard Worker mMetalSamplerState = nil; 951*8975f5c5SAndroid Build Coastguard Worker mFormat = mtl::Format(); 952*8975f5c5SAndroid Build Coastguard Worker } 953*8975f5c5SAndroid Build Coastguard Worker} 954*8975f5c5SAndroid Build Coastguard Worker 955*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::ensureNativeStorageCreated(const gl::Context *context) 956*8975f5c5SAndroid Build Coastguard Worker{ 957*8975f5c5SAndroid Build Coastguard Worker if (mNativeTextureStorage) 958*8975f5c5SAndroid Build Coastguard Worker { 959*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 960*8975f5c5SAndroid Build Coastguard Worker } 961*8975f5c5SAndroid Build Coastguard Worker 962*8975f5c5SAndroid Build Coastguard Worker // This should not be called from immutable texture. 963*8975f5c5SAndroid Build Coastguard Worker ASSERT(!isImmutableOrPBuffer()); 964*8975f5c5SAndroid Build Coastguard Worker ASSERT(mState.getType() != gl::TextureType::_2DMultisample); 965*8975f5c5SAndroid Build Coastguard Worker ASSERT(mState.getType() != gl::TextureType::_2DMultisampleArray); 966*8975f5c5SAndroid Build Coastguard Worker 967*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 968*8975f5c5SAndroid Build Coastguard Worker 969*8975f5c5SAndroid Build Coastguard Worker // Create actual texture object: 970*8975f5c5SAndroid Build Coastguard Worker GLuint mips = mState.getMipmapMaxLevel() - mState.getEffectiveBaseLevel() + 1; 971*8975f5c5SAndroid Build Coastguard Worker gl::ImageDesc desc = mState.getBaseLevelDesc(); 972*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_CHECK(contextMtl, desc.format.valid(), GL_INVALID_OPERATION); 973*8975f5c5SAndroid Build Coastguard Worker angle::FormatID angleFormatId = 974*8975f5c5SAndroid Build Coastguard Worker angle::Format::InternalFormatToID(desc.format.info->sizedInternalFormat); 975*8975f5c5SAndroid Build Coastguard Worker mFormat = contextMtl->getPixelFormat(angleFormatId); 976*8975f5c5SAndroid Build Coastguard Worker 977*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(createNativeStorage(context, mState.getType(), mips, 0, desc.size)); 978*8975f5c5SAndroid Build Coastguard Worker 979*8975f5c5SAndroid Build Coastguard Worker // Transfer data from defined images to actual texture object 980*8975f5c5SAndroid Build Coastguard Worker int numCubeFaces = static_cast<int>(mNativeTextureStorage->cubeFaces()); 981*8975f5c5SAndroid Build Coastguard Worker for (int face = 0; face < numCubeFaces; ++face) 982*8975f5c5SAndroid Build Coastguard Worker { 983*8975f5c5SAndroid Build Coastguard Worker for (mtl::MipmapNativeLevel actualMip = mtl::kZeroNativeMipLevel; actualMip.get() < mips; 984*8975f5c5SAndroid Build Coastguard Worker ++actualMip) 985*8975f5c5SAndroid Build Coastguard Worker { 986*8975f5c5SAndroid Build Coastguard Worker GLuint imageMipLevel = mNativeTextureStorage->getGLLevel(actualMip); 987*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef &imageToTransfer = mTexImageDefs[face][imageMipLevel].image; 988*8975f5c5SAndroid Build Coastguard Worker 989*8975f5c5SAndroid Build Coastguard Worker // Only transfer if this mip & slice image has been defined and in correct size & 990*8975f5c5SAndroid Build Coastguard Worker // format. 991*8975f5c5SAndroid Build Coastguard Worker gl::Extents actualMipSize = mNativeTextureStorage->size(imageMipLevel); 992*8975f5c5SAndroid Build Coastguard Worker if (imageToTransfer && imageToTransfer->sizeAt0() == actualMipSize && 993*8975f5c5SAndroid Build Coastguard Worker imageToTransfer->arrayLength() == mNativeTextureStorage->arrayLength() && 994*8975f5c5SAndroid Build Coastguard Worker imageToTransfer->pixelFormat() == mNativeTextureStorage->pixelFormat()) 995*8975f5c5SAndroid Build Coastguard Worker { 996*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *encoder = GetBlitCommandEncoderForResources( 997*8975f5c5SAndroid Build Coastguard Worker contextMtl, 998*8975f5c5SAndroid Build Coastguard Worker {imageToTransfer.get(), mNativeTextureStorage->getNativeTexture().get()}); 999*8975f5c5SAndroid Build Coastguard Worker 1000*8975f5c5SAndroid Build Coastguard Worker encoder->copyTexture(imageToTransfer, 0, mtl::kZeroNativeMipLevel, 1001*8975f5c5SAndroid Build Coastguard Worker *mNativeTextureStorage, face, actualMip, 1002*8975f5c5SAndroid Build Coastguard Worker imageToTransfer->arrayLength(), 1); 1003*8975f5c5SAndroid Build Coastguard Worker 1004*8975f5c5SAndroid Build Coastguard Worker // Invalidate texture image definition at this index so that we can make it a 1005*8975f5c5SAndroid Build Coastguard Worker // view of the native texture at this index later. 1006*8975f5c5SAndroid Build Coastguard Worker imageToTransfer = nullptr; 1007*8975f5c5SAndroid Build Coastguard Worker } 1008*8975f5c5SAndroid Build Coastguard Worker } 1009*8975f5c5SAndroid Build Coastguard Worker } 1010*8975f5c5SAndroid Build Coastguard Worker 1011*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1012*8975f5c5SAndroid Build Coastguard Worker} 1013*8975f5c5SAndroid Build Coastguard Worker 1014*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::createNativeStorage(const gl::Context *context, 1015*8975f5c5SAndroid Build Coastguard Worker gl::TextureType type, 1016*8975f5c5SAndroid Build Coastguard Worker GLuint mips, 1017*8975f5c5SAndroid Build Coastguard Worker GLuint samples, 1018*8975f5c5SAndroid Build Coastguard Worker const gl::Extents &size) 1019*8975f5c5SAndroid Build Coastguard Worker{ 1020*8975f5c5SAndroid Build Coastguard Worker ASSERT(samples == 0 || mips == 0); 1021*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1022*8975f5c5SAndroid Build Coastguard Worker 1023*8975f5c5SAndroid Build Coastguard Worker // Create actual texture object: 1024*8975f5c5SAndroid Build Coastguard Worker mSlices = 1; 1025*8975f5c5SAndroid Build Coastguard Worker bool allowFormatView = mFormat.hasDepthAndStencilBits() || 1026*8975f5c5SAndroid Build Coastguard Worker needsFormatViewForPixelLocalStorage( 1027*8975f5c5SAndroid Build Coastguard Worker contextMtl->getDisplay()->getNativePixelLocalStorageOptions()); 1028*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef nativeTextureStorage; 1029*8975f5c5SAndroid Build Coastguard Worker switch (type) 1030*8975f5c5SAndroid Build Coastguard Worker { 1031*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2D: 1032*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Texture::Make2DTexture( 1033*8975f5c5SAndroid Build Coastguard Worker contextMtl, mFormat, size.width, size.height, mips, 1034*8975f5c5SAndroid Build Coastguard Worker /** renderTargetOnly */ false, allowFormatView, &nativeTextureStorage)); 1035*8975f5c5SAndroid Build Coastguard Worker break; 1036*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::CubeMap: 1037*8975f5c5SAndroid Build Coastguard Worker mSlices = 6; 1038*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Texture::MakeCubeTexture(contextMtl, mFormat, size.width, mips, 1039*8975f5c5SAndroid Build Coastguard Worker /** renderTargetOnly */ false, allowFormatView, 1040*8975f5c5SAndroid Build Coastguard Worker &nativeTextureStorage)); 1041*8975f5c5SAndroid Build Coastguard Worker break; 1042*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_3D: 1043*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Texture::Make3DTexture( 1044*8975f5c5SAndroid Build Coastguard Worker contextMtl, mFormat, size.width, size.height, size.depth, mips, 1045*8975f5c5SAndroid Build Coastguard Worker /** renderTargetOnly */ false, allowFormatView, &nativeTextureStorage)); 1046*8975f5c5SAndroid Build Coastguard Worker break; 1047*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2DArray: 1048*8975f5c5SAndroid Build Coastguard Worker mSlices = size.depth; 1049*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Texture::Make2DArrayTexture( 1050*8975f5c5SAndroid Build Coastguard Worker contextMtl, mFormat, size.width, size.height, mips, mSlices, 1051*8975f5c5SAndroid Build Coastguard Worker /** renderTargetOnly */ false, allowFormatView, &nativeTextureStorage)); 1052*8975f5c5SAndroid Build Coastguard Worker break; 1053*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2DMultisample: 1054*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Texture::Make2DMSTexture( 1055*8975f5c5SAndroid Build Coastguard Worker contextMtl, mFormat, size.width, size.height, samples, 1056*8975f5c5SAndroid Build Coastguard Worker /** renderTargetOnly */ false, allowFormatView, &nativeTextureStorage)); 1057*8975f5c5SAndroid Build Coastguard Worker break; 1058*8975f5c5SAndroid Build Coastguard Worker default: 1059*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 1060*8975f5c5SAndroid Build Coastguard Worker } 1061*8975f5c5SAndroid Build Coastguard Worker 1062*8975f5c5SAndroid Build Coastguard Worker if (mState.getImmutableFormat()) 1063*8975f5c5SAndroid Build Coastguard Worker { 1064*8975f5c5SAndroid Build Coastguard Worker mNativeTextureStorage = std::make_unique<NativeTextureWrapperWithViewSupport>( 1065*8975f5c5SAndroid Build Coastguard Worker std::move(nativeTextureStorage), /*baseGLLevel=*/0); 1066*8975f5c5SAndroid Build Coastguard Worker } 1067*8975f5c5SAndroid Build Coastguard Worker else 1068*8975f5c5SAndroid Build Coastguard Worker { 1069*8975f5c5SAndroid Build Coastguard Worker mNativeTextureStorage = std::make_unique<NativeTextureWrapperWithViewSupport>( 1070*8975f5c5SAndroid Build Coastguard Worker std::move(nativeTextureStorage), /*baseGLLevel=*/mState.getEffectiveBaseLevel()); 1071*8975f5c5SAndroid Build Coastguard Worker } 1072*8975f5c5SAndroid Build Coastguard Worker 1073*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(checkForEmulatedChannels(context, mFormat, *mNativeTextureStorage)); 1074*8975f5c5SAndroid Build Coastguard Worker 1075*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(createViewFromBaseToMaxLevel()); 1076*8975f5c5SAndroid Build Coastguard Worker 1077*8975f5c5SAndroid Build Coastguard Worker // Create sampler state 1078*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureSamplerStateCreated(context)); 1079*8975f5c5SAndroid Build Coastguard Worker 1080*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1081*8975f5c5SAndroid Build Coastguard Worker} 1082*8975f5c5SAndroid Build Coastguard Worker 1083*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::ensureSamplerStateCreated(const gl::Context *context) 1084*8975f5c5SAndroid Build Coastguard Worker{ 1085*8975f5c5SAndroid Build Coastguard Worker if (mMetalSamplerState) 1086*8975f5c5SAndroid Build Coastguard Worker { 1087*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1088*8975f5c5SAndroid Build Coastguard Worker } 1089*8975f5c5SAndroid Build Coastguard Worker 1090*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1091*8975f5c5SAndroid Build Coastguard Worker 1092*8975f5c5SAndroid Build Coastguard Worker mtl::SamplerDesc samplerDesc(mState.getSamplerState()); 1093*8975f5c5SAndroid Build Coastguard Worker 1094*8975f5c5SAndroid Build Coastguard Worker if (mFormat.actualAngleFormat().depthBits && !mFormat.getCaps().filterable) 1095*8975f5c5SAndroid Build Coastguard Worker { 1096*8975f5c5SAndroid Build Coastguard Worker // On devices not supporting filtering for depth textures, we need to convert to nearest 1097*8975f5c5SAndroid Build Coastguard Worker // here. 1098*8975f5c5SAndroid Build Coastguard Worker samplerDesc.minFilter = MTLSamplerMinMagFilterNearest; 1099*8975f5c5SAndroid Build Coastguard Worker samplerDesc.magFilter = MTLSamplerMinMagFilterNearest; 1100*8975f5c5SAndroid Build Coastguard Worker if (samplerDesc.mipFilter != MTLSamplerMipFilterNotMipmapped) 1101*8975f5c5SAndroid Build Coastguard Worker { 1102*8975f5c5SAndroid Build Coastguard Worker samplerDesc.mipFilter = MTLSamplerMipFilterNearest; 1103*8975f5c5SAndroid Build Coastguard Worker } 1104*8975f5c5SAndroid Build Coastguard Worker 1105*8975f5c5SAndroid Build Coastguard Worker samplerDesc.maxAnisotropy = 1; 1106*8975f5c5SAndroid Build Coastguard Worker } 1107*8975f5c5SAndroid Build Coastguard Worker 1108*8975f5c5SAndroid Build Coastguard Worker // OpenGL ES 3.x: The rules for texel selection are modified 1109*8975f5c5SAndroid Build Coastguard Worker // for cube maps so that texture wrap modes are ignored. 1110*8975f5c5SAndroid Build Coastguard Worker if ((mState.getType() == gl::TextureType::CubeMap || 1111*8975f5c5SAndroid Build Coastguard Worker mState.getType() == gl::TextureType::CubeMapArray) && 1112*8975f5c5SAndroid Build Coastguard Worker context->getState().getClientMajorVersion() >= 3) 1113*8975f5c5SAndroid Build Coastguard Worker { 1114*8975f5c5SAndroid Build Coastguard Worker samplerDesc.rAddressMode = MTLSamplerAddressModeClampToEdge; 1115*8975f5c5SAndroid Build Coastguard Worker samplerDesc.sAddressMode = MTLSamplerAddressModeClampToEdge; 1116*8975f5c5SAndroid Build Coastguard Worker samplerDesc.tAddressMode = MTLSamplerAddressModeClampToEdge; 1117*8975f5c5SAndroid Build Coastguard Worker } 1118*8975f5c5SAndroid Build Coastguard Worker mMetalSamplerState = contextMtl->getDisplay()->getStateCache().getSamplerState( 1119*8975f5c5SAndroid Build Coastguard Worker contextMtl->getMetalDevice(), samplerDesc); 1120*8975f5c5SAndroid Build Coastguard Worker 1121*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1122*8975f5c5SAndroid Build Coastguard Worker} 1123*8975f5c5SAndroid Build Coastguard Worker 1124*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::createViewFromBaseToMaxLevel() 1125*8975f5c5SAndroid Build Coastguard Worker{ 1126*8975f5c5SAndroid Build Coastguard Worker ASSERT(mNativeTextureStorage); 1127*8975f5c5SAndroid Build Coastguard Worker uint32_t maxLevel = 1128*8975f5c5SAndroid Build Coastguard Worker std::min(mNativeTextureStorage->getMaxSupportedGLLevel(), mState.getEffectiveMaxLevel()); 1129*8975f5c5SAndroid Build Coastguard Worker 1130*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef nativeViewFromBaseToMaxLevelRef; 1131*8975f5c5SAndroid Build Coastguard Worker if (maxLevel == mNativeTextureStorage->getMaxSupportedGLLevel() && 1132*8975f5c5SAndroid Build Coastguard Worker mState.getEffectiveBaseLevel() == mNativeTextureStorage->getBaseGLLevel()) 1133*8975f5c5SAndroid Build Coastguard Worker { 1134*8975f5c5SAndroid Build Coastguard Worker // If base & max level are the same in mNativeTextureStorage, we don't need 1135*8975f5c5SAndroid Build Coastguard Worker // a dedicated view. Furthermore, Intel driver has some bugs when sampling a view 1136*8975f5c5SAndroid Build Coastguard Worker // of a stencil texture. 1137*8975f5c5SAndroid Build Coastguard Worker nativeViewFromBaseToMaxLevelRef = mNativeTextureStorage->getNativeTexture(); 1138*8975f5c5SAndroid Build Coastguard Worker } 1139*8975f5c5SAndroid Build Coastguard Worker else 1140*8975f5c5SAndroid Build Coastguard Worker { 1141*8975f5c5SAndroid Build Coastguard Worker uint32_t baseToMaxLevels = maxLevel - mState.getEffectiveBaseLevel() + 1; 1142*8975f5c5SAndroid Build Coastguard Worker nativeViewFromBaseToMaxLevelRef = 1143*8975f5c5SAndroid Build Coastguard Worker mNativeTextureStorage->createMipsView(mState.getEffectiveBaseLevel(), baseToMaxLevels); 1144*8975f5c5SAndroid Build Coastguard Worker } 1145*8975f5c5SAndroid Build Coastguard Worker 1146*8975f5c5SAndroid Build Coastguard Worker mViewFromBaseToMaxLevel = std::make_unique<NativeTextureWrapper>( 1147*8975f5c5SAndroid Build Coastguard Worker nativeViewFromBaseToMaxLevelRef, mState.getEffectiveBaseLevel()); 1148*8975f5c5SAndroid Build Coastguard Worker 1149*8975f5c5SAndroid Build Coastguard Worker // Recreate in bindToShader() 1150*8975f5c5SAndroid Build Coastguard Worker mSwizzleStencilSamplingView = nullptr; 1151*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1152*8975f5c5SAndroid Build Coastguard Worker} 1153*8975f5c5SAndroid Build Coastguard Worker 1154*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::onBaseMaxLevelsChanged(const gl::Context *context) 1155*8975f5c5SAndroid Build Coastguard Worker{ 1156*8975f5c5SAndroid Build Coastguard Worker if (!mNativeTextureStorage) 1157*8975f5c5SAndroid Build Coastguard Worker { 1158*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1159*8975f5c5SAndroid Build Coastguard Worker } 1160*8975f5c5SAndroid Build Coastguard Worker 1161*8975f5c5SAndroid Build Coastguard Worker if (isImmutableOrPBuffer()) 1162*8975f5c5SAndroid Build Coastguard Worker { 1163*8975f5c5SAndroid Build Coastguard Worker // For immutable texture, only recreate base-max view. 1164*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(createViewFromBaseToMaxLevel()); 1165*8975f5c5SAndroid Build Coastguard Worker // Invalidate base-max per level views so that they can be recreated 1166*8975f5c5SAndroid Build Coastguard Worker // in generateMipmap() 1167*8975f5c5SAndroid Build Coastguard Worker for (mtl::TextureRef &view : mLevelViewsWithinBaseMax) 1168*8975f5c5SAndroid Build Coastguard Worker { 1169*8975f5c5SAndroid Build Coastguard Worker view.reset(); 1170*8975f5c5SAndroid Build Coastguard Worker } 1171*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1172*8975f5c5SAndroid Build Coastguard Worker } 1173*8975f5c5SAndroid Build Coastguard Worker 1174*8975f5c5SAndroid Build Coastguard Worker if (mState.getEffectiveBaseLevel() == mNativeTextureStorage->getBaseGLLevel() && 1175*8975f5c5SAndroid Build Coastguard Worker mState.getMipmapMaxLevel() == mNativeTextureStorage->getMaxSupportedGLLevel()) 1176*8975f5c5SAndroid Build Coastguard Worker { 1177*8975f5c5SAndroid Build Coastguard Worker ASSERT(mState.getBaseLevelDesc().size == mNativeTextureStorage->sizeAt0()); 1178*8975f5c5SAndroid Build Coastguard Worker // If level range remain the same, don't recreate the texture storage. 1179*8975f5c5SAndroid Build Coastguard Worker // This might feel unnecessary at first since the front-end might prevent redundant base/max 1180*8975f5c5SAndroid Build Coastguard Worker // level change already. However, there are cases that cause native storage to be created 1181*8975f5c5SAndroid Build Coastguard Worker // before base/max level dirty bit is passed to Metal backend and lead to unwanted problems. 1182*8975f5c5SAndroid Build Coastguard Worker // Example: 1183*8975f5c5SAndroid Build Coastguard Worker // 1. texture with a non-default base/max level state is set. 1184*8975f5c5SAndroid Build Coastguard Worker // 2. The texture is used first as a framebuffer attachment. This operation does not fully 1185*8975f5c5SAndroid Build Coastguard Worker // sync the texture state and therefore does not unset base/max level dirty bits. 1186*8975f5c5SAndroid Build Coastguard Worker // 3. The same texture is then used for sampling; this operation fully syncs the texture 1187*8975f5c5SAndroid Build Coastguard Worker // state. Base/max level dirty bits may lead to recreating the texture storage thus 1188*8975f5c5SAndroid Build Coastguard Worker // invalidating native render target references created in step 2. 1189*8975f5c5SAndroid Build Coastguard Worker // 4. If the framebuffer created in step 2 is used again, its native render target 1190*8975f5c5SAndroid Build Coastguard Worker // references will not be updated to point to the new storage because everything is in 1191*8975f5c5SAndroid Build Coastguard Worker // sync from the frontend point of view. 1192*8975f5c5SAndroid Build Coastguard Worker // 5. Note: if the new range is different, it is expected that native render target 1193*8975f5c5SAndroid Build Coastguard Worker // references will be updated during draw framebuffer sync. 1194*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1195*8975f5c5SAndroid Build Coastguard Worker } 1196*8975f5c5SAndroid Build Coastguard Worker 1197*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1198*8975f5c5SAndroid Build Coastguard Worker 1199*8975f5c5SAndroid Build Coastguard Worker // We need to recreate a new native texture storage with number of levels = max level - base 1200*8975f5c5SAndroid Build Coastguard Worker // level + 1. This can be achieved by simply deleting the old storage. The storage will be 1201*8975f5c5SAndroid Build Coastguard Worker // lazily recreated later via ensureNativeStorageCreated(). 1202*8975f5c5SAndroid Build Coastguard Worker // Note: We release the native texture storage but keep old image definitions. So that when the 1203*8975f5c5SAndroid Build Coastguard Worker // storage is recreated, its levels can be recreated with data from the old image definitions 1204*8975f5c5SAndroid Build Coastguard Worker // respectively. 1205*8975f5c5SAndroid Build Coastguard Worker deallocateNativeStorage(/*keepImages=*/true, /*keepSamplerStateAndFormat=*/true); 1206*8975f5c5SAndroid Build Coastguard Worker 1207*8975f5c5SAndroid Build Coastguard Worker // Tell context to rebind textures 1208*8975f5c5SAndroid Build Coastguard Worker contextMtl->invalidateCurrentTextures(); 1209*8975f5c5SAndroid Build Coastguard Worker 1210*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1211*8975f5c5SAndroid Build Coastguard Worker} 1212*8975f5c5SAndroid Build Coastguard Worker 1213*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::ensureImageCreated(const gl::Context *context, 1214*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index) 1215*8975f5c5SAndroid Build Coastguard Worker{ 1216*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef &image = getImage(index); 1217*8975f5c5SAndroid Build Coastguard Worker if (!image) 1218*8975f5c5SAndroid Build Coastguard Worker { 1219*8975f5c5SAndroid Build Coastguard Worker // Image at this level hasn't been defined yet. We need to define it: 1220*8975f5c5SAndroid Build Coastguard Worker const gl::ImageDesc &desc = mState.getImageDesc(index); 1221*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(redefineImage(context, index, mFormat, desc.size)); 1222*8975f5c5SAndroid Build Coastguard Worker } 1223*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1224*8975f5c5SAndroid Build Coastguard Worker} 1225*8975f5c5SAndroid Build Coastguard Worker 1226*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::ensureLevelViewsWithinBaseMaxCreated() 1227*8975f5c5SAndroid Build Coastguard Worker{ 1228*8975f5c5SAndroid Build Coastguard Worker ASSERT(mViewFromBaseToMaxLevel); 1229*8975f5c5SAndroid Build Coastguard Worker for (mtl::MipmapNativeLevel mip = mtl::kZeroNativeMipLevel; 1230*8975f5c5SAndroid Build Coastguard Worker mip.get() < mViewFromBaseToMaxLevel->mipmapLevels(); ++mip) 1231*8975f5c5SAndroid Build Coastguard Worker { 1232*8975f5c5SAndroid Build Coastguard Worker if (mLevelViewsWithinBaseMax[mip]) 1233*8975f5c5SAndroid Build Coastguard Worker { 1234*8975f5c5SAndroid Build Coastguard Worker continue; 1235*8975f5c5SAndroid Build Coastguard Worker } 1236*8975f5c5SAndroid Build Coastguard Worker 1237*8975f5c5SAndroid Build Coastguard Worker GLuint mipGLLevel = mViewFromBaseToMaxLevel->getGLLevel(mip); 1238*8975f5c5SAndroid Build Coastguard Worker 1239*8975f5c5SAndroid Build Coastguard Worker if (mViewFromBaseToMaxLevel->textureType() != MTLTextureTypeCube && 1240*8975f5c5SAndroid Build Coastguard Worker mTexImageDefs[0][mipGLLevel].image) 1241*8975f5c5SAndroid Build Coastguard Worker { 1242*8975f5c5SAndroid Build Coastguard Worker // Reuse texture image view. 1243*8975f5c5SAndroid Build Coastguard Worker mLevelViewsWithinBaseMax[mip] = mTexImageDefs[0][mipGLLevel].image; 1244*8975f5c5SAndroid Build Coastguard Worker } 1245*8975f5c5SAndroid Build Coastguard Worker else 1246*8975f5c5SAndroid Build Coastguard Worker { 1247*8975f5c5SAndroid Build Coastguard Worker mLevelViewsWithinBaseMax[mip] = mNativeTextureStorage->createMipView(mipGLLevel); 1248*8975f5c5SAndroid Build Coastguard Worker } 1249*8975f5c5SAndroid Build Coastguard Worker } 1250*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1251*8975f5c5SAndroid Build Coastguard Worker} 1252*8975f5c5SAndroid Build Coastguard Worker 1253*8975f5c5SAndroid Build Coastguard Workermtl::TextureRef TextureMtl::createImageViewFromTextureStorage(GLuint cubeFaceOrZero, GLuint glLevel) 1254*8975f5c5SAndroid Build Coastguard Worker{ 1255*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef image; 1256*8975f5c5SAndroid Build Coastguard Worker if (mNativeTextureStorage->textureType() == MTLTextureTypeCube) 1257*8975f5c5SAndroid Build Coastguard Worker { 1258*8975f5c5SAndroid Build Coastguard Worker // Cube texture's image is per face. 1259*8975f5c5SAndroid Build Coastguard Worker image = mNativeTextureStorage->createSliceMipView(cubeFaceOrZero, glLevel); 1260*8975f5c5SAndroid Build Coastguard Worker } 1261*8975f5c5SAndroid Build Coastguard Worker else 1262*8975f5c5SAndroid Build Coastguard Worker { 1263*8975f5c5SAndroid Build Coastguard Worker if (mViewFromBaseToMaxLevel->isGLLevelSupported(glLevel)) 1264*8975f5c5SAndroid Build Coastguard Worker { 1265*8975f5c5SAndroid Build Coastguard Worker mtl::MipmapNativeLevel nativeLevel = mViewFromBaseToMaxLevel->getNativeLevel(glLevel); 1266*8975f5c5SAndroid Build Coastguard Worker if (mLevelViewsWithinBaseMax[nativeLevel]) 1267*8975f5c5SAndroid Build Coastguard Worker { 1268*8975f5c5SAndroid Build Coastguard Worker // Reuse the native level view 1269*8975f5c5SAndroid Build Coastguard Worker image = mLevelViewsWithinBaseMax[nativeLevel]; 1270*8975f5c5SAndroid Build Coastguard Worker } 1271*8975f5c5SAndroid Build Coastguard Worker } 1272*8975f5c5SAndroid Build Coastguard Worker 1273*8975f5c5SAndroid Build Coastguard Worker if (!image) 1274*8975f5c5SAndroid Build Coastguard Worker { 1275*8975f5c5SAndroid Build Coastguard Worker image = mNativeTextureStorage->createMipView(glLevel); 1276*8975f5c5SAndroid Build Coastguard Worker } 1277*8975f5c5SAndroid Build Coastguard Worker } 1278*8975f5c5SAndroid Build Coastguard Worker 1279*8975f5c5SAndroid Build Coastguard Worker return image; 1280*8975f5c5SAndroid Build Coastguard Worker} 1281*8975f5c5SAndroid Build Coastguard Worker 1282*8975f5c5SAndroid Build Coastguard Workervoid TextureMtl::retainImageDefinitions() 1283*8975f5c5SAndroid Build Coastguard Worker{ 1284*8975f5c5SAndroid Build Coastguard Worker if (!mNativeTextureStorage) 1285*8975f5c5SAndroid Build Coastguard Worker { 1286*8975f5c5SAndroid Build Coastguard Worker return; 1287*8975f5c5SAndroid Build Coastguard Worker } 1288*8975f5c5SAndroid Build Coastguard Worker const GLuint mips = mNativeTextureStorage->mipmapLevels(); 1289*8975f5c5SAndroid Build Coastguard Worker 1290*8975f5c5SAndroid Build Coastguard Worker int numCubeFaces = 1; 1291*8975f5c5SAndroid Build Coastguard Worker switch (mState.getType()) 1292*8975f5c5SAndroid Build Coastguard Worker { 1293*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::CubeMap: 1294*8975f5c5SAndroid Build Coastguard Worker numCubeFaces = 6; 1295*8975f5c5SAndroid Build Coastguard Worker break; 1296*8975f5c5SAndroid Build Coastguard Worker default: 1297*8975f5c5SAndroid Build Coastguard Worker break; 1298*8975f5c5SAndroid Build Coastguard Worker } 1299*8975f5c5SAndroid Build Coastguard Worker 1300*8975f5c5SAndroid Build Coastguard Worker // Create image view per cube face, per mip level 1301*8975f5c5SAndroid Build Coastguard Worker for (int face = 0; face < numCubeFaces; ++face) 1302*8975f5c5SAndroid Build Coastguard Worker { 1303*8975f5c5SAndroid Build Coastguard Worker for (mtl::MipmapNativeLevel mip = mtl::kZeroNativeMipLevel; mip.get() < mips; ++mip) 1304*8975f5c5SAndroid Build Coastguard Worker { 1305*8975f5c5SAndroid Build Coastguard Worker GLuint imageMipLevel = mNativeTextureStorage->getGLLevel(mip); 1306*8975f5c5SAndroid Build Coastguard Worker ImageDefinitionMtl &imageDef = mTexImageDefs[face][imageMipLevel]; 1307*8975f5c5SAndroid Build Coastguard Worker if (imageDef.image) 1308*8975f5c5SAndroid Build Coastguard Worker { 1309*8975f5c5SAndroid Build Coastguard Worker continue; 1310*8975f5c5SAndroid Build Coastguard Worker } 1311*8975f5c5SAndroid Build Coastguard Worker imageDef.image = createImageViewFromTextureStorage(face, imageMipLevel); 1312*8975f5c5SAndroid Build Coastguard Worker imageDef.formatID = mFormat.intendedFormatId; 1313*8975f5c5SAndroid Build Coastguard Worker } 1314*8975f5c5SAndroid Build Coastguard Worker } 1315*8975f5c5SAndroid Build Coastguard Worker} 1316*8975f5c5SAndroid Build Coastguard Worker 1317*8975f5c5SAndroid Build Coastguard Workermtl::TextureRef &TextureMtl::getImage(const gl::ImageIndex &imageIndex) 1318*8975f5c5SAndroid Build Coastguard Worker{ 1319*8975f5c5SAndroid Build Coastguard Worker return getImageDefinition(imageIndex).image; 1320*8975f5c5SAndroid Build Coastguard Worker} 1321*8975f5c5SAndroid Build Coastguard Worker 1322*8975f5c5SAndroid Build Coastguard WorkerImageDefinitionMtl &TextureMtl::getImageDefinition(const gl::ImageIndex &imageIndex) 1323*8975f5c5SAndroid Build Coastguard Worker{ 1324*8975f5c5SAndroid Build Coastguard Worker GLuint cubeFaceOrZero = GetImageCubeFaceIndexOrZeroFrom(imageIndex); 1325*8975f5c5SAndroid Build Coastguard Worker ImageDefinitionMtl &imageDef = mTexImageDefs[cubeFaceOrZero][imageIndex.getLevelIndex()]; 1326*8975f5c5SAndroid Build Coastguard Worker 1327*8975f5c5SAndroid Build Coastguard Worker if (!imageDef.image && mNativeTextureStorage) 1328*8975f5c5SAndroid Build Coastguard Worker { 1329*8975f5c5SAndroid Build Coastguard Worker // If native texture is already created, and the image at this index is not available, 1330*8975f5c5SAndroid Build Coastguard Worker // then create a view of native texture at this index, so that modifications of the image 1331*8975f5c5SAndroid Build Coastguard Worker // are reflected back to native texture's respective index. 1332*8975f5c5SAndroid Build Coastguard Worker if (!mNativeTextureStorage->isGLLevelSupported(imageIndex.getLevelIndex())) 1333*8975f5c5SAndroid Build Coastguard Worker { 1334*8975f5c5SAndroid Build Coastguard Worker // Image outside native texture's mip levels is skipped. 1335*8975f5c5SAndroid Build Coastguard Worker return imageDef; 1336*8975f5c5SAndroid Build Coastguard Worker } 1337*8975f5c5SAndroid Build Coastguard Worker 1338*8975f5c5SAndroid Build Coastguard Worker imageDef.image = 1339*8975f5c5SAndroid Build Coastguard Worker createImageViewFromTextureStorage(cubeFaceOrZero, imageIndex.getLevelIndex()); 1340*8975f5c5SAndroid Build Coastguard Worker imageDef.formatID = mFormat.intendedFormatId; 1341*8975f5c5SAndroid Build Coastguard Worker } 1342*8975f5c5SAndroid Build Coastguard Worker 1343*8975f5c5SAndroid Build Coastguard Worker return imageDef; 1344*8975f5c5SAndroid Build Coastguard Worker} 1345*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::getRenderTarget(ContextMtl *context, 1346*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &imageIndex, 1347*8975f5c5SAndroid Build Coastguard Worker GLsizei implicitSamples, 1348*8975f5c5SAndroid Build Coastguard Worker RenderTargetMtl **renderTargetOut) 1349*8975f5c5SAndroid Build Coastguard Worker{ 1350*8975f5c5SAndroid Build Coastguard Worker ASSERT(imageIndex.getType() == gl::TextureType::_2D || 1351*8975f5c5SAndroid Build Coastguard Worker imageIndex.getType() == gl::TextureType::Rectangle || 1352*8975f5c5SAndroid Build Coastguard Worker imageIndex.getType() == gl::TextureType::_2DMultisample || imageIndex.hasLayer()); 1353*8975f5c5SAndroid Build Coastguard Worker 1354*8975f5c5SAndroid Build Coastguard Worker const gl::RenderToTextureImageIndex renderToTextureIndex = 1355*8975f5c5SAndroid Build Coastguard Worker implicitSamples <= 1 1356*8975f5c5SAndroid Build Coastguard Worker ? gl::RenderToTextureImageIndex::Default 1357*8975f5c5SAndroid Build Coastguard Worker : static_cast<gl::RenderToTextureImageIndex>(PackSampleCount(implicitSamples)); 1358*8975f5c5SAndroid Build Coastguard Worker 1359*8975f5c5SAndroid Build Coastguard Worker GLuint layer = GetImageLayerIndexFrom(imageIndex); 1360*8975f5c5SAndroid Build Coastguard Worker RenderTargetMtl &rtt = mRenderTargets[imageIndex][renderToTextureIndex]; 1361*8975f5c5SAndroid Build Coastguard Worker if (!rtt.getTexture()) 1362*8975f5c5SAndroid Build Coastguard Worker { 1363*8975f5c5SAndroid Build Coastguard Worker // Lazy initialization of render target: 1364*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef &image = getImage(imageIndex); 1365*8975f5c5SAndroid Build Coastguard Worker if (image) 1366*8975f5c5SAndroid Build Coastguard Worker { 1367*8975f5c5SAndroid Build Coastguard Worker if (imageIndex.getType() == gl::TextureType::CubeMap) 1368*8975f5c5SAndroid Build Coastguard Worker { 1369*8975f5c5SAndroid Build Coastguard Worker // Cube map is special, the image is already the view of its layer 1370*8975f5c5SAndroid Build Coastguard Worker rtt.set(image, mtl::kZeroNativeMipLevel, 0, mFormat); 1371*8975f5c5SAndroid Build Coastguard Worker } 1372*8975f5c5SAndroid Build Coastguard Worker else 1373*8975f5c5SAndroid Build Coastguard Worker { 1374*8975f5c5SAndroid Build Coastguard Worker rtt.set(image, mtl::kZeroNativeMipLevel, layer, mFormat); 1375*8975f5c5SAndroid Build Coastguard Worker } 1376*8975f5c5SAndroid Build Coastguard Worker } 1377*8975f5c5SAndroid Build Coastguard Worker } 1378*8975f5c5SAndroid Build Coastguard Worker 1379*8975f5c5SAndroid Build Coastguard Worker if (implicitSamples > 1 && !rtt.getImplicitMSTexture()) 1380*8975f5c5SAndroid Build Coastguard Worker { 1381*8975f5c5SAndroid Build Coastguard Worker // This format must supports implicit resolve 1382*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_CHECK(context, mFormat.getCaps().resolve, GL_INVALID_VALUE); 1383*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef &msTexture = mImplicitMSTextures[imageIndex][renderToTextureIndex]; 1384*8975f5c5SAndroid Build Coastguard Worker if (!msTexture) 1385*8975f5c5SAndroid Build Coastguard Worker { 1386*8975f5c5SAndroid Build Coastguard Worker const gl::ImageDesc &desc = mState.getImageDesc(imageIndex); 1387*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Texture::MakeMemoryLess2DMSTexture( 1388*8975f5c5SAndroid Build Coastguard Worker context, mFormat, desc.size.width, desc.size.height, implicitSamples, &msTexture)); 1389*8975f5c5SAndroid Build Coastguard Worker } 1390*8975f5c5SAndroid Build Coastguard Worker rtt.setImplicitMSTexture(msTexture); 1391*8975f5c5SAndroid Build Coastguard Worker } 1392*8975f5c5SAndroid Build Coastguard Worker 1393*8975f5c5SAndroid Build Coastguard Worker *renderTargetOut = &rtt; 1394*8975f5c5SAndroid Build Coastguard Worker 1395*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1396*8975f5c5SAndroid Build Coastguard Worker} 1397*8975f5c5SAndroid Build Coastguard Worker 1398*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setImage(const gl::Context *context, 1399*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 1400*8975f5c5SAndroid Build Coastguard Worker GLenum internalFormat, 1401*8975f5c5SAndroid Build Coastguard Worker const gl::Extents &size, 1402*8975f5c5SAndroid Build Coastguard Worker GLenum format, 1403*8975f5c5SAndroid Build Coastguard Worker GLenum type, 1404*8975f5c5SAndroid Build Coastguard Worker const gl::PixelUnpackState &unpack, 1405*8975f5c5SAndroid Build Coastguard Worker gl::Buffer *unpackBuffer, 1406*8975f5c5SAndroid Build Coastguard Worker const uint8_t *pixels) 1407*8975f5c5SAndroid Build Coastguard Worker{ 1408*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &dstFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); 1409*8975f5c5SAndroid Build Coastguard Worker 1410*8975f5c5SAndroid Build Coastguard Worker return setImageImpl(context, index, dstFormatInfo, size, format, type, unpack, unpackBuffer, 1411*8975f5c5SAndroid Build Coastguard Worker pixels); 1412*8975f5c5SAndroid Build Coastguard Worker} 1413*8975f5c5SAndroid Build Coastguard Worker 1414*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setSubImage(const gl::Context *context, 1415*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 1416*8975f5c5SAndroid Build Coastguard Worker const gl::Box &area, 1417*8975f5c5SAndroid Build Coastguard Worker GLenum format, 1418*8975f5c5SAndroid Build Coastguard Worker GLenum type, 1419*8975f5c5SAndroid Build Coastguard Worker const gl::PixelUnpackState &unpack, 1420*8975f5c5SAndroid Build Coastguard Worker gl::Buffer *unpackBuffer, 1421*8975f5c5SAndroid Build Coastguard Worker const uint8_t *pixels) 1422*8975f5c5SAndroid Build Coastguard Worker{ 1423*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type); 1424*8975f5c5SAndroid Build Coastguard Worker 1425*8975f5c5SAndroid Build Coastguard Worker return setSubImageImpl(context, index, area, formatInfo, type, unpack, unpackBuffer, pixels); 1426*8975f5c5SAndroid Build Coastguard Worker} 1427*8975f5c5SAndroid Build Coastguard Worker 1428*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setCompressedImage(const gl::Context *context, 1429*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 1430*8975f5c5SAndroid Build Coastguard Worker GLenum internalFormat, 1431*8975f5c5SAndroid Build Coastguard Worker const gl::Extents &size, 1432*8975f5c5SAndroid Build Coastguard Worker const gl::PixelUnpackState &unpack, 1433*8975f5c5SAndroid Build Coastguard Worker size_t imageSize, 1434*8975f5c5SAndroid Build Coastguard Worker const uint8_t *pixels) 1435*8975f5c5SAndroid Build Coastguard Worker{ 1436*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); 1437*8975f5c5SAndroid Build Coastguard Worker const gl::State &glState = context->getState(); 1438*8975f5c5SAndroid Build Coastguard Worker gl::Buffer *unpackBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelUnpack); 1439*8975f5c5SAndroid Build Coastguard Worker 1440*8975f5c5SAndroid Build Coastguard Worker return setImageImpl(context, index, formatInfo, size, internalFormat, GL_UNSIGNED_BYTE, unpack, 1441*8975f5c5SAndroid Build Coastguard Worker unpackBuffer, pixels); 1442*8975f5c5SAndroid Build Coastguard Worker} 1443*8975f5c5SAndroid Build Coastguard Worker 1444*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setCompressedSubImage(const gl::Context *context, 1445*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 1446*8975f5c5SAndroid Build Coastguard Worker const gl::Box &area, 1447*8975f5c5SAndroid Build Coastguard Worker GLenum format, 1448*8975f5c5SAndroid Build Coastguard Worker const gl::PixelUnpackState &unpack, 1449*8975f5c5SAndroid Build Coastguard Worker size_t imageSize, 1450*8975f5c5SAndroid Build Coastguard Worker const uint8_t *pixels) 1451*8975f5c5SAndroid Build Coastguard Worker{ 1452*8975f5c5SAndroid Build Coastguard Worker 1453*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, GL_UNSIGNED_BYTE); 1454*8975f5c5SAndroid Build Coastguard Worker 1455*8975f5c5SAndroid Build Coastguard Worker const gl::State &glState = context->getState(); 1456*8975f5c5SAndroid Build Coastguard Worker gl::Buffer *unpackBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelUnpack); 1457*8975f5c5SAndroid Build Coastguard Worker 1458*8975f5c5SAndroid Build Coastguard Worker return setSubImageImpl(context, index, area, formatInfo, GL_UNSIGNED_BYTE, unpack, unpackBuffer, 1459*8975f5c5SAndroid Build Coastguard Worker pixels); 1460*8975f5c5SAndroid Build Coastguard Worker} 1461*8975f5c5SAndroid Build Coastguard Worker 1462*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copyImage(const gl::Context *context, 1463*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 1464*8975f5c5SAndroid Build Coastguard Worker const gl::Rectangle &sourceArea, 1465*8975f5c5SAndroid Build Coastguard Worker GLenum internalFormat, 1466*8975f5c5SAndroid Build Coastguard Worker gl::Framebuffer *source) 1467*8975f5c5SAndroid Build Coastguard Worker{ 1468*8975f5c5SAndroid Build Coastguard Worker gl::Extents newImageSize(sourceArea.width, sourceArea.height, 1); 1469*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormatInfo = 1470*8975f5c5SAndroid Build Coastguard Worker gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); 1471*8975f5c5SAndroid Build Coastguard Worker 1472*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1473*8975f5c5SAndroid Build Coastguard Worker angle::FormatID angleFormatId = 1474*8975f5c5SAndroid Build Coastguard Worker angle::Format::InternalFormatToID(internalFormatInfo.sizedInternalFormat); 1475*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId); 1476*8975f5c5SAndroid Build Coastguard Worker 1477*8975f5c5SAndroid Build Coastguard Worker FramebufferMtl *srcFramebufferMtl = mtl::GetImpl(source); 1478*8975f5c5SAndroid Build Coastguard Worker RenderTargetMtl *srcReadRT = srcFramebufferMtl->getColorReadRenderTarget(context); 1479*8975f5c5SAndroid Build Coastguard Worker RenderTargetMtl colorReadRT; 1480*8975f5c5SAndroid Build Coastguard Worker if (srcReadRT) 1481*8975f5c5SAndroid Build Coastguard Worker { 1482*8975f5c5SAndroid Build Coastguard Worker // Need to duplicate RenderTargetMtl since the srcReadRT would be invalidated in 1483*8975f5c5SAndroid Build Coastguard Worker // redefineImage(). This can happen if the source and this texture are the same texture. 1484*8975f5c5SAndroid Build Coastguard Worker // Duplication ensures the copyImage() will be able to proceed even if the source texture 1485*8975f5c5SAndroid Build Coastguard Worker // will be redefined. 1486*8975f5c5SAndroid Build Coastguard Worker colorReadRT.duplicateFrom(*srcReadRT); 1487*8975f5c5SAndroid Build Coastguard Worker } 1488*8975f5c5SAndroid Build Coastguard Worker 1489*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(redefineImage(context, index, mtlFormat, newImageSize)); 1490*8975f5c5SAndroid Build Coastguard Worker 1491*8975f5c5SAndroid Build Coastguard Worker gl::Extents fbSize = source->getReadColorAttachment()->getSize(); 1492*8975f5c5SAndroid Build Coastguard Worker gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height); 1493*8975f5c5SAndroid Build Coastguard Worker if (context->isWebGL() && !fbRect.encloses(sourceArea)) 1494*8975f5c5SAndroid Build Coastguard Worker { 1495*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(initializeContents(context, GL_NONE, index)); 1496*8975f5c5SAndroid Build Coastguard Worker } 1497*8975f5c5SAndroid Build Coastguard Worker 1498*8975f5c5SAndroid Build Coastguard Worker return copySubImageImpl(context, index, gl::Offset(0, 0, 0), sourceArea, internalFormatInfo, 1499*8975f5c5SAndroid Build Coastguard Worker srcFramebufferMtl, &colorReadRT); 1500*8975f5c5SAndroid Build Coastguard Worker} 1501*8975f5c5SAndroid Build Coastguard Worker 1502*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubImage(const gl::Context *context, 1503*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 1504*8975f5c5SAndroid Build Coastguard Worker const gl::Offset &destOffset, 1505*8975f5c5SAndroid Build Coastguard Worker const gl::Rectangle &sourceArea, 1506*8975f5c5SAndroid Build Coastguard Worker gl::Framebuffer *source) 1507*8975f5c5SAndroid Build Coastguard Worker{ 1508*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat ¤tFormat = *mState.getImageDesc(index).format.info; 1509*8975f5c5SAndroid Build Coastguard Worker FramebufferMtl *srcFramebufferMtl = mtl::GetImpl(source); 1510*8975f5c5SAndroid Build Coastguard Worker RenderTargetMtl *colorReadRT = srcFramebufferMtl->getColorReadRenderTarget(context); 1511*8975f5c5SAndroid Build Coastguard Worker return copySubImageImpl(context, index, destOffset, sourceArea, currentFormat, 1512*8975f5c5SAndroid Build Coastguard Worker srcFramebufferMtl, colorReadRT); 1513*8975f5c5SAndroid Build Coastguard Worker} 1514*8975f5c5SAndroid Build Coastguard Worker 1515*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copyTexture(const gl::Context *context, 1516*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 1517*8975f5c5SAndroid Build Coastguard Worker GLenum internalFormat, 1518*8975f5c5SAndroid Build Coastguard Worker GLenum type, 1519*8975f5c5SAndroid Build Coastguard Worker GLint sourceLevel, 1520*8975f5c5SAndroid Build Coastguard Worker bool unpackFlipY, 1521*8975f5c5SAndroid Build Coastguard Worker bool unpackPremultiplyAlpha, 1522*8975f5c5SAndroid Build Coastguard Worker bool unpackUnmultiplyAlpha, 1523*8975f5c5SAndroid Build Coastguard Worker const gl::Texture *source) 1524*8975f5c5SAndroid Build Coastguard Worker{ 1525*8975f5c5SAndroid Build Coastguard Worker const gl::ImageDesc &sourceImageDesc = source->getTextureState().getImageDesc( 1526*8975f5c5SAndroid Build Coastguard Worker NonCubeTextureTypeToTarget(source->getType()), sourceLevel); 1527*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); 1528*8975f5c5SAndroid Build Coastguard Worker 1529*8975f5c5SAndroid Build Coastguard Worker // Only 2D textures are supported. 1530*8975f5c5SAndroid Build Coastguard Worker ASSERT(sourceImageDesc.size.depth == 1); 1531*8975f5c5SAndroid Build Coastguard Worker 1532*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1533*8975f5c5SAndroid Build Coastguard Worker angle::FormatID angleFormatId = 1534*8975f5c5SAndroid Build Coastguard Worker angle::Format::InternalFormatToID(internalFormatInfo.sizedInternalFormat); 1535*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId); 1536*8975f5c5SAndroid Build Coastguard Worker 1537*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(redefineImage(context, index, mtlFormat, sourceImageDesc.size)); 1538*8975f5c5SAndroid Build Coastguard Worker 1539*8975f5c5SAndroid Build Coastguard Worker return copySubTextureImpl( 1540*8975f5c5SAndroid Build Coastguard Worker context, index, gl::Offset(0, 0, 0), internalFormatInfo, sourceLevel, 1541*8975f5c5SAndroid Build Coastguard Worker gl::Box(0, 0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height, 1), unpackFlipY, 1542*8975f5c5SAndroid Build Coastguard Worker unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source); 1543*8975f5c5SAndroid Build Coastguard Worker} 1544*8975f5c5SAndroid Build Coastguard Worker 1545*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubTexture(const gl::Context *context, 1546*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 1547*8975f5c5SAndroid Build Coastguard Worker const gl::Offset &destOffset, 1548*8975f5c5SAndroid Build Coastguard Worker GLint sourceLevel, 1549*8975f5c5SAndroid Build Coastguard Worker const gl::Box &sourceBox, 1550*8975f5c5SAndroid Build Coastguard Worker bool unpackFlipY, 1551*8975f5c5SAndroid Build Coastguard Worker bool unpackPremultiplyAlpha, 1552*8975f5c5SAndroid Build Coastguard Worker bool unpackUnmultiplyAlpha, 1553*8975f5c5SAndroid Build Coastguard Worker const gl::Texture *source) 1554*8975f5c5SAndroid Build Coastguard Worker{ 1555*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat ¤tFormat = *mState.getImageDesc(index).format.info; 1556*8975f5c5SAndroid Build Coastguard Worker 1557*8975f5c5SAndroid Build Coastguard Worker return copySubTextureImpl(context, index, destOffset, currentFormat, sourceLevel, sourceBox, 1558*8975f5c5SAndroid Build Coastguard Worker unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source); 1559*8975f5c5SAndroid Build Coastguard Worker} 1560*8975f5c5SAndroid Build Coastguard Worker 1561*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copyCompressedTexture(const gl::Context *context, 1562*8975f5c5SAndroid Build Coastguard Worker const gl::Texture *source) 1563*8975f5c5SAndroid Build Coastguard Worker{ 1564*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED(); 1565*8975f5c5SAndroid Build Coastguard Worker 1566*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Stop; 1567*8975f5c5SAndroid Build Coastguard Worker} 1568*8975f5c5SAndroid Build Coastguard Worker 1569*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setStorage(const gl::Context *context, 1570*8975f5c5SAndroid Build Coastguard Worker gl::TextureType type, 1571*8975f5c5SAndroid Build Coastguard Worker size_t mipmaps, 1572*8975f5c5SAndroid Build Coastguard Worker GLenum internalFormat, 1573*8975f5c5SAndroid Build Coastguard Worker const gl::Extents &size) 1574*8975f5c5SAndroid Build Coastguard Worker{ 1575*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1576*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); 1577*8975f5c5SAndroid Build Coastguard Worker angle::FormatID angleFormatId = 1578*8975f5c5SAndroid Build Coastguard Worker angle::Format::InternalFormatToID(formatInfo.sizedInternalFormat); 1579*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId); 1580*8975f5c5SAndroid Build Coastguard Worker 1581*8975f5c5SAndroid Build Coastguard Worker return setStorageImpl(context, type, mState.getImmutableLevels(), 0, mtlFormat, size); 1582*8975f5c5SAndroid Build Coastguard Worker} 1583*8975f5c5SAndroid Build Coastguard Worker 1584*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setStorageExternalMemory(const gl::Context *context, 1585*8975f5c5SAndroid Build Coastguard Worker gl::TextureType type, 1586*8975f5c5SAndroid Build Coastguard Worker size_t levels, 1587*8975f5c5SAndroid Build Coastguard Worker GLenum internalFormat, 1588*8975f5c5SAndroid Build Coastguard Worker const gl::Extents &size, 1589*8975f5c5SAndroid Build Coastguard Worker gl::MemoryObject *memoryObject, 1590*8975f5c5SAndroid Build Coastguard Worker GLuint64 offset, 1591*8975f5c5SAndroid Build Coastguard Worker GLbitfield createFlags, 1592*8975f5c5SAndroid Build Coastguard Worker GLbitfield usageFlags, 1593*8975f5c5SAndroid Build Coastguard Worker const void *imageCreateInfoPNext) 1594*8975f5c5SAndroid Build Coastguard Worker{ 1595*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED(); 1596*8975f5c5SAndroid Build Coastguard Worker 1597*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Stop; 1598*8975f5c5SAndroid Build Coastguard Worker} 1599*8975f5c5SAndroid Build Coastguard Worker 1600*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setStorageMultisample(const gl::Context *context, 1601*8975f5c5SAndroid Build Coastguard Worker gl::TextureType type, 1602*8975f5c5SAndroid Build Coastguard Worker GLsizei samples, 1603*8975f5c5SAndroid Build Coastguard Worker GLint internalFormat, 1604*8975f5c5SAndroid Build Coastguard Worker const gl::Extents &size, 1605*8975f5c5SAndroid Build Coastguard Worker bool fixedSampleLocations) 1606*8975f5c5SAndroid Build Coastguard Worker{ 1607*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1608*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); 1609*8975f5c5SAndroid Build Coastguard Worker angle::FormatID angleFormatId = 1610*8975f5c5SAndroid Build Coastguard Worker angle::Format::InternalFormatToID(formatInfo.sizedInternalFormat); 1611*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId); 1612*8975f5c5SAndroid Build Coastguard Worker 1613*8975f5c5SAndroid Build Coastguard Worker return setStorageImpl(context, type, 0, mState.getLevelZeroDesc().samples, mtlFormat, size); 1614*8975f5c5SAndroid Build Coastguard Worker} 1615*8975f5c5SAndroid Build Coastguard Worker 1616*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setEGLImageTarget(const gl::Context *context, 1617*8975f5c5SAndroid Build Coastguard Worker gl::TextureType type, 1618*8975f5c5SAndroid Build Coastguard Worker egl::Image *image) 1619*8975f5c5SAndroid Build Coastguard Worker{ 1620*8975f5c5SAndroid Build Coastguard Worker deallocateNativeStorage(/*keepImages=*/false); 1621*8975f5c5SAndroid Build Coastguard Worker 1622*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1623*8975f5c5SAndroid Build Coastguard Worker 1624*8975f5c5SAndroid Build Coastguard Worker ImageMtl *imageMtl = mtl::GetImpl(image); 1625*8975f5c5SAndroid Build Coastguard Worker if (type != imageMtl->getImageTextureType()) 1626*8975f5c5SAndroid Build Coastguard Worker { 1627*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Stop; 1628*8975f5c5SAndroid Build Coastguard Worker } 1629*8975f5c5SAndroid Build Coastguard Worker 1630*8975f5c5SAndroid Build Coastguard Worker mNativeTextureStorage = std::make_unique<NativeTextureWrapperWithViewSupport>( 1631*8975f5c5SAndroid Build Coastguard Worker imageMtl->getTexture(), /*baseGLLevel=*/0); 1632*8975f5c5SAndroid Build Coastguard Worker 1633*8975f5c5SAndroid Build Coastguard Worker const angle::FormatID angleFormatId = 1634*8975f5c5SAndroid Build Coastguard Worker angle::Format::InternalFormatToID(image->getFormat().info->sizedInternalFormat); 1635*8975f5c5SAndroid Build Coastguard Worker mFormat = contextMtl->getPixelFormat(angleFormatId); 1636*8975f5c5SAndroid Build Coastguard Worker 1637*8975f5c5SAndroid Build Coastguard Worker mSlices = mNativeTextureStorage->cubeFacesOrArrayLength(); 1638*8975f5c5SAndroid Build Coastguard Worker 1639*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureSamplerStateCreated(context)); 1640*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(createViewFromBaseToMaxLevel()); 1641*8975f5c5SAndroid Build Coastguard Worker 1642*8975f5c5SAndroid Build Coastguard Worker // Tell context to rebind textures 1643*8975f5c5SAndroid Build Coastguard Worker contextMtl->invalidateCurrentTextures(); 1644*8975f5c5SAndroid Build Coastguard Worker 1645*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1646*8975f5c5SAndroid Build Coastguard Worker} 1647*8975f5c5SAndroid Build Coastguard Worker 1648*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setImageExternal(const gl::Context *context, 1649*8975f5c5SAndroid Build Coastguard Worker gl::TextureType type, 1650*8975f5c5SAndroid Build Coastguard Worker egl::Stream *stream, 1651*8975f5c5SAndroid Build Coastguard Worker const egl::Stream::GLTextureDescription &desc) 1652*8975f5c5SAndroid Build Coastguard Worker{ 1653*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED(); 1654*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Stop; 1655*8975f5c5SAndroid Build Coastguard Worker} 1656*8975f5c5SAndroid Build Coastguard Worker 1657*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::generateMipmap(const gl::Context *context) 1658*8975f5c5SAndroid Build Coastguard Worker{ 1659*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureNativeStorageCreated(context)); 1660*8975f5c5SAndroid Build Coastguard Worker 1661*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1662*8975f5c5SAndroid Build Coastguard Worker if (!mViewFromBaseToMaxLevel) 1663*8975f5c5SAndroid Build Coastguard Worker { 1664*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1665*8975f5c5SAndroid Build Coastguard Worker } 1666*8975f5c5SAndroid Build Coastguard Worker 1667*8975f5c5SAndroid Build Coastguard Worker const mtl::FormatCaps &caps = mFormat.getCaps(); 1668*8975f5c5SAndroid Build Coastguard Worker // 1669*8975f5c5SAndroid Build Coastguard Worker bool sRGB = mFormat.actualInternalFormat().colorEncoding == GL_SRGB; 1670*8975f5c5SAndroid Build Coastguard Worker 1671*8975f5c5SAndroid Build Coastguard Worker bool avoidGPUPath = 1672*8975f5c5SAndroid Build Coastguard Worker contextMtl->getDisplay()->getFeatures().forceNonCSBaseMipmapGeneration.enabled && 1673*8975f5c5SAndroid Build Coastguard Worker mViewFromBaseToMaxLevel->widthAt0() < 5; 1674*8975f5c5SAndroid Build Coastguard Worker 1675*8975f5c5SAndroid Build Coastguard Worker if (!avoidGPUPath && caps.writable && mState.getType() == gl::TextureType::_3D) 1676*8975f5c5SAndroid Build Coastguard Worker { 1677*8975f5c5SAndroid Build Coastguard Worker // http://anglebug.com/42263496. 1678*8975f5c5SAndroid Build Coastguard Worker // Use compute for 3D mipmap generation. 1679*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureLevelViewsWithinBaseMaxCreated()); 1680*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(contextMtl->getDisplay()->getUtils().generateMipmapCS( 1681*8975f5c5SAndroid Build Coastguard Worker contextMtl, *mViewFromBaseToMaxLevel, sRGB, &mLevelViewsWithinBaseMax)); 1682*8975f5c5SAndroid Build Coastguard Worker } 1683*8975f5c5SAndroid Build Coastguard Worker else if (!avoidGPUPath && caps.filterable && caps.colorRenderable) 1684*8975f5c5SAndroid Build Coastguard Worker { 1685*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *blitEncoder = GetBlitCommandEncoderForResources( 1686*8975f5c5SAndroid Build Coastguard Worker contextMtl, {mViewFromBaseToMaxLevel->getNativeTexture().get()}); 1687*8975f5c5SAndroid Build Coastguard Worker blitEncoder->generateMipmapsForTexture(*mViewFromBaseToMaxLevel); 1688*8975f5c5SAndroid Build Coastguard Worker } 1689*8975f5c5SAndroid Build Coastguard Worker else 1690*8975f5c5SAndroid Build Coastguard Worker { 1691*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(generateMipmapCPU(context)); 1692*8975f5c5SAndroid Build Coastguard Worker } 1693*8975f5c5SAndroid Build Coastguard Worker 1694*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1695*8975f5c5SAndroid Build Coastguard Worker} 1696*8975f5c5SAndroid Build Coastguard Worker 1697*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::generateMipmapCPU(const gl::Context *context) 1698*8975f5c5SAndroid Build Coastguard Worker{ 1699*8975f5c5SAndroid Build Coastguard Worker ASSERT(mViewFromBaseToMaxLevel); 1700*8975f5c5SAndroid Build Coastguard Worker 1701*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1702*8975f5c5SAndroid Build Coastguard Worker const angle::Format &angleFormat = mFormat.actualAngleFormat(); 1703*8975f5c5SAndroid Build Coastguard Worker // This format must have mip generation function. 1704*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_TRY(contextMtl, angleFormat.mipGenerationFunction); 1705*8975f5c5SAndroid Build Coastguard Worker 1706*8975f5c5SAndroid Build Coastguard Worker for (uint32_t slice = 0; slice < mSlices; ++slice) 1707*8975f5c5SAndroid Build Coastguard Worker { 1708*8975f5c5SAndroid Build Coastguard Worker GLuint baseGLLevel = mViewFromBaseToMaxLevel->getBaseGLLevel(); 1709*8975f5c5SAndroid Build Coastguard Worker 1710*8975f5c5SAndroid Build Coastguard Worker uint32_t prevLevelWidth = mViewFromBaseToMaxLevel->widthAt0(); 1711*8975f5c5SAndroid Build Coastguard Worker uint32_t prevLevelHeight = mViewFromBaseToMaxLevel->heightAt0(); 1712*8975f5c5SAndroid Build Coastguard Worker uint32_t prevLevelDepth = mViewFromBaseToMaxLevel->depthAt0(); 1713*8975f5c5SAndroid Build Coastguard Worker size_t prevLevelRowPitch = angleFormat.pixelBytes * prevLevelWidth; 1714*8975f5c5SAndroid Build Coastguard Worker size_t prevLevelDepthPitch = prevLevelRowPitch * prevLevelHeight; 1715*8975f5c5SAndroid Build Coastguard Worker std::unique_ptr<uint8_t[]> prevLevelData(new (std::nothrow) 1716*8975f5c5SAndroid Build Coastguard Worker uint8_t[prevLevelDepthPitch * prevLevelDepth]); 1717*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_ALLOC(contextMtl, prevLevelData); 1718*8975f5c5SAndroid Build Coastguard Worker std::unique_ptr<uint8_t[]> dstLevelData; 1719*8975f5c5SAndroid Build Coastguard Worker 1720*8975f5c5SAndroid Build Coastguard Worker // Download base level data 1721*8975f5c5SAndroid Build Coastguard Worker mViewFromBaseToMaxLevel->getBytes( 1722*8975f5c5SAndroid Build Coastguard Worker contextMtl, prevLevelRowPitch, prevLevelDepthPitch, 1723*8975f5c5SAndroid Build Coastguard Worker MTLRegionMake3D(0, 0, 0, prevLevelWidth, prevLevelHeight, prevLevelDepth), baseGLLevel, 1724*8975f5c5SAndroid Build Coastguard Worker slice, prevLevelData.get()); 1725*8975f5c5SAndroid Build Coastguard Worker 1726*8975f5c5SAndroid Build Coastguard Worker for (GLuint mip = 1; mip < mViewFromBaseToMaxLevel->mipmapLevels(); ++mip) 1727*8975f5c5SAndroid Build Coastguard Worker { 1728*8975f5c5SAndroid Build Coastguard Worker GLuint glLevel = baseGLLevel + mip; 1729*8975f5c5SAndroid Build Coastguard Worker uint32_t dstWidth = mViewFromBaseToMaxLevel->width(glLevel); 1730*8975f5c5SAndroid Build Coastguard Worker uint32_t dstHeight = mViewFromBaseToMaxLevel->height(glLevel); 1731*8975f5c5SAndroid Build Coastguard Worker uint32_t dstDepth = mViewFromBaseToMaxLevel->depth(glLevel); 1732*8975f5c5SAndroid Build Coastguard Worker 1733*8975f5c5SAndroid Build Coastguard Worker size_t dstRowPitch = angleFormat.pixelBytes * dstWidth; 1734*8975f5c5SAndroid Build Coastguard Worker size_t dstDepthPitch = dstRowPitch * dstHeight; 1735*8975f5c5SAndroid Build Coastguard Worker size_t dstDataSize = dstDepthPitch * dstDepth; 1736*8975f5c5SAndroid Build Coastguard Worker if (!dstLevelData) 1737*8975f5c5SAndroid Build Coastguard Worker { 1738*8975f5c5SAndroid Build Coastguard Worker // Allocate once and reuse the buffer 1739*8975f5c5SAndroid Build Coastguard Worker dstLevelData.reset(new (std::nothrow) uint8_t[dstDataSize]); 1740*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_ALLOC(contextMtl, dstLevelData); 1741*8975f5c5SAndroid Build Coastguard Worker } 1742*8975f5c5SAndroid Build Coastguard Worker 1743*8975f5c5SAndroid Build Coastguard Worker // Generate mip level 1744*8975f5c5SAndroid Build Coastguard Worker angleFormat.mipGenerationFunction( 1745*8975f5c5SAndroid Build Coastguard Worker prevLevelWidth, prevLevelHeight, 1, prevLevelData.get(), prevLevelRowPitch, 1746*8975f5c5SAndroid Build Coastguard Worker prevLevelDepthPitch, dstLevelData.get(), dstRowPitch, dstDepthPitch); 1747*8975f5c5SAndroid Build Coastguard Worker 1748*8975f5c5SAndroid Build Coastguard Worker mtl::MipmapNativeLevel nativeLevel = mViewFromBaseToMaxLevel->getNativeLevel(glLevel); 1749*8975f5c5SAndroid Build Coastguard Worker 1750*8975f5c5SAndroid Build Coastguard Worker // Upload to texture 1751*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadTextureContents(context, angleFormat, 1752*8975f5c5SAndroid Build Coastguard Worker MTLRegionMake3D(0, 0, 0, dstWidth, dstHeight, dstDepth), 1753*8975f5c5SAndroid Build Coastguard Worker nativeLevel, slice, dstLevelData.get(), dstRowPitch, 1754*8975f5c5SAndroid Build Coastguard Worker dstDepthPitch, false, *mViewFromBaseToMaxLevel)); 1755*8975f5c5SAndroid Build Coastguard Worker 1756*8975f5c5SAndroid Build Coastguard Worker prevLevelWidth = dstWidth; 1757*8975f5c5SAndroid Build Coastguard Worker prevLevelHeight = dstHeight; 1758*8975f5c5SAndroid Build Coastguard Worker prevLevelDepth = dstDepth; 1759*8975f5c5SAndroid Build Coastguard Worker prevLevelRowPitch = dstRowPitch; 1760*8975f5c5SAndroid Build Coastguard Worker prevLevelDepthPitch = dstDepthPitch; 1761*8975f5c5SAndroid Build Coastguard Worker std::swap(prevLevelData, dstLevelData); 1762*8975f5c5SAndroid Build Coastguard Worker } // for mip level 1763*8975f5c5SAndroid Build Coastguard Worker 1764*8975f5c5SAndroid Build Coastguard Worker } // For layers 1765*8975f5c5SAndroid Build Coastguard Worker 1766*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1767*8975f5c5SAndroid Build Coastguard Worker} 1768*8975f5c5SAndroid Build Coastguard Worker 1769*8975f5c5SAndroid Build Coastguard Workerbool TextureMtl::needsFormatViewForPixelLocalStorage( 1770*8975f5c5SAndroid Build Coastguard Worker const ShPixelLocalStorageOptions &plsOptions) const 1771*8975f5c5SAndroid Build Coastguard Worker{ 1772*8975f5c5SAndroid Build Coastguard Worker // On iOS devices with GPU family 5 and later, Metal doesn't apply lossless compression to 1773*8975f5c5SAndroid Build Coastguard Worker // the texture if we set MTLTextureUsagePixelFormatView. This shouldn't be a problem though 1774*8975f5c5SAndroid Build Coastguard Worker // because iOS devices implement pixel local storage with framebuffer fetch instead of shader 1775*8975f5c5SAndroid Build Coastguard Worker // images. 1776*8975f5c5SAndroid Build Coastguard Worker if (plsOptions.type == ShPixelLocalStorageType::ImageLoadStore) 1777*8975f5c5SAndroid Build Coastguard Worker { 1778*8975f5c5SAndroid Build Coastguard Worker switch (mFormat.metalFormat) 1779*8975f5c5SAndroid Build Coastguard Worker { 1780*8975f5c5SAndroid Build Coastguard Worker case MTLPixelFormatRGBA8Unorm: 1781*8975f5c5SAndroid Build Coastguard Worker case MTLPixelFormatRGBA8Uint: 1782*8975f5c5SAndroid Build Coastguard Worker case MTLPixelFormatRGBA8Sint: 1783*8975f5c5SAndroid Build Coastguard Worker return !plsOptions.supportsNativeRGBA8ImageFormats; 1784*8975f5c5SAndroid Build Coastguard Worker default: 1785*8975f5c5SAndroid Build Coastguard Worker break; 1786*8975f5c5SAndroid Build Coastguard Worker } 1787*8975f5c5SAndroid Build Coastguard Worker } 1788*8975f5c5SAndroid Build Coastguard Worker return false; 1789*8975f5c5SAndroid Build Coastguard Worker} 1790*8975f5c5SAndroid Build Coastguard Worker 1791*8975f5c5SAndroid Build Coastguard Workerbool TextureMtl::isImmutableOrPBuffer() const 1792*8975f5c5SAndroid Build Coastguard Worker{ 1793*8975f5c5SAndroid Build Coastguard Worker return mState.getImmutableFormat() || mBoundSurface; 1794*8975f5c5SAndroid Build Coastguard Worker} 1795*8975f5c5SAndroid Build Coastguard Worker 1796*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setBaseLevel(const gl::Context *context, GLuint baseLevel) 1797*8975f5c5SAndroid Build Coastguard Worker{ 1798*8975f5c5SAndroid Build Coastguard Worker return onBaseMaxLevelsChanged(context); 1799*8975f5c5SAndroid Build Coastguard Worker} 1800*8975f5c5SAndroid Build Coastguard Worker 1801*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::bindTexImage(const gl::Context *context, egl::Surface *surface) 1802*8975f5c5SAndroid Build Coastguard Worker{ 1803*8975f5c5SAndroid Build Coastguard Worker deallocateNativeStorage(/*keepImages=*/false); 1804*8975f5c5SAndroid Build Coastguard Worker 1805*8975f5c5SAndroid Build Coastguard Worker mBoundSurface = surface; 1806*8975f5c5SAndroid Build Coastguard Worker auto pBuffer = GetImplAs<OffscreenSurfaceMtl>(surface); 1807*8975f5c5SAndroid Build Coastguard Worker mNativeTextureStorage = std::make_unique<NativeTextureWrapperWithViewSupport>( 1808*8975f5c5SAndroid Build Coastguard Worker pBuffer->getColorTexture(), /*baseGLLevel=*/0); 1809*8975f5c5SAndroid Build Coastguard Worker mFormat = pBuffer->getColorFormat(); 1810*8975f5c5SAndroid Build Coastguard Worker mSlices = mNativeTextureStorage->cubeFacesOrArrayLength(); 1811*8975f5c5SAndroid Build Coastguard Worker 1812*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureSamplerStateCreated(context)); 1813*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(createViewFromBaseToMaxLevel()); 1814*8975f5c5SAndroid Build Coastguard Worker 1815*8975f5c5SAndroid Build Coastguard Worker // Tell context to rebind textures 1816*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1817*8975f5c5SAndroid Build Coastguard Worker contextMtl->invalidateCurrentTextures(); 1818*8975f5c5SAndroid Build Coastguard Worker 1819*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1820*8975f5c5SAndroid Build Coastguard Worker} 1821*8975f5c5SAndroid Build Coastguard Worker 1822*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::releaseTexImage(const gl::Context *context) 1823*8975f5c5SAndroid Build Coastguard Worker{ 1824*8975f5c5SAndroid Build Coastguard Worker deallocateNativeStorage(/*keepImages=*/false); 1825*8975f5c5SAndroid Build Coastguard Worker mBoundSurface = nullptr; 1826*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1827*8975f5c5SAndroid Build Coastguard Worker} 1828*8975f5c5SAndroid Build Coastguard Worker 1829*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::getAttachmentRenderTarget(const gl::Context *context, 1830*8975f5c5SAndroid Build Coastguard Worker GLenum binding, 1831*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &imageIndex, 1832*8975f5c5SAndroid Build Coastguard Worker GLsizei samples, 1833*8975f5c5SAndroid Build Coastguard Worker FramebufferAttachmentRenderTarget **rtOut) 1834*8975f5c5SAndroid Build Coastguard Worker{ 1835*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureNativeStorageCreated(context)); 1836*8975f5c5SAndroid Build Coastguard Worker 1837*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1838*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_TRY(contextMtl, mNativeTextureStorage); 1839*8975f5c5SAndroid Build Coastguard Worker 1840*8975f5c5SAndroid Build Coastguard Worker RenderTargetMtl *rtt; 1841*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(getRenderTarget(contextMtl, imageIndex, samples, &rtt)); 1842*8975f5c5SAndroid Build Coastguard Worker 1843*8975f5c5SAndroid Build Coastguard Worker *rtOut = rtt; 1844*8975f5c5SAndroid Build Coastguard Worker 1845*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1846*8975f5c5SAndroid Build Coastguard Worker} 1847*8975f5c5SAndroid Build Coastguard Worker 1848*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::syncState(const gl::Context *context, 1849*8975f5c5SAndroid Build Coastguard Worker const gl::Texture::DirtyBits &dirtyBits, 1850*8975f5c5SAndroid Build Coastguard Worker gl::Command source) 1851*8975f5c5SAndroid Build Coastguard Worker{ 1852*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1853*8975f5c5SAndroid Build Coastguard Worker for (size_t dirtyBit : dirtyBits) 1854*8975f5c5SAndroid Build Coastguard Worker { 1855*8975f5c5SAndroid Build Coastguard Worker switch (dirtyBit) 1856*8975f5c5SAndroid Build Coastguard Worker { 1857*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_COMPARE_MODE: 1858*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_COMPARE_FUNC: 1859*8975f5c5SAndroid Build Coastguard Worker // Tell context to rebind textures so that ProgramMtl has a chance to verify 1860*8975f5c5SAndroid Build Coastguard Worker // depth texture compare mode. 1861*8975f5c5SAndroid Build Coastguard Worker contextMtl->invalidateCurrentTextures(); 1862*8975f5c5SAndroid Build Coastguard Worker // fall through 1863*8975f5c5SAndroid Build Coastguard Worker OS_FALLTHROUGH; 1864*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_MIN_FILTER: 1865*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_MAG_FILTER: 1866*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_WRAP_S: 1867*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_WRAP_T: 1868*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_WRAP_R: 1869*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY: 1870*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_MIN_LOD: 1871*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_MAX_LOD: 1872*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_SRGB_DECODE: 1873*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_BORDER_COLOR: 1874*8975f5c5SAndroid Build Coastguard Worker // Recreate sampler state 1875*8975f5c5SAndroid Build Coastguard Worker mMetalSamplerState = nil; 1876*8975f5c5SAndroid Build Coastguard Worker break; 1877*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_MAX_LEVEL: 1878*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_BASE_LEVEL: 1879*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(onBaseMaxLevelsChanged(context)); 1880*8975f5c5SAndroid Build Coastguard Worker break; 1881*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_SWIZZLE_RED: 1882*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN: 1883*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE: 1884*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA: 1885*8975f5c5SAndroid Build Coastguard Worker case gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE: 1886*8975f5c5SAndroid Build Coastguard Worker { 1887*8975f5c5SAndroid Build Coastguard Worker // Recreate swizzle/stencil view. 1888*8975f5c5SAndroid Build Coastguard Worker mSwizzleStencilSamplingView = nullptr; 1889*8975f5c5SAndroid Build Coastguard Worker } 1890*8975f5c5SAndroid Build Coastguard Worker break; 1891*8975f5c5SAndroid Build Coastguard Worker default: 1892*8975f5c5SAndroid Build Coastguard Worker break; 1893*8975f5c5SAndroid Build Coastguard Worker } 1894*8975f5c5SAndroid Build Coastguard Worker } 1895*8975f5c5SAndroid Build Coastguard Worker 1896*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureNativeStorageCreated(context)); 1897*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureSamplerStateCreated(context)); 1898*8975f5c5SAndroid Build Coastguard Worker 1899*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1900*8975f5c5SAndroid Build Coastguard Worker} 1901*8975f5c5SAndroid Build Coastguard Worker 1902*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::bindToShader(const gl::Context *context, 1903*8975f5c5SAndroid Build Coastguard Worker mtl::RenderCommandEncoder *cmdEncoder, 1904*8975f5c5SAndroid Build Coastguard Worker gl::ShaderType shaderType, 1905*8975f5c5SAndroid Build Coastguard Worker gl::Sampler *sampler, 1906*8975f5c5SAndroid Build Coastguard Worker int textureSlotIndex, 1907*8975f5c5SAndroid Build Coastguard Worker int samplerSlotIndex) 1908*8975f5c5SAndroid Build Coastguard Worker{ 1909*8975f5c5SAndroid Build Coastguard Worker ASSERT(mNativeTextureStorage); 1910*8975f5c5SAndroid Build Coastguard Worker ASSERT(mViewFromBaseToMaxLevel); 1911*8975f5c5SAndroid Build Coastguard Worker 1912*8975f5c5SAndroid Build Coastguard Worker float minLodClamp; 1913*8975f5c5SAndroid Build Coastguard Worker float maxLodClamp; 1914*8975f5c5SAndroid Build Coastguard Worker id<MTLSamplerState> samplerState; 1915*8975f5c5SAndroid Build Coastguard Worker 1916*8975f5c5SAndroid Build Coastguard Worker if (!mSwizzleStencilSamplingView) 1917*8975f5c5SAndroid Build Coastguard Worker { 1918*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 1919*8975f5c5SAndroid Build Coastguard Worker const angle::FeaturesMtl &features = contextMtl->getDisplay()->getFeatures(); 1920*8975f5c5SAndroid Build Coastguard Worker 1921*8975f5c5SAndroid Build Coastguard Worker // Sampling from unused channels of depth and stencil textures is undefined in Metal. 1922*8975f5c5SAndroid Build Coastguard Worker // ANGLE relies on swizzled views to enforce values required by OpenGL ES specs. Some 1923*8975f5c5SAndroid Build Coastguard Worker // drivers fail to sample from a swizzled view of a stencil texture so skip this step. 1924*8975f5c5SAndroid Build Coastguard Worker const bool skipStencilSwizzle = mFormat.actualFormatId == angle::FormatID::S8_UINT && 1925*8975f5c5SAndroid Build Coastguard Worker features.avoidStencilTextureSwizzle.enabled; 1926*8975f5c5SAndroid Build Coastguard Worker if (!skipStencilSwizzle && 1927*8975f5c5SAndroid Build Coastguard Worker (mState.getSwizzleState().swizzleRequired() || 1928*8975f5c5SAndroid Build Coastguard Worker mFormat.actualAngleFormat().hasDepthOrStencilBits() || mFormat.swizzled) && 1929*8975f5c5SAndroid Build Coastguard Worker features.hasTextureSwizzle.enabled) 1930*8975f5c5SAndroid Build Coastguard Worker { 1931*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &glInternalFormat = *mState.getBaseLevelDesc().format.info; 1932*8975f5c5SAndroid Build Coastguard Worker 1933*8975f5c5SAndroid Build Coastguard Worker MTLTextureSwizzleChannels swizzle = MTLTextureSwizzleChannelsMake( 1934*8975f5c5SAndroid Build Coastguard Worker mtl::GetTextureSwizzle(OverrideSwizzleValue( 1935*8975f5c5SAndroid Build Coastguard Worker context, mState.getSwizzleState().swizzleRed, mFormat, glInternalFormat)), 1936*8975f5c5SAndroid Build Coastguard Worker mtl::GetTextureSwizzle(OverrideSwizzleValue( 1937*8975f5c5SAndroid Build Coastguard Worker context, mState.getSwizzleState().swizzleGreen, mFormat, glInternalFormat)), 1938*8975f5c5SAndroid Build Coastguard Worker mtl::GetTextureSwizzle(OverrideSwizzleValue( 1939*8975f5c5SAndroid Build Coastguard Worker context, mState.getSwizzleState().swizzleBlue, mFormat, glInternalFormat)), 1940*8975f5c5SAndroid Build Coastguard Worker mtl::GetTextureSwizzle(OverrideSwizzleValue( 1941*8975f5c5SAndroid Build Coastguard Worker context, mState.getSwizzleState().swizzleAlpha, mFormat, glInternalFormat))); 1942*8975f5c5SAndroid Build Coastguard Worker 1943*8975f5c5SAndroid Build Coastguard Worker MTLPixelFormat format = mViewFromBaseToMaxLevel->pixelFormat(); 1944*8975f5c5SAndroid Build Coastguard Worker if (mState.isStencilMode()) 1945*8975f5c5SAndroid Build Coastguard Worker { 1946*8975f5c5SAndroid Build Coastguard Worker if (format == MTLPixelFormatDepth32Float_Stencil8) 1947*8975f5c5SAndroid Build Coastguard Worker { 1948*8975f5c5SAndroid Build Coastguard Worker format = MTLPixelFormatX32_Stencil8; 1949*8975f5c5SAndroid Build Coastguard Worker } 1950*8975f5c5SAndroid Build Coastguard Worker# if TARGET_OS_OSX || TARGET_OS_MACCATALYST 1951*8975f5c5SAndroid Build Coastguard Worker else if (format == MTLPixelFormatDepth24Unorm_Stencil8) 1952*8975f5c5SAndroid Build Coastguard Worker { 1953*8975f5c5SAndroid Build Coastguard Worker format = MTLPixelFormatX24_Stencil8; 1954*8975f5c5SAndroid Build Coastguard Worker } 1955*8975f5c5SAndroid Build Coastguard Worker# endif 1956*8975f5c5SAndroid Build Coastguard Worker } 1957*8975f5c5SAndroid Build Coastguard Worker 1958*8975f5c5SAndroid Build Coastguard Worker mSwizzleStencilSamplingView = mNativeTextureStorage->createMipsSwizzleView( 1959*8975f5c5SAndroid Build Coastguard Worker mViewFromBaseToMaxLevel->getBaseGLLevel(), mViewFromBaseToMaxLevel->mipmapLevels(), 1960*8975f5c5SAndroid Build Coastguard Worker format, swizzle); 1961*8975f5c5SAndroid Build Coastguard Worker } 1962*8975f5c5SAndroid Build Coastguard Worker else 1963*8975f5c5SAndroid Build Coastguard Worker { 1964*8975f5c5SAndroid Build Coastguard Worker mSwizzleStencilSamplingView = mState.isStencilMode() 1965*8975f5c5SAndroid Build Coastguard Worker ? mViewFromBaseToMaxLevel->getStencilView() 1966*8975f5c5SAndroid Build Coastguard Worker : mViewFromBaseToMaxLevel->getNativeTexture(); 1967*8975f5c5SAndroid Build Coastguard Worker } 1968*8975f5c5SAndroid Build Coastguard Worker } 1969*8975f5c5SAndroid Build Coastguard Worker 1970*8975f5c5SAndroid Build Coastguard Worker if (!sampler) 1971*8975f5c5SAndroid Build Coastguard Worker { 1972*8975f5c5SAndroid Build Coastguard Worker samplerState = mMetalSamplerState; 1973*8975f5c5SAndroid Build Coastguard Worker minLodClamp = mState.getSamplerState().getMinLod(); 1974*8975f5c5SAndroid Build Coastguard Worker maxLodClamp = mState.getSamplerState().getMaxLod(); 1975*8975f5c5SAndroid Build Coastguard Worker } 1976*8975f5c5SAndroid Build Coastguard Worker else 1977*8975f5c5SAndroid Build Coastguard Worker { 1978*8975f5c5SAndroid Build Coastguard Worker SamplerMtl *samplerMtl = mtl::GetImpl(sampler); 1979*8975f5c5SAndroid Build Coastguard Worker samplerState = samplerMtl->getSampler(mtl::GetImpl(context)); 1980*8975f5c5SAndroid Build Coastguard Worker minLodClamp = sampler->getSamplerState().getMinLod(); 1981*8975f5c5SAndroid Build Coastguard Worker maxLodClamp = sampler->getSamplerState().getMaxLod(); 1982*8975f5c5SAndroid Build Coastguard Worker } 1983*8975f5c5SAndroid Build Coastguard Worker 1984*8975f5c5SAndroid Build Coastguard Worker minLodClamp = std::max(minLodClamp, 0.f); 1985*8975f5c5SAndroid Build Coastguard Worker 1986*8975f5c5SAndroid Build Coastguard Worker cmdEncoder->setTexture(shaderType, mSwizzleStencilSamplingView, textureSlotIndex); 1987*8975f5c5SAndroid Build Coastguard Worker cmdEncoder->setSamplerState(shaderType, samplerState, minLodClamp, maxLodClamp, 1988*8975f5c5SAndroid Build Coastguard Worker samplerSlotIndex); 1989*8975f5c5SAndroid Build Coastguard Worker 1990*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1991*8975f5c5SAndroid Build Coastguard Worker} 1992*8975f5c5SAndroid Build Coastguard Worker 1993*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::bindToShaderImage(const gl::Context *context, 1994*8975f5c5SAndroid Build Coastguard Worker mtl::RenderCommandEncoder *cmdEncoder, 1995*8975f5c5SAndroid Build Coastguard Worker gl::ShaderType shaderType, 1996*8975f5c5SAndroid Build Coastguard Worker int textureSlotIndex, 1997*8975f5c5SAndroid Build Coastguard Worker int level, 1998*8975f5c5SAndroid Build Coastguard Worker int layer, 1999*8975f5c5SAndroid Build Coastguard Worker GLenum format) 2000*8975f5c5SAndroid Build Coastguard Worker{ 2001*8975f5c5SAndroid Build Coastguard Worker ASSERT(mNativeTextureStorage); 2002*8975f5c5SAndroid Build Coastguard Worker ASSERT(mState.getImmutableFormat()); 2003*8975f5c5SAndroid Build Coastguard Worker ASSERT(0 <= level && static_cast<uint32_t>(level) < mState.getImmutableLevels()); 2004*8975f5c5SAndroid Build Coastguard Worker ASSERT(0 <= layer && static_cast<uint32_t>(layer) < mSlices); 2005*8975f5c5SAndroid Build Coastguard Worker 2006*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2007*8975f5c5SAndroid Build Coastguard Worker angle::FormatID angleFormatId = angle::Format::InternalFormatToID(format); 2008*8975f5c5SAndroid Build Coastguard Worker mtl::Format imageAccessFormat = contextMtl->getPixelFormat(angleFormatId); 2009*8975f5c5SAndroid Build Coastguard Worker LayerLevelTextureViewVector &textureViewVector = 2010*8975f5c5SAndroid Build Coastguard Worker mShaderImageViews[imageAccessFormat.metalFormat]; 2011*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef &textureRef = GetLayerLevelTextureView(&textureViewVector, layer, level, 2012*8975f5c5SAndroid Build Coastguard Worker mSlices, mState.getImmutableLevels()); 2013*8975f5c5SAndroid Build Coastguard Worker 2014*8975f5c5SAndroid Build Coastguard Worker if (textureRef == nullptr) 2015*8975f5c5SAndroid Build Coastguard Worker { 2016*8975f5c5SAndroid Build Coastguard Worker textureRef = mNativeTextureStorage->createShaderImageView2D(level, layer, 2017*8975f5c5SAndroid Build Coastguard Worker imageAccessFormat.metalFormat); 2018*8975f5c5SAndroid Build Coastguard Worker } 2019*8975f5c5SAndroid Build Coastguard Worker 2020*8975f5c5SAndroid Build Coastguard Worker cmdEncoder->setRWTexture(shaderType, textureRef, textureSlotIndex); 2021*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2022*8975f5c5SAndroid Build Coastguard Worker} 2023*8975f5c5SAndroid Build Coastguard Worker 2024*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::redefineImage(const gl::Context *context, 2025*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 2026*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &mtlFormat, 2027*8975f5c5SAndroid Build Coastguard Worker const gl::Extents &size) 2028*8975f5c5SAndroid Build Coastguard Worker{ 2029*8975f5c5SAndroid Build Coastguard Worker bool imageWithinNativeStorageLevels = false; 2030*8975f5c5SAndroid Build Coastguard Worker if (mNativeTextureStorage && mNativeTextureStorage->isGLLevelSupported(index.getLevelIndex())) 2031*8975f5c5SAndroid Build Coastguard Worker { 2032*8975f5c5SAndroid Build Coastguard Worker imageWithinNativeStorageLevels = true; 2033*8975f5c5SAndroid Build Coastguard Worker GLuint glLevel = index.getLevelIndex(); 2034*8975f5c5SAndroid Build Coastguard Worker // Calculate the expected size for the index we are defining. If the size is different 2035*8975f5c5SAndroid Build Coastguard Worker // from the given size, or the format is different, we are redefining the image so we 2036*8975f5c5SAndroid Build Coastguard Worker // must release it. 2037*8975f5c5SAndroid Build Coastguard Worker ASSERT(mNativeTextureStorage->textureType() == mtl::GetTextureType(index.getType())); 2038*8975f5c5SAndroid Build Coastguard Worker if (mFormat != mtlFormat || size != mNativeTextureStorage->size(glLevel)) 2039*8975f5c5SAndroid Build Coastguard Worker { 2040*8975f5c5SAndroid Build Coastguard Worker // Keep other images 2041*8975f5c5SAndroid Build Coastguard Worker deallocateNativeStorage(/*keepImages=*/true); 2042*8975f5c5SAndroid Build Coastguard Worker } 2043*8975f5c5SAndroid Build Coastguard Worker } 2044*8975f5c5SAndroid Build Coastguard Worker 2045*8975f5c5SAndroid Build Coastguard Worker // Early-out on empty textures, don't create a zero-sized storage. 2046*8975f5c5SAndroid Build Coastguard Worker if (size.empty()) 2047*8975f5c5SAndroid Build Coastguard Worker { 2048*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2049*8975f5c5SAndroid Build Coastguard Worker } 2050*8975f5c5SAndroid Build Coastguard Worker 2051*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2052*8975f5c5SAndroid Build Coastguard Worker // Cache last defined image format: 2053*8975f5c5SAndroid Build Coastguard Worker mFormat = mtlFormat; 2054*8975f5c5SAndroid Build Coastguard Worker ImageDefinitionMtl &imageDef = getImageDefinition(index); 2055*8975f5c5SAndroid Build Coastguard Worker 2056*8975f5c5SAndroid Build Coastguard Worker // If native texture still exists, it means the size hasn't been changed, no need to create new 2057*8975f5c5SAndroid Build Coastguard Worker // image 2058*8975f5c5SAndroid Build Coastguard Worker if (mNativeTextureStorage && imageDef.image && imageWithinNativeStorageLevels) 2059*8975f5c5SAndroid Build Coastguard Worker { 2060*8975f5c5SAndroid Build Coastguard Worker ASSERT(imageDef.image->textureType() == 2061*8975f5c5SAndroid Build Coastguard Worker mtl::GetTextureType(GetTextureImageType(index.getType())) && 2062*8975f5c5SAndroid Build Coastguard Worker imageDef.formatID == mFormat.intendedFormatId && imageDef.image->sizeAt0() == size); 2063*8975f5c5SAndroid Build Coastguard Worker } 2064*8975f5c5SAndroid Build Coastguard Worker else 2065*8975f5c5SAndroid Build Coastguard Worker { 2066*8975f5c5SAndroid Build Coastguard Worker imageDef.formatID = mtlFormat.intendedFormatId; 2067*8975f5c5SAndroid Build Coastguard Worker bool allowFormatView = mFormat.hasDepthAndStencilBits() || 2068*8975f5c5SAndroid Build Coastguard Worker needsFormatViewForPixelLocalStorage( 2069*8975f5c5SAndroid Build Coastguard Worker contextMtl->getDisplay()->getNativePixelLocalStorageOptions()); 2070*8975f5c5SAndroid Build Coastguard Worker // Create image to hold texture's data at this level & slice: 2071*8975f5c5SAndroid Build Coastguard Worker switch (index.getType()) 2072*8975f5c5SAndroid Build Coastguard Worker { 2073*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2D: 2074*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::CubeMap: 2075*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Texture::Make2DTexture( 2076*8975f5c5SAndroid Build Coastguard Worker contextMtl, mtlFormat, size.width, size.height, 1, 2077*8975f5c5SAndroid Build Coastguard Worker /** renderTargetOnly */ false, allowFormatView, &imageDef.image)); 2078*8975f5c5SAndroid Build Coastguard Worker break; 2079*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_3D: 2080*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Texture::Make3DTexture( 2081*8975f5c5SAndroid Build Coastguard Worker contextMtl, mtlFormat, size.width, size.height, size.depth, 1, 2082*8975f5c5SAndroid Build Coastguard Worker /** renderTargetOnly */ false, allowFormatView, &imageDef.image)); 2083*8975f5c5SAndroid Build Coastguard Worker break; 2084*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2DArray: 2085*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Texture::Make2DArrayTexture( 2086*8975f5c5SAndroid Build Coastguard Worker contextMtl, mtlFormat, size.width, size.height, 1, size.depth, 2087*8975f5c5SAndroid Build Coastguard Worker /** renderTargetOnly */ false, allowFormatView, &imageDef.image)); 2088*8975f5c5SAndroid Build Coastguard Worker break; 2089*8975f5c5SAndroid Build Coastguard Worker default: 2090*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 2091*8975f5c5SAndroid Build Coastguard Worker } 2092*8975f5c5SAndroid Build Coastguard Worker 2093*8975f5c5SAndroid Build Coastguard Worker // Make sure emulated channels are properly initialized in this newly allocated texture. 2094*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(checkForEmulatedChannels(context, mtlFormat, imageDef.image)); 2095*8975f5c5SAndroid Build Coastguard Worker } 2096*8975f5c5SAndroid Build Coastguard Worker 2097*8975f5c5SAndroid Build Coastguard Worker // Tell context to rebind textures 2098*8975f5c5SAndroid Build Coastguard Worker contextMtl->invalidateCurrentTextures(); 2099*8975f5c5SAndroid Build Coastguard Worker 2100*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2101*8975f5c5SAndroid Build Coastguard Worker} 2102*8975f5c5SAndroid Build Coastguard Worker 2103*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setStorageImpl(const gl::Context *context, 2104*8975f5c5SAndroid Build Coastguard Worker gl::TextureType type, 2105*8975f5c5SAndroid Build Coastguard Worker GLuint mips, 2106*8975f5c5SAndroid Build Coastguard Worker GLuint samples, 2107*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &mtlFormat, 2108*8975f5c5SAndroid Build Coastguard Worker const gl::Extents &size) 2109*8975f5c5SAndroid Build Coastguard Worker{ 2110*8975f5c5SAndroid Build Coastguard Worker // Don't need to hold old images data. 2111*8975f5c5SAndroid Build Coastguard Worker deallocateNativeStorage(/*keepImages=*/false); 2112*8975f5c5SAndroid Build Coastguard Worker 2113*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2114*8975f5c5SAndroid Build Coastguard Worker 2115*8975f5c5SAndroid Build Coastguard Worker // Tell context to rebind textures 2116*8975f5c5SAndroid Build Coastguard Worker contextMtl->invalidateCurrentTextures(); 2117*8975f5c5SAndroid Build Coastguard Worker 2118*8975f5c5SAndroid Build Coastguard Worker mFormat = mtlFormat; 2119*8975f5c5SAndroid Build Coastguard Worker 2120*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(createNativeStorage(context, type, mips, samples, size)); 2121*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(createViewFromBaseToMaxLevel()); 2122*8975f5c5SAndroid Build Coastguard Worker 2123*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2124*8975f5c5SAndroid Build Coastguard Worker} 2125*8975f5c5SAndroid Build Coastguard Worker 2126*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setImageImpl(const gl::Context *context, 2127*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 2128*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &dstFormatInfo, 2129*8975f5c5SAndroid Build Coastguard Worker const gl::Extents &size, 2130*8975f5c5SAndroid Build Coastguard Worker GLenum srcFormat, 2131*8975f5c5SAndroid Build Coastguard Worker GLenum srcType, 2132*8975f5c5SAndroid Build Coastguard Worker const gl::PixelUnpackState &unpack, 2133*8975f5c5SAndroid Build Coastguard Worker gl::Buffer *unpackBuffer, 2134*8975f5c5SAndroid Build Coastguard Worker const uint8_t *pixels) 2135*8975f5c5SAndroid Build Coastguard Worker{ 2136*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2137*8975f5c5SAndroid Build Coastguard Worker angle::FormatID angleFormatId = 2138*8975f5c5SAndroid Build Coastguard Worker angle::Format::InternalFormatToID(dstFormatInfo.sizedInternalFormat); 2139*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId); 2140*8975f5c5SAndroid Build Coastguard Worker 2141*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(redefineImage(context, index, mtlFormat, size)); 2142*8975f5c5SAndroid Build Coastguard Worker 2143*8975f5c5SAndroid Build Coastguard Worker // Early-out on empty textures, don't create a zero-sized storage. 2144*8975f5c5SAndroid Build Coastguard Worker if (size.empty()) 2145*8975f5c5SAndroid Build Coastguard Worker { 2146*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2147*8975f5c5SAndroid Build Coastguard Worker } 2148*8975f5c5SAndroid Build Coastguard Worker 2149*8975f5c5SAndroid Build Coastguard Worker // Format of the supplied pixels. 2150*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat *srcFormatInfo; 2151*8975f5c5SAndroid Build Coastguard Worker if (srcFormat != dstFormatInfo.format || srcType != dstFormatInfo.type) 2152*8975f5c5SAndroid Build Coastguard Worker { 2153*8975f5c5SAndroid Build Coastguard Worker srcFormatInfo = &gl::GetInternalFormatInfo(srcFormat, srcType); 2154*8975f5c5SAndroid Build Coastguard Worker } 2155*8975f5c5SAndroid Build Coastguard Worker else 2156*8975f5c5SAndroid Build Coastguard Worker { 2157*8975f5c5SAndroid Build Coastguard Worker srcFormatInfo = &dstFormatInfo; 2158*8975f5c5SAndroid Build Coastguard Worker } 2159*8975f5c5SAndroid Build Coastguard Worker return setSubImageImpl(context, index, gl::Box(0, 0, 0, size.width, size.height, size.depth), 2160*8975f5c5SAndroid Build Coastguard Worker *srcFormatInfo, srcType, unpack, unpackBuffer, pixels); 2161*8975f5c5SAndroid Build Coastguard Worker} 2162*8975f5c5SAndroid Build Coastguard Worker 2163*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setSubImageImpl(const gl::Context *context, 2164*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 2165*8975f5c5SAndroid Build Coastguard Worker const gl::Box &area, 2166*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &formatInfo, 2167*8975f5c5SAndroid Build Coastguard Worker GLenum type, 2168*8975f5c5SAndroid Build Coastguard Worker const gl::PixelUnpackState &unpack, 2169*8975f5c5SAndroid Build Coastguard Worker gl::Buffer *unpackBuffer, 2170*8975f5c5SAndroid Build Coastguard Worker const uint8_t *oriPixels) 2171*8975f5c5SAndroid Build Coastguard Worker{ 2172*8975f5c5SAndroid Build Coastguard Worker if (!oriPixels && !unpackBuffer) 2173*8975f5c5SAndroid Build Coastguard Worker { 2174*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2175*8975f5c5SAndroid Build Coastguard Worker } 2176*8975f5c5SAndroid Build Coastguard Worker 2177*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2178*8975f5c5SAndroid Build Coastguard Worker 2179*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureImageCreated(context, index)); 2180*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef &image = getImage(index); 2181*8975f5c5SAndroid Build Coastguard Worker 2182*8975f5c5SAndroid Build Coastguard Worker GLuint sourceRowPitch = 0; 2183*8975f5c5SAndroid Build Coastguard Worker GLuint sourceDepthPitch = 0; 2184*8975f5c5SAndroid Build Coastguard Worker GLuint sourceSkipBytes = 0; 2185*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_MATH(contextMtl, formatInfo.computeRowPitch(type, area.width, unpack.alignment, 2186*8975f5c5SAndroid Build Coastguard Worker unpack.rowLength, &sourceRowPitch)); 2187*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_MATH( 2188*8975f5c5SAndroid Build Coastguard Worker contextMtl, formatInfo.computeDepthPitch(area.height, unpack.imageHeight, sourceRowPitch, 2189*8975f5c5SAndroid Build Coastguard Worker &sourceDepthPitch)); 2190*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_MATH(contextMtl, 2191*8975f5c5SAndroid Build Coastguard Worker formatInfo.computeSkipBytes(type, sourceRowPitch, sourceDepthPitch, unpack, 2192*8975f5c5SAndroid Build Coastguard Worker index.usesTex3D(), &sourceSkipBytes)); 2193*8975f5c5SAndroid Build Coastguard Worker 2194*8975f5c5SAndroid Build Coastguard Worker // Get corresponding source data's ANGLE format 2195*8975f5c5SAndroid Build Coastguard Worker angle::FormatID srcAngleFormatId; 2196*8975f5c5SAndroid Build Coastguard Worker if (formatInfo.sizedInternalFormat == GL_DEPTH_COMPONENT24) 2197*8975f5c5SAndroid Build Coastguard Worker { 2198*8975f5c5SAndroid Build Coastguard Worker // GL_DEPTH_COMPONENT24 is special case, its supplied data is 32 bit depth. 2199*8975f5c5SAndroid Build Coastguard Worker srcAngleFormatId = angle::FormatID::D32_UNORM; 2200*8975f5c5SAndroid Build Coastguard Worker } 2201*8975f5c5SAndroid Build Coastguard Worker else 2202*8975f5c5SAndroid Build Coastguard Worker { 2203*8975f5c5SAndroid Build Coastguard Worker srcAngleFormatId = angle::Format::InternalFormatToID(formatInfo.sizedInternalFormat); 2204*8975f5c5SAndroid Build Coastguard Worker } 2205*8975f5c5SAndroid Build Coastguard Worker const angle::Format &srcAngleFormat = angle::Format::Get(srcAngleFormatId); 2206*8975f5c5SAndroid Build Coastguard Worker 2207*8975f5c5SAndroid Build Coastguard Worker const uint8_t *usablePixels = oriPixels + sourceSkipBytes; 2208*8975f5c5SAndroid Build Coastguard Worker 2209*8975f5c5SAndroid Build Coastguard Worker // Upload to texture 2210*8975f5c5SAndroid Build Coastguard Worker if (index.getType() == gl::TextureType::_2DArray) 2211*8975f5c5SAndroid Build Coastguard Worker { 2212*8975f5c5SAndroid Build Coastguard Worker // OpenGL unifies texture array and texture 3d's box area by using z & depth as array start 2213*8975f5c5SAndroid Build Coastguard Worker // index & length for texture array. However, Metal treats them differently. We need to 2214*8975f5c5SAndroid Build Coastguard Worker // handle them in separate code. 2215*8975f5c5SAndroid Build Coastguard Worker MTLRegion mtlRegion = MTLRegionMake3D(area.x, area.y, 0, area.width, area.height, 1); 2216*8975f5c5SAndroid Build Coastguard Worker 2217*8975f5c5SAndroid Build Coastguard Worker for (int slice = 0; slice < area.depth; ++slice) 2218*8975f5c5SAndroid Build Coastguard Worker { 2219*8975f5c5SAndroid Build Coastguard Worker int sliceIndex = slice + area.z; 2220*8975f5c5SAndroid Build Coastguard Worker const uint8_t *srcPixels = usablePixels + slice * sourceDepthPitch; 2221*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(setPerSliceSubImage(context, sliceIndex, mtlRegion, formatInfo, type, 2222*8975f5c5SAndroid Build Coastguard Worker srcAngleFormat, sourceRowPitch, sourceDepthPitch, 2223*8975f5c5SAndroid Build Coastguard Worker unpackBuffer, srcPixels, image)); 2224*8975f5c5SAndroid Build Coastguard Worker } 2225*8975f5c5SAndroid Build Coastguard Worker } 2226*8975f5c5SAndroid Build Coastguard Worker else 2227*8975f5c5SAndroid Build Coastguard Worker { 2228*8975f5c5SAndroid Build Coastguard Worker MTLRegion mtlRegion = 2229*8975f5c5SAndroid Build Coastguard Worker MTLRegionMake3D(area.x, area.y, area.z, area.width, area.height, area.depth); 2230*8975f5c5SAndroid Build Coastguard Worker 2231*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(setPerSliceSubImage(context, 0, mtlRegion, formatInfo, type, srcAngleFormat, 2232*8975f5c5SAndroid Build Coastguard Worker sourceRowPitch, sourceDepthPitch, unpackBuffer, usablePixels, 2233*8975f5c5SAndroid Build Coastguard Worker image)); 2234*8975f5c5SAndroid Build Coastguard Worker } 2235*8975f5c5SAndroid Build Coastguard Worker 2236*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2237*8975f5c5SAndroid Build Coastguard Worker} 2238*8975f5c5SAndroid Build Coastguard Worker 2239*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::setPerSliceSubImage(const gl::Context *context, 2240*8975f5c5SAndroid Build Coastguard Worker int slice, 2241*8975f5c5SAndroid Build Coastguard Worker const MTLRegion &mtlArea, 2242*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormat, 2243*8975f5c5SAndroid Build Coastguard Worker GLenum type, 2244*8975f5c5SAndroid Build Coastguard Worker const angle::Format &pixelsAngleFormat, 2245*8975f5c5SAndroid Build Coastguard Worker size_t pixelsRowPitch, 2246*8975f5c5SAndroid Build Coastguard Worker size_t pixelsDepthPitch, 2247*8975f5c5SAndroid Build Coastguard Worker gl::Buffer *unpackBuffer, 2248*8975f5c5SAndroid Build Coastguard Worker const uint8_t *pixels, 2249*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &image) 2250*8975f5c5SAndroid Build Coastguard Worker{ 2251*8975f5c5SAndroid Build Coastguard Worker // If source pixels are luminance or RGB8, we need to convert them to RGBA 2252*8975f5c5SAndroid Build Coastguard Worker 2253*8975f5c5SAndroid Build Coastguard Worker if (mFormat.needConversion(pixelsAngleFormat.id)) 2254*8975f5c5SAndroid Build Coastguard Worker { 2255*8975f5c5SAndroid Build Coastguard Worker return convertAndSetPerSliceSubImage(context, slice, mtlArea, internalFormat, type, 2256*8975f5c5SAndroid Build Coastguard Worker pixelsAngleFormat, pixelsRowPitch, pixelsDepthPitch, 2257*8975f5c5SAndroid Build Coastguard Worker unpackBuffer, pixels, image); 2258*8975f5c5SAndroid Build Coastguard Worker } 2259*8975f5c5SAndroid Build Coastguard Worker 2260*8975f5c5SAndroid Build Coastguard Worker // No conversion needed. 2261*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2262*8975f5c5SAndroid Build Coastguard Worker 2263*8975f5c5SAndroid Build Coastguard Worker if (unpackBuffer) 2264*8975f5c5SAndroid Build Coastguard Worker { 2265*8975f5c5SAndroid Build Coastguard Worker uintptr_t offset = reinterpret_cast<uintptr_t>(pixels); 2266*8975f5c5SAndroid Build Coastguard Worker GLuint minRowPitch; 2267*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_MATH(contextMtl, internalFormat.computeRowPitch( 2268*8975f5c5SAndroid Build Coastguard Worker type, static_cast<GLint>(mtlArea.size.width), 2269*8975f5c5SAndroid Build Coastguard Worker /** aligment */ 1, /** rowLength */ 0, &minRowPitch)); 2270*8975f5c5SAndroid Build Coastguard Worker if (offset % mFormat.actualAngleFormat().pixelBytes || pixelsRowPitch < minRowPitch) 2271*8975f5c5SAndroid Build Coastguard Worker { 2272*8975f5c5SAndroid Build Coastguard Worker // offset is not divisible by pixelByte or the source row pitch is smaller than minimum 2273*8975f5c5SAndroid Build Coastguard Worker // row pitch, use convertAndSetPerSliceSubImage() function. 2274*8975f5c5SAndroid Build Coastguard Worker return convertAndSetPerSliceSubImage(context, slice, mtlArea, internalFormat, type, 2275*8975f5c5SAndroid Build Coastguard Worker pixelsAngleFormat, pixelsRowPitch, 2276*8975f5c5SAndroid Build Coastguard Worker pixelsDepthPitch, unpackBuffer, pixels, image); 2277*8975f5c5SAndroid Build Coastguard Worker } 2278*8975f5c5SAndroid Build Coastguard Worker 2279*8975f5c5SAndroid Build Coastguard Worker BufferMtl *unpackBufferMtl = mtl::GetImpl(unpackBuffer); 2280*8975f5c5SAndroid Build Coastguard Worker 2281*8975f5c5SAndroid Build Coastguard Worker if (mFormat.hasDepthAndStencilBits()) 2282*8975f5c5SAndroid Build Coastguard Worker { 2283*8975f5c5SAndroid Build Coastguard Worker // NOTE(hqle): packed depth & stencil texture cannot copy from buffer directly, needs 2284*8975f5c5SAndroid Build Coastguard Worker // to split its depth & stencil data and copy separately. 2285*8975f5c5SAndroid Build Coastguard Worker const uint8_t *clientData = unpackBufferMtl->getBufferDataReadOnly(contextMtl); 2286*8975f5c5SAndroid Build Coastguard Worker clientData += offset; 2287*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadTextureContents(context, mFormat.actualAngleFormat(), mtlArea, 2288*8975f5c5SAndroid Build Coastguard Worker mtl::kZeroNativeMipLevel, slice, clientData, 2289*8975f5c5SAndroid Build Coastguard Worker pixelsRowPitch, pixelsDepthPitch, false, image)); 2290*8975f5c5SAndroid Build Coastguard Worker } 2291*8975f5c5SAndroid Build Coastguard Worker else 2292*8975f5c5SAndroid Build Coastguard Worker { 2293*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef sourceBuffer = unpackBufferMtl->getCurrentBuffer(); 2294*8975f5c5SAndroid Build Coastguard Worker // PVRTC1 blocks are stored in a reflected Morton order 2295*8975f5c5SAndroid Build Coastguard Worker // and need to be linearized for buffer uploads in Metal. 2296*8975f5c5SAndroid Build Coastguard Worker // This step is skipped for textures that have only one block. 2297*8975f5c5SAndroid Build Coastguard Worker if (mFormat.isPVRTC() && mtlArea.size.height > 4) 2298*8975f5c5SAndroid Build Coastguard Worker { 2299*8975f5c5SAndroid Build Coastguard Worker // PVRTC1 inherent requirement. 2300*8975f5c5SAndroid Build Coastguard Worker ASSERT(gl::isPow2(mtlArea.size.width) && gl::isPow2(mtlArea.size.height)); 2301*8975f5c5SAndroid Build Coastguard Worker // Metal-specific limitation enforced by ANGLE validation. 2302*8975f5c5SAndroid Build Coastguard Worker ASSERT(mtlArea.size.width == mtlArea.size.height); 2303*8975f5c5SAndroid Build Coastguard Worker static_assert(gl::IMPLEMENTATION_MAX_2D_TEXTURE_SIZE <= 262144, 2304*8975f5c5SAndroid Build Coastguard Worker "The current kernel can handle up to 65536 blocks per dimension."); 2305*8975f5c5SAndroid Build Coastguard Worker 2306*8975f5c5SAndroid Build Coastguard Worker // Current command buffer implementation does not support 64-bit offsets. 2307*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_CHECK(contextMtl, offset <= std::numeric_limits<uint32_t>::max(), 2308*8975f5c5SAndroid Build Coastguard Worker GL_INVALID_OPERATION); 2309*8975f5c5SAndroid Build Coastguard Worker 2310*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef stagingBuffer; 2311*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY( 2312*8975f5c5SAndroid Build Coastguard Worker mtl::Buffer::MakeBuffer(contextMtl, pixelsDepthPitch, nullptr, &stagingBuffer)); 2313*8975f5c5SAndroid Build Coastguard Worker 2314*8975f5c5SAndroid Build Coastguard Worker mtl::BlockLinearizationParams params; 2315*8975f5c5SAndroid Build Coastguard Worker params.srcBuffer = sourceBuffer; 2316*8975f5c5SAndroid Build Coastguard Worker params.dstBuffer = stagingBuffer; 2317*8975f5c5SAndroid Build Coastguard Worker params.srcBufferOffset = static_cast<uint32_t>(offset); 2318*8975f5c5SAndroid Build Coastguard Worker params.blocksWide = 2319*8975f5c5SAndroid Build Coastguard Worker static_cast<GLuint>(mtlArea.size.width) / internalFormat.compressedBlockWidth; 2320*8975f5c5SAndroid Build Coastguard Worker params.blocksHigh = 2321*8975f5c5SAndroid Build Coastguard Worker static_cast<GLuint>(mtlArea.size.height) / internalFormat.compressedBlockHeight; 2322*8975f5c5SAndroid Build Coastguard Worker 2323*8975f5c5SAndroid Build Coastguard Worker // PVRTC1 textures always have at least 2 blocks in each dimension. 2324*8975f5c5SAndroid Build Coastguard Worker // Enforce correct block layout for 8x8 textures that use 8x4 blocks. 2325*8975f5c5SAndroid Build Coastguard Worker params.blocksWide = std::max(params.blocksWide, 2u); 2326*8975f5c5SAndroid Build Coastguard Worker 2327*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(contextMtl->getDisplay()->getUtils().linearizeBlocks(contextMtl, params)); 2328*8975f5c5SAndroid Build Coastguard Worker 2329*8975f5c5SAndroid Build Coastguard Worker sourceBuffer = stagingBuffer; 2330*8975f5c5SAndroid Build Coastguard Worker offset = 0; 2331*8975f5c5SAndroid Build Coastguard Worker } 2332*8975f5c5SAndroid Build Coastguard Worker else if (pixelsAngleFormat.id == angle::FormatID::D32_FLOAT) 2333*8975f5c5SAndroid Build Coastguard Worker { 2334*8975f5c5SAndroid Build Coastguard Worker // Current command buffer implementation does not support 64-bit offsets. 2335*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_CHECK(contextMtl, offset <= std::numeric_limits<uint32_t>::max(), 2336*8975f5c5SAndroid Build Coastguard Worker GL_INVALID_OPERATION); 2337*8975f5c5SAndroid Build Coastguard Worker 2338*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef stagingBuffer; 2339*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY( 2340*8975f5c5SAndroid Build Coastguard Worker mtl::Buffer::MakeBuffer(contextMtl, pixelsDepthPitch, nullptr, &stagingBuffer)); 2341*8975f5c5SAndroid Build Coastguard Worker 2342*8975f5c5SAndroid Build Coastguard Worker ASSERT(pixelsAngleFormat.pixelBytes == 4 && offset % 4 == 0); 2343*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(SaturateDepth(contextMtl, sourceBuffer, stagingBuffer, 2344*8975f5c5SAndroid Build Coastguard Worker static_cast<uint32_t>(offset), 2345*8975f5c5SAndroid Build Coastguard Worker static_cast<uint32_t>(pixelsRowPitch) / 4, mtlArea.size)); 2346*8975f5c5SAndroid Build Coastguard Worker 2347*8975f5c5SAndroid Build Coastguard Worker sourceBuffer = stagingBuffer; 2348*8975f5c5SAndroid Build Coastguard Worker offset = 0; 2349*8975f5c5SAndroid Build Coastguard Worker } 2350*8975f5c5SAndroid Build Coastguard Worker 2351*8975f5c5SAndroid Build Coastguard Worker // Use blit encoder to copy 2352*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *blitEncoder = 2353*8975f5c5SAndroid Build Coastguard Worker GetBlitCommandEncoderForResources(contextMtl, {sourceBuffer.get(), image.get()}); 2354*8975f5c5SAndroid Build Coastguard Worker CopyBufferToOriginalTextureIfDstIsAView( 2355*8975f5c5SAndroid Build Coastguard Worker contextMtl, blitEncoder, sourceBuffer, offset, pixelsRowPitch, pixelsDepthPitch, 2356*8975f5c5SAndroid Build Coastguard Worker mtlArea.size, image, slice, mtl::kZeroNativeMipLevel, mtlArea.origin, 2357*8975f5c5SAndroid Build Coastguard Worker mFormat.isPVRTC() ? MTLBlitOptionRowLinearPVRTC : MTLBlitOptionNone); 2358*8975f5c5SAndroid Build Coastguard Worker } 2359*8975f5c5SAndroid Build Coastguard Worker } 2360*8975f5c5SAndroid Build Coastguard Worker else 2361*8975f5c5SAndroid Build Coastguard Worker { 2362*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadTextureContents(context, mFormat.actualAngleFormat(), mtlArea, 2363*8975f5c5SAndroid Build Coastguard Worker mtl::kZeroNativeMipLevel, slice, pixels, pixelsRowPitch, 2364*8975f5c5SAndroid Build Coastguard Worker pixelsDepthPitch, false, image)); 2365*8975f5c5SAndroid Build Coastguard Worker } 2366*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2367*8975f5c5SAndroid Build Coastguard Worker} 2368*8975f5c5SAndroid Build Coastguard Worker 2369*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::convertAndSetPerSliceSubImage(const gl::Context *context, 2370*8975f5c5SAndroid Build Coastguard Worker int slice, 2371*8975f5c5SAndroid Build Coastguard Worker const MTLRegion &mtlArea, 2372*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormat, 2373*8975f5c5SAndroid Build Coastguard Worker GLenum type, 2374*8975f5c5SAndroid Build Coastguard Worker const angle::Format &pixelsAngleFormat, 2375*8975f5c5SAndroid Build Coastguard Worker size_t pixelsRowPitch, 2376*8975f5c5SAndroid Build Coastguard Worker size_t pixelsDepthPitch, 2377*8975f5c5SAndroid Build Coastguard Worker gl::Buffer *unpackBuffer, 2378*8975f5c5SAndroid Build Coastguard Worker const uint8_t *pixels, 2379*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &image) 2380*8975f5c5SAndroid Build Coastguard Worker{ 2381*8975f5c5SAndroid Build Coastguard Worker ASSERT(image && image->valid()); 2382*8975f5c5SAndroid Build Coastguard Worker 2383*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2384*8975f5c5SAndroid Build Coastguard Worker 2385*8975f5c5SAndroid Build Coastguard Worker if (unpackBuffer) 2386*8975f5c5SAndroid Build Coastguard Worker { 2387*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_CHECK(contextMtl, 2388*8975f5c5SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(pixels) <= std::numeric_limits<uint32_t>::max(), 2389*8975f5c5SAndroid Build Coastguard Worker GL_INVALID_OPERATION); 2390*8975f5c5SAndroid Build Coastguard Worker 2391*8975f5c5SAndroid Build Coastguard Worker uint32_t offset = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pixels)); 2392*8975f5c5SAndroid Build Coastguard Worker 2393*8975f5c5SAndroid Build Coastguard Worker BufferMtl *unpackBufferMtl = mtl::GetImpl(unpackBuffer); 2394*8975f5c5SAndroid Build Coastguard Worker if (!mFormat.getCaps().writable || mFormat.hasDepthOrStencilBits() || 2395*8975f5c5SAndroid Build Coastguard Worker mFormat.intendedAngleFormat().isBlock) 2396*8975f5c5SAndroid Build Coastguard Worker { 2397*8975f5c5SAndroid Build Coastguard Worker // Unsupported format, use CPU path. 2398*8975f5c5SAndroid Build Coastguard Worker const uint8_t *clientData = unpackBufferMtl->getBufferDataReadOnly(contextMtl); 2399*8975f5c5SAndroid Build Coastguard Worker clientData += offset; 2400*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(convertAndSetPerSliceSubImage(context, slice, mtlArea, internalFormat, type, 2401*8975f5c5SAndroid Build Coastguard Worker pixelsAngleFormat, pixelsRowPitch, 2402*8975f5c5SAndroid Build Coastguard Worker pixelsDepthPitch, nullptr, clientData, image)); 2403*8975f5c5SAndroid Build Coastguard Worker } 2404*8975f5c5SAndroid Build Coastguard Worker else 2405*8975f5c5SAndroid Build Coastguard Worker { 2406*8975f5c5SAndroid Build Coastguard Worker // Use compute shader 2407*8975f5c5SAndroid Build Coastguard Worker mtl::CopyPixelsFromBufferParams params; 2408*8975f5c5SAndroid Build Coastguard Worker params.buffer = unpackBufferMtl->getCurrentBuffer(); 2409*8975f5c5SAndroid Build Coastguard Worker params.bufferStartOffset = offset; 2410*8975f5c5SAndroid Build Coastguard Worker params.bufferRowPitch = static_cast<uint32_t>(pixelsRowPitch); 2411*8975f5c5SAndroid Build Coastguard Worker params.bufferDepthPitch = static_cast<uint32_t>(pixelsDepthPitch); 2412*8975f5c5SAndroid Build Coastguard Worker params.texture = image; 2413*8975f5c5SAndroid Build Coastguard Worker params.textureArea = mtl::MTLRegionToGLBox(mtlArea); 2414*8975f5c5SAndroid Build Coastguard Worker 2415*8975f5c5SAndroid Build Coastguard Worker // If texture is not array, slice must be zero, if texture is array, mtlArea.origin.z 2416*8975f5c5SAndroid Build Coastguard Worker // must be zero. 2417*8975f5c5SAndroid Build Coastguard Worker // This is because this function uses Metal convention: where slice is only used for 2418*8975f5c5SAndroid Build Coastguard Worker // array textures, and z layer of mtlArea.origin is only used for 3D textures. 2419*8975f5c5SAndroid Build Coastguard Worker ASSERT(slice == 0 || params.textureArea.z == 0); 2420*8975f5c5SAndroid Build Coastguard Worker 2421*8975f5c5SAndroid Build Coastguard Worker // For mtl::RenderUtils we convert to OpenGL convention: z layer is used as either array 2422*8975f5c5SAndroid Build Coastguard Worker // texture's slice or 3D texture's layer index. 2423*8975f5c5SAndroid Build Coastguard Worker params.textureArea.z += slice; 2424*8975f5c5SAndroid Build Coastguard Worker 2425*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(contextMtl->getDisplay()->getUtils().unpackPixelsFromBufferToTexture( 2426*8975f5c5SAndroid Build Coastguard Worker contextMtl, pixelsAngleFormat, params)); 2427*8975f5c5SAndroid Build Coastguard Worker } 2428*8975f5c5SAndroid Build Coastguard Worker } // if (unpackBuffer) 2429*8975f5c5SAndroid Build Coastguard Worker else 2430*8975f5c5SAndroid Build Coastguard Worker { 2431*8975f5c5SAndroid Build Coastguard Worker LoadImageFunctionInfo loadFunctionInfo = mFormat.textureLoadFunctions 2432*8975f5c5SAndroid Build Coastguard Worker ? mFormat.textureLoadFunctions(type) 2433*8975f5c5SAndroid Build Coastguard Worker : LoadImageFunctionInfo(); 2434*8975f5c5SAndroid Build Coastguard Worker const angle::Format &dstFormat = angle::Format::Get(mFormat.actualFormatId); 2435*8975f5c5SAndroid Build Coastguard Worker const size_t dstRowPitch = dstFormat.pixelBytes * mtlArea.size.width; 2436*8975f5c5SAndroid Build Coastguard Worker 2437*8975f5c5SAndroid Build Coastguard Worker // It is very important to avoid allocating a new buffer for each row during these 2438*8975f5c5SAndroid Build Coastguard Worker // uploads. 2439*8975f5c5SAndroid Build Coastguard Worker const bool kAvoidStagingBuffers = true; 2440*8975f5c5SAndroid Build Coastguard Worker 2441*8975f5c5SAndroid Build Coastguard Worker // Check if original image data is compressed: 2442*8975f5c5SAndroid Build Coastguard Worker if (mFormat.intendedAngleFormat().isBlock) 2443*8975f5c5SAndroid Build Coastguard Worker { 2444*8975f5c5SAndroid Build Coastguard Worker if (mFormat.intendedFormatId != mFormat.actualFormatId) 2445*8975f5c5SAndroid Build Coastguard Worker { 2446*8975f5c5SAndroid Build Coastguard Worker ASSERT(loadFunctionInfo.loadFunction); 2447*8975f5c5SAndroid Build Coastguard Worker 2448*8975f5c5SAndroid Build Coastguard Worker // Need to create a buffer to hold entire decompressed image. 2449*8975f5c5SAndroid Build Coastguard Worker const size_t dstDepthPitch = dstRowPitch * mtlArea.size.height; 2450*8975f5c5SAndroid Build Coastguard Worker angle::MemoryBuffer decompressBuf; 2451*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_ALLOC(contextMtl, 2452*8975f5c5SAndroid Build Coastguard Worker decompressBuf.resize(dstDepthPitch * mtlArea.size.depth)); 2453*8975f5c5SAndroid Build Coastguard Worker 2454*8975f5c5SAndroid Build Coastguard Worker // Decompress 2455*8975f5c5SAndroid Build Coastguard Worker loadFunctionInfo.loadFunction(contextMtl->getImageLoadContext(), mtlArea.size.width, 2456*8975f5c5SAndroid Build Coastguard Worker mtlArea.size.height, mtlArea.size.depth, pixels, 2457*8975f5c5SAndroid Build Coastguard Worker pixelsRowPitch, pixelsDepthPitch, 2458*8975f5c5SAndroid Build Coastguard Worker decompressBuf.data(), dstRowPitch, dstDepthPitch); 2459*8975f5c5SAndroid Build Coastguard Worker 2460*8975f5c5SAndroid Build Coastguard Worker // Upload to texture 2461*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadTextureContents( 2462*8975f5c5SAndroid Build Coastguard Worker context, dstFormat, mtlArea, mtl::kZeroNativeMipLevel, slice, 2463*8975f5c5SAndroid Build Coastguard Worker decompressBuf.data(), dstRowPitch, dstDepthPitch, kAvoidStagingBuffers, image)); 2464*8975f5c5SAndroid Build Coastguard Worker } 2465*8975f5c5SAndroid Build Coastguard Worker else 2466*8975f5c5SAndroid Build Coastguard Worker { 2467*8975f5c5SAndroid Build Coastguard Worker // Assert that we're filling the level in it's entierety. 2468*8975f5c5SAndroid Build Coastguard Worker ASSERT(mtlArea.size.width == static_cast<unsigned int>(image->sizeAt0().width)); 2469*8975f5c5SAndroid Build Coastguard Worker ASSERT(mtlArea.size.height == static_cast<unsigned int>(image->sizeAt0().height)); 2470*8975f5c5SAndroid Build Coastguard Worker const size_t dstDepthPitch = dstRowPitch * mtlArea.size.height; 2471*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadTextureContents( 2472*8975f5c5SAndroid Build Coastguard Worker context, dstFormat, mtlArea, mtl::kZeroNativeMipLevel, slice, pixels, 2473*8975f5c5SAndroid Build Coastguard Worker dstRowPitch, dstDepthPitch, kAvoidStagingBuffers, image)); 2474*8975f5c5SAndroid Build Coastguard Worker } 2475*8975f5c5SAndroid Build Coastguard Worker } // if (mFormat.intendedAngleFormat().isBlock) 2476*8975f5c5SAndroid Build Coastguard Worker else 2477*8975f5c5SAndroid Build Coastguard Worker { 2478*8975f5c5SAndroid Build Coastguard Worker // Create scratch row buffer 2479*8975f5c5SAndroid Build Coastguard Worker angle::MemoryBuffer conversionRow; 2480*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_ALLOC(contextMtl, conversionRow.resize(dstRowPitch)); 2481*8975f5c5SAndroid Build Coastguard Worker 2482*8975f5c5SAndroid Build Coastguard Worker // Convert row by row: 2483*8975f5c5SAndroid Build Coastguard Worker MTLRegion mtlRow = mtlArea; 2484*8975f5c5SAndroid Build Coastguard Worker mtlRow.size.height = mtlRow.size.depth = 1; 2485*8975f5c5SAndroid Build Coastguard Worker for (NSUInteger d = 0; d < mtlArea.size.depth; ++d) 2486*8975f5c5SAndroid Build Coastguard Worker { 2487*8975f5c5SAndroid Build Coastguard Worker mtlRow.origin.z = mtlArea.origin.z + d; 2488*8975f5c5SAndroid Build Coastguard Worker for (NSUInteger r = 0; r < mtlArea.size.height; ++r) 2489*8975f5c5SAndroid Build Coastguard Worker { 2490*8975f5c5SAndroid Build Coastguard Worker const uint8_t *psrc = pixels + d * pixelsDepthPitch + r * pixelsRowPitch; 2491*8975f5c5SAndroid Build Coastguard Worker mtlRow.origin.y = mtlArea.origin.y + r; 2492*8975f5c5SAndroid Build Coastguard Worker 2493*8975f5c5SAndroid Build Coastguard Worker // Convert pixels 2494*8975f5c5SAndroid Build Coastguard Worker if (loadFunctionInfo.loadFunction) 2495*8975f5c5SAndroid Build Coastguard Worker { 2496*8975f5c5SAndroid Build Coastguard Worker loadFunctionInfo.loadFunction(contextMtl->getImageLoadContext(), 2497*8975f5c5SAndroid Build Coastguard Worker mtlRow.size.width, 1, 1, psrc, pixelsRowPitch, 2498*8975f5c5SAndroid Build Coastguard Worker 0, conversionRow.data(), dstRowPitch, 0); 2499*8975f5c5SAndroid Build Coastguard Worker } 2500*8975f5c5SAndroid Build Coastguard Worker else if (mFormat.hasDepthOrStencilBits()) 2501*8975f5c5SAndroid Build Coastguard Worker { 2502*8975f5c5SAndroid Build Coastguard Worker ConvertDepthStencilData(mtlRow.size, pixelsAngleFormat, pixelsRowPitch, 0, 2503*8975f5c5SAndroid Build Coastguard Worker psrc, dstFormat, nullptr, dstRowPitch, 0, 2504*8975f5c5SAndroid Build Coastguard Worker conversionRow.data()); 2505*8975f5c5SAndroid Build Coastguard Worker } 2506*8975f5c5SAndroid Build Coastguard Worker else 2507*8975f5c5SAndroid Build Coastguard Worker { 2508*8975f5c5SAndroid Build Coastguard Worker CopyImageCHROMIUM(psrc, pixelsRowPitch, pixelsAngleFormat.pixelBytes, 0, 2509*8975f5c5SAndroid Build Coastguard Worker pixelsAngleFormat.pixelReadFunction, conversionRow.data(), 2510*8975f5c5SAndroid Build Coastguard Worker dstRowPitch, dstFormat.pixelBytes, 0, 2511*8975f5c5SAndroid Build Coastguard Worker dstFormat.pixelWriteFunction, internalFormat.format, 2512*8975f5c5SAndroid Build Coastguard Worker dstFormat.componentType, mtlRow.size.width, 1, 1, false, 2513*8975f5c5SAndroid Build Coastguard Worker false, false); 2514*8975f5c5SAndroid Build Coastguard Worker } 2515*8975f5c5SAndroid Build Coastguard Worker 2516*8975f5c5SAndroid Build Coastguard Worker // Upload to texture 2517*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadTextureContents( 2518*8975f5c5SAndroid Build Coastguard Worker context, dstFormat, mtlRow, mtl::kZeroNativeMipLevel, slice, 2519*8975f5c5SAndroid Build Coastguard Worker conversionRow.data(), dstRowPitch, 0, kAvoidStagingBuffers, image)); 2520*8975f5c5SAndroid Build Coastguard Worker } 2521*8975f5c5SAndroid Build Coastguard Worker } 2522*8975f5c5SAndroid Build Coastguard Worker } // if (mFormat.intendedAngleFormat().isBlock) 2523*8975f5c5SAndroid Build Coastguard Worker } // if (unpackBuffer) 2524*8975f5c5SAndroid Build Coastguard Worker 2525*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2526*8975f5c5SAndroid Build Coastguard Worker} 2527*8975f5c5SAndroid Build Coastguard Worker 2528*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::checkForEmulatedChannels(const gl::Context *context, 2529*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &mtlFormat, 2530*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &texture) 2531*8975f5c5SAndroid Build Coastguard Worker{ 2532*8975f5c5SAndroid Build Coastguard Worker bool emulatedChannels = mtl::IsFormatEmulated(mtlFormat); 2533*8975f5c5SAndroid Build Coastguard Worker 2534*8975f5c5SAndroid Build Coastguard Worker // For emulated channels that GL texture intends to not have, 2535*8975f5c5SAndroid Build Coastguard Worker // we need to initialize their content. 2536*8975f5c5SAndroid Build Coastguard Worker if (emulatedChannels) 2537*8975f5c5SAndroid Build Coastguard Worker { 2538*8975f5c5SAndroid Build Coastguard Worker uint32_t mipmaps = texture->mipmapLevels(); 2539*8975f5c5SAndroid Build Coastguard Worker 2540*8975f5c5SAndroid Build Coastguard Worker uint32_t layers = texture->cubeFacesOrArrayLength(); 2541*8975f5c5SAndroid Build Coastguard Worker for (uint32_t layer = 0; layer < layers; ++layer) 2542*8975f5c5SAndroid Build Coastguard Worker { 2543*8975f5c5SAndroid Build Coastguard Worker for (uint32_t mip = 0; mip < mipmaps; ++mip) 2544*8975f5c5SAndroid Build Coastguard Worker { 2545*8975f5c5SAndroid Build Coastguard Worker auto index = mtl::ImageNativeIndex::FromBaseZeroGLIndex( 2546*8975f5c5SAndroid Build Coastguard Worker GetCubeOrArraySliceMipIndex(texture, layer, mip)); 2547*8975f5c5SAndroid Build Coastguard Worker 2548*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::InitializeTextureContents(context, texture, mtlFormat, index)); 2549*8975f5c5SAndroid Build Coastguard Worker } 2550*8975f5c5SAndroid Build Coastguard Worker } 2551*8975f5c5SAndroid Build Coastguard Worker } 2552*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2553*8975f5c5SAndroid Build Coastguard Worker} 2554*8975f5c5SAndroid Build Coastguard Worker 2555*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::initializeContents(const gl::Context *context, 2556*8975f5c5SAndroid Build Coastguard Worker GLenum binding, 2557*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index) 2558*8975f5c5SAndroid Build Coastguard Worker{ 2559*8975f5c5SAndroid Build Coastguard Worker if (index.isLayered()) 2560*8975f5c5SAndroid Build Coastguard Worker { 2561*8975f5c5SAndroid Build Coastguard Worker // InitializeTextureContents is only able to initialize one layer at a time. 2562*8975f5c5SAndroid Build Coastguard Worker const gl::ImageDesc &desc = mState.getImageDesc(index); 2563*8975f5c5SAndroid Build Coastguard Worker uint32_t layerCount; 2564*8975f5c5SAndroid Build Coastguard Worker if (index.isEntireLevelCubeMap()) 2565*8975f5c5SAndroid Build Coastguard Worker { 2566*8975f5c5SAndroid Build Coastguard Worker layerCount = 6; 2567*8975f5c5SAndroid Build Coastguard Worker } 2568*8975f5c5SAndroid Build Coastguard Worker else 2569*8975f5c5SAndroid Build Coastguard Worker { 2570*8975f5c5SAndroid Build Coastguard Worker layerCount = desc.size.depth; 2571*8975f5c5SAndroid Build Coastguard Worker } 2572*8975f5c5SAndroid Build Coastguard Worker 2573*8975f5c5SAndroid Build Coastguard Worker gl::ImageIndexIterator ite = index.getLayerIterator(layerCount); 2574*8975f5c5SAndroid Build Coastguard Worker while (ite.hasNext()) 2575*8975f5c5SAndroid Build Coastguard Worker { 2576*8975f5c5SAndroid Build Coastguard Worker gl::ImageIndex layerIndex = ite.next(); 2577*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(initializeContents(context, GL_NONE, layerIndex)); 2578*8975f5c5SAndroid Build Coastguard Worker } 2579*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2580*8975f5c5SAndroid Build Coastguard Worker } 2581*8975f5c5SAndroid Build Coastguard Worker else if (index.getLayerCount() > 1) 2582*8975f5c5SAndroid Build Coastguard Worker { 2583*8975f5c5SAndroid Build Coastguard Worker for (int layer = 0; layer < index.getLayerCount(); ++layer) 2584*8975f5c5SAndroid Build Coastguard Worker { 2585*8975f5c5SAndroid Build Coastguard Worker int layerIdx = layer + index.getLayerIndex(); 2586*8975f5c5SAndroid Build Coastguard Worker gl::ImageIndex layerIndex = 2587*8975f5c5SAndroid Build Coastguard Worker gl::ImageIndex::MakeFromType(index.getType(), index.getLevelIndex(), layerIdx); 2588*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(initializeContents(context, GL_NONE, layerIndex)); 2589*8975f5c5SAndroid Build Coastguard Worker } 2590*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2591*8975f5c5SAndroid Build Coastguard Worker } 2592*8975f5c5SAndroid Build Coastguard Worker 2593*8975f5c5SAndroid Build Coastguard Worker ASSERT(index.getLayerCount() == 1 && !index.isLayered()); 2594*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureImageCreated(context, index)); 2595*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2596*8975f5c5SAndroid Build Coastguard Worker ImageDefinitionMtl &imageDef = getImageDefinition(index); 2597*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &image = imageDef.image; 2598*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &format = contextMtl->getPixelFormat(imageDef.formatID); 2599*8975f5c5SAndroid Build Coastguard Worker // For Texture's image definition, we always use zero mip level. 2600*8975f5c5SAndroid Build Coastguard Worker if (format.metalFormat == MTLPixelFormatInvalid) 2601*8975f5c5SAndroid Build Coastguard Worker { 2602*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Stop; 2603*8975f5c5SAndroid Build Coastguard Worker } 2604*8975f5c5SAndroid Build Coastguard Worker return mtl::InitializeTextureContents( 2605*8975f5c5SAndroid Build Coastguard Worker context, image, format, 2606*8975f5c5SAndroid Build Coastguard Worker mtl::ImageNativeIndex::FromBaseZeroGLIndex( 2607*8975f5c5SAndroid Build Coastguard Worker GetLayerMipIndex(image, GetImageLayerIndexFrom(index), /** level */ 0))); 2608*8975f5c5SAndroid Build Coastguard Worker} 2609*8975f5c5SAndroid Build Coastguard Worker 2610*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubImageImpl(const gl::Context *context, 2611*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 2612*8975f5c5SAndroid Build Coastguard Worker const gl::Offset &destOffset, 2613*8975f5c5SAndroid Build Coastguard Worker const gl::Rectangle &sourceArea, 2614*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormat, 2615*8975f5c5SAndroid Build Coastguard Worker const FramebufferMtl *source, 2616*8975f5c5SAndroid Build Coastguard Worker const RenderTargetMtl *colorReadRT) 2617*8975f5c5SAndroid Build Coastguard Worker{ 2618*8975f5c5SAndroid Build Coastguard Worker if (!colorReadRT || !colorReadRT->getTexture()) 2619*8975f5c5SAndroid Build Coastguard Worker { 2620*8975f5c5SAndroid Build Coastguard Worker // Is this an error? 2621*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2622*8975f5c5SAndroid Build Coastguard Worker } 2623*8975f5c5SAndroid Build Coastguard Worker 2624*8975f5c5SAndroid Build Coastguard Worker gl::Extents fbSize = colorReadRT->getTexture()->size(colorReadRT->getLevelIndex()); 2625*8975f5c5SAndroid Build Coastguard Worker gl::Rectangle clippedSourceArea; 2626*8975f5c5SAndroid Build Coastguard Worker if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), 2627*8975f5c5SAndroid Build Coastguard Worker &clippedSourceArea)) 2628*8975f5c5SAndroid Build Coastguard Worker { 2629*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2630*8975f5c5SAndroid Build Coastguard Worker } 2631*8975f5c5SAndroid Build Coastguard Worker 2632*8975f5c5SAndroid Build Coastguard Worker // If negative offsets are given, clippedSourceArea ensures we don't read from those offsets. 2633*8975f5c5SAndroid Build Coastguard Worker // However, that changes the sourceOffset->destOffset mapping. Here, destOffset is shifted by 2634*8975f5c5SAndroid Build Coastguard Worker // the same amount as clipped to correct the error. 2635*8975f5c5SAndroid Build Coastguard Worker const gl::Offset modifiedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, 2636*8975f5c5SAndroid Build Coastguard Worker destOffset.y + clippedSourceArea.y - sourceArea.y, 0); 2637*8975f5c5SAndroid Build Coastguard Worker 2638*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureImageCreated(context, index)); 2639*8975f5c5SAndroid Build Coastguard Worker 2640*8975f5c5SAndroid Build Coastguard Worker if (!mFormat.getCaps().isRenderable()) 2641*8975f5c5SAndroid Build Coastguard Worker { 2642*8975f5c5SAndroid Build Coastguard Worker return copySubImageCPU(context, index, modifiedDestOffset, clippedSourceArea, 2643*8975f5c5SAndroid Build Coastguard Worker internalFormat, source, colorReadRT); 2644*8975f5c5SAndroid Build Coastguard Worker } 2645*8975f5c5SAndroid Build Coastguard Worker 2646*8975f5c5SAndroid Build Coastguard Worker // NOTE(hqle): Use compute shader. 2647*8975f5c5SAndroid Build Coastguard Worker return copySubImageWithDraw(context, index, modifiedDestOffset, clippedSourceArea, 2648*8975f5c5SAndroid Build Coastguard Worker internalFormat, source, colorReadRT); 2649*8975f5c5SAndroid Build Coastguard Worker} 2650*8975f5c5SAndroid Build Coastguard Worker 2651*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context, 2652*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 2653*8975f5c5SAndroid Build Coastguard Worker const gl::Offset &modifiedDestOffset, 2654*8975f5c5SAndroid Build Coastguard Worker const gl::Rectangle &clippedSourceArea, 2655*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormat, 2656*8975f5c5SAndroid Build Coastguard Worker const FramebufferMtl *source, 2657*8975f5c5SAndroid Build Coastguard Worker const RenderTargetMtl *colorReadRT) 2658*8975f5c5SAndroid Build Coastguard Worker{ 2659*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2660*8975f5c5SAndroid Build Coastguard Worker DisplayMtl *displayMtl = contextMtl->getDisplay(); 2661*8975f5c5SAndroid Build Coastguard Worker 2662*8975f5c5SAndroid Build Coastguard Worker RenderTargetMtl *imageRtt; 2663*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(getRenderTarget(contextMtl, index, /*implicitSamples=*/0, &imageRtt)); 2664*8975f5c5SAndroid Build Coastguard Worker 2665*8975f5c5SAndroid Build Coastguard Worker mtl::RenderCommandEncoder *cmdEncoder = contextMtl->getRenderTargetCommandEncoder(*imageRtt); 2666*8975f5c5SAndroid Build Coastguard Worker mtl::ColorBlitParams blitParams; 2667*8975f5c5SAndroid Build Coastguard Worker 2668*8975f5c5SAndroid Build Coastguard Worker blitParams.dstTextureSize = imageRtt->getTexture()->size(imageRtt->getLevelIndex()); 2669*8975f5c5SAndroid Build Coastguard Worker blitParams.dstRect = gl::Rectangle(modifiedDestOffset.x, modifiedDestOffset.y, 2670*8975f5c5SAndroid Build Coastguard Worker clippedSourceArea.width, clippedSourceArea.height); 2671*8975f5c5SAndroid Build Coastguard Worker blitParams.dstScissorRect = blitParams.dstRect; 2672*8975f5c5SAndroid Build Coastguard Worker 2673*8975f5c5SAndroid Build Coastguard Worker blitParams.enabledBuffers.set(0); 2674*8975f5c5SAndroid Build Coastguard Worker 2675*8975f5c5SAndroid Build Coastguard Worker blitParams.src = colorReadRT->getTexture(); 2676*8975f5c5SAndroid Build Coastguard Worker blitParams.srcLevel = colorReadRT->getLevelIndex(); 2677*8975f5c5SAndroid Build Coastguard Worker blitParams.srcLayer = colorReadRT->getLayerIndex(); 2678*8975f5c5SAndroid Build Coastguard Worker 2679*8975f5c5SAndroid Build Coastguard Worker blitParams.srcNormalizedCoords = mtl::NormalizedCoords( 2680*8975f5c5SAndroid Build Coastguard Worker clippedSourceArea, colorReadRT->getTexture()->size(blitParams.srcLevel)); 2681*8975f5c5SAndroid Build Coastguard Worker blitParams.srcYFlipped = source->flipY(); 2682*8975f5c5SAndroid Build Coastguard Worker blitParams.dstLuminance = internalFormat.isLUMA(); 2683*8975f5c5SAndroid Build Coastguard Worker 2684*8975f5c5SAndroid Build Coastguard Worker return displayMtl->getUtils().blitColorWithDraw( 2685*8975f5c5SAndroid Build Coastguard Worker context, cmdEncoder, colorReadRT->getFormat().actualAngleFormat(), blitParams); 2686*8975f5c5SAndroid Build Coastguard Worker} 2687*8975f5c5SAndroid Build Coastguard Worker 2688*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubImageCPU(const gl::Context *context, 2689*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 2690*8975f5c5SAndroid Build Coastguard Worker const gl::Offset &modifiedDestOffset, 2691*8975f5c5SAndroid Build Coastguard Worker const gl::Rectangle &clippedSourceArea, 2692*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormat, 2693*8975f5c5SAndroid Build Coastguard Worker const FramebufferMtl *source, 2694*8975f5c5SAndroid Build Coastguard Worker const RenderTargetMtl *colorReadRT) 2695*8975f5c5SAndroid Build Coastguard Worker{ 2696*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef &image = getImage(index); 2697*8975f5c5SAndroid Build Coastguard Worker ASSERT(image && image->valid()); 2698*8975f5c5SAndroid Build Coastguard Worker 2699*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2700*8975f5c5SAndroid Build Coastguard Worker 2701*8975f5c5SAndroid Build Coastguard Worker const angle::Format &dstFormat = angle::Format::Get(mFormat.actualFormatId); 2702*8975f5c5SAndroid Build Coastguard Worker const int dstRowPitch = dstFormat.pixelBytes * clippedSourceArea.width; 2703*8975f5c5SAndroid Build Coastguard Worker angle::MemoryBuffer conversionRow; 2704*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_ALLOC(contextMtl, conversionRow.resize(dstRowPitch)); 2705*8975f5c5SAndroid Build Coastguard Worker 2706*8975f5c5SAndroid Build Coastguard Worker gl::Rectangle srcRowArea = gl::Rectangle(clippedSourceArea.x, 0, clippedSourceArea.width, 1); 2707*8975f5c5SAndroid Build Coastguard Worker MTLRegion mtlDstRowArea = MTLRegionMake2D(modifiedDestOffset.x, 0, clippedSourceArea.width, 1); 2708*8975f5c5SAndroid Build Coastguard Worker uint32_t dstSlice = 0; 2709*8975f5c5SAndroid Build Coastguard Worker switch (index.getType()) 2710*8975f5c5SAndroid Build Coastguard Worker { 2711*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2D: 2712*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::CubeMap: 2713*8975f5c5SAndroid Build Coastguard Worker dstSlice = 0; 2714*8975f5c5SAndroid Build Coastguard Worker break; 2715*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_2DArray: 2716*8975f5c5SAndroid Build Coastguard Worker ASSERT(index.hasLayer()); 2717*8975f5c5SAndroid Build Coastguard Worker dstSlice = index.getLayerIndex(); 2718*8975f5c5SAndroid Build Coastguard Worker break; 2719*8975f5c5SAndroid Build Coastguard Worker case gl::TextureType::_3D: 2720*8975f5c5SAndroid Build Coastguard Worker ASSERT(index.hasLayer()); 2721*8975f5c5SAndroid Build Coastguard Worker dstSlice = 0; 2722*8975f5c5SAndroid Build Coastguard Worker mtlDstRowArea.origin.z = index.getLayerIndex(); 2723*8975f5c5SAndroid Build Coastguard Worker break; 2724*8975f5c5SAndroid Build Coastguard Worker default: 2725*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 2726*8975f5c5SAndroid Build Coastguard Worker } 2727*8975f5c5SAndroid Build Coastguard Worker 2728*8975f5c5SAndroid Build Coastguard Worker // It is very important to avoid allocating a new buffer for each row during these 2729*8975f5c5SAndroid Build Coastguard Worker // uploads. 2730*8975f5c5SAndroid Build Coastguard Worker const bool kAvoidStagingBuffers = true; 2731*8975f5c5SAndroid Build Coastguard Worker 2732*8975f5c5SAndroid Build Coastguard Worker // Copy row by row: 2733*8975f5c5SAndroid Build Coastguard Worker for (int r = 0; r < clippedSourceArea.height; ++r) 2734*8975f5c5SAndroid Build Coastguard Worker { 2735*8975f5c5SAndroid Build Coastguard Worker mtlDstRowArea.origin.y = modifiedDestOffset.y + r; 2736*8975f5c5SAndroid Build Coastguard Worker srcRowArea.y = clippedSourceArea.y + r; 2737*8975f5c5SAndroid Build Coastguard Worker 2738*8975f5c5SAndroid Build Coastguard Worker PackPixelsParams packParams(srcRowArea, dstFormat, dstRowPitch, false, nullptr, 0); 2739*8975f5c5SAndroid Build Coastguard Worker 2740*8975f5c5SAndroid Build Coastguard Worker // Read pixels from framebuffer to memory: 2741*8975f5c5SAndroid Build Coastguard Worker gl::Rectangle flippedSrcRowArea = source->getCorrectFlippedReadArea(context, srcRowArea); 2742*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(source->readPixelsImpl(context, flippedSrcRowArea, packParams, colorReadRT, 2743*8975f5c5SAndroid Build Coastguard Worker conversionRow.data())); 2744*8975f5c5SAndroid Build Coastguard Worker 2745*8975f5c5SAndroid Build Coastguard Worker // Upload to texture 2746*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadTextureContents(context, dstFormat, mtlDstRowArea, mtl::kZeroNativeMipLevel, 2747*8975f5c5SAndroid Build Coastguard Worker dstSlice, conversionRow.data(), dstRowPitch, 0, 2748*8975f5c5SAndroid Build Coastguard Worker kAvoidStagingBuffers, image)); 2749*8975f5c5SAndroid Build Coastguard Worker } 2750*8975f5c5SAndroid Build Coastguard Worker 2751*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2752*8975f5c5SAndroid Build Coastguard Worker} 2753*8975f5c5SAndroid Build Coastguard Worker 2754*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubTextureImpl(const gl::Context *context, 2755*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 2756*8975f5c5SAndroid Build Coastguard Worker const gl::Offset &destOffset, 2757*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormat, 2758*8975f5c5SAndroid Build Coastguard Worker GLint sourceLevel, 2759*8975f5c5SAndroid Build Coastguard Worker const gl::Box &sourceBox, 2760*8975f5c5SAndroid Build Coastguard Worker bool unpackFlipY, 2761*8975f5c5SAndroid Build Coastguard Worker bool unpackPremultiplyAlpha, 2762*8975f5c5SAndroid Build Coastguard Worker bool unpackUnmultiplyAlpha, 2763*8975f5c5SAndroid Build Coastguard Worker const gl::Texture *source) 2764*8975f5c5SAndroid Build Coastguard Worker{ 2765*8975f5c5SAndroid Build Coastguard Worker // Only 2D textures are supported. 2766*8975f5c5SAndroid Build Coastguard Worker ASSERT(sourceBox.depth == 1); 2767*8975f5c5SAndroid Build Coastguard Worker ASSERT(source->getType() == gl::TextureType::_2D); 2768*8975f5c5SAndroid Build Coastguard Worker gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(sourceLevel); 2769*8975f5c5SAndroid Build Coastguard Worker 2770*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2771*8975f5c5SAndroid Build Coastguard Worker TextureMtl *sourceMtl = mtl::GetImpl(source); 2772*8975f5c5SAndroid Build Coastguard Worker 2773*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(ensureImageCreated(context, index)); 2774*8975f5c5SAndroid Build Coastguard Worker 2775*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(sourceMtl->ensureImageCreated(context, sourceIndex)); 2776*8975f5c5SAndroid Build Coastguard Worker 2777*8975f5c5SAndroid Build Coastguard Worker const ImageDefinitionMtl &srcImageDef = sourceMtl->getImageDefinition(sourceIndex); 2778*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &sourceImage = srcImageDef.image; 2779*8975f5c5SAndroid Build Coastguard Worker const mtl::Format &sourceFormat = contextMtl->getPixelFormat(srcImageDef.formatID); 2780*8975f5c5SAndroid Build Coastguard Worker const angle::Format &sourceAngleFormat = sourceFormat.actualAngleFormat(); 2781*8975f5c5SAndroid Build Coastguard Worker 2782*8975f5c5SAndroid Build Coastguard Worker if (!mFormat.getCaps().isRenderable()) 2783*8975f5c5SAndroid Build Coastguard Worker { 2784*8975f5c5SAndroid Build Coastguard Worker return copySubTextureCPU(context, index, destOffset, internalFormat, 2785*8975f5c5SAndroid Build Coastguard Worker mtl::kZeroNativeMipLevel, sourceBox, sourceAngleFormat, 2786*8975f5c5SAndroid Build Coastguard Worker unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, 2787*8975f5c5SAndroid Build Coastguard Worker sourceImage); 2788*8975f5c5SAndroid Build Coastguard Worker } 2789*8975f5c5SAndroid Build Coastguard Worker return copySubTextureWithDraw( 2790*8975f5c5SAndroid Build Coastguard Worker context, index, destOffset, internalFormat, mtl::kZeroNativeMipLevel, sourceBox, 2791*8975f5c5SAndroid Build Coastguard Worker sourceAngleFormat, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, sourceImage); 2792*8975f5c5SAndroid Build Coastguard Worker} 2793*8975f5c5SAndroid Build Coastguard Worker 2794*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context, 2795*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 2796*8975f5c5SAndroid Build Coastguard Worker const gl::Offset &destOffset, 2797*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormat, 2798*8975f5c5SAndroid Build Coastguard Worker const mtl::MipmapNativeLevel &sourceNativeLevel, 2799*8975f5c5SAndroid Build Coastguard Worker const gl::Box &sourceBox, 2800*8975f5c5SAndroid Build Coastguard Worker const angle::Format &sourceAngleFormat, 2801*8975f5c5SAndroid Build Coastguard Worker bool unpackFlipY, 2802*8975f5c5SAndroid Build Coastguard Worker bool unpackPremultiplyAlpha, 2803*8975f5c5SAndroid Build Coastguard Worker bool unpackUnmultiplyAlpha, 2804*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &sourceTexture) 2805*8975f5c5SAndroid Build Coastguard Worker{ 2806*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2807*8975f5c5SAndroid Build Coastguard Worker DisplayMtl *displayMtl = contextMtl->getDisplay(); 2808*8975f5c5SAndroid Build Coastguard Worker 2809*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef image = getImage(index); 2810*8975f5c5SAndroid Build Coastguard Worker ASSERT(image && image->valid()); 2811*8975f5c5SAndroid Build Coastguard Worker 2812*8975f5c5SAndroid Build Coastguard Worker if (internalFormat.colorEncoding == GL_SRGB) 2813*8975f5c5SAndroid Build Coastguard Worker { 2814*8975f5c5SAndroid Build Coastguard Worker image = image->getLinearColorView(); 2815*8975f5c5SAndroid Build Coastguard Worker } 2816*8975f5c5SAndroid Build Coastguard Worker 2817*8975f5c5SAndroid Build Coastguard Worker mtl::RenderCommandEncoder *cmdEncoder = contextMtl->getTextureRenderCommandEncoder( 2818*8975f5c5SAndroid Build Coastguard Worker image, mtl::ImageNativeIndex::FromBaseZeroGLIndex(GetZeroLevelIndex(image))); 2819*8975f5c5SAndroid Build Coastguard Worker mtl::ColorBlitParams blitParams; 2820*8975f5c5SAndroid Build Coastguard Worker 2821*8975f5c5SAndroid Build Coastguard Worker blitParams.dstTextureSize = image->sizeAt0(); 2822*8975f5c5SAndroid Build Coastguard Worker blitParams.dstRect = 2823*8975f5c5SAndroid Build Coastguard Worker gl::Rectangle(destOffset.x, destOffset.y, sourceBox.width, sourceBox.height); 2824*8975f5c5SAndroid Build Coastguard Worker blitParams.dstScissorRect = blitParams.dstRect; 2825*8975f5c5SAndroid Build Coastguard Worker 2826*8975f5c5SAndroid Build Coastguard Worker blitParams.enabledBuffers.set(0); 2827*8975f5c5SAndroid Build Coastguard Worker 2828*8975f5c5SAndroid Build Coastguard Worker blitParams.src = sourceTexture; 2829*8975f5c5SAndroid Build Coastguard Worker blitParams.srcLevel = sourceNativeLevel; 2830*8975f5c5SAndroid Build Coastguard Worker blitParams.srcLayer = 0; 2831*8975f5c5SAndroid Build Coastguard Worker blitParams.srcNormalizedCoords = 2832*8975f5c5SAndroid Build Coastguard Worker mtl::NormalizedCoords(sourceBox.toRect(), sourceTexture->size(sourceNativeLevel)); 2833*8975f5c5SAndroid Build Coastguard Worker blitParams.srcYFlipped = false; 2834*8975f5c5SAndroid Build Coastguard Worker blitParams.dstLuminance = internalFormat.isLUMA(); 2835*8975f5c5SAndroid Build Coastguard Worker blitParams.unpackFlipY = unpackFlipY; 2836*8975f5c5SAndroid Build Coastguard Worker blitParams.unpackPremultiplyAlpha = unpackPremultiplyAlpha; 2837*8975f5c5SAndroid Build Coastguard Worker blitParams.unpackUnmultiplyAlpha = unpackUnmultiplyAlpha; 2838*8975f5c5SAndroid Build Coastguard Worker blitParams.transformLinearToSrgb = sourceAngleFormat.isSRGB; 2839*8975f5c5SAndroid Build Coastguard Worker 2840*8975f5c5SAndroid Build Coastguard Worker return displayMtl->getUtils().copyTextureWithDraw(context, cmdEncoder, sourceAngleFormat, 2841*8975f5c5SAndroid Build Coastguard Worker mFormat.actualAngleFormat(), blitParams); 2842*8975f5c5SAndroid Build Coastguard Worker} 2843*8975f5c5SAndroid Build Coastguard Worker 2844*8975f5c5SAndroid Build Coastguard Workerangle::Result TextureMtl::copySubTextureCPU(const gl::Context *context, 2845*8975f5c5SAndroid Build Coastguard Worker const gl::ImageIndex &index, 2846*8975f5c5SAndroid Build Coastguard Worker const gl::Offset &destOffset, 2847*8975f5c5SAndroid Build Coastguard Worker const gl::InternalFormat &internalFormat, 2848*8975f5c5SAndroid Build Coastguard Worker const mtl::MipmapNativeLevel &sourceNativeLevel, 2849*8975f5c5SAndroid Build Coastguard Worker const gl::Box &sourceBox, 2850*8975f5c5SAndroid Build Coastguard Worker const angle::Format &sourceAngleFormat, 2851*8975f5c5SAndroid Build Coastguard Worker bool unpackFlipY, 2852*8975f5c5SAndroid Build Coastguard Worker bool unpackPremultiplyAlpha, 2853*8975f5c5SAndroid Build Coastguard Worker bool unpackUnmultiplyAlpha, 2854*8975f5c5SAndroid Build Coastguard Worker const mtl::TextureRef &sourceTexture) 2855*8975f5c5SAndroid Build Coastguard Worker{ 2856*8975f5c5SAndroid Build Coastguard Worker mtl::TextureRef &image = getImage(index); 2857*8975f5c5SAndroid Build Coastguard Worker ASSERT(image && image->valid()); 2858*8975f5c5SAndroid Build Coastguard Worker 2859*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 2860*8975f5c5SAndroid Build Coastguard Worker 2861*8975f5c5SAndroid Build Coastguard Worker const angle::Format &dstAngleFormat = mFormat.actualAngleFormat(); 2862*8975f5c5SAndroid Build Coastguard Worker const int srcRowPitch = sourceAngleFormat.pixelBytes * sourceBox.width; 2863*8975f5c5SAndroid Build Coastguard Worker const int srcImageSize = srcRowPitch * sourceBox.height; 2864*8975f5c5SAndroid Build Coastguard Worker const int convRowPitch = dstAngleFormat.pixelBytes * sourceBox.width; 2865*8975f5c5SAndroid Build Coastguard Worker const int convImageSize = convRowPitch * sourceBox.height; 2866*8975f5c5SAndroid Build Coastguard Worker angle::MemoryBuffer conversionSrc, conversionDst; 2867*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_ALLOC(contextMtl, conversionSrc.resize(srcImageSize)); 2868*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_ALLOC(contextMtl, conversionDst.resize(convImageSize)); 2869*8975f5c5SAndroid Build Coastguard Worker 2870*8975f5c5SAndroid Build Coastguard Worker MTLRegion mtlSrcArea = 2871*8975f5c5SAndroid Build Coastguard Worker MTLRegionMake2D(sourceBox.x, sourceBox.y, sourceBox.width, sourceBox.height); 2872*8975f5c5SAndroid Build Coastguard Worker MTLRegion mtlDstArea = 2873*8975f5c5SAndroid Build Coastguard Worker MTLRegionMake2D(destOffset.x, destOffset.y, sourceBox.width, sourceBox.height); 2874*8975f5c5SAndroid Build Coastguard Worker 2875*8975f5c5SAndroid Build Coastguard Worker // Read pixels from source to memory: 2876*8975f5c5SAndroid Build Coastguard Worker sourceTexture->getBytes(contextMtl, srcRowPitch, 0, mtlSrcArea, sourceNativeLevel, 0, 2877*8975f5c5SAndroid Build Coastguard Worker conversionSrc.data()); 2878*8975f5c5SAndroid Build Coastguard Worker 2879*8975f5c5SAndroid Build Coastguard Worker // Convert to destination format 2880*8975f5c5SAndroid Build Coastguard Worker CopyImageCHROMIUM(conversionSrc.data(), srcRowPitch, sourceAngleFormat.pixelBytes, 0, 2881*8975f5c5SAndroid Build Coastguard Worker sourceAngleFormat.pixelReadFunction, conversionDst.data(), convRowPitch, 2882*8975f5c5SAndroid Build Coastguard Worker dstAngleFormat.pixelBytes, 0, dstAngleFormat.pixelWriteFunction, 2883*8975f5c5SAndroid Build Coastguard Worker internalFormat.format, internalFormat.componentType, sourceBox.width, 2884*8975f5c5SAndroid Build Coastguard Worker sourceBox.height, 1, unpackFlipY, unpackPremultiplyAlpha, 2885*8975f5c5SAndroid Build Coastguard Worker unpackUnmultiplyAlpha); 2886*8975f5c5SAndroid Build Coastguard Worker 2887*8975f5c5SAndroid Build Coastguard Worker // Upload to texture 2888*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(UploadTextureContents(context, dstAngleFormat, mtlDstArea, mtl::kZeroNativeMipLevel, 2889*8975f5c5SAndroid Build Coastguard Worker 0, conversionDst.data(), convRowPitch, 0, false, image)); 2890*8975f5c5SAndroid Build Coastguard Worker 2891*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 2892*8975f5c5SAndroid Build Coastguard Worker} 2893*8975f5c5SAndroid Build Coastguard Worker 2894*8975f5c5SAndroid Build Coastguard Worker} // namespace rx 2895