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.
}
......
......@@ -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