Commit fe59f6b5 by Geoff Lang Committed by Commit Bot

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: 's avatarJamie Madill <jmadill@chromium.org>
parent abf6dbbb
......@@ -197,6 +197,7 @@ rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() c
ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
: label(nullptr),
target(target),
imageIndex(GetImageIndex(target, attribs)),
source(buffer),
targets(),
......@@ -242,6 +243,8 @@ void Image::onDestroy(const Display *display)
mState.source = nullptr;
}
mImplementation->onDestroy(display);
}
Image::~Image()
......
......@@ -110,6 +110,7 @@ struct ImageState : private angle::NonCopyable
~ImageState();
EGLLabelKHR label;
EGLenum target;
gl::ImageIndex imageIndex;
ImageSibling *source;
std::set<ImageSibling *> targets;
......
......@@ -45,6 +45,8 @@ class ImageImpl : angle::NonCopyable
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;
......
......@@ -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 @@ ImageImpl *DisplayVk::createImage(const egl::ImageState &state,
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 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const
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
......
......@@ -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
......@@ -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 @@ namespace rx
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
......
......@@ -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 @@ constexpr VkClearColorValue kBlackClearColorValue = {{0}};
} // anonymous namespace
RenderbufferVk::RenderbufferVk(const gl::RenderbufferState &state)
: RenderbufferImpl(state), mImage(nullptr)
: RenderbufferImpl(state), mOwnsImage(false), mImage(nullptr)
{}
RenderbufferVk::~RenderbufferVk() {}
......@@ -33,15 +35,7 @@ void RenderbufferVk::onDestroy(const gl::Context *context)
{
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 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
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 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
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 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
{
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::setStorageMultisample(const gl::Context *context,
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 @@ angle::Result RenderbufferVk::initializeContents(const gl::Context *context,
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
......@@ -44,7 +44,14 @@ class RenderbufferVk : public RenderbufferImpl
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;
......
......@@ -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 @@ angle::Result TextureVk::setStorage(const gl::Context *context,
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 @@ angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
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 @@ angle::Result TextureVk::redefineImage(const gl::Context *context,
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 @@ angle::Result TextureVk::initializeContents(const gl::Context *context,
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());
......
......@@ -139,6 +139,8 @@ class TextureVk : public TextureImpl
return *mImage;
}
void releaseOwnershipOfImage(const gl::Context *context);
const vk::ImageView &getReadImageView() const;
angle::Result getLayerLevelDrawImageView(vk::Context *context,
size_t layer,
......
......@@ -50,6 +50,12 @@ void GenerateCaps(const VkPhysicalDeviceProperties &physicalDeviceProperties,
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;
......
......@@ -1958,7 +1958,7 @@ angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk,
newBufferAllocatedOut);
}
angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
angle::Result ImageHelper::flushStagedUpdates(Context *context,
uint32_t levelCount,
vk::CommandBuffer *commandBuffer)
{
......@@ -1967,9 +1967,9 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
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 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
if (mSubresourceUpdates.empty())
{
mStagingBuffer.releaseRetainedBuffers(contextVk->getRenderer());
mStagingBuffer.releaseRetainedBuffers(context->getRenderer());
}
else
{
......
......@@ -659,7 +659,7 @@ class ImageHelper final : public CommandGraphResource
VkDeviceSize *offsetOut,
bool *newBufferAllocatedOut);
angle::Result flushStagedUpdates(ContextVk *contextVk,
angle::Result flushStagedUpdates(Context *context,
uint32_t levelCount,
vk::CommandBuffer *commandBuffer);
......
......@@ -33,6 +33,7 @@
namespace egl
{
class Display;
class Image;
}
namespace gl
......@@ -55,6 +56,7 @@ namespace rx
{
class CommandGraphResource;
class DisplayVk;
class ImageVk;
class RenderTargetVk;
class RendererVk;
class RenderPassCache;
......@@ -136,6 +138,12 @@ struct ImplTypeHelper<egl::Display>
using ImplType = DisplayVk;
};
template <>
struct ImplTypeHelper<egl::Image>
{
using ImplType = ImageVk;
};
template <typename T>
using GetImplType = typename ImplTypeHelper<T>::ImplType;
......
......@@ -272,6 +272,14 @@
2546 ANDROID : dEQP-EGL.functional.thread_cleanup.multi_context_* = SKIP
2546 ANDROID : dEQP-EGL.functional.thread_cleanup.single_context_* = FAIL
// Vulkan
3081 VULKAN : dEQP-EGL.functional.image.create.gles2_renderbuffer_depth16_depth_buffer = SKIP
3081 VULKAN : dEQP-EGL.functional.image.create.gles2_renderbuffer_stencil_stencil_buffer = SKIP
3081 VULKAN : dEQP-EGL.functional.image.modify.renderbuffer_depth16_renderbuffer_clear_depth = SKIP
3081 VULKAN : dEQP-EGL.functional.image.modify.renderbuffer_stencil_renderbuffer_clear_stencil = SKIP
3081 VULKAN : dEQP-EGL.functional.image.render_multiple_contexts.gles2_renderbuffer_depth16_depth_buffer = SKIP
3081 VULKAN : dEQP-EGL.functional.image.render_multiple_contexts.gles2_renderbuffer_stencil_stencil_buffer = SKIP
// ES 1 tests
2306 WIN MAC LINUX : dEQP-EGL.functional.color_clears.single_context.gles1* = FAIL
2306 WIN MAC LINUX : dEQP-EGL.functional.color_clears.multi_context.gles1* = FAIL
......
......@@ -514,6 +514,19 @@ TEST_P(ImageTest, ANGLEExtensionAvailability)
EXPECT_FALSE(hasExternalESSL3Ext());
}
}
else if (IsVulkan())
{
EXPECT_TRUE(hasOESExt());
// TODO(geofflang): Support GL_OES_EGL_image_external. http://anglebug.com/2668
EXPECT_FALSE(hasExternalExt());
EXPECT_TRUE(hasBaseExt());
EXPECT_TRUE(has2DTextureExt());
// TODO(geofflang): Support EGL_KHR_gl_texture_cubemap_image. http://anglebug.com/2668
EXPECT_FALSE(hasCubemapExt());
EXPECT_TRUE(hasRenderbufferExt());
// TODO(geofflang): Support GL_OES_EGL_image_external_essl3. http://anglebug.com/2668
EXPECT_FALSE(hasExternalESSL3Ext());
}
else
{
EXPECT_FALSE(hasOESExt());
......@@ -1620,6 +1633,10 @@ 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());
......@@ -1846,6 +1863,10 @@ TEST_P(ImageTest, RespecificationOfOtherLevel)
// image does not cause orphaning on Qualcomm devices. http://anglebug.com/2744
ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
// It is undefined what happens to the mip 0 of the dest texture after it is orphaned. Some
// backends explicitly copy the data but Vulkan does not.
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