Commit a0880831 by Le Hoang Quyen Committed by Commit Bot

Metal: Implement CHROMIUM_copy_texture

Bug: angleproject:4930 Bug: angleproject:2634 Change-Id: I9fd958aa1dd872855be06a14bdbba4c6624dc934 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2340396 Commit-Queue: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com>
parent 559d54d0
......@@ -582,7 +582,7 @@ void DisplayMtl::initializeExtensions() const
mNativeExtensions.fragDepth = true;
mNativeExtensions.framebufferBlit = false;
mNativeExtensions.framebufferMultisample = false;
mNativeExtensions.copyTexture = false;
mNativeExtensions.copyTexture = true;
mNativeExtensions.copyCompressedTexture = false;
mNativeExtensions.debugMarker = false;
mNativeExtensions.robustness = true;
......
......@@ -45,8 +45,8 @@ class RenderTargetMtl final : public FramebufferAttachmentRenderTarget
void setImplicitMSTexture(const mtl::TextureRef &implicitMSTexture);
void reset();
mtl::TextureRef getTexture() const { return mTexture; }
mtl::TextureRef getImplicitMSTexture() const { return mImplicitMSTexture; }
mtl::TextureRef getTexture() const { return mTexture.lock(); }
mtl::TextureRef getImplicitMSTexture() const { return mImplicitMSTexture.lock(); }
uint32_t getLevelIndex() const { return mLevelIndex; }
uint32_t getLayerIndex() const { return mLayerIndex; }
uint32_t getRenderSamples() const;
......@@ -55,8 +55,8 @@ class RenderTargetMtl final : public FramebufferAttachmentRenderTarget
void toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const;
private:
mtl::TextureRef mTexture;
mtl::TextureRef mImplicitMSTexture;
mtl::TextureWeakRef mTexture;
mtl::TextureWeakRef mImplicitMSTexture;
uint32_t mLevelIndex = 0;
uint32_t mLayerIndex = 0;
const mtl::Format *mFormat = nullptr;
......
......@@ -67,13 +67,14 @@ void RenderTargetMtl::reset()
uint32_t RenderTargetMtl::getRenderSamples() const
{
return mImplicitMSTexture ? mImplicitMSTexture->samples()
: (mTexture ? mTexture->samples() : 1);
mtl::TextureRef implicitMSTex = getImplicitMSTexture();
mtl::TextureRef tex = getTexture();
return implicitMSTex ? implicitMSTex->samples() : (tex ? tex->samples() : 1);
}
void RenderTargetMtl::toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const
{
rpaDescOut->texture = mTexture;
rpaDescOut->implicitMSTexture = mImplicitMSTexture;
rpaDescOut->texture = mTexture.lock();
rpaDescOut->implicitMSTexture = mImplicitMSTexture.lock();
rpaDescOut->level = mLevelIndex;
rpaDescOut->sliceOrDepth = mLayerIndex;
}
......
......@@ -64,6 +64,9 @@ class SurfaceMtl : public SurfaceImpl
EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override;
angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override;
const mtl::TextureRef &getColorTexture() { return mColorTexture; }
const mtl::Format &getColorFormat() const { return mColorFormat; }
int getSamples() const { return mSamples; }
......
......@@ -410,6 +410,13 @@ EGLint SurfaceMtl::getSwapBehavior() const
return EGL_BUFFER_PRESERVED;
}
angle::Result SurfaceMtl::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
angle::Result SurfaceMtl::getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
......
......@@ -215,6 +215,41 @@ class TextureMtl : public TextureImpl
const gl::InternalFormat &internalFormat,
gl::Framebuffer *source);
angle::Result copySubTextureImpl(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::InternalFormat &internalFormat,
size_t sourceLevel,
const gl::Box &sourceBox,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const gl::Texture *source);
angle::Result copySubTextureWithDraw(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::InternalFormat &internalFormat,
uint32_t sourceNativeLevel,
const gl::Box &sourceBox,
const angle::Format &sourceAngleFormat,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const mtl::TextureRef &sourceTexture);
angle::Result copySubTextureCPU(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::InternalFormat &internalFormat,
uint32_t sourceNativeLevel,
const gl::Box &sourceBox,
const angle::Format &sourceAngleFormat,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const mtl::TextureRef &sourceTexture);
// Convert pixels to suported format before uploading to texture
angle::Result convertAndSetSubImage(const gl::Context *context,
const gl::ImageIndex &index,
......
......@@ -547,9 +547,24 @@ angle::Result TextureMtl::copyTexture(const gl::Context *context,
bool unpackUnmultiplyAlpha,
const gl::Texture *source)
{
UNIMPLEMENTED();
const gl::ImageDesc &sourceImageDesc = source->getTextureState().getImageDesc(
NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
return angle::Result::Stop;
// Only 2D textures are supported.
ASSERT(sourceImageDesc.size.depth == 1);
ContextMtl *contextMtl = mtl::GetImpl(context);
angle::FormatID angleFormatId =
angle::Format::InternalFormatToID(internalFormatInfo.sizedInternalFormat);
const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId);
ANGLE_TRY(redefineImage(context, index, mtlFormat, sourceImageDesc.size));
return copySubTextureImpl(
context, index, gl::Offset(0, 0, 0), internalFormatInfo, sourceLevel,
gl::Box(0, 0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height, 1), unpackFlipY,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source);
}
angle::Result TextureMtl::copySubTexture(const gl::Context *context,
......@@ -562,9 +577,10 @@ angle::Result TextureMtl::copySubTexture(const gl::Context *context,
bool unpackUnmultiplyAlpha,
const gl::Texture *source)
{
UNIMPLEMENTED();
const gl::InternalFormat &currentFormat = *mState.getImageDesc(index).format.info;
return angle::Result::Stop;
return copySubTextureImpl(context, index, destOffset, currentFormat, sourceLevel, sourceBox,
unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source);
}
angle::Result TextureMtl::copyCompressedTexture(const gl::Context *context,
......@@ -1089,6 +1105,10 @@ angle::Result TextureMtl::initializeContents(const gl::Context *context,
const gl::ImageIndex &index)
{
mtl::TextureRef &image = mTexImages[GetImageLayerIndex(index)][index.getLevelIndex()];
if (!image)
{
ANGLE_TRY(ensureTextureCreated(context));
}
return mtl::InitializeTextureContents(context, image, mFormat, GetImageBaseLevelIndex(image));
}
......@@ -1212,4 +1232,140 @@ angle::Result TextureMtl::copySubImageCPU(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result TextureMtl::copySubTextureImpl(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::InternalFormat &internalFormat,
size_t sourceLevel,
const gl::Box &sourceBox,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const gl::Texture *source)
{
// Only 2D textures are supported.
ASSERT(sourceBox.depth == 1);
ASSERT(source->getType() == gl::TextureType::_2D);
gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel));
ContextMtl *contextMtl = mtl::GetImpl(context);
TextureMtl *sourceMtl = mtl::GetImpl(source);
ANGLE_TRY(ensureImageCreated(context, index));
ANGLE_TRY(sourceMtl->ensureImageCreated(context, sourceIndex));
const gl::ImageDesc &srcDesc = source->getState().getImageDesc(sourceIndex);
const mtl::TextureRef &srcImage = sourceMtl->mTexImages[0][sourceLevel];
const mtl::Format &srcFormat = contextMtl->getPixelFormat(
angle::Format::InternalFormatToID(srcDesc.format.info->sizedInternalFormat));
const angle::Format &srcAngleFormat = srcFormat.actualAngleFormat();
const mtl::Format &dstFormat = contextMtl->getPixelFormat(
angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat));
if (!mtl::Format::FormatRenderable(dstFormat.metalFormat))
{
return copySubTextureCPU(context, index, destOffset, internalFormat, 0, sourceBox,
srcAngleFormat, unpackFlipY, unpackPremultiplyAlpha,
unpackUnmultiplyAlpha, srcImage);
}
return copySubTextureWithDraw(context, index, destOffset, internalFormat, 0, sourceBox,
srcAngleFormat, unpackFlipY, unpackPremultiplyAlpha,
unpackUnmultiplyAlpha, srcImage);
}
angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::InternalFormat &internalFormat,
uint32_t sourceNativeLevel,
const gl::Box &sourceBox,
const angle::Format &sourceAngleFormat,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const mtl::TextureRef &sourceTexture)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
DisplayMtl *displayMtl = contextMtl->getDisplay();
mtl::TextureRef image = mTexImages[GetImageLayerIndex(index)][index.getLevelIndex()];
ASSERT(image && image->valid());
if (internalFormat.colorEncoding == GL_SRGB)
{
image = image->getLinearColorView();
}
mtl::RenderCommandEncoder *cmdEncoder =
contextMtl->getRenderCommandEncoder(image, GetImageBaseLevelIndex(image));
mtl::BlitParams blitParams;
blitParams.dstOffset = destOffset;
blitParams.dstColorMask = image->getColorWritableMask();
blitParams.src = sourceTexture;
blitParams.srcLevel = sourceNativeLevel;
blitParams.srcRect = gl::Rectangle(sourceBox.x, sourceBox.y, sourceBox.width, sourceBox.height);
blitParams.srcYFlipped = false;
blitParams.dstLuminance = internalFormat.isLUMA();
blitParams.unpackFlipY = unpackFlipY;
blitParams.unpackPremultiplyAlpha = unpackPremultiplyAlpha;
blitParams.unpackUnmultiplyAlpha = unpackUnmultiplyAlpha;
return displayMtl->getUtils().blitWithDraw(context, cmdEncoder, blitParams);
}
angle::Result TextureMtl::copySubTextureCPU(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::InternalFormat &internalFormat,
uint32_t sourceNativeLevel,
const gl::Box &sourceBox,
const angle::Format &sourceAngleFormat,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const mtl::TextureRef &sourceTexture)
{
mtl::TextureRef &image = mTexImages[GetImageLayerIndex(index)][index.getLevelIndex()];
ASSERT(image && image->valid());
ContextMtl *contextMtl = mtl::GetImpl(context);
const angle::Format &dstAngleFormat = mFormat.actualAngleFormat();
const int srcRowPitch = sourceAngleFormat.pixelBytes * sourceBox.width;
const int srcImageSize = srcRowPitch * sourceBox.height;
const int convRowPitch = dstAngleFormat.pixelBytes * sourceBox.width;
const int convImageSize = convRowPitch * sourceBox.height;
angle::MemoryBuffer conversionSrc, conversionDst;
ANGLE_CHECK_GL_ALLOC(contextMtl, conversionSrc.resize(srcImageSize));
ANGLE_CHECK_GL_ALLOC(contextMtl, conversionDst.resize(convImageSize));
MTLRegion mtlSrcArea =
MTLRegionMake2D(sourceBox.x, sourceBox.y, sourceBox.width, sourceBox.height);
MTLRegion mtlDstArea =
MTLRegionMake2D(destOffset.x, destOffset.y, sourceBox.width, sourceBox.height);
// Read pixels from source to memory:
sourceTexture->getBytes(contextMtl, srcRowPitch, mtlSrcArea, sourceNativeLevel,
conversionSrc.data());
// Convert to destination format
CopyImageCHROMIUM(conversionSrc.data(), srcRowPitch, sourceAngleFormat.pixelBytes, 0,
sourceAngleFormat.pixelReadFunction, conversionDst.data(), convRowPitch,
dstAngleFormat.pixelBytes, 0, dstAngleFormat.pixelWriteFunction,
internalFormat.format, internalFormat.componentType, sourceBox.width,
sourceBox.height, 1, unpackFlipY, unpackPremultiplyAlpha,
unpackUnmultiplyAlpha);
// Upload to texture
ANGLE_TRY(UploadTextureContents(context, image, dstAngleFormat, mtlDstArea, 0, 0,
conversionDst.data(), convRowPitch));
return angle::Result::Continue;
}
}
......@@ -163,6 +163,9 @@ class Texture final : public Resource,
MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
// Get linear color space view. Only usable for sRGB textures.
TextureRef getLinearColorView();
// Change the wrapped metal object. Special case for swapchain image
void set(id<MTLTexture> metalTexture);
......@@ -187,6 +190,9 @@ class Texture final : public Resource,
// This property is shared between this object and its views:
std::shared_ptr<MTLColorWriteMask> mColorWritableMask;
// Linear view of sRGB texture
TextureRef mLinearColorView;
};
class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>>
......
......@@ -443,9 +443,34 @@ uint32_t Texture::samples() const
return static_cast<uint32_t>(get().sampleCount);
}
TextureRef Texture::getLinearColorView()
{
if (mLinearColorView)
{
return mLinearColorView;
}
switch (pixelFormat())
{
case MTLPixelFormatRGBA8Unorm_sRGB:
mLinearColorView = createViewWithDifferentFormat(MTLPixelFormatRGBA8Unorm);
break;
case MTLPixelFormatBGRA8Unorm_sRGB:
mLinearColorView = createViewWithDifferentFormat(MTLPixelFormatBGRA8Unorm);
break;
default:
// NOTE(hqle): Not all sRGB formats are supported yet.
UNREACHABLE();
}
return mLinearColorView;
}
void Texture::set(id<MTLTexture> metalTexture)
{
ParentClass::set(metalTexture);
mLinearColorView = nullptr;
}
// Buffer implementation
......
......@@ -145,6 +145,9 @@ std::string CopyTextureVariationsTestPrint(
case GL_BGRA_EXT:
out << "BGRA";
break;
case GL_SRGB_ALPHA_EXT:
out << "SRGBA";
break;
default:
out << "UPDATE_THIS_SWITCH";
}
......@@ -162,6 +165,9 @@ std::string CopyTextureVariationsTestPrint(
case GL_BGRA_EXT:
out << "BGRA";
break;
case GL_SRGB_ALPHA_EXT:
out << "SRGBA";
break;
default:
out << "UPDATE_THIS_SWITCH";
}
......@@ -232,6 +238,12 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
return false;
}
if ((sourceFormat == GL_SRGB_ALPHA_EXT || destFormat == GL_SRGB_ALPHA_EXT) &&
!IsGLExtensionEnabled("GL_EXT_sRGB"))
{
return false;
}
return true;
}
......@@ -292,6 +304,7 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
break;
case GL_RGBA:
case GL_BGRA_EXT:
case GL_SRGB_ALPHA_EXT:
break;
default:
EXPECT_EQ(true, false);
......@@ -423,6 +436,9 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
// Old drivers buggy with optimized ImageCopy shader given LUMA textures.
// http://anglebug.com/4721
ANGLE_SKIP_TEST_IF(IsLinux() && IsNVIDIA() && IsVulkan());
// http://anglebug.com/4939
ANGLE_SKIP_TEST_IF(IsOpenGL() && destFormat == GL_SRGB_ALPHA_EXT);
}
size_t colorCount;
......@@ -487,6 +503,9 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
// Old drivers buggy with optimized ImageCopy shader given LUMA textures.
// http://anglebug.com/4721
ANGLE_SKIP_TEST_IF(IsLinux() && IsNVIDIA() && IsVulkan());
// http://anglebug.com/4939
ANGLE_SKIP_TEST_IF(IsOpenGL() && destFormat == GL_SRGB_ALPHA_EXT);
}
size_t colorCount;
......@@ -880,7 +899,8 @@ namespace
{
constexpr GLenum kCopyTextureVariationsSrcFormats[] = {
GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGRA_EXT};
constexpr GLenum kCopyTextureVariationsDstFormats[] = {GL_RGB, GL_RGBA, GL_BGRA_EXT};
constexpr GLenum kCopyTextureVariationsDstFormats[] = {GL_RGB, GL_RGBA, GL_BGRA_EXT,
GL_SRGB_ALPHA_EXT};
} // anonymous namespace
TEST_P(CopyTextureVariationsTest, CopyTexture)
......@@ -1637,6 +1657,7 @@ TEST_P(CopyTextureTestDest, AlphaCopyWithRGB)
// http://anglebug.com/4121
ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGLES());
ANGLE_SKIP_TEST_IF(!checkExtensions());
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float"));
GLColor originalPixels(50u, 100u, 150u, 155u);
GLColor expectedPixels(0u, 0u, 0u, 155u);
......@@ -2363,13 +2384,15 @@ ANGLE_INSTANTIATE_TEST_COMBINE_5(CopyTextureVariationsTest,
ES2_D3D11(),
ES2_OPENGL(),
ES2_OPENGLES(),
ES2_VULKAN());
ES2_VULKAN(),
ES2_METAL());
ANGLE_INSTANTIATE_TEST_ES2(CopyTextureTestWebGL);
ANGLE_INSTANTIATE_TEST(CopyTextureTestDest,
ES2_D3D11(),
ES2_OPENGL(),
ES2_OPENGLES(),
ES2_VULKAN());
ES2_VULKAN(),
ES2_METAL());
ANGLE_INSTANTIATE_TEST_ES3(CopyTextureTestES3);
} // namespace angle
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment