Commit 27e7e446 by Le Hoang Quyen Committed by Commit Bot

Metal: Support 2D array textures and base & max levels.

Bug: angleproject:2634 Change-Id: If9e50cec46bdf5f472f1e58c6e82a67b524e2408 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2433327 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 b4fb7cc9
...@@ -166,6 +166,7 @@ angle::Result ContextMtl::ensureIncompleteTexturesCreated(const gl::Context *con ...@@ -166,6 +166,7 @@ angle::Result ContextMtl::ensureIncompleteTexturesCreated(const gl::Context *con
return angle::Result::Continue; return angle::Result::Continue;
} }
constexpr gl::TextureType supportedTextureTypes[] = {gl::TextureType::_2D, gl::TextureType::_3D, constexpr gl::TextureType supportedTextureTypes[] = {gl::TextureType::_2D, gl::TextureType::_3D,
gl::TextureType::_2DArray,
gl::TextureType::CubeMap}; gl::TextureType::CubeMap};
for (gl::TextureType texType : supportedTextureTypes) for (gl::TextureType texType : supportedTextureTypes)
{ {
......
...@@ -175,6 +175,7 @@ class TextureMtl : public TextureImpl ...@@ -175,6 +175,7 @@ class TextureMtl : public TextureImpl
gl::TextureType type, gl::TextureType type,
GLuint mips, GLuint mips,
const gl::Extents &size); const gl::Extents &size);
angle::Result onBaseMaxLevelsChanged(const gl::Context *context);
angle::Result ensureSamplerStateCreated(const gl::Context *context); angle::Result ensureSamplerStateCreated(const gl::Context *context);
// Ensure image at given index is created: // Ensure image at given index is created:
angle::Result ensureImageCreated(const gl::Context *context, const gl::ImageIndex &index); angle::Result ensureImageCreated(const gl::Context *context, const gl::ImageIndex &index);
...@@ -334,6 +335,9 @@ class TextureMtl : public TextureImpl ...@@ -334,6 +335,9 @@ class TextureMtl : public TextureImpl
// Mipmap views are indexed by native level (ignored base level): // Mipmap views are indexed by native level (ignored base level):
mtl::NativeTexLevelArray mNativeLevelViews; mtl::NativeTexLevelArray mNativeLevelViews;
GLuint mCurrentBaseLevel = 0;
GLuint mCurrentMaxLevel = 1000;
bool mIsPow2 = false; bool mIsPow2 = false;
}; };
......
...@@ -454,7 +454,9 @@ angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context) ...@@ -454,7 +454,9 @@ angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context)
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
// Create actual texture object: // Create actual texture object:
const GLuint mips = mState.getMipmapMaxLevel() - mState.getEffectiveBaseLevel() + 1; mCurrentBaseLevel = mState.getEffectiveBaseLevel();
const GLuint mips = mState.getMipmapMaxLevel() - mCurrentBaseLevel + 1;
gl::ImageDesc desc = mState.getBaseLevelDesc(); gl::ImageDesc desc = mState.getBaseLevelDesc();
ANGLE_MTL_CHECK(contextMtl, desc.format.valid(), GL_INVALID_OPERATION); ANGLE_MTL_CHECK(contextMtl, desc.format.valid(), GL_INVALID_OPERATION);
angle::FormatID angleFormatId = angle::FormatID angleFormatId =
...@@ -472,6 +474,9 @@ angle::Result TextureMtl::createNativeTexture(const gl::Context *context, ...@@ -472,6 +474,9 @@ angle::Result TextureMtl::createNativeTexture(const gl::Context *context,
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
// Create actual texture object: // Create actual texture object:
mCurrentBaseLevel = mState.getEffectiveBaseLevel();
mCurrentMaxLevel = mState.getEffectiveMaxLevel();
mIsPow2 = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth); mIsPow2 = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth);
mSlices = 1; mSlices = 1;
int numCubeFaces = 1; int numCubeFaces = 1;
...@@ -496,6 +501,13 @@ angle::Result TextureMtl::createNativeTexture(const gl::Context *context, ...@@ -496,6 +501,13 @@ angle::Result TextureMtl::createNativeTexture(const gl::Context *context,
/** renderTargetOnly */ false, /** renderTargetOnly */ false,
/** allowFormatView */ mFormat.hasDepthAndStencilBits(), &mNativeTexture)); /** allowFormatView */ mFormat.hasDepthAndStencilBits(), &mNativeTexture));
break; break;
case gl::TextureType::_2DArray:
mSlices = size.depth;
ANGLE_TRY(mtl::Texture::Make2DArrayTexture(
contextMtl, mFormat, size.width, size.height, mips, mSlices,
/** renderTargetOnly */ false,
/** allowFormatView */ mFormat.hasDepthAndStencilBits(), &mNativeTexture));
break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -569,6 +581,26 @@ angle::Result TextureMtl::ensureSamplerStateCreated(const gl::Context *context) ...@@ -569,6 +581,26 @@ angle::Result TextureMtl::ensureSamplerStateCreated(const gl::Context *context)
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result TextureMtl::onBaseMaxLevelsChanged(const gl::Context *context)
{
if (!mNativeTexture || (mCurrentBaseLevel == mState.getEffectiveBaseLevel() &&
mCurrentMaxLevel == mState.getEffectiveMaxLevel()))
{
return angle::Result::Continue;
}
ContextMtl *contextMtl = mtl::GetImpl(context);
// Release native texture but keep old image definitions so that it can be recreated from old
// image definitions with different base level
releaseTexture(false, true);
// Tell context to rebind textures
contextMtl->invalidateCurrentTextures();
return angle::Result::Continue;
}
angle::Result TextureMtl::ensureImageCreated(const gl::Context *context, angle::Result TextureMtl::ensureImageCreated(const gl::Context *context,
const gl::ImageIndex &index) const gl::ImageIndex &index)
{ {
...@@ -657,7 +689,7 @@ void TextureMtl::retainImageDefinitions() ...@@ -657,7 +689,7 @@ void TextureMtl::retainImageDefinitions()
{ {
for (mtl::MipmapNativeLevel mip = mtl::kZeroNativeMipLevel; mip.get() < mips; ++mip) for (mtl::MipmapNativeLevel mip = mtl::kZeroNativeMipLevel; mip.get() < mips; ++mip)
{ {
GLuint imageMipLevel = mtl::GetGLMipLevel(mip, mState.getEffectiveBaseLevel()); GLuint imageMipLevel = mtl::GetGLMipLevel(mip, mCurrentBaseLevel);
ImageDefinitionMtl &imageDef = mTexImageDefs[face][imageMipLevel]; ImageDefinitionMtl &imageDef = mTexImageDefs[face][imageMipLevel];
if (imageDef.image) if (imageDef.image)
{ {
...@@ -1065,10 +1097,7 @@ angle::Result TextureMtl::generateMipmapCPU(const gl::Context *context) ...@@ -1065,10 +1097,7 @@ angle::Result TextureMtl::generateMipmapCPU(const gl::Context *context)
angle::Result TextureMtl::setBaseLevel(const gl::Context *context, GLuint baseLevel) angle::Result TextureMtl::setBaseLevel(const gl::Context *context, GLuint baseLevel)
{ {
// NOTE(hqle): ES 3.0 return onBaseMaxLevelsChanged(context);
UNIMPLEMENTED();
return angle::Result::Stop;
} }
angle::Result TextureMtl::bindTexImage(const gl::Context *context, egl::Surface *surface) angle::Result TextureMtl::bindTexImage(const gl::Context *context, egl::Surface *surface)
...@@ -1115,10 +1144,46 @@ angle::Result TextureMtl::syncState(const gl::Context *context, ...@@ -1115,10 +1144,46 @@ angle::Result TextureMtl::syncState(const gl::Context *context,
const gl::Texture::DirtyBits &dirtyBits, const gl::Texture::DirtyBits &dirtyBits,
gl::Command source) gl::Command source)
{ {
if (dirtyBits.any()) ContextMtl *contextMtl = mtl::GetImpl(context);
for (size_t dirtyBit : dirtyBits)
{ {
// Invalidate sampler state switch (dirtyBit)
mMetalSamplerState = nil; {
case gl::Texture::DIRTY_BIT_COMPARE_MODE:
case gl::Texture::DIRTY_BIT_COMPARE_FUNC:
// Tell context to rebind textures so that ProgramMtl has a chance to verify
// depth texture compare mode.
contextMtl->invalidateCurrentTextures();
// fall through
OS_FALLTHROUGH;
case gl::Texture::DIRTY_BIT_MIN_FILTER:
case gl::Texture::DIRTY_BIT_MAG_FILTER:
case gl::Texture::DIRTY_BIT_WRAP_S:
case gl::Texture::DIRTY_BIT_WRAP_T:
case gl::Texture::DIRTY_BIT_WRAP_R:
case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY:
case gl::Texture::DIRTY_BIT_MIN_LOD:
case gl::Texture::DIRTY_BIT_MAX_LOD:
case gl::Texture::DIRTY_BIT_SRGB_DECODE:
case gl::Texture::DIRTY_BIT_BORDER_COLOR:
// Recreate sampler state
mMetalSamplerState = nil;
break;
case gl::Texture::DIRTY_BIT_MAX_LEVEL:
case gl::Texture::DIRTY_BIT_BASE_LEVEL:
ANGLE_TRY(onBaseMaxLevelsChanged(context));
break;
case gl::Texture::DIRTY_BIT_SWIZZLE_RED:
case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN:
case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE:
case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA:
{
UNIMPLEMENTED();
}
break;
default:
break;
}
} }
ANGLE_TRY(ensureTextureCreated(context)); ANGLE_TRY(ensureTextureCreated(context));
...@@ -1205,6 +1270,12 @@ angle::Result TextureMtl::redefineImage(const gl::Context *context, ...@@ -1205,6 +1270,12 @@ angle::Result TextureMtl::redefineImage(const gl::Context *context,
/** renderTargetOnly */ false, /** renderTargetOnly */ false,
/** allowFormatView */ mFormat.hasDepthAndStencilBits(), &imageDef.image)); /** allowFormatView */ mFormat.hasDepthAndStencilBits(), &imageDef.image));
break; break;
case gl::TextureType::_2DArray:
ANGLE_TRY(mtl::Texture::Make2DArrayTexture(
contextMtl, mtlFormat, size.width, size.height, 1, size.depth,
/** renderTargetOnly */ false,
/** allowFormatView */ mFormat.hasDepthAndStencilBits(), &imageDef.image));
break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -1326,11 +1397,32 @@ angle::Result TextureMtl::setSubImageImpl(const gl::Context *context, ...@@ -1326,11 +1397,32 @@ angle::Result TextureMtl::setSubImageImpl(const gl::Context *context,
const uint8_t *usablePixels = oriPixels + sourceSkipBytes; const uint8_t *usablePixels = oriPixels + sourceSkipBytes;
auto mtlRegion = MTLRegionMake3D(area.x, area.y, area.z, area.width, area.height, area.depth); // Upload to texture
if (index.getType() == gl::TextureType::_2DArray)
{
// OpenGL unifies texture array and texture 3d's box area by using z & depth as array start
// index & length for texture array. However, Metal treats them differently. We need to
// handle them in separate code.
MTLRegion mtlRegion = MTLRegionMake3D(area.x, area.y, 0, area.width, area.height, 1);
for (int slice = 0; slice < area.depth; ++slice)
{
int sliceIndex = slice + area.z;
const uint8_t *srcPixels = usablePixels + slice * sourceDepthPitch;
ANGLE_TRY(setPerSliceSubImage(context, sliceIndex, mtlRegion, formatInfo, type,
srcAngleFormat, sourceRowPitch, sourceDepthPitch,
unpackBuffer, srcPixels, image));
}
}
else
{
MTLRegion mtlRegion =
MTLRegionMake3D(area.x, area.y, area.z, area.width, area.height, area.depth);
ANGLE_TRY(setPerSliceSubImage(context, 0, mtlRegion, formatInfo, type, srcAngleFormat, ANGLE_TRY(setPerSliceSubImage(context, 0, mtlRegion, formatInfo, type, srcAngleFormat,
sourceRowPitch, sourceDepthPitch, unpackBuffer, usablePixels, sourceRowPitch, sourceDepthPitch, unpackBuffer, usablePixels,
image)); image));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1725,6 +1817,10 @@ angle::Result TextureMtl::copySubImageCPU(const gl::Context *context, ...@@ -1725,6 +1817,10 @@ angle::Result TextureMtl::copySubImageCPU(const gl::Context *context,
case gl::TextureType::CubeMap: case gl::TextureType::CubeMap:
dstSlice = 0; dstSlice = 0;
break; break;
case gl::TextureType::_2DArray:
ASSERT(index.hasLayer());
dstSlice = index.getLayerIndex();
break;
case gl::TextureType::_3D: case gl::TextureType::_3D:
ASSERT(index.hasLayer()); ASSERT(index.hasLayer());
dstSlice = 0; dstSlice = 0;
......
...@@ -127,6 +127,16 @@ class Texture final : public Resource, ...@@ -127,6 +127,16 @@ class Texture final : public Resource,
bool allowFormatView, bool allowFormatView,
TextureRef *refOut); TextureRef *refOut);
static angle::Result Make2DArrayTexture(ContextMtl *context,
const Format &format,
uint32_t width,
uint32_t height,
uint32_t mips,
uint32_t arrayLength,
bool renderTargetOnly,
bool allowFormatView,
TextureRef *refOut);
static angle::Result Make3DTexture(ContextMtl *context, static angle::Result Make3DTexture(ContextMtl *context,
const Format &format, const Format &format,
uint32_t width, uint32_t width,
......
...@@ -182,6 +182,33 @@ angle::Result Texture::Make2DMSTexture(ContextMtl *context, ...@@ -182,6 +182,33 @@ angle::Result Texture::Make2DMSTexture(ContextMtl *context,
} }
/** static */ /** static */
angle::Result Texture::Make2DArrayTexture(ContextMtl *context,
const Format &format,
uint32_t width,
uint32_t height,
uint32_t mips,
uint32_t arrayLength,
bool renderTargetOnly,
bool allowFormatView,
TextureRef *refOut)
{
ANGLE_MTL_OBJC_SCOPE
{
// Use texture2DDescriptorWithPixelFormat to calculate full range mipmap range:
MTLTextureDescriptor *desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format.metalFormat
width:width
height:height
mipmapped:mips == 0 || mips > 1];
desc.textureType = MTLTextureType2DArray;
desc.arrayLength = arrayLength;
return MakeTexture(context, format, desc, mips, renderTargetOnly, allowFormatView, refOut);
} // ANGLE_MTL_OBJC_SCOPE
}
/** static */
angle::Result Texture::Make3DTexture(ContextMtl *context, angle::Result Texture::Make3DTexture(ContextMtl *context,
const Format &format, const Format &format,
uint32_t width, uint32_t width,
......
...@@ -8095,7 +8095,7 @@ ANGLE_INSTANTIATE_TEST_ES3(Texture2DIntegerAlpha1TestES3); ...@@ -8095,7 +8095,7 @@ ANGLE_INSTANTIATE_TEST_ES3(Texture2DIntegerAlpha1TestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DUnsignedIntegerAlpha1TestES3); ANGLE_INSTANTIATE_TEST_ES3(Texture2DUnsignedIntegerAlpha1TestES3);
ANGLE_INSTANTIATE_TEST_ES3(ShadowSamplerPlusSampler3DTestES3); ANGLE_INSTANTIATE_TEST_ES3(ShadowSamplerPlusSampler3DTestES3);
ANGLE_INSTANTIATE_TEST_ES3(SamplerTypeMixTestES3); ANGLE_INSTANTIATE_TEST_ES3(SamplerTypeMixTestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DArrayTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DArrayTestES3, ES3_METAL());
ANGLE_INSTANTIATE_TEST_ES3(TextureSizeTextureArrayTest); ANGLE_INSTANTIATE_TEST_ES3(TextureSizeTextureArrayTest);
ANGLE_INSTANTIATE_TEST_ES2(SamplerInStructTest); ANGLE_INSTANTIATE_TEST_ES2(SamplerInStructTest);
ANGLE_INSTANTIATE_TEST_ES2(SamplerInStructAsFunctionParameterTest); ANGLE_INSTANTIATE_TEST_ES2(SamplerInStructAsFunctionParameterTest);
......
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