Commit f37f1dcb by Le Hoang Quyen Committed by Commit Bot

Metal: Init format table using Metal-Feature-Set-Tables.pdf

- Format table is now initialized using informations from https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf. Previously, it was setup using gl::GenerateMinimumTextureCaps(). - This CL also adds InitializeTextureDataFunction and LoadFunctionMap to mtl::Format. They are needed to properly initialize/convert textures with non-normalized formats. - This CL is prerequisite for integer & floating point format supports. - New test: DXT1CompressedTextureTest.DXT1Alpha (this test was added in the past but was reverted for some reasons). Bug: angleproject:2634 Change-Id: I5eaad812909a49c4c138d0f65fd21a6a199fcb22 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2332144 Commit-Queue: Le Hoang Quyen <le.hoang.q@gmail.com> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 23335ac0
...@@ -34,6 +34,14 @@ struct FeaturesMtl : FeatureSetBase ...@@ -34,6 +34,14 @@ struct FeaturesMtl : FeatureSetBase
Feature hasTextureSwizzle = {"has_texture_swizzle", FeatureCategory::MetalFeatures, Feature hasTextureSwizzle = {"has_texture_swizzle", FeatureCategory::MetalFeatures,
"The renderer supports texture swizzle", &members}; "The renderer supports texture swizzle", &members};
Feature hasDepthAutoResolve = {
"has_msaa_depth_auto_resolve", FeatureCategory::MetalFeatures,
"The renderer supports MSAA depth auto resolve at the end of render pass", &members};
Feature hasStencilAutoResolve = {
"has_msaa_stencil_auto_resolve", FeatureCategory::MetalFeatures,
"The renderer supports MSAA stencil auto resolve at the end of render pass", &members};
// On macos, separate depth & stencil buffers are not supproted. However, on iOS devices, // On macos, separate depth & stencil buffers are not supproted. However, on iOS devices,
// they are supproted: // they are supproted:
Feature allowSeparatedDepthStencilBuffers = { Feature allowSeparatedDepthStencilBuffers = {
......
{ {
"src/libANGLE/renderer/angle_format.py": "src/libANGLE/renderer/angle_format.py":
"32ba71942c0fd00e6807104f1bb80a3c", "32ba71942c0fd00e6807104f1bb80a3c",
"src/libANGLE/renderer/angle_format_map.json":
"aa4a0d3463b76858a75787b9cdec8e98",
"src/libANGLE/renderer/metal/gen_mtl_format_table.py": "src/libANGLE/renderer/metal/gen_mtl_format_table.py":
"780f56abea19db610d2b829ba817fdc6", "27769e4e9cce3b7af18b69d41351c3ed",
"src/libANGLE/renderer/metal/mtl_format_map.json": "src/libANGLE/renderer/metal/mtl_format_map.json":
"7aad5b3ed806e0d932cbbfe6d3b8a834", "b202d7a0349006e2bbd58c603d9cdc28",
"src/libANGLE/renderer/metal/mtl_format_table_autogen.mm": "src/libANGLE/renderer/metal/mtl_format_table_autogen.mm":
"efd031ead828c19f5476413b2b743087" "7a0ee6139ca1e7ec8b8b0a7de9180ef7"
} }
\ No newline at end of file
...@@ -80,6 +80,7 @@ angle_source_set("angle_metal_backend") { ...@@ -80,6 +80,7 @@ angle_source_set("angle_metal_backend") {
public_deps = [ public_deps = [
"${angle_root}:angle_glslang_wrapper", "${angle_root}:angle_glslang_wrapper",
"${angle_root}:angle_image_util",
"${angle_root}:libANGLE_headers", "${angle_root}:libANGLE_headers",
] ]
......
...@@ -278,6 +278,7 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -278,6 +278,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
bool getDepthMask() const; bool getDepthMask() const;
const mtl::Format &getPixelFormat(angle::FormatID angleFormatId) const; const mtl::Format &getPixelFormat(angle::FormatID angleFormatId) const;
const mtl::FormatCaps &getNativeFormatCaps(MTLPixelFormat mtlFormat) const;
// See mtl::FormatTable::getVertexFormat() // See mtl::FormatTable::getVertexFormat()
const mtl::VertexFormat &getVertexFormat(angle::FormatID angleFormatId, const mtl::VertexFormat &getVertexFormat(angle::FormatID angleFormatId,
bool tightlyPacked) const; bool tightlyPacked) const;
......
...@@ -1118,6 +1118,11 @@ const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormat ...@@ -1118,6 +1118,11 @@ const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormat
return getDisplay()->getVertexFormat(angleFormatId, tightlyPacked); return getDisplay()->getVertexFormat(angleFormatId, tightlyPacked);
} }
const mtl::FormatCaps &ContextMtl::getNativeFormatCaps(MTLPixelFormat mtlFormat) const
{
return getDisplay()->getNativeFormatCaps(mtlFormat);
}
angle::Result ContextMtl::getIncompleteTexture(const gl::Context *context, angle::Result ContextMtl::getIncompleteTexture(const gl::Context *context,
gl::TextureType type, gl::TextureType type,
gl::Texture **textureOut) gl::Texture **textureOut)
......
...@@ -107,6 +107,11 @@ class DisplayMtl : public DisplayImpl ...@@ -107,6 +107,11 @@ class DisplayMtl : public DisplayImpl
const gl::Limitations &getNativeLimitations() const { return mNativeLimitations; } const gl::Limitations &getNativeLimitations() const { return mNativeLimitations; }
const angle::FeaturesMtl &getFeatures() const { return mFeatures; } const angle::FeaturesMtl &getFeatures() const { return mFeatures; }
// Check whether either of the specified iOS or Mac GPU family is supported
bool supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) const;
bool supportsIOSGPUFamily(uint8_t iOSFamily) const;
bool supportsMacGPUFamily(uint8_t macFamily) const;
id<MTLDevice> getMetalDevice() const { return mMetalDevice; } id<MTLDevice> getMetalDevice() const { return mMetalDevice; }
mtl::CommandQueue &cmdQueue() { return mCmdQueue; } mtl::CommandQueue &cmdQueue() { return mCmdQueue; }
...@@ -129,6 +134,10 @@ class DisplayMtl : public DisplayImpl ...@@ -129,6 +134,10 @@ class DisplayMtl : public DisplayImpl
{ {
return mFormatTable.getPixelFormat(angleFormatId); return mFormatTable.getPixelFormat(angleFormatId);
} }
const mtl::FormatCaps &getNativeFormatCaps(MTLPixelFormat mtlFormat) const
{
return mFormatTable.getNativeFormatCaps(mtlFormat);
}
// See mtl::FormatTable::getVertexFormat() // See mtl::FormatTable::getVertexFormat()
const mtl::VertexFormat &getVertexFormat(angle::FormatID angleFormatId, const mtl::VertexFormat &getVertexFormat(angle::FormatID angleFormatId,
...@@ -154,7 +163,7 @@ class DisplayMtl : public DisplayImpl ...@@ -154,7 +163,7 @@ class DisplayMtl : public DisplayImpl
mtl::CommandQueue mCmdQueue; mtl::CommandQueue mCmdQueue;
mtl::FormatTable mFormatTable; mutable mtl::FormatTable mFormatTable;
mtl::StateCache mStateCache; mtl::StateCache mStateCache;
mtl::RenderUtils mUtils; mtl::RenderUtils mUtils;
......
...@@ -452,7 +452,7 @@ void DisplayMtl::ensureCapsInitialized() const ...@@ -452,7 +452,7 @@ void DisplayMtl::ensureCapsInitialized() const
mNativeCaps.maxVaryingVectors = 31; mNativeCaps.maxVaryingVectors = 31;
mNativeCaps.maxVertexOutputComponents = 124; mNativeCaps.maxVertexOutputComponents = 124;
#else #else
if ([getMetalDevice() supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) if (supportsIOSGPUFamily(3))
{ {
mNativeCaps.max2DTextureSize = 16384; mNativeCaps.max2DTextureSize = 16384;
mNativeCaps.maxVertexOutputComponents = 124; mNativeCaps.maxVertexOutputComponents = 124;
...@@ -662,6 +662,12 @@ void DisplayMtl::initializeTextureCaps() const ...@@ -662,6 +662,12 @@ void DisplayMtl::initializeTextureCaps() const
void DisplayMtl::initializeFeatures() void DisplayMtl::initializeFeatures()
{ {
bool isMetal2_2 = false;
if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
{
isMetal2_2 = true;
}
// default values: // default values:
mFeatures.hasBaseVertexInstancedDraw.enabled = true; mFeatures.hasBaseVertexInstancedDraw.enabled = true;
mFeatures.hasDepthTextureFiltering.enabled = false; mFeatures.hasDepthTextureFiltering.enabled = false;
...@@ -669,33 +675,25 @@ void DisplayMtl::initializeFeatures() ...@@ -669,33 +675,25 @@ void DisplayMtl::initializeFeatures()
mFeatures.hasTextureSwizzle.enabled = false; mFeatures.hasTextureSwizzle.enabled = false;
mFeatures.allowSeparatedDepthStencilBuffers.enabled = false; mFeatures.allowSeparatedDepthStencilBuffers.enabled = false;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST ANGLE_FEATURE_CONDITION((&mFeatures), hasDepthTextureFiltering,
mFeatures.hasDepthTextureFiltering.enabled = true; TARGET_OS_OSX || TARGET_OS_MACCATALYST);
mFeatures.allowMultisampleStoreAndResolve.enabled = true; ANGLE_FEATURE_CONDITION((&mFeatures), hasDepthAutoResolve, supportsEitherGPUFamily(3, 2));
ANGLE_FEATURE_CONDITION((&mFeatures), hasStencilAutoResolve, supportsEitherGPUFamily(5, 2));
ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve,
supportsEitherGPUFamily(3, 1));
// Texture swizzle is only supported if macos sdk 10.15 is present
# if defined(__MAC_10_15)
if (ANGLE_APPLE_AVAILABLE_XC(10.15, 13.0))
{
// The runtime OS must be MacOS 10.15+ or Mac Catalyst for this to be supported:
ANGLE_FEATURE_CONDITION((&mFeatures), hasTextureSwizzle, ANGLE_FEATURE_CONDITION((&mFeatures), hasTextureSwizzle,
[getMetalDevice() supportsFamily:MTLGPUFamilyMac2]); isMetal2_2 && supportsEitherGPUFamily(1, 2));
}
# endif #if !TARGET_OS_MACCATALYST && (TARGET_OS_IOS || TARGET_OS_TV)
#elif TARGET_OS_IOS
// Base Vertex drawing is only supported since GPU family 3. // Base Vertex drawing is only supported since GPU family 3.
ANGLE_FEATURE_CONDITION((&mFeatures), hasBaseVertexInstancedDraw, ANGLE_FEATURE_CONDITION((&mFeatures), hasBaseVertexInstancedDraw, supportsIOSGPUFamily(3));
[getMetalDevice() supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]);
ANGLE_FEATURE_CONDITION((&mFeatures), hasNonUniformDispatch, ANGLE_FEATURE_CONDITION((&mFeatures), hasNonUniformDispatch,
[getMetalDevice() supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]); TARGET_OS_IOS && supportsIOSGPUFamily(4));
ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve, ANGLE_FEATURE_CONDITION((&mFeatures), allowSeparatedDepthStencilBuffers, !TARGET_OS_SIMULATOR);
[getMetalDevice() supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]);
# if !TARGET_OS_SIMULATOR
mFeatures.allowSeparatedDepthStencilBuffers.enabled = true;
# endif
#endif #endif
angle::PlatformMethods *platform = ANGLEPlatformCurrent(); angle::PlatformMethods *platform = ANGLEPlatformCurrent();
...@@ -734,4 +732,151 @@ angle::Result DisplayMtl::initializeShaderLibrary() ...@@ -734,4 +732,151 @@ angle::Result DisplayMtl::initializeShaderLibrary()
return angle::Result::Continue; return angle::Result::Continue;
} }
bool DisplayMtl::supportsIOSGPUFamily(uint8_t iOSFamily) const
{
#if (!TARGET_OS_IOS && !TARGET_OS_TV) || TARGET_OS_MACCATALYST
return false;
#else
# if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000) || (__TV_OS_VERSION_MAX_ALLOWED >= 130000)
// If device supports [MTLDevice supportsFamily:], then use it.
if (ANGLE_APPLE_AVAILABLE_I(13.0))
{
MTLGPUFamily family;
switch (iOSFamily)
{
case 1:
family = MTLGPUFamilyApple1;
break;
case 2:
family = MTLGPUFamilyApple2;
break;
case 3:
family = MTLGPUFamilyApple3;
break;
case 4:
family = MTLGPUFamilyApple4;
break;
case 5:
family = MTLGPUFamilyApple5;
break;
# if TARGET_OS_IOS
case 6:
family = MTLGPUFamilyApple6;
break;
# endif
default:
return false;
}
return [getMetalDevice() supportsFamily:family];
} // Metal 2.2
# endif // __IPHONE_OS_VERSION_MAX_ALLOWED
// If device doesn't support [MTLDevice supportsFamily:], then use
// [MTLDevice supportsFeatureSet:].
MTLFeatureSet featureSet;
switch (iOSFamily)
{
# if TARGET_OS_IOS
case 1:
featureSet = MTLFeatureSet_iOS_GPUFamily1_v1;
break;
case 2:
featureSet = MTLFeatureSet_iOS_GPUFamily2_v1;
break;
case 3:
featureSet = MTLFeatureSet_iOS_GPUFamily3_v1;
break;
case 4:
featureSet = MTLFeatureSet_iOS_GPUFamily4_v1;
break;
# if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000
case 5:
featureSet = MTLFeatureSet_iOS_GPUFamily5_v1;
break;
# endif // __IPHONE_OS_VERSION_MAX_ALLOWED
# elif TARGET_OS_TV
case 1:
case 2:
featureSet = MTLFeatureSet_tvOS_GPUFamily1_v1;
break;
case 3:
featureSet = MTLFeatureSet_tvOS_GPUFamily2_v1;
break;
# endif // TARGET_OS_IOS
default:
return false;
}
return [getMetalDevice() supportsFeatureSet:featureSet];
#endif // TARGET_OS_IOS || TARGET_OS_TV
}
bool DisplayMtl::supportsMacGPUFamily(uint8_t macFamily) const
{
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
# if defined(__MAC_10_15)
// If device supports [MTLDevice supportsFamily:], then use it.
if (ANGLE_APPLE_AVAILABLE_XC(10.15, 13.0))
{
MTLGPUFamily family;
switch (macFamily)
{
# if TARGET_OS_MACCATALYST
case 1:
family = MTLGPUFamilyMacCatalyst1;
break;
case 2:
family = MTLGPUFamilyMacCatalyst2;
break;
# else // TARGET_OS_MACCATALYST
case 1:
family = MTLGPUFamilyMac1;
break;
case 2:
family = MTLGPUFamilyMac2;
break;
# endif // TARGET_OS_MACCATALYST
default:
return false;
}
return [getMetalDevice() supportsFamily:family];
} // Metal 2.2
# endif
// If device doesn't support [MTLDevice supportsFamily:], then use
// [MTLDevice supportsFeatureSet:].
# if TARGET_OS_MACCATALYST
UNREACHABLE();
return false;
# else
MTLFeatureSet featureSet;
switch (macFamily)
{
case 1:
featureSet = MTLFeatureSet_macOS_GPUFamily1_v1;
break;
# if defined(__MAC_10_14)
case 2:
featureSet = MTLFeatureSet_macOS_GPUFamily2_v1;
break;
# endif
default:
return false;
}
return [getMetalDevice() supportsFeatureSet:featureSet];
# endif // TARGET_OS_MACCATALYST
#else // #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
return false;
#endif
}
bool DisplayMtl::supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) const
{
return supportsIOSGPUFamily(iOSFamily) || supportsMacGPUFamily(macFamily);
}
} // namespace rx } // namespace rx
...@@ -67,8 +67,7 @@ angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context, ...@@ -67,8 +67,7 @@ angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context,
// For emulated channels that GL texture intends to not have, // For emulated channels that GL texture intends to not have,
// we need to initialize their content. // we need to initialize their content.
bool emulatedChannels; bool emulatedChannels = mtl::IsFormatEmulated(mFormat);
mTexture->setColorWritableMask(mtl::GetEmulatedColorWriteMask(mFormat, &emulatedChannels));
if (emulatedChannels) if (emulatedChannels)
{ {
gl::ImageIndex index; gl::ImageIndex index;
......
...@@ -255,6 +255,7 @@ class TextureMtl : public TextureImpl ...@@ -255,6 +255,7 @@ class TextureMtl : public TextureImpl
const gl::ImageIndex &index, const gl::ImageIndex &index,
const MTLRegion &mtlArea, const MTLRegion &mtlArea,
const gl::InternalFormat &internalFormat, const gl::InternalFormat &internalFormat,
GLenum type,
const angle::Format &pixelsFormat, const angle::Format &pixelsFormat,
size_t pixelsRowPitch, size_t pixelsRowPitch,
const uint8_t *pixels); const uint8_t *pixels);
......
...@@ -1007,9 +1007,9 @@ angle::Result TextureMtl::setSubImageImpl(const gl::Context *context, ...@@ -1007,9 +1007,9 @@ angle::Result TextureMtl::setSubImageImpl(const gl::Context *context,
angle::Format::Get(angle::Format::InternalFormatToID(formatInfo.sizedInternalFormat)); angle::Format::Get(angle::Format::InternalFormatToID(formatInfo.sizedInternalFormat));
// If source pixels are luminance or RGB8, we need to convert them to RGBA // If source pixels are luminance or RGB8, we need to convert them to RGBA
if (mFormat.actualFormatId != srcAngleFormat.id) if (mFormat.needConversion(srcAngleFormat.id))
{ {
return convertAndSetSubImage(context, index, mtlRegion, formatInfo, srcAngleFormat, return convertAndSetSubImage(context, index, mtlRegion, formatInfo, type, srcAngleFormat,
sourceRowPitch, pixels); sourceRowPitch, pixels);
} }
...@@ -1024,6 +1024,7 @@ angle::Result TextureMtl::convertAndSetSubImage(const gl::Context *context, ...@@ -1024,6 +1024,7 @@ angle::Result TextureMtl::convertAndSetSubImage(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
const MTLRegion &mtlArea, const MTLRegion &mtlArea,
const gl::InternalFormat &internalFormat, const gl::InternalFormat &internalFormat,
GLenum type,
const angle::Format &pixelsFormat, const angle::Format &pixelsFormat,
size_t pixelsRowPitch, size_t pixelsRowPitch,
const uint8_t *pixels) const uint8_t *pixels)
...@@ -1034,10 +1035,35 @@ angle::Result TextureMtl::convertAndSetSubImage(const gl::Context *context, ...@@ -1034,10 +1035,35 @@ angle::Result TextureMtl::convertAndSetSubImage(const gl::Context *context,
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
// Create scratch buffer LoadImageFunctionInfo loadFunctionInfo =
mFormat.textureLoadFunctions ? mFormat.textureLoadFunctions(type) : LoadImageFunctionInfo();
const angle::Format &dstFormat = angle::Format::Get(mFormat.actualFormatId); const angle::Format &dstFormat = angle::Format::Get(mFormat.actualFormatId);
angle::MemoryBuffer conversionRow;
const size_t dstRowPitch = dstFormat.pixelBytes * mtlArea.size.width; const size_t dstRowPitch = dstFormat.pixelBytes * mtlArea.size.width;
// Check if original image data is compressed:
if (mFormat.intendedAngleFormat().isBlock)
{
ASSERT(loadFunctionInfo.loadFunction);
// Need to create a buffer to hold entire decompressed image.
const size_t dstDepthPitch = dstRowPitch * mtlArea.size.height;
angle::MemoryBuffer decompressBuf;
ANGLE_CHECK_GL_ALLOC(contextMtl, decompressBuf.resize(dstDepthPitch * mtlArea.size.depth));
// Decompress
loadFunctionInfo.loadFunction(mtlArea.size.width, mtlArea.size.height, mtlArea.size.depth,
pixels, pixelsRowPitch, 0, decompressBuf.data(), dstRowPitch,
dstDepthPitch);
// Upload to texture
ANGLE_TRY(UploadTextureContents(context, image, dstFormat, mtlArea, 0, 0,
decompressBuf.data(), dstRowPitch));
} // if (mFormat.intendedAngleFormat().isBlock)
else
{
// Create scratch buffer
angle::MemoryBuffer conversionRow;
ANGLE_CHECK_GL_ALLOC(contextMtl, conversionRow.resize(dstRowPitch)); ANGLE_CHECK_GL_ALLOC(contextMtl, conversionRow.resize(dstRowPitch));
MTLRegion mtlRow = mtlArea; MTLRegion mtlRow = mtlArea;
...@@ -1048,16 +1074,25 @@ angle::Result TextureMtl::convertAndSetSubImage(const gl::Context *context, ...@@ -1048,16 +1074,25 @@ angle::Result TextureMtl::convertAndSetSubImage(const gl::Context *context,
mtlRow.origin.y = mtlArea.origin.y + r; mtlRow.origin.y = mtlArea.origin.y + r;
// Convert pixels // Convert pixels
if (loadFunctionInfo.loadFunction)
{
loadFunctionInfo.loadFunction(mtlRow.size.width, 1, 1, psrc, pixelsRowPitch, 0,
conversionRow.data(), dstRowPitch, 0);
}
else
{
CopyImageCHROMIUM(psrc, pixelsRowPitch, pixelsFormat.pixelBytes, 0, CopyImageCHROMIUM(psrc, pixelsRowPitch, pixelsFormat.pixelBytes, 0,
pixelsFormat.pixelReadFunction, conversionRow.data(), dstRowPitch, pixelsFormat.pixelReadFunction, conversionRow.data(), dstRowPitch,
dstFormat.pixelBytes, 0, dstFormat.pixelWriteFunction, dstFormat.pixelBytes, 0, dstFormat.pixelWriteFunction,
internalFormat.format, dstFormat.componentType, mtlRow.size.width, 1, 1, internalFormat.format, dstFormat.componentType, mtlRow.size.width,
false, false, false); 1, 1, false, false, false);
}
// Upload to texture // Upload to texture
ANGLE_TRY(UploadTextureContents(context, image, dstFormat, mtlRow, 0, 0, ANGLE_TRY(UploadTextureContents(context, image, dstFormat, mtlRow, 0, 0,
conversionRow.data(), dstRowPitch)); conversionRow.data(), dstRowPitch));
} }
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1066,10 +1101,7 @@ angle::Result TextureMtl::checkForEmulatedChannels(const gl::Context *context, ...@@ -1066,10 +1101,7 @@ angle::Result TextureMtl::checkForEmulatedChannels(const gl::Context *context,
const mtl::Format &mtlFormat, const mtl::Format &mtlFormat,
const mtl::TextureRef &texture) const mtl::TextureRef &texture)
{ {
bool emulatedChannels = false; bool emulatedChannels = mtl::IsFormatEmulated(mtlFormat);
MTLColorWriteMask colorWritableMask =
mtl::GetEmulatedColorWriteMask(mtlFormat, &emulatedChannels);
texture->setColorWritableMask(colorWritableMask);
// For emulated channels that GL texture intends to not have, // For emulated channels that GL texture intends to not have,
// we need to initialize their content. // we need to initialize their content.
...@@ -1135,7 +1167,7 @@ angle::Result TextureMtl::copySubImageImpl(const gl::Context *context, ...@@ -1135,7 +1167,7 @@ angle::Result TextureMtl::copySubImageImpl(const gl::Context *context,
ANGLE_TRY(ensureImageCreated(context, index)); ANGLE_TRY(ensureImageCreated(context, index));
if (!mtl::Format::FormatRenderable(mFormat.metalFormat)) if (!mFormat.getCaps().isRenderable())
{ {
return copySubImageCPU(context, index, modifiedDestOffset, clippedSourceArea, return copySubImageCPU(context, index, modifiedDestOffset, clippedSourceArea,
internalFormat, source); internalFormat, source);
...@@ -1265,7 +1297,7 @@ angle::Result TextureMtl::copySubTextureImpl(const gl::Context *context, ...@@ -1265,7 +1297,7 @@ angle::Result TextureMtl::copySubTextureImpl(const gl::Context *context,
const mtl::Format &dstFormat = contextMtl->getPixelFormat( const mtl::Format &dstFormat = contextMtl->getPixelFormat(
angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat)); angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat));
if (!mtl::Format::FormatRenderable(dstFormat.metalFormat)) if (!dstFormat.getCaps().isRenderable())
{ {
return copySubTextureCPU(context, index, destOffset, internalFormat, 0, sourceBox, return copySubTextureCPU(context, index, destOffset, internalFormat, 0, sourceBox,
srcAngleFormat, unpackFlipY, unpackPremultiplyAlpha, srcAngleFormat, unpackFlipY, unpackPremultiplyAlpha,
......
...@@ -13,10 +13,13 @@ ...@@ -13,10 +13,13 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
#include <unordered_map>
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libANGLE/Caps.h" #include "libANGLE/Caps.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/copyvertex.h" #include "libANGLE/renderer/copyvertex.h"
#include "libANGLE/renderer/renderer_utils.h"
namespace rx namespace rx
{ {
...@@ -41,6 +44,19 @@ struct FormatBase ...@@ -41,6 +44,19 @@ struct FormatBase
angle::FormatID intendedFormatId = angle::FormatID::NONE; angle::FormatID intendedFormatId = angle::FormatID::NONE;
}; };
struct FormatCaps
{
bool isRenderable() const { return colorRenderable || depthRenderable; }
bool filterable = false;
bool writable = false;
bool colorRenderable = false;
bool depthRenderable = false;
bool blendable = false;
bool multisample = false; // can be used as MSAA target
bool resolve = false; // Can be used as resolve target
};
// Pixel format // Pixel format
struct Format : public FormatBase struct Format : public FormatBase
{ {
...@@ -49,12 +65,31 @@ struct Format : public FormatBase ...@@ -49,12 +65,31 @@ struct Format : public FormatBase
const gl::InternalFormat &intendedInternalFormat() const; const gl::InternalFormat &intendedInternalFormat() const;
bool valid() const { return metalFormat != MTLPixelFormatInvalid; } bool valid() const { return metalFormat != MTLPixelFormatInvalid; }
bool hasDepthAndStencilBits() const
{
return actualAngleFormat().depthBits && actualAngleFormat().stencilBits;
}
bool hasDepthOrStencilBits() const
{
return actualAngleFormat().depthBits || actualAngleFormat().stencilBits;
}
bool isPVRTC() const;
static bool FormatRenderable(MTLPixelFormat format); const FormatCaps &getCaps() const { return *caps; }
static bool FormatCPUReadable(MTLPixelFormat format);
// Need conversion between source format and this format?
bool needConversion(angle::FormatID srcFormatId) const;
MTLPixelFormat metalFormat = MTLPixelFormatInvalid; MTLPixelFormat metalFormat = MTLPixelFormatInvalid;
LoadFunctionMap textureLoadFunctions = nullptr;
InitializeTextureDataFunction initFunction = nullptr;
const FormatCaps *caps = nullptr;
bool swizzled = false;
std::array<GLenum, 4> swizzle;
private: private:
void init(const DisplayMtl *display, angle::FormatID intendedFormatId); void init(const DisplayMtl *display, angle::FormatID intendedFormatId);
...@@ -70,6 +105,11 @@ struct VertexFormat : public FormatBase ...@@ -70,6 +105,11 @@ struct VertexFormat : public FormatBase
VertexCopyFunction vertexLoadFunction = nullptr; VertexCopyFunction vertexLoadFunction = nullptr;
uint32_t defaultAlpha = 0;
// Intended and actual format have same GL type, and possibly only differ in number of
// components?
bool actualSameGLType = true;
private: private:
void init(angle::FormatID angleFormatId, bool tightlyPacked = false); void init(angle::FormatID angleFormatId, bool tightlyPacked = false);
...@@ -86,9 +126,10 @@ class FormatTable final : angle::NonCopyable ...@@ -86,9 +126,10 @@ class FormatTable final : angle::NonCopyable
void generateTextureCaps(const DisplayMtl *display, void generateTextureCaps(const DisplayMtl *display,
gl::TextureCapsMap *capsMapOut, gl::TextureCapsMap *capsMapOut,
std::vector<GLenum> *compressedFormatsOut) const; std::vector<GLenum> *compressedFormatsOut);
const Format &getPixelFormat(angle::FormatID angleFormatId) const; const Format &getPixelFormat(angle::FormatID angleFormatId) const;
const FormatCaps &getNativeFormatCaps(MTLPixelFormat mtlFormat) const;
// tightlyPacked means this format will be used in a tightly packed vertex buffer. // tightlyPacked means this format will be used in a tightly packed vertex buffer.
// In that case, it's easier to just convert everything to float to ensure // In that case, it's easier to just convert everything to float to ensure
...@@ -96,10 +137,34 @@ class FormatTable final : angle::NonCopyable ...@@ -96,10 +137,34 @@ class FormatTable final : angle::NonCopyable
// of how many components each element has. // of how many components each element has.
const VertexFormat &getVertexFormat(angle::FormatID angleFormatId, bool tightlyPacked) const; const VertexFormat &getVertexFormat(angle::FormatID angleFormatId, bool tightlyPacked) const;
uint32_t getMaxSamples() const { return mMaxSamples; }
private: private:
void initNativeFormatCaps(const DisplayMtl *display);
void setFormatCaps(MTLPixelFormat formatId,
bool filterable,
bool writable,
bool blendable,
bool multisample,
bool resolve,
bool colorRenderable);
void setFormatCaps(MTLPixelFormat formatId,
bool filterable,
bool writable,
bool blendable,
bool multisample,
bool resolve,
bool colorRenderable,
bool depthRenderable);
void setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable);
std::array<Format, angle::kNumANGLEFormats> mPixelFormatTable; std::array<Format, angle::kNumANGLEFormats> mPixelFormatTable;
std::unordered_map<MTLPixelFormat, FormatCaps> mNativePixelFormatCapsTable;
// One for tightly packed buffers, one for general cases. // One for tightly packed buffers, one for general cases.
std::array<VertexFormat, angle::kNumANGLEFormats> mVertexFormatTables[2]; std::array<VertexFormat, angle::kNumANGLEFormats> mVertexFormatTables[2];
uint32_t mMaxSamples;
}; };
} // namespace mtl } // namespace mtl
......
...@@ -100,7 +100,7 @@ class Texture final : public Resource, ...@@ -100,7 +100,7 @@ class Texture final : public Resource,
uint32_t height, uint32_t height,
uint32_t mips /** use zero to create full mipmaps chain */, uint32_t mips /** use zero to create full mipmaps chain */,
bool renderTargetOnly, bool renderTargetOnly,
bool allowTextureView, bool allowFormatView,
TextureRef *refOut); TextureRef *refOut);
static angle::Result MakeCubeTexture(ContextMtl *context, static angle::Result MakeCubeTexture(ContextMtl *context,
...@@ -108,7 +108,7 @@ class Texture final : public Resource, ...@@ -108,7 +108,7 @@ class Texture final : public Resource,
uint32_t size, uint32_t size,
uint32_t mips /** use zero to create full mipmaps chain */, uint32_t mips /** use zero to create full mipmaps chain */,
bool renderTargetOnly, bool renderTargetOnly,
bool allowTextureView, bool allowFormatView,
TextureRef *refOut); TextureRef *refOut);
static angle::Result Make2DMSTexture(ContextMtl *context, static angle::Result Make2DMSTexture(ContextMtl *context,
...@@ -117,7 +117,7 @@ class Texture final : public Resource, ...@@ -117,7 +117,7 @@ class Texture final : public Resource,
uint32_t height, uint32_t height,
uint32_t samples, uint32_t samples,
bool renderTargetOnly, bool renderTargetOnly,
bool allowTextureView, bool allowFormatView,
TextureRef *refOut); TextureRef *refOut);
static TextureRef MakeFromMetal(id<MTLTexture> metalTexture); static TextureRef MakeFromMetal(id<MTLTexture> metalTexture);
...@@ -125,6 +125,8 @@ class Texture final : public Resource, ...@@ -125,6 +125,8 @@ class Texture final : public Resource,
// Allow CPU to read & write data directly to this texture? // Allow CPU to read & write data directly to this texture?
bool isCPUAccessible() const; bool isCPUAccessible() const;
bool supportFormatView() const;
void replaceRegion(ContextMtl *context, void replaceRegion(ContextMtl *context,
MTLRegion region, MTLRegion region,
uint32_t mipmapLevel, uint32_t mipmapLevel,
...@@ -145,6 +147,9 @@ class Texture final : public Resource, ...@@ -145,6 +147,9 @@ class Texture final : public Resource,
TextureRef createSliceMipView(uint32_t slice, uint32_t level); TextureRef createSliceMipView(uint32_t slice, uint32_t level);
// Create a view with different format // Create a view with different format
TextureRef createViewWithDifferentFormat(MTLPixelFormat format); TextureRef createViewWithDifferentFormat(MTLPixelFormat format);
// Same as above but the target format must be compatible, for example sRGB to linear. In this
// case texture doesn't need format view usage flag.
TextureRef createViewWithCompatibleFormat(MTLPixelFormat format);
MTLTextureType textureType() const; MTLTextureType textureType() const;
MTLPixelFormat pixelFormat() const; MTLPixelFormat pixelFormat() const;
...@@ -175,12 +180,20 @@ class Texture final : public Resource, ...@@ -175,12 +180,20 @@ class Texture final : public Resource,
private: private:
using ParentClass = WrappedObject<id<MTLTexture>>; using ParentClass = WrappedObject<id<MTLTexture>>;
static angle::Result MakeTexture(ContextMtl *context,
const Format &mtlFormat,
MTLTextureDescriptor *desc,
uint32_t mips,
bool renderTargetOnly,
bool allowFormatView,
TextureRef *refOut);
Texture(id<MTLTexture> metalTexture); Texture(id<MTLTexture> metalTexture);
Texture(ContextMtl *context, Texture(ContextMtl *context,
MTLTextureDescriptor *desc, MTLTextureDescriptor *desc,
uint32_t mips, uint32_t mips,
bool renderTargetOnly, bool renderTargetOnly,
bool supportTextureView); bool allowFormatView);
// Create a texture view // Create a texture view
Texture(Texture *original, MTLPixelFormat format); Texture(Texture *original, MTLPixelFormat format);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "libANGLE/renderer/metal/DisplayMtl.h" #include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/mtl_command_buffer.h" #include "libANGLE/renderer/metal/mtl_command_buffer.h"
#include "libANGLE/renderer/metal/mtl_format_utils.h" #include "libANGLE/renderer/metal/mtl_format_utils.h"
#include "libANGLE/renderer/metal/mtl_utils.h"
namespace rx namespace rx
{ {
...@@ -35,21 +36,12 @@ void SetTextureSwizzle(ContextMtl *context, ...@@ -35,21 +36,12 @@ void SetTextureSwizzle(ContextMtl *context,
MTLTextureDescriptor *textureDescOut) MTLTextureDescriptor *textureDescOut)
{ {
// Texture swizzle functions's declarations are only available if macos 10.15 sdk is present // Texture swizzle functions's declarations are only available if macos 10.15 sdk is present
#if defined(__MAC_10_15) #if defined(__IPHONE_13_0) || defined(__MAC_10_15)
if (context->getDisplay()->getFeatures().hasTextureSwizzle.enabled) if (context->getDisplay()->getFeatures().hasTextureSwizzle.enabled && format.swizzled)
{ {
// Work around Metal doesn't have native support for DXT1 without alpha. textureDescOut.swizzle = MTLTextureSwizzleChannelsMake(
switch (format.intendedFormatId) GetTextureSwizzle(format.swizzle[0]), GetTextureSwizzle(format.swizzle[1]),
{ GetTextureSwizzle(format.swizzle[2]), GetTextureSwizzle(format.swizzle[3]));
case angle::FormatID::BC1_RGB_UNORM_BLOCK:
case angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK:
textureDescOut.swizzle =
MTLTextureSwizzleChannelsMake(MTLTextureSwizzleRed, MTLTextureSwizzleGreen,
MTLTextureSwizzleBlue, MTLTextureSwizzleOne);
break;
default:
break;
}
} }
#endif #endif
} }
...@@ -97,7 +89,7 @@ angle::Result Texture::Make2DTexture(ContextMtl *context, ...@@ -97,7 +89,7 @@ angle::Result Texture::Make2DTexture(ContextMtl *context,
uint32_t height, uint32_t height,
uint32_t mips, uint32_t mips,
bool renderTargetOnly, bool renderTargetOnly,
bool allowTextureView, bool allowFormatView,
TextureRef *refOut) TextureRef *refOut)
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
...@@ -108,16 +100,8 @@ angle::Result Texture::Make2DTexture(ContextMtl *context, ...@@ -108,16 +100,8 @@ angle::Result Texture::Make2DTexture(ContextMtl *context,
height:height height:height
mipmapped:mips == 0 || mips > 1]; mipmapped:mips == 0 || mips > 1];
SetTextureSwizzle(context, format, desc); return MakeTexture(context, format, desc, mips, renderTargetOnly, allowFormatView, refOut);
refOut->reset(new Texture(context, desc, mips, renderTargetOnly, allowTextureView));
} // ANGLE_MTL_OBJC_SCOPE } // ANGLE_MTL_OBJC_SCOPE
if (!refOut || !refOut->get())
{
ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY);
}
return angle::Result::Continue;
} }
/** static */ /** static */
...@@ -126,7 +110,7 @@ angle::Result Texture::MakeCubeTexture(ContextMtl *context, ...@@ -126,7 +110,7 @@ angle::Result Texture::MakeCubeTexture(ContextMtl *context,
uint32_t size, uint32_t size,
uint32_t mips, uint32_t mips,
bool renderTargetOnly, bool renderTargetOnly,
bool allowTextureView, bool allowFormatView,
TextureRef *refOut) TextureRef *refOut)
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
...@@ -135,16 +119,9 @@ angle::Result Texture::MakeCubeTexture(ContextMtl *context, ...@@ -135,16 +119,9 @@ angle::Result Texture::MakeCubeTexture(ContextMtl *context,
[MTLTextureDescriptor textureCubeDescriptorWithPixelFormat:format.metalFormat [MTLTextureDescriptor textureCubeDescriptorWithPixelFormat:format.metalFormat
size:size size:size
mipmapped:mips == 0 || mips > 1]; mipmapped:mips == 0 || mips > 1];
SetTextureSwizzle(context, format, desc);
refOut->reset(new Texture(context, desc, mips, renderTargetOnly, allowTextureView));
} // ANGLE_MTL_OBJC_SCOPE
if (!refOut || !refOut->get()) return MakeTexture(context, format, desc, mips, renderTargetOnly, allowFormatView, refOut);
{ } // ANGLE_MTL_OBJC_SCOPE
ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY);
}
return angle::Result::Continue;
} }
/** static */ /** static */
...@@ -154,7 +131,7 @@ angle::Result Texture::Make2DMSTexture(ContextMtl *context, ...@@ -154,7 +131,7 @@ angle::Result Texture::Make2DMSTexture(ContextMtl *context,
uint32_t height, uint32_t height,
uint32_t samples, uint32_t samples,
bool renderTargetOnly, bool renderTargetOnly,
bool allowTextureView, bool allowFormatView,
TextureRef *refOut) TextureRef *refOut)
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
...@@ -167,14 +144,31 @@ angle::Result Texture::Make2DMSTexture(ContextMtl *context, ...@@ -167,14 +144,31 @@ angle::Result Texture::Make2DMSTexture(ContextMtl *context,
desc.mipmapLevelCount = 1; desc.mipmapLevelCount = 1;
desc.sampleCount = samples; desc.sampleCount = samples;
SetTextureSwizzle(context, format, desc); return MakeTexture(context, format, desc, 1, renderTargetOnly, allowFormatView, refOut);
refOut->reset(new Texture(context, desc, 1, renderTargetOnly, allowTextureView));
} // ANGLE_MTL_OBJC_SCOPE } // ANGLE_MTL_OBJC_SCOPE
}
/** static */
angle::Result Texture::MakeTexture(ContextMtl *context,
const Format &mtlFormat,
MTLTextureDescriptor *desc,
uint32_t mips,
bool renderTargetOnly,
bool allowFormatView,
TextureRef *refOut)
{
SetTextureSwizzle(context, mtlFormat, desc);
refOut->reset(new Texture(context, desc, mips, renderTargetOnly, allowFormatView));
if (!refOut || !refOut->get()) if (!refOut || !refOut->get())
{ {
ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY); ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY);
} }
if (!mtlFormat.hasDepthAndStencilBits())
{
refOut->get()->setColorWritableMask(GetEmulatedColorWriteMask(mtlFormat));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -195,7 +189,7 @@ Texture::Texture(ContextMtl *context, ...@@ -195,7 +189,7 @@ Texture::Texture(ContextMtl *context,
MTLTextureDescriptor *desc, MTLTextureDescriptor *desc,
uint32_t mips, uint32_t mips,
bool renderTargetOnly, bool renderTargetOnly,
bool supportTextureView) bool allowFormatView)
: mColorWritableMask(std::make_shared<MTLColorWriteMask>(MTLColorWriteMaskAll)) : mColorWritableMask(std::make_shared<MTLColorWriteMask>(MTLColorWriteMaskAll))
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
...@@ -210,14 +204,15 @@ Texture::Texture(ContextMtl *context, ...@@ -210,14 +204,15 @@ Texture::Texture(ContextMtl *context,
// Every texture will support being rendered for now // Every texture will support being rendered for now
desc.usage = 0; desc.usage = 0;
if (Format::FormatRenderable(desc.pixelFormat)) if (context->getNativeFormatCaps(desc.pixelFormat).isRenderable())
{ {
desc.usage |= MTLTextureUsageRenderTarget; desc.usage |= MTLTextureUsageRenderTarget;
} }
if (!Format::FormatCPUReadable(desc.pixelFormat) || if (context->getNativeFormatCaps(desc.pixelFormat).depthRenderable ||
desc.textureType == MTLTextureType2DMultisample) desc.textureType == MTLTextureType2DMultisample)
{ {
// Metal doesn't support host access to depth stencil texture's data
desc.resourceOptions = MTLResourceStorageModePrivate; desc.resourceOptions = MTLResourceStorageModePrivate;
} }
...@@ -226,7 +221,7 @@ Texture::Texture(ContextMtl *context, ...@@ -226,7 +221,7 @@ Texture::Texture(ContextMtl *context,
desc.usage = desc.usage | MTLTextureUsageShaderRead; desc.usage = desc.usage | MTLTextureUsageShaderRead;
} }
if (supportTextureView) if (allowFormatView)
{ {
desc.usage = desc.usage | MTLTextureUsagePixelFormatView; desc.usage = desc.usage | MTLTextureUsagePixelFormatView;
} }
...@@ -299,6 +294,11 @@ bool Texture::isCPUAccessible() const ...@@ -299,6 +294,11 @@ bool Texture::isCPUAccessible() const
return get().storageMode == MTLStorageModeShared; return get().storageMode == MTLStorageModeShared;
} }
bool Texture::supportFormatView() const
{
return get().usage & MTLTextureUsagePixelFormatView;
}
void Texture::replaceRegion(ContextMtl *context, void Texture::replaceRegion(ContextMtl *context,
MTLRegion region, MTLRegion region,
uint32_t mipmapLevel, uint32_t mipmapLevel,
...@@ -391,6 +391,12 @@ TextureRef Texture::createSliceMipView(uint32_t slice, uint32_t level) ...@@ -391,6 +391,12 @@ TextureRef Texture::createSliceMipView(uint32_t slice, uint32_t level)
TextureRef Texture::createViewWithDifferentFormat(MTLPixelFormat format) TextureRef Texture::createViewWithDifferentFormat(MTLPixelFormat format)
{ {
ASSERT(supportFormatView());
return TextureRef(new Texture(this, format));
}
TextureRef Texture::createViewWithCompatibleFormat(MTLPixelFormat format)
{
// No need for ASSERT(supportFormatView());
return TextureRef(new Texture(this, format)); return TextureRef(new Texture(this, format));
} }
...@@ -453,10 +459,10 @@ TextureRef Texture::getLinearColorView() ...@@ -453,10 +459,10 @@ TextureRef Texture::getLinearColorView()
switch (pixelFormat()) switch (pixelFormat())
{ {
case MTLPixelFormatRGBA8Unorm_sRGB: case MTLPixelFormatRGBA8Unorm_sRGB:
mLinearColorView = createViewWithDifferentFormat(MTLPixelFormatRGBA8Unorm); mLinearColorView = createViewWithCompatibleFormat(MTLPixelFormatRGBA8Unorm);
break; break;
case MTLPixelFormatBGRA8Unorm_sRGB: case MTLPixelFormatBGRA8Unorm_sRGB:
mLinearColorView = createViewWithDifferentFormat(MTLPixelFormatBGRA8Unorm); mLinearColorView = createViewWithCompatibleFormat(MTLPixelFormatBGRA8Unorm);
break; break;
default: default:
// NOTE(hqle): Not all sRGB formats are supported yet. // NOTE(hqle): Not all sRGB formats are supported yet.
......
...@@ -99,6 +99,10 @@ PrimitiveTopologyClass GetPrimitiveTopologyClass(gl::PrimitiveMode mode); ...@@ -99,6 +99,10 @@ PrimitiveTopologyClass GetPrimitiveTopologyClass(gl::PrimitiveMode mode);
MTLPrimitiveType GetPrimitiveType(gl::PrimitiveMode mode); MTLPrimitiveType GetPrimitiveType(gl::PrimitiveMode mode);
MTLIndexType GetIndexType(gl::DrawElementsType type); MTLIndexType GetIndexType(gl::DrawElementsType type);
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
MTLTextureSwizzle GetTextureSwizzle(GLenum swizzle);
#endif
// Get color write mask for a specified format. Some formats such as RGB565 doesn't have alpha // Get color write mask for a specified format. Some formats such as RGB565 doesn't have alpha
// channel but is emulated by a RGBA8 format, we need to disable alpha write for this format. // channel but is emulated by a RGBA8 format, we need to disable alpha write for this format.
// - isFormatEmulated: if the format is emulated, this pointer will store a true value. // - isFormatEmulated: if the format is emulated, this pointer will store a true value.
......
...@@ -44,25 +44,36 @@ angle::Result InitializeTextureContents(const gl::Context *context, ...@@ -44,25 +44,36 @@ angle::Result InitializeTextureContents(const gl::Context *context,
gl::Extents size = texture->size(index); gl::Extents size = texture->size(index);
// Intialize the content to black // Initialize the content to black
const angle::Format &srcFormat = if (texture->isCPUAccessible() && index.getType() != gl::TextureType::_2DMultisample &&
angle::Format::Get(intendedInternalFormat.alphaBits > 0 ? angle::FormatID::R8G8B8A8_UNORM index.getType() != gl::TextureType::_2DMultisampleArray)
: angle::FormatID::R8G8B8_UNORM); {
const size_t srcRowPitch = srcFormat.pixelBytes * size.width;
angle::MemoryBuffer srcRow;
ANGLE_CHECK_GL_ALLOC(contextMtl, srcRow.resize(srcRowPitch));
memset(srcRow.data(), 0, srcRowPitch);
const angle::Format &dstFormat = angle::Format::Get(textureObjFormat.actualFormatId); const angle::Format &dstFormat = angle::Format::Get(textureObjFormat.actualFormatId);
const size_t dstRowPitch = dstFormat.pixelBytes * size.width; const size_t dstRowPitch = dstFormat.pixelBytes * size.width;
angle::MemoryBuffer conversionRow; angle::MemoryBuffer conversionRow;
ANGLE_CHECK_GL_ALLOC(contextMtl, conversionRow.resize(dstRowPitch)); ANGLE_CHECK_GL_ALLOC(contextMtl, conversionRow.resize(dstRowPitch));
if (textureObjFormat.initFunction)
{
textureObjFormat.initFunction(size.width, 1, 1, conversionRow.data(), dstRowPitch, 0);
}
else
{
const angle::Format &srcFormat = angle::Format::Get(
intendedInternalFormat.alphaBits > 0 ? angle::FormatID::R8G8B8A8_UNORM
: angle::FormatID::R8G8B8_UNORM);
const size_t srcRowPitch = srcFormat.pixelBytes * size.width;
angle::MemoryBuffer srcRow;
ANGLE_CHECK_GL_ALLOC(contextMtl, srcRow.resize(srcRowPitch));
memset(srcRow.data(), 0, srcRowPitch);
CopyImageCHROMIUM(srcRow.data(), srcRowPitch, srcFormat.pixelBytes, 0, CopyImageCHROMIUM(srcRow.data(), srcRowPitch, srcFormat.pixelBytes, 0,
srcFormat.pixelReadFunction, conversionRow.data(), dstRowPitch, srcFormat.pixelReadFunction, conversionRow.data(), dstRowPitch,
dstFormat.pixelBytes, 0, dstFormat.pixelWriteFunction, dstFormat.pixelBytes, 0, dstFormat.pixelWriteFunction,
intendedInternalFormat.format, dstFormat.componentType, size.width, 1, 1, intendedInternalFormat.format, dstFormat.componentType, size.width, 1,
false, false, false); 1, false, false, false);
}
auto mtlRowRegion = MTLRegionMake2D(0, 0, size.width, 1); auto mtlRowRegion = MTLRegionMake2D(0, 0, size.width, 1);
...@@ -75,6 +86,11 @@ angle::Result InitializeTextureContents(const gl::Context *context, ...@@ -75,6 +86,11 @@ angle::Result InitializeTextureContents(const gl::Context *context,
index.hasLayer() ? index.cubeMapFaceIndex() : 0, index.hasLayer() ? index.cubeMapFaceIndex() : 0,
conversionRow.data(), dstRowPitch); conversionRow.data(), dstRowPitch);
} }
}
else
{
ANGLE_TRY(InitializeTextureContentsGPU(context, texture, index, MTLColorWriteMaskAll));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -476,6 +492,30 @@ MTLIndexType GetIndexType(gl::DrawElementsType type) ...@@ -476,6 +492,30 @@ MTLIndexType GetIndexType(gl::DrawElementsType type)
} }
} }
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
MTLTextureSwizzle GetTextureSwizzle(GLenum swizzle)
{
switch (swizzle)
{
case GL_RED:
return MTLTextureSwizzleRed;
case GL_GREEN:
return MTLTextureSwizzleGreen;
case GL_BLUE:
return MTLTextureSwizzleBlue;
case GL_ALPHA:
return MTLTextureSwizzleAlpha;
case GL_ZERO:
return MTLTextureSwizzleZero;
case GL_ONE:
return MTLTextureSwizzleOne;
default:
UNREACHABLE();
return MTLTextureSwizzleZero;
}
}
#endif
MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool *isEmulatedOut) MTLColorWriteMask GetEmulatedColorWriteMask(const mtl::Format &mtlFormat, bool *isEmulatedOut)
{ {
const angle::Format &intendedFormat = mtlFormat.intendedAngleFormat(); const angle::Format &intendedFormat = mtlFormat.intendedAngleFormat();
......
...@@ -110,6 +110,47 @@ TEST_P(DXT1CompressedTextureTest, CompressedTexImage) ...@@ -110,6 +110,47 @@ TEST_P(DXT1CompressedTextureTest, CompressedTexImage)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Verify that DXT1 RGB textures have 1.0 alpha when sampled
TEST_P(DXT1CompressedTextureTest, DXT1Alpha)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
// http://anglebug.com/4917
ANGLE_SKIP_TEST_IF(IsD3D());
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Image using pixels with the code for transparent black:
// "BLACK, if color0 <= color1 and code(x,y) == 3"
constexpr uint8_t CompressedImageDXT1[] = {0, 0, 0, 0, 51, 204, 51, 204};
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
sizeof(CompressedImageDXT1), CompressedImageDXT1);
EXPECT_GL_NO_ERROR();
glUseProgram(mTextureProgram);
glUniform1i(mTextureUniformLocation, 0);
constexpr GLint kDrawSize = 4;
// The image is one 4x4 block, make the viewport only 4x4.
glViewport(0, 0, kDrawSize, kDrawSize);
drawQuad(mTextureProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
for (GLint y = 0; y < kDrawSize; y++)
{
for (GLint x = 0; x < kDrawSize; x++)
{
EXPECT_PIXEL_EQ(x, y, 0, 0, 0, 255) << "at (" << x << ", " << y << ")";
}
}
}
TEST_P(DXT1CompressedTextureTest, CompressedTexStorage) TEST_P(DXT1CompressedTextureTest, CompressedTexStorage)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
......
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