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) ...@@ -297,10 +297,9 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
vk::ImageHelper *image = colorRenderTarget->getImageForWrite(&mFramebuffer); 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. // 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); colorRenderTarget->getLayerIndex(), 1, commandBuffer);
} }
...@@ -1138,7 +1137,7 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, ...@@ -1138,7 +1137,7 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
region.imageSubresource.aspectMask = copyAspectFlags; region.imageSubresource.aspectMask = copyAspectFlags;
region.imageSubresource.baseArrayLayer = renderTarget->getLayerIndex(); region.imageSubresource.baseArrayLayer = renderTarget->getLayerIndex();
region.imageSubresource.layerCount = 1; region.imageSubresource.layerCount = 1;
region.imageSubresource.mipLevel = 0; region.imageSubresource.mipLevel = renderTarget->getLevelIndex();
commandBuffer->copyImageToBuffer(srcImage->getImage(), srcImage->getCurrentLayout(), commandBuffer->copyImageToBuffer(srcImage->getImage(), srcImage->getCurrentLayout(),
bufferHandle, 1, &region); bufferHandle, 1, &region);
......
...@@ -22,7 +22,7 @@ namespace rx ...@@ -22,7 +22,7 @@ namespace rx
{ {
ImageVk::ImageVk(const egl::ImageState &state, const gl::Context *context) 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() {} ImageVk::~ImageVk() {}
...@@ -43,7 +43,6 @@ void ImageVk::onDestroy(const egl::Display *display) ...@@ -43,7 +43,6 @@ void ImageVk::onDestroy(const egl::Display *display)
egl::Error ImageVk::initialize(const egl::Display *display) egl::Error ImageVk::initialize(const egl::Display *display)
{ {
if (egl::IsTextureTarget(mState.target)) if (egl::IsTextureTarget(mState.target))
{ {
TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source)); TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source));
...@@ -59,7 +58,7 @@ egl::Error ImageVk::initialize(const egl::Display *display) ...@@ -59,7 +58,7 @@ egl::Error ImageVk::initialize(const egl::Display *display)
mOwnsImage = false; mOwnsImage = false;
ASSERT(mState.imageIndex.getLevelIndex() == 0); mImageLevel = mState.imageIndex.getLevelIndex();
} }
else if (egl::IsRenderbufferTarget(mState.target)) else if (egl::IsRenderbufferTarget(mState.target))
{ {
...@@ -74,6 +73,8 @@ egl::Error ImageVk::initialize(const egl::Display *display) ...@@ -74,6 +73,8 @@ egl::Error ImageVk::initialize(const egl::Display *display)
mImage->initStagingBuffer(renderer); mImage->initStagingBuffer(renderer);
mOwnsImage = false; mOwnsImage = false;
mImageLevel = 0;
} }
else else
{ {
......
...@@ -28,8 +28,11 @@ class ImageVk : public ImageImpl ...@@ -28,8 +28,11 @@ class ImageVk : public ImageImpl
angle::Result orphan(const gl::Context *context, egl::ImageSibling *sibling) override; angle::Result orphan(const gl::Context *context, egl::ImageSibling *sibling) override;
vk::ImageHelper *getImage() const { return mImage; } vk::ImageHelper *getImage() const { return mImage; }
uint32_t getImageLevel() const { return mImageLevel; }
private: private:
uint32_t mImageLevel;
bool mOwnsImage; bool mOwnsImage;
vk::ImageHelper *mImage; vk::ImageHelper *mImage;
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
namespace rx namespace rx
{ {
RenderTargetVk::RenderTargetVk() RenderTargetVk::RenderTargetVk()
: mImage(nullptr), mImageView(nullptr), mLayerIndex(0), mOwner(nullptr) : mImage(nullptr), mImageView(nullptr), mLevelIndex(0), mLayerIndex(0), mOwner(nullptr)
{} {}
RenderTargetVk::~RenderTargetVk() {} RenderTargetVk::~RenderTargetVk() {}
...@@ -25,17 +25,20 @@ RenderTargetVk::~RenderTargetVk() {} ...@@ -25,17 +25,20 @@ RenderTargetVk::~RenderTargetVk() {}
RenderTargetVk::RenderTargetVk(RenderTargetVk &&other) RenderTargetVk::RenderTargetVk(RenderTargetVk &&other)
: mImage(other.mImage), : mImage(other.mImage),
mImageView(other.mImageView), mImageView(other.mImageView),
mLevelIndex(other.mLevelIndex),
mLayerIndex(other.mLayerIndex), mLayerIndex(other.mLayerIndex),
mOwner(other.mOwner) mOwner(other.mOwner)
{} {}
void RenderTargetVk::init(vk::ImageHelper *image, void RenderTargetVk::init(vk::ImageHelper *image,
vk::ImageView *imageView, vk::ImageView *imageView,
size_t levelIndex,
size_t layerIndex, size_t layerIndex,
TextureVk *owner) TextureVk *owner)
{ {
mImage = image; mImage = image;
mImageView = imageView; mImageView = imageView;
mLevelIndex = levelIndex;
mLayerIndex = layerIndex; mLayerIndex = layerIndex;
mOwner = owner; mOwner = owner;
} }
...@@ -44,6 +47,7 @@ void RenderTargetVk::reset() ...@@ -44,6 +47,7 @@ void RenderTargetVk::reset()
{ {
mImage = nullptr; mImage = nullptr;
mImageView = nullptr; mImageView = nullptr;
mLevelIndex = 0;
mLayerIndex = 0; mLayerIndex = 0;
mOwner = nullptr; mOwner = nullptr;
} }
......
...@@ -46,6 +46,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -46,6 +46,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
void init(vk::ImageHelper *image, void init(vk::ImageHelper *image,
vk::ImageView *imageView, vk::ImageView *imageView,
size_t levelIndex,
size_t layerIndex, size_t layerIndex,
TextureVk *owner); TextureVk *owner);
void reset(); void reset();
...@@ -72,6 +73,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -72,6 +73,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
const vk::Format &getImageFormat() const; const vk::Format &getImageFormat() const;
const gl::Extents &getImageExtents() const; const gl::Extents &getImageExtents() const;
size_t getLevelIndex() const { return mLevelIndex; }
size_t getLayerIndex() const { return mLayerIndex; } size_t getLayerIndex() const { return mLayerIndex; }
// Special mutator for Surface RenderTargets. Allows the Framebuffer to keep a single // Special mutator for Surface RenderTargets. Allows the Framebuffer to keep a single
...@@ -85,6 +87,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -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 // Note that the draw and read image views are the same, given the requirements of a render
// target. // target.
vk::ImageView *mImageView; vk::ImageView *mImageView;
size_t mLevelIndex;
size_t mLayerIndex; size_t mLayerIndex;
// If owned by the texture, this will be non-nullptr, and is used to ensure texture changes // 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, ...@@ -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 // Note that LUMA textures are not color-renderable, so a read-view with swizzle is not
// needed. // needed.
ANGLE_TRY(mImage->initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(), 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 // TODO(jmadill): Fold this into the RenderPass load/store ops. http://anglebug.com/2361
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
...@@ -106,7 +106,7 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context, ...@@ -106,7 +106,7 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
mImage->clearColor(kBlackClearColorValue, 0, 1, commandBuffer); mImage->clearColor(kBlackClearColorValue, 0, 1, commandBuffer);
} }
mRenderTarget.init(mImage, &mImageView, 0, nullptr); mRenderTarget.init(mImage, &mImageView, 0, 0, nullptr);
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -140,9 +140,9 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex ...@@ -140,9 +140,9 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex
VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat); VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
ANGLE_TRY(mImage->initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(), 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; return angle::Result::Continue;
} }
......
...@@ -80,7 +80,7 @@ constexpr VkImageUsageFlags kSurfaceVKDepthStencilImageUsageFlags = ...@@ -80,7 +80,7 @@ constexpr VkImageUsageFlags kSurfaceVKDepthStencilImageUsageFlags =
OffscreenSurfaceVk::AttachmentImage::AttachmentImage() OffscreenSurfaceVk::AttachmentImage::AttachmentImage()
{ {
renderTarget.init(&image, &imageView, 0, nullptr); renderTarget.init(&image, &imageView, 0, 0, nullptr);
} }
OffscreenSurfaceVk::AttachmentImage::~AttachmentImage() = default; OffscreenSurfaceVk::AttachmentImage::~AttachmentImage() = default;
...@@ -107,7 +107,7 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display ...@@ -107,7 +107,7 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display
VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat); VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
ANGLE_TRY(image.initImageView(displayVk, gl::TextureType::_2D, aspect, gl::SwizzleState(), ANGLE_TRY(image.initImageView(displayVk, gl::TextureType::_2D, aspect, gl::SwizzleState(),
&imageView, 1)); &imageView, 0, 1));
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -291,7 +291,7 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, ...@@ -291,7 +291,7 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState,
mCurrentSwapchainImageIndex(0), mCurrentSwapchainImageIndex(0),
mCurrentSwapHistoryIndex(0) mCurrentSwapHistoryIndex(0)
{ {
mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageView, 0, nullptr); mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageView, 0, 0, nullptr);
} }
WindowSurfaceVk::~WindowSurfaceVk() WindowSurfaceVk::~WindowSurfaceVk()
...@@ -540,7 +540,7 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, ...@@ -540,7 +540,7 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
ANGLE_TRY(member.image.initImageView(displayVk, gl::TextureType::_2D, ANGLE_TRY(member.image.initImageView(displayVk, gl::TextureType::_2D,
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
&member.imageView, 1)); &member.imageView, 0, 1));
// Allocate a command buffer for clearing our images to black. // Allocate a command buffer for clearing our images to black.
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
...@@ -571,7 +571,8 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, ...@@ -571,7 +571,8 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
mDepthStencilImage.clearDepthStencil(aspect, aspect, depthStencilClearValue, commandBuffer); mDepthStencilImage.clearDepthStencil(aspect, aspect, depthStencilClearValue, commandBuffer);
ANGLE_TRY(mDepthStencilImage.initImageView(displayVk, gl::TextureType::_2D, aspect, 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. // We will need to pass depth/stencil image views to the RenderTargetVk in the future.
} }
......
...@@ -151,9 +151,17 @@ class TextureVk : public TextureImpl ...@@ -151,9 +151,17 @@ class TextureVk : public TextureImpl
angle::Result ensureImageInitialized(ContextVk *contextVk); angle::Result ensureImageInitialized(ContextVk *contextVk);
private: 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); void releaseAndDeleteImage(const gl::Context *context, RendererVk *renderer);
angle::Result ensureImageAllocated(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, angle::Result redefineImage(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
...@@ -228,7 +236,13 @@ class TextureVk : public TextureImpl ...@@ -228,7 +236,13 @@ class TextureVk : public TextureImpl
const vk::Format &format); const vk::Format &format);
bool mOwnsImage; 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::ImageHelper *mImage;
vk::ImageView mDrawBaseLevelImageView; vk::ImageView mDrawBaseLevelImageView;
vk::ImageView mReadBaseLevelImageView; vk::ImageView mReadBaseLevelImageView;
vk::ImageView mReadMipmapImageView; vk::ImageView mReadMipmapImageView;
......
...@@ -1338,10 +1338,11 @@ angle::Result ImageHelper::initImageView(Context *context, ...@@ -1338,10 +1338,11 @@ angle::Result ImageHelper::initImageView(Context *context,
VkImageAspectFlags aspectMask, VkImageAspectFlags aspectMask,
const gl::SwizzleState &swizzleMap, const gl::SwizzleState &swizzleMap,
ImageView *imageViewOut, ImageView *imageViewOut,
uint32_t baseMipLevel,
uint32_t levelCount) uint32_t levelCount)
{ {
return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut, 0, return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut,
levelCount, 0, mLayerCount); baseMipLevel, levelCount, 0, mLayerCount);
} }
angle::Result ImageHelper::initLayerImageView(Context *context, angle::Result ImageHelper::initLayerImageView(Context *context,
...@@ -1959,6 +1960,7 @@ angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk, ...@@ -1959,6 +1960,7 @@ angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk,
} }
angle::Result ImageHelper::flushStagedUpdates(Context *context, angle::Result ImageHelper::flushStagedUpdates(Context *context,
uint32_t baseLevel,
uint32_t levelCount, uint32_t levelCount,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
{ {
...@@ -1985,7 +1987,7 @@ angle::Result ImageHelper::flushStagedUpdates(Context *context, ...@@ -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 // 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 // never been flushed but the image description has changed. Check if this level exist for
// this image. // this image.
if (updateMipLevel >= levelCount) if (updateMipLevel < baseLevel || updateMipLevel >= baseLevel + levelCount)
{ {
updatesToKeep.emplace_back(update); updatesToKeep.emplace_back(update);
continue; continue;
......
...@@ -552,6 +552,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -552,6 +552,7 @@ class ImageHelper final : public CommandGraphResource
VkImageAspectFlags aspectMask, VkImageAspectFlags aspectMask,
const gl::SwizzleState &swizzleMap, const gl::SwizzleState &swizzleMap,
ImageView *imageViewOut, ImageView *imageViewOut,
uint32_t baseMipLevel,
uint32_t levelCount); uint32_t levelCount);
// Create a 2D[Array] for staging purposes. Used by: // Create a 2D[Array] for staging purposes. Used by:
// //
...@@ -660,6 +661,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -660,6 +661,7 @@ class ImageHelper final : public CommandGraphResource
bool *newBufferAllocatedOut); bool *newBufferAllocatedOut);
angle::Result flushStagedUpdates(Context *context, angle::Result flushStagedUpdates(Context *context,
uint32_t baseLevel,
uint32_t levelCount, uint32_t levelCount,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
......
...@@ -1633,10 +1633,6 @@ TEST_P(ImageTest, MipLevels) ...@@ -1633,10 +1633,6 @@ TEST_P(ImageTest, MipLevels)
// Also fails on NVIDIA Shield TV bot. // Also fails on NVIDIA Shield TV bot.
ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES()); 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(); EGLWindow *window = getEGLWindow();
ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt() || !has2DTextureExt()); 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