Commit 4a298703 by Geoff Lang Committed by Commit Bot

Vulkan: Support creating EGL images from non-zero mipmaps of textures.

Store a mip offset in TextureVK to apply to all operations on the ImageHelper. There is no need to store the mip offset in RenderbufferVk because it creates the resource with the mip offset on the call to setStorageEGLImageTarget. Store a mipmap level in the RenderTargetVk object so that clear operations will target the correct mipmap of the image. BUG=angleproject:2668 Change-Id: Ie976e3dd3a8de8135a7fbb8c84bd51eec0dddce8 Reviewed-on: https://chromium-review.googlesource.com/c/1422059 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 199a9f38
......@@ -297,10 +297,9 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
ASSERT(colorRenderTarget);
vk::ImageHelper *image = colorRenderTarget->getImageForWrite(&mFramebuffer);
GLint mipLevelToClear = (attachment->type() == GL_TEXTURE) ? attachment->mipLevel() : 0;
// If we're clearing a cube map face ensure we only clear the selected layer.
image->clearColorLayer(modifiedClearColorValue, mipLevelToClear, 1,
image->clearColorLayer(modifiedClearColorValue, colorRenderTarget->getLevelIndex(), 1,
colorRenderTarget->getLayerIndex(), 1, commandBuffer);
}
......@@ -1138,7 +1137,7 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
region.imageSubresource.aspectMask = copyAspectFlags;
region.imageSubresource.baseArrayLayer = renderTarget->getLayerIndex();
region.imageSubresource.layerCount = 1;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.mipLevel = renderTarget->getLevelIndex();
commandBuffer->copyImageToBuffer(srcImage->getImage(), srcImage->getCurrentLayout(),
bufferHandle, 1, &region);
......
......@@ -22,7 +22,7 @@ namespace rx
{
ImageVk::ImageVk(const egl::ImageState &state, const gl::Context *context)
: ImageImpl(state), mOwnsImage(false), mImage(nullptr), mContext(context)
: ImageImpl(state), mImageLevel(0), mOwnsImage(false), mImage(nullptr), mContext(context)
{}
ImageVk::~ImageVk() {}
......@@ -43,7 +43,6 @@ void ImageVk::onDestroy(const egl::Display *display)
egl::Error ImageVk::initialize(const egl::Display *display)
{
if (egl::IsTextureTarget(mState.target))
{
TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source));
......@@ -59,7 +58,7 @@ egl::Error ImageVk::initialize(const egl::Display *display)
mOwnsImage = false;
ASSERT(mState.imageIndex.getLevelIndex() == 0);
mImageLevel = mState.imageIndex.getLevelIndex();
}
else if (egl::IsRenderbufferTarget(mState.target))
{
......@@ -74,6 +73,8 @@ egl::Error ImageVk::initialize(const egl::Display *display)
mImage->initStagingBuffer(renderer);
mOwnsImage = false;
mImageLevel = 0;
}
else
{
......
......@@ -28,8 +28,11 @@ class ImageVk : public ImageImpl
angle::Result orphan(const gl::Context *context, egl::ImageSibling *sibling) override;
vk::ImageHelper *getImage() const { return mImage; }
uint32_t getImageLevel() const { return mImageLevel; }
private:
uint32_t mImageLevel;
bool mOwnsImage;
vk::ImageHelper *mImage;
......
......@@ -17,7 +17,7 @@
namespace rx
{
RenderTargetVk::RenderTargetVk()
: mImage(nullptr), mImageView(nullptr), mLayerIndex(0), mOwner(nullptr)
: mImage(nullptr), mImageView(nullptr), mLevelIndex(0), mLayerIndex(0), mOwner(nullptr)
{}
RenderTargetVk::~RenderTargetVk() {}
......@@ -25,17 +25,20 @@ RenderTargetVk::~RenderTargetVk() {}
RenderTargetVk::RenderTargetVk(RenderTargetVk &&other)
: mImage(other.mImage),
mImageView(other.mImageView),
mLevelIndex(other.mLevelIndex),
mLayerIndex(other.mLayerIndex),
mOwner(other.mOwner)
{}
void RenderTargetVk::init(vk::ImageHelper *image,
vk::ImageView *imageView,
size_t levelIndex,
size_t layerIndex,
TextureVk *owner)
{
mImage = image;
mImageView = imageView;
mLevelIndex = levelIndex;
mLayerIndex = layerIndex;
mOwner = owner;
}
......@@ -44,6 +47,7 @@ void RenderTargetVk::reset()
{
mImage = nullptr;
mImageView = nullptr;
mLevelIndex = 0;
mLayerIndex = 0;
mOwner = nullptr;
}
......
......@@ -46,6 +46,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
void init(vk::ImageHelper *image,
vk::ImageView *imageView,
size_t levelIndex,
size_t layerIndex,
TextureVk *owner);
void reset();
......@@ -72,6 +73,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
const vk::Format &getImageFormat() const;
const gl::Extents &getImageExtents() const;
size_t getLevelIndex() const { return mLevelIndex; }
size_t getLayerIndex() const { return mLayerIndex; }
// Special mutator for Surface RenderTargets. Allows the Framebuffer to keep a single
......@@ -85,6 +87,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
// Note that the draw and read image views are the same, given the requirements of a render
// target.
vk::ImageView *mImageView;
size_t mLevelIndex;
size_t mLayerIndex;
// If owned by the texture, this will be non-nullptr, and is used to ensure texture changes
......
......@@ -90,7 +90,7 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
// Note that LUMA textures are not color-renderable, so a read-view with swizzle is not
// needed.
ANGLE_TRY(mImage->initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(),
&mImageView, 1));
&mImageView, 0, 1));
// TODO(jmadill): Fold this into the RenderPass load/store ops. http://anglebug.com/2361
vk::CommandBuffer *commandBuffer = nullptr;
......@@ -106,7 +106,7 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
mImage->clearColor(kBlackClearColorValue, 0, 1, commandBuffer);
}
mRenderTarget.init(mImage, &mImageView, 0, nullptr);
mRenderTarget.init(mImage, &mImageView, 0, 0, nullptr);
}
return angle::Result::Continue;
......@@ -140,9 +140,9 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex
VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
ANGLE_TRY(mImage->initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(),
&mImageView, 1));
&mImageView, imageVk->getImageLevel(), 1));
mRenderTarget.init(mImage, &mImageView, 0, nullptr);
mRenderTarget.init(mImage, &mImageView, imageVk->getImageLevel(), 0, nullptr);
return angle::Result::Continue;
}
......
......@@ -80,7 +80,7 @@ constexpr VkImageUsageFlags kSurfaceVKDepthStencilImageUsageFlags =
OffscreenSurfaceVk::AttachmentImage::AttachmentImage()
{
renderTarget.init(&image, &imageView, 0, nullptr);
renderTarget.init(&image, &imageView, 0, 0, nullptr);
}
OffscreenSurfaceVk::AttachmentImage::~AttachmentImage() = default;
......@@ -107,7 +107,7 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display
VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
ANGLE_TRY(image.initImageView(displayVk, gl::TextureType::_2D, aspect, gl::SwizzleState(),
&imageView, 1));
&imageView, 0, 1));
return angle::Result::Continue;
}
......@@ -291,7 +291,7 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState,
mCurrentSwapchainImageIndex(0),
mCurrentSwapHistoryIndex(0)
{
mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageView, 0, nullptr);
mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageView, 0, 0, nullptr);
}
WindowSurfaceVk::~WindowSurfaceVk()
......@@ -540,7 +540,7 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
ANGLE_TRY(member.image.initImageView(displayVk, gl::TextureType::_2D,
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
&member.imageView, 1));
&member.imageView, 0, 1));
// Allocate a command buffer for clearing our images to black.
vk::CommandBuffer *commandBuffer = nullptr;
......@@ -571,7 +571,8 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
mDepthStencilImage.clearDepthStencil(aspect, aspect, depthStencilClearValue, commandBuffer);
ANGLE_TRY(mDepthStencilImage.initImageView(displayVk, gl::TextureType::_2D, aspect,
gl::SwizzleState(), &mDepthStencilImageView, 1));
gl::SwizzleState(), &mDepthStencilImageView, 0,
1));
// We will need to pass depth/stencil image views to the RenderTargetVk in the future.
}
......
......@@ -168,8 +168,8 @@ angle::Result TextureVk::setImage(const gl::Context *context,
// Handle initial data.
if (pixels)
{
ANGLE_TRY(mImage->stageSubresourceUpdate(contextVk, index, size, gl::Offset(), formatInfo,
unpack, type, pixels));
ANGLE_TRY(mImage->stageSubresourceUpdate(contextVk, getNativeImageIndex(index), size,
gl::Offset(), formatInfo, unpack, type, pixels));
}
return angle::Result::Continue;
......@@ -187,7 +187,7 @@ angle::Result TextureVk::setSubImage(const gl::Context *context,
ContextVk *contextVk = vk::GetImpl(context);
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type);
ANGLE_TRY(mImage->stageSubresourceUpdate(
contextVk, index, gl::Extents(area.width, area.height, area.depth),
contextVk, getNativeImageIndex(index), gl::Extents(area.width, area.height, area.depth),
gl::Offset(area.x, area.y, area.z), formatInfo, unpack, type, pixels));
// Create a new graph node to store image initialization commands.
......@@ -308,6 +308,7 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
RendererVk *renderer = contextVk->getRenderer();
FramebufferVk *framebufferVk = vk::GetImpl(source);
const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index);
const gl::Offset modifiedDestOffset(destOffset.x, destOffset.y, 0);
const vk::Format &srcFormat = framebufferVk->getColorReadRenderTarget()->getImageFormat();
......@@ -324,16 +325,17 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
// Layer count can only be 1 as the source is a framebuffer.
ASSERT(index.getLayerCount() == 1);
ANGLE_TRY(copySubImageImplWithDraw(
contextVk, index, modifiedDestOffset, destFormat, 0, clippedSourceArea, isViewportFlipY,
false, false, false, &colorReadRT->getImage(), colorReadRT->getReadImageView()));
ANGLE_TRY(copySubImageImplWithDraw(contextVk, offsetImageIndex, modifiedDestOffset,
destFormat, 0, clippedSourceArea, isViewportFlipY, false,
false, false, &colorReadRT->getImage(),
colorReadRT->getReadImageView()));
return angle::Result::Continue;
}
// Do a CPU readback that does the conversion, and then stage the change to the pixel buffer.
ANGLE_TRY(mImage->stageSubresourceUpdateFromFramebuffer(
context, index, clippedSourceArea, modifiedDestOffset,
context, offsetImageIndex, clippedSourceArea, modifiedDestOffset,
gl::Extents(clippedSourceArea.width, clippedSourceArea.height, 1), internalFormat,
framebufferVk));
......@@ -360,15 +362,17 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
const vk::Format &sourceVkFormat = source->getImage().getFormat();
const vk::Format &destVkFormat = renderer->getFormat(destFormat.sizedInternalFormat);
const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index);
bool forceCpuPath = ForceCpuPathForCopy(renderer, mImage);
// If it's possible to perform the copy with a draw call, do that.
if (CanCopyWithDraw(renderer, sourceVkFormat, destVkFormat) && !forceCpuPath)
{
ANGLE_TRY(copySubImageImplWithDraw(contextVk, index, destOffset, destVkFormat, sourceLevel,
sourceArea, false, unpackFlipY, unpackPremultiplyAlpha,
unpackUnmultiplyAlpha, &source->getImage(),
&source->getReadImageView()));
ANGLE_TRY(copySubImageImplWithDraw(contextVk, offsetImageIndex, destOffset, destVkFormat,
sourceLevel, sourceArea, false, unpackFlipY,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
&source->getImage(), &source->getReadImageView()));
return angle::Result::Continue;
}
......@@ -391,7 +395,7 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
// Allocate memory in the destination texture for the copy/conversion
uint8_t *destData = nullptr;
ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(
contextVk, destinationAllocationSize, index,
contextVk, destinationAllocationSize, offsetImageIndex,
gl::Extents(sourceArea.width, sourceArea.height, 1), destOffset, &destData));
// Source and dest data is tightly packed
......@@ -560,7 +564,7 @@ angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
releaseAndDeleteImage(context, renderer);
ImageVk *imageVk = vk::GetImpl(image);
setImageHelper(renderer, imageVk->getImage(), false);
setImageHelper(renderer, imageVk->getImage(), imageVk->getImageLevel(), false);
const vk::Format &format = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
ANGLE_TRY(initImageViews(contextVk, format, 1));
......@@ -577,6 +581,18 @@ angle::Result TextureVk::setImageExternal(const gl::Context *context,
return angle::Result::Stop;
}
gl::ImageIndex TextureVk::getNativeImageIndex(const gl::ImageIndex &inputImageIndex) const
{
return gl::ImageIndex::MakeFromType(
inputImageIndex.getType(), getNativeImageLevel(inputImageIndex.getLevelIndex()),
inputImageIndex.getLayerIndex(), inputImageIndex.getLayerCount());
}
uint32_t TextureVk::getNativeImageLevel(uint32_t frontendLevel) const
{
return mImageLevelOffset + frontendLevel;
}
void TextureVk::releaseAndDeleteImage(const gl::Context *context, RendererVk *renderer)
{
if (mImage)
......@@ -591,21 +607,25 @@ angle::Result TextureVk::ensureImageAllocated(RendererVk *renderer)
{
if (mImage == nullptr)
{
setImageHelper(renderer, new vk::ImageHelper(), true);
setImageHelper(renderer, new vk::ImageHelper(), 0, true);
}
return angle::Result::Continue;
}
void TextureVk::setImageHelper(RendererVk *renderer, vk::ImageHelper *imageHelper, bool selfOwned)
void TextureVk::setImageHelper(RendererVk *renderer,
vk::ImageHelper *imageHelper,
uint32_t imageMipOffset,
bool selfOwned)
{
ASSERT(mImage == nullptr);
mOwnsImage = selfOwned;
mImage = imageHelper;
mOwnsImage = selfOwned;
mImageLevelOffset = imageMipOffset;
mImage = imageHelper;
mImage->initStagingBuffer(renderer);
mRenderTarget.init(mImage, &mDrawBaseLevelImageView, 0, this);
mRenderTarget.init(mImage, &mDrawBaseLevelImageView, getNativeImageLevel(0), 0, this);
// Force re-creation of cube map render targets next time they are needed
mCubeMapRenderTargets.clear();
......@@ -734,7 +754,8 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
vk::CommandBuffer *commandBuffer;
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
return mImage->flushStagedUpdates(contextVk, getLevelCount(), commandBuffer);
return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), getLevelCount(),
commandBuffer);
}
angle::Result TextureVk::generateMipmap(const gl::Context *context)
......@@ -793,7 +814,8 @@ angle::Result TextureVk::bindTexImage(const gl::Context *context, egl::Surface *
// eglBindTexImage can only be called with pbuffer (offscreen) surfaces
OffscreenSurfaceVk *offscreenSurface = GetImplAs<OffscreenSurfaceVk>(surface);
setImageHelper(renderer, offscreenSurface->getColorAttachmentImage(), false);
setImageHelper(renderer, offscreenSurface->getColorAttachmentImage(), surface->getMipmapLevel(),
false);
const vk::Format &format = renderer->getFormat(surface->getConfig()->renderTargetFormat);
return initImageViews(contextVk, format, 1);
......@@ -865,7 +887,7 @@ angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk,
ANGLE_TRY(initImage(contextVk, format, baseLevelExtents, levelCount, commandBuffer));
}
return mImage->flushStagedUpdates(contextVk, levelCount, commandBuffer);
return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), levelCount, commandBuffer);
}
angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk)
......@@ -879,7 +901,8 @@ angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk)
{
vk::ImageView *imageView;
ANGLE_TRY(getLayerLevelDrawImageView(contextVk, cubeMapFaceIndex, 0, &imageView));
mCubeMapRenderTargets[cubeMapFaceIndex].init(mImage, imageView, cubeMapFaceIndex, this);
mCubeMapRenderTargets[cubeMapFaceIndex].init(mImage, imageView, getNativeImageLevel(0),
cubeMapFaceIndex, this);
}
return angle::Result::Continue;
}
......@@ -999,7 +1022,8 @@ angle::Result TextureVk::getLayerLevelDrawImageView(vk::Context *context,
// Note that these views are specifically made to be used as color attachments, and therefore
// don't have swizzle.
return mImage->initLayerImageView(context, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT,
gl::SwizzleState(), *imageViewOut, level, 1, layer, 1);
gl::SwizzleState(), *imageViewOut, getNativeImageLevel(level),
1, layer, 1);
}
const vk::Sampler &TextureVk::getSampler() const
......@@ -1044,12 +1068,16 @@ angle::Result TextureVk::initImageViews(ContextVk *contextVk,
gl::SwizzleState mappedSwizzle;
MapSwizzleState(format, mState.getSwizzleState(), &mappedSwizzle);
// TODO: Support non-zero base level for ES 3.0 by passing it to getNativeImageLevel.
// http://anglebug.com/3148
uint32_t baseLevel = getNativeImageLevel(0);
ANGLE_TRY(mImage->initImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT,
mappedSwizzle, &mReadMipmapImageView, levelCount));
mappedSwizzle, &mReadMipmapImageView, baseLevel, levelCount));
ANGLE_TRY(mImage->initImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT,
mappedSwizzle, &mReadBaseLevelImageView, 1));
mappedSwizzle, &mReadBaseLevelImageView, baseLevel, 1));
ANGLE_TRY(mImage->initImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT,
gl::SwizzleState(), &mDrawBaseLevelImageView, 1));
gl::SwizzleState(), &mDrawBaseLevelImageView, baseLevel, 1));
return angle::Result::Continue;
}
......
......@@ -151,9 +151,17 @@ class TextureVk : public TextureImpl
angle::Result ensureImageInitialized(ContextVk *contextVk);
private:
// Transform an image index from the frontend into one that can be used on the backing
// ImageHelper, taking into account mipmap or cube face offsets
gl::ImageIndex getNativeImageIndex(const gl::ImageIndex &inputImageIndex) const;
uint32_t getNativeImageLevel(uint32_t frontendLevel) const;
void releaseAndDeleteImage(const gl::Context *context, RendererVk *renderer);
angle::Result ensureImageAllocated(RendererVk *renderer);
void setImageHelper(RendererVk *renderer, vk::ImageHelper *imageHelper, bool selfOwned);
void setImageHelper(RendererVk *renderer,
vk::ImageHelper *imageHelper,
uint32_t imageMipOffset,
bool selfOwned);
angle::Result redefineImage(const gl::Context *context,
const gl::ImageIndex &index,
......@@ -228,7 +236,13 @@ class TextureVk : public TextureImpl
const vk::Format &format);
bool mOwnsImage;
// The level offset to apply when converting from a frontend texture level to texture level in
// mImage.
uint32_t mImageLevelOffset;
vk::ImageHelper *mImage;
vk::ImageView mDrawBaseLevelImageView;
vk::ImageView mReadBaseLevelImageView;
vk::ImageView mReadMipmapImageView;
......
......@@ -1338,10 +1338,11 @@ angle::Result ImageHelper::initImageView(Context *context,
VkImageAspectFlags aspectMask,
const gl::SwizzleState &swizzleMap,
ImageView *imageViewOut,
uint32_t baseMipLevel,
uint32_t levelCount)
{
return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut, 0,
levelCount, 0, mLayerCount);
return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut,
baseMipLevel, levelCount, 0, mLayerCount);
}
angle::Result ImageHelper::initLayerImageView(Context *context,
......@@ -1959,6 +1960,7 @@ angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk,
}
angle::Result ImageHelper::flushStagedUpdates(Context *context,
uint32_t baseLevel,
uint32_t levelCount,
vk::CommandBuffer *commandBuffer)
{
......@@ -1985,7 +1987,7 @@ angle::Result ImageHelper::flushStagedUpdates(Context *context,
// It's possible we've accumulated updates that are no longer applicable if the image has
// never been flushed but the image description has changed. Check if this level exist for
// this image.
if (updateMipLevel >= levelCount)
if (updateMipLevel < baseLevel || updateMipLevel >= baseLevel + levelCount)
{
updatesToKeep.emplace_back(update);
continue;
......
......@@ -552,6 +552,7 @@ class ImageHelper final : public CommandGraphResource
VkImageAspectFlags aspectMask,
const gl::SwizzleState &swizzleMap,
ImageView *imageViewOut,
uint32_t baseMipLevel,
uint32_t levelCount);
// Create a 2D[Array] for staging purposes. Used by:
//
......@@ -660,6 +661,7 @@ class ImageHelper final : public CommandGraphResource
bool *newBufferAllocatedOut);
angle::Result flushStagedUpdates(Context *context,
uint32_t baseLevel,
uint32_t levelCount,
vk::CommandBuffer *commandBuffer);
......
......@@ -1633,10 +1633,6 @@ TEST_P(ImageTest, MipLevels)
// Also fails on NVIDIA Shield TV bot.
ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
// TODO(geofflang): Support creating EGL images from non-zero mipmaps in Vulkan.
// http://anglebug.com/2668
ANGLE_SKIP_TEST_IF(IsVulkan());
EGLWindow *window = getEGLWindow();
ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt() || !has2DTextureExt());
......
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