blob: 9bf7c7b5e15507bf8f3d1d4eab133c9fc8264fe6 [file] [log] [blame]
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ImageVk.cpp:
// Implements the class methods for ImageVk.
//
#include "libANGLE/renderer/vulkan/ImageVk.h"
#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, 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);
vk::Renderer *renderer = displayVk->getRenderer();
if (mImage != nullptr && mOwnsImage)
{
// TODO: We need to handle the case that EGLImage used in two context that aren't shared.
// https://issuetracker.google.com/169868803
mImage->releaseImage(renderer);
mImage->releaseStagedUpdates(renderer);
SafeDelete(mImage);
}
else if (egl::IsExternalImageTarget(mState.target))
{
ASSERT(mState.source != nullptr);
ExternalImageSiblingVk *externalImageSibling =
GetImplAs<ExternalImageSiblingVk>(GetAs<egl::ExternalImageSibling>(mState.source));
externalImageSibling->release(renderer);
mImage = nullptr;
// This is called as a special case where resources may be allocated by the caller, without
// the caller ever issuing a draw command to free them. Specifically, SurfaceFlinger
// optimistically allocates EGLImages that it may never draw to.
renderer->cleanupGarbage();
}
}
egl::Error ImageVk::initialize(const egl::Display *display)
{
if (mContext != nullptr)
{
ContextVk *contextVk = vk::GetImpl(mContext);
ANGLE_TRY(ResultToEGL(contextVk->getShareGroup()->lockDefaultContextsPriority(contextVk)));
}
if (egl::IsTextureTarget(mState.target))
{
ASSERT(mContext != nullptr);
ContextVk *contextVk = vk::GetImpl(mContext);
TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source));
// Make sure the texture uses renderable format
TextureUpdateResult updateResult = TextureUpdateResult::ImageUnaffected;
ANGLE_TRY(ResultToEGL(textureVk->ensureRenderable(contextVk, &updateResult)));
// Make sure the texture has created its backing storage
ANGLE_TRY(ResultToEGL(
textureVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels)));
mImage = &textureVk->getImage();
// The staging buffer for a texture source should already be initialized
mOwnsImage = false;
}
else
{
if (egl::IsRenderbufferTarget(mState.target))
{
RenderbufferVk *renderbufferVk =
GetImplAs<RenderbufferVk>(GetAs<gl::Renderbuffer>(mState.source));
mImage = renderbufferVk->getImage();
ASSERT(mContext != nullptr);
}
else if (egl::IsExternalImageTarget(mState.target))
{
const ExternalImageSiblingVk *externalImageSibling =
GetImplAs<ExternalImageSiblingVk>(GetAs<egl::ExternalImageSibling>(mState.source));
mImage = externalImageSibling->getImage();
ASSERT(mContext == nullptr);
}
else
{
UNREACHABLE();
return egl::EglBadAccess();
}
mOwnsImage = false;
}
// mContext is no longer needed, make sure it's not used by accident.
mContext = nullptr;
return egl::NoError();
}
angle::Result ImageVk::orphan(const gl::Context *context, egl::ImageSibling *sibling)
{
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;
}
egl::Error ImageVk::exportVkImage(void *vkImage, void *vkImageCreateInfo)
{
*reinterpret_cast<VkImage *>(vkImage) = mImage->getImage().getHandle();
auto *info = reinterpret_cast<VkImageCreateInfo *>(vkImageCreateInfo);
*info = mImage->getVkImageCreateInfo();
return egl::NoError();
}
gl::TextureType ImageVk::getImageTextureType() const
{
return mState.imageIndex.getType();
}
gl::LevelIndex ImageVk::getImageLevel() const
{
return gl::LevelIndex(mState.imageIndex.getLevelIndex());
}
uint32_t ImageVk::getImageLayer() const
{
return mState.imageIndex.hasLayer() ? mState.imageIndex.getLayerIndex() : 0;
}
} // namespace rx