Vulkan: Implement EGL Images for 2D and Renderbuffer sources.
No support for non-zero mipmaps as sources yet.
Suppress dEQP tests due to apparent driver bugs with scissored clears on depth
or stencil attachments.
BUG=angleproject:2668
Change-Id: Idaa5e70ce9b0c91232fbb989cbf4de1b9134aafb
Reviewed-on: https://chromium-review.googlesource.com/c/1415010
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Image.cpp b/src/libANGLE/Image.cpp
index 9305041..60c2d7e 100644
--- a/src/libANGLE/Image.cpp
+++ b/src/libANGLE/Image.cpp
@@ -197,6 +197,7 @@
ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
: label(nullptr),
+ target(target),
imageIndex(GetImageIndex(target, attribs)),
source(buffer),
targets(),
@@ -242,6 +243,8 @@
mState.source = nullptr;
}
+
+ mImplementation->onDestroy(display);
}
Image::~Image()
diff --git a/src/libANGLE/Image.h b/src/libANGLE/Image.h
index e5c4562..cdcf010 100644
--- a/src/libANGLE/Image.h
+++ b/src/libANGLE/Image.h
@@ -110,6 +110,7 @@
~ImageState();
EGLLabelKHR label;
+ EGLenum target;
gl::ImageIndex imageIndex;
ImageSibling *source;
std::set<ImageSibling *> targets;
diff --git a/src/libANGLE/renderer/ImageImpl.h b/src/libANGLE/renderer/ImageImpl.h
index 5ee7aed..3ba16f5 100644
--- a/src/libANGLE/renderer/ImageImpl.h
+++ b/src/libANGLE/renderer/ImageImpl.h
@@ -45,6 +45,8 @@
public:
ImageImpl(const egl::ImageState &state) : mState(state) {}
virtual ~ImageImpl() {}
+ virtual void onDestroy(const egl::Display *display) {}
+
virtual egl::Error initialize(const egl::Display *display) = 0;
virtual angle::Result orphan(const gl::Context *context, egl::ImageSibling *sibling) = 0;
diff --git a/src/libANGLE/renderer/vulkan/DisplayVk.cpp b/src/libANGLE/renderer/vulkan/DisplayVk.cpp
index 3116837..dea564a 100644
--- a/src/libANGLE/renderer/vulkan/DisplayVk.cpp
+++ b/src/libANGLE/renderer/vulkan/DisplayVk.cpp
@@ -13,6 +13,7 @@
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
+#include "libANGLE/renderer/vulkan/ImageVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/SurfaceVk.h"
#include "libANGLE/renderer/vulkan/SyncVk.h"
@@ -135,8 +136,7 @@
EGLenum target,
const egl::AttributeMap &attribs)
{
- UNIMPLEMENTED();
- return static_cast<ImageImpl *>(0);
+ return new ImageVk(state, context);
}
rx::ContextImpl *DisplayVk::createContext(const gl::State &state,
@@ -183,6 +183,16 @@
outExtensions->fenceSync = true;
outExtensions->waitSync = true;
+
+ outExtensions->image = true;
+ outExtensions->imageBase = true;
+ outExtensions->imagePixmap = false; // ANGLE does not support pixmaps
+ outExtensions->glTexture2DImage = true;
+ // TODO(geofflang): Support EGL_KHR_gl_texture_cubemap_image. http://anglebug.com/2668
+ outExtensions->glTextureCubemapImage = false;
+ // TODO(geofflang): Support ES3 and EGL_KHR_gl_texture_3D_image. http://anglebug.com/2668
+ outExtensions->glTexture3DImage = false;
+ outExtensions->glRenderbufferImage = true;
}
void DisplayVk::generateCaps(egl::Caps *outCaps) const
diff --git a/src/libANGLE/renderer/vulkan/ImageVk.cpp b/src/libANGLE/renderer/vulkan/ImageVk.cpp
index 5ad2903..a804547 100644
--- a/src/libANGLE/renderer/vulkan/ImageVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ImageVk.cpp
@@ -11,25 +11,106 @@
#include "common/debug.h"
#include "libANGLE/Context.h"
+#include "libANGLE/Display.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
+#include "libANGLE/renderer/vulkan/DisplayVk.h"
+#include "libANGLE/renderer/vulkan/RenderbufferVk.h"
+#include "libANGLE/renderer/vulkan/TextureVk.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
-ImageVk::ImageVk(const egl::ImageState &state) : ImageImpl(state) {}
+ImageVk::ImageVk(const egl::ImageState &state, const gl::Context *context)
+ : ImageImpl(state), mOwnsImage(false), mImage(nullptr), mContext(context)
+{}
ImageVk::~ImageVk() {}
+void ImageVk::onDestroy(const egl::Display *display)
+{
+ DisplayVk *displayVk = vk::GetImpl(display);
+ RendererVk *renderer = displayVk->getRenderer();
+
+ if (mImage != nullptr && mOwnsImage)
+ {
+ mImage->releaseImage(renderer);
+ mImage->releaseStagingBuffer(renderer);
+ delete mImage;
+ }
+ mImage = nullptr;
+}
+
egl::Error ImageVk::initialize(const egl::Display *display)
{
- UNIMPLEMENTED();
- return egl::EglBadAccess();
+
+ if (egl::IsTextureTarget(mState.target))
+ {
+ TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source));
+
+ // Make sure the texture has created its backing storage
+ ASSERT(mContext != nullptr);
+ ContextVk *contextVk = vk::GetImpl(mContext);
+ ANGLE_TRY(ResultToEGL(textureVk->ensureImageInitialized(contextVk)));
+
+ mImage = &textureVk->getImage();
+
+ // The staging buffer for a texture source should already be initialized
+
+ mOwnsImage = false;
+
+ ASSERT(mState.imageIndex.getLevelIndex() == 0);
+ }
+ else if (egl::IsRenderbufferTarget(mState.target))
+ {
+ RenderbufferVk *renderbufferVk =
+ GetImplAs<RenderbufferVk>(GetAs<gl::Renderbuffer>(mState.source));
+ mImage = renderbufferVk->getImage();
+
+ // Make sure a staging buffer is ready to use to upload data
+ ASSERT(mContext != nullptr);
+ ContextVk *contextVk = vk::GetImpl(mContext);
+ RendererVk *renderer = contextVk->getRenderer();
+ mImage->initStagingBuffer(renderer);
+
+ mOwnsImage = false;
+ }
+ else
+ {
+ UNREACHABLE();
+ return egl::EglBadAccess();
+ }
+
+ return egl::NoError();
}
angle::Result ImageVk::orphan(const gl::Context *context, egl::ImageSibling *sibling)
{
- ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
- return angle::Result::Stop;
+ if (sibling == mState.source)
+ {
+ if (egl::IsTextureTarget(mState.target))
+ {
+ TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source));
+ ASSERT(mImage == &textureVk->getImage());
+ textureVk->releaseOwnershipOfImage(context);
+ mOwnsImage = true;
+ }
+ else if (egl::IsRenderbufferTarget(mState.target))
+ {
+ RenderbufferVk *renderbufferVk =
+ GetImplAs<RenderbufferVk>(GetAs<gl::Renderbuffer>(mState.source));
+ ASSERT(mImage == renderbufferVk->getImage());
+ renderbufferVk->releaseOwnershipOfImage(context);
+ mOwnsImage = true;
+ }
+ else
+ {
+ ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
+ return angle::Result::Stop;
+ }
+ }
+
+ return angle::Result::Continue;
}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/ImageVk.h b/src/libANGLE/renderer/vulkan/ImageVk.h
index c6611b7..f93eb27 100644
--- a/src/libANGLE/renderer/vulkan/ImageVk.h
+++ b/src/libANGLE/renderer/vulkan/ImageVk.h
@@ -11,6 +11,7 @@
#define LIBANGLE_RENDERER_VULKAN_IMAGEVK_H_
#include "libANGLE/renderer/ImageImpl.h"
+#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx
{
@@ -18,11 +19,21 @@
class ImageVk : public ImageImpl
{
public:
- ImageVk(const egl::ImageState &state);
+ ImageVk(const egl::ImageState &state, const gl::Context *context);
~ImageVk() override;
+ void onDestroy(const egl::Display *display) override;
+
egl::Error initialize(const egl::Display *display) override;
angle::Result orphan(const gl::Context *context, egl::ImageSibling *sibling) override;
+
+ vk::ImageHelper *getImage() const { return mImage; }
+
+ private:
+ bool mOwnsImage;
+ vk::ImageHelper *mImage;
+
+ const gl::Context *mContext;
};
} // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp b/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp
index 9eb9445..5640703 100644
--- a/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp
@@ -10,7 +10,9 @@
#include "libANGLE/renderer/vulkan/RenderbufferVk.h"
#include "libANGLE/Context.h"
+#include "libANGLE/Image.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
+#include "libANGLE/renderer/vulkan/ImageVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
namespace rx
@@ -24,7 +26,7 @@
} // anonymous namespace
RenderbufferVk::RenderbufferVk(const gl::RenderbufferState &state)
- : RenderbufferImpl(state), mImage(nullptr)
+ : RenderbufferImpl(state), mOwnsImage(false), mImage(nullptr)
{}
RenderbufferVk::~RenderbufferVk() {}
@@ -33,15 +35,7 @@
{
ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer();
-
- if (mImage)
- {
- mImage->releaseImage(renderer);
- mImage->releaseStagingBuffer(renderer);
- SafeDelete(mImage);
- }
-
- renderer->releaseObject(renderer->getCurrentQueueSerial(), &mImageView);
+ releaseAndDeleteImage(context, renderer);
}
angle::Result RenderbufferVk::setStorage(const gl::Context *context,
@@ -53,6 +47,11 @@
RendererVk *renderer = contextVk->getRenderer();
const vk::Format &vkFormat = renderer->getFormat(internalformat);
+ if (!mOwnsImage)
+ {
+ releaseAndDeleteImage(context, renderer);
+ }
+
if (mImage != nullptr && mImage->valid())
{
// Check against the state if we need to recreate the storage.
@@ -60,8 +59,7 @@
static_cast<GLsizei>(width) != mState.getWidth() ||
static_cast<GLsizei>(height) != mState.getHeight())
{
- mImage->releaseImage(renderer);
- renderer->releaseObject(renderer->getCurrentQueueSerial(), &mImageView);
+ releaseImage(context, renderer);
}
}
@@ -69,7 +67,8 @@
{
if (mImage == nullptr)
{
- mImage = new vk::ImageHelper();
+ mImage = new vk::ImageHelper();
+ mOwnsImage = true;
}
const angle::Format &textureFormat = vkFormat.textureFormat();
@@ -126,8 +125,26 @@
angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *context,
egl::Image *image)
{
- ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
- return angle::Result::Stop;
+ ContextVk *contextVk = vk::GetImpl(context);
+ RendererVk *renderer = contextVk->getRenderer();
+
+ releaseAndDeleteImage(context, renderer);
+
+ ImageVk *imageVk = vk::GetImpl(image);
+ mImage = imageVk->getImage();
+ mOwnsImage = false;
+
+ const vk::Format &vkFormat = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
+ const angle::Format &textureFormat = vkFormat.textureFormat();
+
+ VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
+
+ ANGLE_TRY(mImage->initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(),
+ &mImageView, 1));
+
+ mRenderTarget.init(mImage, &mImageView, 0, nullptr);
+
+ return angle::Result::Continue;
}
angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *context,
@@ -147,4 +164,34 @@
return angle::Result::Continue;
}
+void RenderbufferVk::releaseOwnershipOfImage(const gl::Context *context)
+{
+ ContextVk *contextVk = vk::GetImpl(context);
+ RendererVk *renderer = contextVk->getRenderer();
+
+ mOwnsImage = false;
+ releaseAndDeleteImage(context, renderer);
+}
+
+void RenderbufferVk::releaseAndDeleteImage(const gl::Context *context, RendererVk *renderer)
+{
+ releaseImage(context, renderer);
+ SafeDelete(mImage);
+}
+
+void RenderbufferVk::releaseImage(const gl::Context *context, RendererVk *renderer)
+{
+ if (mImage && mOwnsImage)
+ {
+ mImage->releaseImage(renderer);
+ mImage->releaseStagingBuffer(renderer);
+ }
+ else
+ {
+ mImage = nullptr;
+ }
+
+ renderer->releaseObject(renderer->getCurrentQueueSerial(), &mImageView);
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/RenderbufferVk.h b/src/libANGLE/renderer/vulkan/RenderbufferVk.h
index 67d94b6..57c6ccc 100644
--- a/src/libANGLE/renderer/vulkan/RenderbufferVk.h
+++ b/src/libANGLE/renderer/vulkan/RenderbufferVk.h
@@ -44,7 +44,14 @@
angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override;
+ vk::ImageHelper *getImage() const { return mImage; }
+ void releaseOwnershipOfImage(const gl::Context *context);
+
private:
+ void releaseAndDeleteImage(const gl::Context *context, RendererVk *renderer);
+ void releaseImage(const gl::Context *context, RendererVk *renderer);
+
+ bool mOwnsImage;
vk::ImageHelper *mImage;
vk::ImageView mImageView;
RenderTargetVk mRenderTarget;
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index 0607606..ab346c1 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -13,9 +13,11 @@
#include "image_util/generatemip.inl"
#include "libANGLE/Config.h"
#include "libANGLE/Context.h"
+#include "libANGLE/Image.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
+#include "libANGLE/renderer/vulkan/ImageVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/SurfaceVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
@@ -528,6 +530,11 @@
ContextVk *contextVk = GetAs<ContextVk>(context->getImplementation());
RendererVk *renderer = contextVk->getRenderer();
+ if (!mOwnsImage)
+ {
+ releaseAndDeleteImage(context, renderer);
+ }
+
ANGLE_TRY(ensureImageAllocated(renderer));
const vk::Format &format = renderer->getFormat(internalFormat);
@@ -547,8 +554,18 @@
gl::TextureType type,
egl::Image *image)
{
- ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
- return angle::Result::Stop;
+ ContextVk *contextVk = vk::GetImpl(context);
+ RendererVk *renderer = contextVk->getRenderer();
+
+ releaseAndDeleteImage(context, renderer);
+
+ ImageVk *imageVk = vk::GetImpl(image);
+ setImageHelper(renderer, imageVk->getImage(), false);
+
+ const vk::Format &format = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
+ ANGLE_TRY(initImageViews(contextVk, format, 1));
+
+ return angle::Result::Continue;
}
angle::Result TextureVk::setImageExternal(const gl::Context *context,
@@ -602,9 +619,10 @@
ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer();
- // Make sure the image is not allocated yet or it is owned by this texture. We don't want to
- // redefine an external image.
- ASSERT(mImage == nullptr || mOwnsImage);
+ if (!mOwnsImage)
+ {
+ releaseAndDeleteImage(context, renderer);
+ }
if (!size.empty())
{
@@ -929,6 +947,15 @@
return angle::Result::Continue;
}
+void TextureVk::releaseOwnershipOfImage(const gl::Context *context)
+{
+ ContextVk *contextVk = vk::GetImpl(context);
+ RendererVk *renderer = contextVk->getRenderer();
+
+ mOwnsImage = false;
+ releaseAndDeleteImage(context, renderer);
+}
+
const vk::ImageView &TextureVk::getReadImageView() const
{
ASSERT(mImage->valid());
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.h b/src/libANGLE/renderer/vulkan/TextureVk.h
index 33fceff..35c00db 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.h
+++ b/src/libANGLE/renderer/vulkan/TextureVk.h
@@ -139,6 +139,8 @@
return *mImage;
}
+ void releaseOwnershipOfImage(const gl::Context *context);
+
const vk::ImageView &getReadImageView() const;
angle::Result getLayerLevelDrawImageView(vk::Context *context,
size_t layer,
diff --git a/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp b/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp
index c9a2cbd..ef3917c 100644
--- a/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp
@@ -50,6 +50,12 @@
outExtensions->textureBorderClamp = false; // not implemented yet
outExtensions->translatedShaderSource = true;
+ outExtensions->eglImage = true;
+ // TODO(geofflang): Support GL_OES_EGL_image_external. http://anglebug.com/2668
+ outExtensions->eglImageExternal = false;
+ // TODO(geofflang): Support GL_OES_EGL_image_external_essl3. http://anglebug.com/2668
+ outExtensions->eglImageExternalEssl3 = false;
+
// Only expose robust buffer access if the physical device supports it.
outExtensions->robustBufferAccessBehavior = physicalDeviceFeatures.robustBufferAccess;
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
index ed1eb30..75ed286 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
@@ -1958,7 +1958,7 @@
newBufferAllocatedOut);
}
-angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
+angle::Result ImageHelper::flushStagedUpdates(Context *context,
uint32_t levelCount,
vk::CommandBuffer *commandBuffer)
{
@@ -1967,9 +1967,9 @@
return angle::Result::Continue;
}
- RendererVk *renderer = contextVk->getRenderer();
+ RendererVk *renderer = context->getRenderer();
- ANGLE_TRY(mStagingBuffer.flush(contextVk));
+ ANGLE_TRY(mStagingBuffer.flush(context));
std::vector<SubresourceUpdate> updatesToKeep;
@@ -2025,7 +2025,7 @@
if (mSubresourceUpdates.empty())
{
- mStagingBuffer.releaseRetainedBuffers(contextVk->getRenderer());
+ mStagingBuffer.releaseRetainedBuffers(context->getRenderer());
}
else
{
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
index bb4592c..bbf79bc 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
@@ -659,7 +659,7 @@
VkDeviceSize *offsetOut,
bool *newBufferAllocatedOut);
- angle::Result flushStagedUpdates(ContextVk *contextVk,
+ angle::Result flushStagedUpdates(Context *context,
uint32_t levelCount,
vk::CommandBuffer *commandBuffer);
diff --git a/src/libANGLE/renderer/vulkan/vk_utils.h b/src/libANGLE/renderer/vulkan/vk_utils.h
index 8e762e8..70c12b7 100644
--- a/src/libANGLE/renderer/vulkan/vk_utils.h
+++ b/src/libANGLE/renderer/vulkan/vk_utils.h
@@ -33,6 +33,7 @@
namespace egl
{
class Display;
+class Image;
}
namespace gl
@@ -55,6 +56,7 @@
{
class CommandGraphResource;
class DisplayVk;
+class ImageVk;
class RenderTargetVk;
class RendererVk;
class RenderPassCache;
@@ -136,6 +138,12 @@
using ImplType = DisplayVk;
};
+template <>
+struct ImplTypeHelper<egl::Image>
+{
+ using ImplType = ImageVk;
+};
+
template <typename T>
using GetImplType = typename ImplTypeHelper<T>::ImplType;