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
return angle::Result::Continue;
}
constexpr gl::TextureType supportedTextureTypes[] = {gl::TextureType::_2D, gl::TextureType::_3D,
gl::TextureType::_2DArray,
gl::TextureType::CubeMap};
for (gl::TextureType texType : supportedTextureTypes)
{
......
......@@ -175,6 +175,7 @@ class TextureMtl : public TextureImpl
gl::TextureType type,
GLuint mips,
const gl::Extents &size);
angle::Result onBaseMaxLevelsChanged(const gl::Context *context);
angle::Result ensureSamplerStateCreated(const gl::Context *context);
// Ensure image at given index is created:
angle::Result ensureImageCreated(const gl::Context *context, const gl::ImageIndex &index);
......@@ -334,6 +335,9 @@ class TextureMtl : public TextureImpl
// Mipmap views are indexed by native level (ignored base level):
mtl::NativeTexLevelArray mNativeLevelViews;
GLuint mCurrentBaseLevel = 0;
GLuint mCurrentMaxLevel = 1000;
bool mIsPow2 = false;
};
......
......@@ -454,7 +454,9 @@ angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context)
ContextMtl *contextMtl = mtl::GetImpl(context);
// 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();
ANGLE_MTL_CHECK(contextMtl, desc.format.valid(), GL_INVALID_OPERATION);
angle::FormatID angleFormatId =
......@@ -472,6 +474,9 @@ angle::Result TextureMtl::createNativeTexture(const gl::Context *context,
ContextMtl *contextMtl = mtl::GetImpl(context);
// Create actual texture object:
mCurrentBaseLevel = mState.getEffectiveBaseLevel();
mCurrentMaxLevel = mState.getEffectiveMaxLevel();
mIsPow2 = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth);
mSlices = 1;
int numCubeFaces = 1;
......@@ -496,6 +501,13 @@ angle::Result TextureMtl::createNativeTexture(const gl::Context *context,
/** renderTargetOnly */ false,
/** allowFormatView */ mFormat.hasDepthAndStencilBits(), &mNativeTexture));
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:
UNREACHABLE();
}
......@@ -569,6 +581,26 @@ angle::Result TextureMtl::ensureSamplerStateCreated(const gl::Context *context)
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,
const gl::ImageIndex &index)
{
......@@ -657,7 +689,7 @@ void TextureMtl::retainImageDefinitions()
{
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];
if (imageDef.image)
{
......@@ -1065,10 +1097,7 @@ angle::Result TextureMtl::generateMipmapCPU(const gl::Context *context)
angle::Result TextureMtl::setBaseLevel(const gl::Context *context, GLuint baseLevel)
{
// NOTE(hqle): ES 3.0
UNIMPLEMENTED();
return angle::Result::Stop;
return onBaseMaxLevelsChanged(context);
}
angle::Result TextureMtl::bindTexImage(const gl::Context *context, egl::Surface *surface)
......@@ -1115,10 +1144,46 @@ angle::Result TextureMtl::syncState(const gl::Context *context,
const gl::Texture::DirtyBits &dirtyBits,
gl::Command source)
{
if (dirtyBits.any())
ContextMtl *contextMtl = mtl::GetImpl(context);
for (size_t dirtyBit : dirtyBits)
{
// Invalidate sampler state
mMetalSamplerState = nil;
switch (dirtyBit)
{
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));
......@@ -1205,6 +1270,12 @@ angle::Result TextureMtl::redefineImage(const gl::Context *context,
/** renderTargetOnly */ false,
/** allowFormatView */ mFormat.hasDepthAndStencilBits(), &imageDef.image));
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:
UNREACHABLE();
}
......@@ -1326,11 +1397,32 @@ angle::Result TextureMtl::setSubImageImpl(const gl::Context *context,
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,
sourceRowPitch, sourceDepthPitch, unpackBuffer, usablePixels,
image));
ANGLE_TRY(setPerSliceSubImage(context, 0, mtlRegion, formatInfo, type, srcAngleFormat,
sourceRowPitch, sourceDepthPitch, unpackBuffer, usablePixels,
image));
}
return angle::Result::Continue;
}
......@@ -1725,6 +1817,10 @@ angle::Result TextureMtl::copySubImageCPU(const gl::Context *context,
case gl::TextureType::CubeMap:
dstSlice = 0;
break;
case gl::TextureType::_2DArray:
ASSERT(index.hasLayer());
dstSlice = index.getLayerIndex();
break;
case gl::TextureType::_3D:
ASSERT(index.hasLayer());
dstSlice = 0;
......
......@@ -127,6 +127,16 @@ class Texture final : public Resource,
bool allowFormatView,
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,
const Format &format,
uint32_t width,
......
......@@ -182,6 +182,33 @@ angle::Result Texture::Make2DMSTexture(ContextMtl *context,
}
/** 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,
const Format &format,
uint32_t width,
......
......@@ -8095,7 +8095,7 @@ ANGLE_INSTANTIATE_TEST_ES3(Texture2DIntegerAlpha1TestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DUnsignedIntegerAlpha1TestES3);
ANGLE_INSTANTIATE_TEST_ES3(ShadowSamplerPlusSampler3DTestES3);
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_ES2(SamplerInStructTest);
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