Commit 009696c5 by Geoff Lang Committed by Commit Bot

Vulkan: Support EGL_ANDROID_image_native_buffer on Android.

BUG=angleproject:2668 BUG=angleproject:3121 Change-Id: I0dfb2ec0737ebd963b0fadb78cf720a90874f00b Reviewed-on: https://chromium-review.googlesource.com/c/1452264 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 46d32e0f
......@@ -62,6 +62,10 @@ struct FeaturesVk
// Intel drivers on windows that have an issue with creating single-layer views on cube map
// textures.
bool forceCpuPathForCubeMapCopy = false;
// Whether the VkDevice supports the VK_ANDROID_external_memory_android_hardware_buffer
// extension, on which the EGL_ANDROID_image_native_buffer extension can be layered.
bool supportsAndroidHardwareBuffer = false;
};
} // namespace angle
......
......@@ -6,13 +6,51 @@
// android_util.cpp: Utilities for the using the Android platform
#include "libANGLE/renderer/gl/egl/android/android_util.h"
#include "common/android_util.h"
namespace rx
// Taken from cutils/native_handle.h:
// https://android.googlesource.com/platform/system/core/+/master/libcutils/include/cutils/native_handle.h
typedef struct native_handle
{
int version; /* sizeof(native_handle_t) */
int numFds; /* number of file-descriptors at &data[0] */
int numInts; /* number of ints at &data[numFds] */
int data[0]; /* numFds + numInts ints */
} native_handle_t;
namespace
// Taken from nativebase/nativebase.h
// https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativebase/include/nativebase/nativebase.h
typedef const native_handle_t *buffer_handle_t;
typedef struct android_native_base_t
{
/* a magic value defined by the actual EGL native type */
int magic;
/* the sizeof() of the actual EGL native type */
int version;
void *reserved[4];
/* reference-counting interface */
void (*incRef)(struct android_native_base_t *base);
void (*decRef)(struct android_native_base_t *base);
} android_native_base_t;
typedef struct ANativeWindowBuffer
{
struct android_native_base_t common;
int width;
int height;
int stride;
int format;
int usage_deprecated;
uintptr_t layerCount;
void *reserved[1];
const native_handle_t *handle;
uint64_t usage;
// we needed extra space for storing the 64-bits usage flags
// the number of slots to use from reserved_proc depends on the
// architecture.
void *reserved_proc[8 - (sizeof(uint64_t) / sizeof(void *))];
} ANativeWindowBuffer_t;
// Taken from android/hardware_buffer.h
// https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativewindow/include/android/hardware_buffer.h
......@@ -31,6 +69,7 @@ enum {
* OpenGL ES: GL_RGBA8
*/
AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1,
/**
* 32 bits per pixel, 8 bits per channel format where alpha values are
* ignored (always opaque).
......@@ -39,68 +78,79 @@ enum {
* OpenGL ES: GL_RGB8
*/
AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R8G8B8_UNORM
* OpenGL ES: GL_RGB8
*/
AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM = 3,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R5G6B5_UNORM_PACK16
* OpenGL ES: GL_RGB565
*/
AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4,
AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM = 5,
AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM = 6,
AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM = 7,
AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM = 6,
AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM = 7,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R16G16B16A16_SFLOAT
* OpenGL ES: GL_RGBA16F
*/
AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT = 0x16,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_A2B10G10R10_UNORM_PACK32
* OpenGL ES: GL_RGB10_A2
*/
AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM = 0x2b,
/**
* An opaque binary blob format that must have height 1, with width equal to
* the buffer size in bytes.
*/
AHARDWAREBUFFER_FORMAT_BLOB = 0x21,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_D16_UNORM
* OpenGL ES: GL_DEPTH_COMPONENT16
*/
AHARDWAREBUFFER_FORMAT_D16_UNORM = 0x30,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_X8_D24_UNORM_PACK32
* OpenGL ES: GL_DEPTH_COMPONENT24
*/
AHARDWAREBUFFER_FORMAT_D24_UNORM = 0x31,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_D24_UNORM_S8_UINT
* OpenGL ES: GL_DEPTH24_STENCIL8
*/
AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT = 0x32,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_D32_SFLOAT
* OpenGL ES: GL_DEPTH_COMPONENT32F
*/
AHARDWAREBUFFER_FORMAT_D32_FLOAT = 0x33,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_D32_SFLOAT_S8_UINT
* OpenGL ES: GL_DEPTH32F_STENCIL8
*/
AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT = 0x34,
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_S8_UINT
......@@ -110,10 +160,41 @@ enum {
};
// clang-format on
namespace
{
template <typename T1, typename T2>
T1 *offsetPointer(T2 *ptr, int bytes)
{
return reinterpret_cast<T1 *>(reinterpret_cast<intptr_t>(ptr) + bytes);
}
} // anonymous namespace
namespace angle
{
namespace android
{
struct ANativeWindowBuffer *ClientBufferToANativeWindowBuffer(EGLClientBuffer clientBuffer)
{
return reinterpret_cast<struct ANativeWindowBuffer *>(clientBuffer);
}
void GetANativeWindowBufferProperties(const struct ANativeWindowBuffer *buffer,
int *width,
int *height,
int *depth,
int *pixelFormat)
{
*width = buffer->width;
*height = buffer->height;
*depth = static_cast<int>(buffer->layerCount);
*height = buffer->height;
*pixelFormat = buffer->format;
}
GLenum NativePixelFormatToGLInternalFormat(int pixelFormat)
{
switch (pixelFormat)
......@@ -128,10 +209,10 @@ GLenum NativePixelFormatToGLInternalFormat(int pixelFormat)
return GL_RGB565;
case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
return GL_BGRA8_EXT;
case AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM:
return GL_RGBA4;
case AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM:
return GL_RGB5_A1;
case AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM:
return GL_RGBA4;
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
return GL_RGBA16F;
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
......@@ -154,5 +235,25 @@ GLenum NativePixelFormatToGLInternalFormat(int pixelFormat)
return GL_NONE;
}
}
struct AHardwareBuffer *ANativeWindowBufferToAHardwareBuffer(
struct ANativeWindowBuffer *windowBuffer)
{
// In the Android system:
// - AHardwareBuffer is essentially a typedef of GraphicBuffer. Conversion functions simply
// reinterpret_cast.
// - GraphicBuffer inherits from two base classes, ANativeWindowBuffer and RefBase.
//
// GraphicBuffer implements a getter for ANativeWindowBuffer (getNativeBuffer) by static_casting
// itself to its base class ANativeWindowBuffer. The offset of the ANativeWindowBuffer pointer
// from the GraphicBuffer pointer is 16 bytes. This is likely due to two pointers: The vtable of
// GraphicBuffer and the one pointer member of the RefBase class.
//
// This is not future proof at all. We need to look into getting utilities added to Android to
// perform this cast for us.
int offset = -(static_cast<int>(sizeof(void *)) * 2);
return offsetPointer<struct AHardwareBuffer>(windowBuffer, offset);
}
} // namespace android
} // namespace rx
} // namespace angle
//
// Copyright 2018 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.
//
// android_util.h: Utilities for the using the Android platform
#ifndef COMMON_ANDROIDUTIL_H_
#define COMMON_ANDROIDUTIL_H_
#include <EGL/egl.h>
#include "angle_gl.h"
struct ANativeWindowBuffer;
struct AHardwareBuffer;
namespace angle
{
namespace android
{
struct ANativeWindowBuffer *ClientBufferToANativeWindowBuffer(EGLClientBuffer clientBuffer);
void GetANativeWindowBufferProperties(const struct ANativeWindowBuffer *buffer,
int *width,
int *height,
int *depth,
int *pixelFormat);
GLenum NativePixelFormatToGLInternalFormat(int pixelFormat);
struct AHardwareBuffer *ANativeWindowBufferToAHardwareBuffer(
struct ANativeWindowBuffer *windowBuffer);
} // namespace android
} // namespace angle
#endif // COMMON_ANDROIDUTIL_H_
......@@ -139,6 +139,16 @@ ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
ExternalImageSibling::~ExternalImageSibling() = default;
void ExternalImageSibling::onDestroy(const egl::Display *display)
{
mImplementation->onDestroy(display);
}
Error ExternalImageSibling::initialize(const egl::Display *display)
{
return mImplementation->initialize(display);
}
gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
{
return mImplementation->getSize();
......@@ -201,9 +211,9 @@ ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap
imageIndex(GetImageIndex(target, attribs)),
source(buffer),
targets(),
format(buffer->getAttachmentFormat(GL_NONE, imageIndex)),
size(buffer->getAttachmentSize(imageIndex)),
samples(buffer->getAttachmentSamples(imageIndex)),
format(GL_NONE),
size(),
samples(),
sourceType(target)
{}
......@@ -238,7 +248,9 @@ void Image::onDestroy(const Display *display)
// If the source is an external object, delete it
if (IsExternalImageTarget(mState.sourceType))
{
delete mState.source;
ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
externalSibling->onDestroy(display);
delete externalSibling;
}
mState.source = nullptr;
......@@ -363,6 +375,15 @@ rx::ImageImpl *Image::getImplementation() const
Error Image::initialize(const Display *display)
{
if (IsExternalImageTarget(mState.sourceType))
{
ANGLE_TRY(rx::GetAs<ExternalImageSibling>(mState.source)->initialize(display));
}
mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
mState.size = mState.source->getAttachmentSize(mState.imageIndex);
mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
return mImplementation->initialize(display);
}
......
......@@ -80,6 +80,10 @@ class ExternalImageSibling : public ImageSibling
const AttributeMap &attribs);
~ExternalImageSibling() override;
void onDestroy(const egl::Display *display);
Error initialize(const Display *display);
gl::Extents getAttachmentSize(const gl::ImageIndex &imageIndex) const override;
gl::Format getAttachmentFormat(GLenum binding, const gl::ImageIndex &imageIndex) const override;
GLsizei getAttachmentSamples(const gl::ImageIndex &imageIndex) const override;
......
......@@ -33,6 +33,9 @@ class ExternalImageSiblingImpl : public FramebufferAttachmentObjectImpl
public:
~ExternalImageSiblingImpl() override {}
virtual egl::Error initialize(const egl::Display *display) = 0;
virtual void onDestroy(const egl::Display *display) {}
virtual gl::Format getFormat() const = 0;
virtual bool isRenderable(const gl::Context *context) const = 0;
virtual bool isTexturable(const gl::Context *context) const = 0;
......
......@@ -8,63 +8,30 @@
#include "libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h"
#include "libANGLE/renderer/gl/egl/android/android_util.h"
// Taken from cutils/native_handle.h:
// https://android.googlesource.com/platform/system/core/+/master/libcutils/include/cutils/native_handle.h
typedef struct native_handle
{
int version; /* sizeof(native_handle_t) */
int numFds; /* number of file-descriptors at &data[0] */
int numInts; /* number of ints at &data[numFds] */
int data[0]; /* numFds + numInts ints */
} native_handle_t;
// Taken from nativebase/nativebase.h
// https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativebase/include/nativebase/nativebase.h
typedef const native_handle_t *buffer_handle_t;
typedef struct android_native_base_t
{
/* a magic value defined by the actual EGL native type */
int magic;
/* the sizeof() of the actual EGL native type */
int version;
void *reserved[4];
/* reference-counting interface */
void (*incRef)(struct android_native_base_t *base);
void (*decRef)(struct android_native_base_t *base);
} android_native_base_t;
typedef struct ANativeWindowBuffer
{
struct android_native_base_t common;
int width;
int height;
int stride;
int format;
int usage_deprecated;
uintptr_t layerCount;
void *reserved[1];
const native_handle_t *handle;
uint64_t usage;
// we needed extra space for storing the 64-bits usage flags
// the number of slots to use from reserved_proc depends on the
// architecture.
void *reserved_proc[8 - (sizeof(uint64_t) / sizeof(void *))];
} ANativeWindowBuffer_t;
#include "common/android_util.h"
namespace rx
{
NativeBufferImageSiblingAndroid::NativeBufferImageSiblingAndroid(EGLClientBuffer buffer)
: mBuffer(static_cast<struct ANativeWindowBuffer *>(buffer))
: mBuffer(buffer), mFormat(GL_NONE)
{}
NativeBufferImageSiblingAndroid::~NativeBufferImageSiblingAndroid() {}
egl::Error NativeBufferImageSiblingAndroid::initialize(const egl::Display *display)
{
int pixelFormat = 0;
angle::android::GetANativeWindowBufferProperties(
angle::android::ClientBufferToANativeWindowBuffer(mBuffer), &mSize.width, &mSize.height,
&mSize.depth, &pixelFormat);
mFormat = gl::Format(angle::android::NativePixelFormatToGLInternalFormat(pixelFormat));
return egl::NoError();
}
gl::Format NativeBufferImageSiblingAndroid::getFormat() const
{
return gl::Format(android::NativePixelFormatToGLInternalFormat(mBuffer->format));
return mFormat;
}
bool NativeBufferImageSiblingAndroid::isRenderable(const gl::Context *context) const
......@@ -79,7 +46,7 @@ bool NativeBufferImageSiblingAndroid::isTexturable(const gl::Context *context) c
gl::Extents NativeBufferImageSiblingAndroid::getSize() const
{
return gl::Extents(mBuffer->width, mBuffer->height, 1);
return mSize;
}
size_t NativeBufferImageSiblingAndroid::getSamples() const
......@@ -89,7 +56,7 @@ size_t NativeBufferImageSiblingAndroid::getSamples() const
EGLClientBuffer NativeBufferImageSiblingAndroid::getBuffer() const
{
return static_cast<EGLClientBuffer>(mBuffer);
return mBuffer;
}
} // namespace rx
......@@ -12,8 +12,6 @@
#include "libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h"
struct ANativeWindowBuffer;
namespace rx
{
......@@ -23,6 +21,8 @@ class NativeBufferImageSiblingAndroid : public ExternalImageSiblingEGL
NativeBufferImageSiblingAndroid(EGLClientBuffer buffer);
virtual ~NativeBufferImageSiblingAndroid();
egl::Error initialize(const egl::Display *display) override;
// ExternalImageSiblingImpl interface
gl::Format getFormat() const override;
bool isRenderable(const gl::Context *context) const override;
......@@ -34,7 +34,9 @@ class NativeBufferImageSiblingAndroid : public ExternalImageSiblingEGL
EGLClientBuffer getBuffer() const override;
private:
struct ANativeWindowBuffer *mBuffer;
EGLClientBuffer mBuffer;
gl::Extents mSize;
gl::Format mFormat;
};
} // namespace rx
......
//
// Copyright 2018 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.
//
// android_util.h: Utilities for the using the Android platform
#ifndef LIBANGLE_RENDERER_GL_EGL_ANDROID_ANDROID_UTIL_H_
#define LIBANGLE_RENDERER_GL_EGL_ANDROID_ANDROID_UTIL_H_
#include "angle_gl.h"
namespace rx
{
namespace android
{
GLenum NativePixelFormatToGLInternalFormat(int pixelFormat);
}
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_EGL_ANDROID_ANDROID_UTIL_H_
\ No newline at end of file
......@@ -191,6 +191,7 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->glTextureCubemapImage = true;
outExtensions->glTexture3DImage = false;
outExtensions->glRenderbufferImage = true;
outExtensions->imageNativeBuffer = getRenderer()->getFeatures().supportsAndroidHardwareBuffer;
}
void DisplayVk::generateCaps(egl::Caps *outCaps) const
......
......@@ -62,17 +62,37 @@ egl::Error ImageVk::initialize(const egl::Display *display)
mImageLevel = mState.imageIndex.getLevelIndex();
mImageLayer = mState.imageIndex.hasLayer() ? mState.imageIndex.getLayerIndex() : 0;
}
else if (egl::IsRenderbufferTarget(mState.target))
else
{
RenderbufferVk *renderbufferVk =
GetImplAs<RenderbufferVk>(GetAs<gl::Renderbuffer>(mState.source));
mImage = renderbufferVk->getImage();
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);
// 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);
}
else if (egl::IsExternalImageTarget(mState.target))
{
const ExternalImageSiblingVk *externalImageSibling =
GetImplAs<ExternalImageSiblingVk>(GetAs<egl::ExternalImageSibling>(mState.source));
mImage = externalImageSibling->getImage();
// Make sure a staging buffer is ready to use to upload data
ASSERT(mContext == nullptr);
DisplayVk *displayVk = vk::GetImpl(display);
RendererVk *renderer = displayVk->getRenderer();
mImage->initStagingBuffer(renderer);
}
else
{
UNREACHABLE();
return egl::EglBadAccess();
}
mOwnsImage = false;
......@@ -80,11 +100,6 @@ egl::Error ImageVk::initialize(const egl::Display *display)
mImageLevel = 0;
mImageLayer = 0;
}
else
{
UNREACHABLE();
return egl::EglBadAccess();
}
return egl::NoError();
}
......
......@@ -16,6 +16,15 @@
namespace rx
{
class ExternalImageSiblingVk : public ExternalImageSiblingImpl
{
public:
ExternalImageSiblingVk() {}
~ExternalImageSiblingVk() override {}
virtual vk::ImageHelper *getImage() const = 0;
};
class ImageVk : public ImageImpl
{
public:
......
......@@ -139,6 +139,16 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex
VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
// Transfer the image to this queue if needed
uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
{
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
mImage->changeLayoutAndQueue(aspect, vk::ImageLayout::ColorAttachment,
rendererQueueFamilyIndex, commandBuffer);
}
ANGLE_TRY(mImage->initLayerImageView(contextVk, imageVk->getImageTextureType(), aspect,
gl::SwizzleState(), &mImageView, imageVk->getImageLevel(),
1, imageVk->getImageLayer(), 1));
......
......@@ -923,6 +923,18 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledDeviceExtensions.push_back(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
}
#if defined(ANGLE_PLATFORM_ANDROID)
if (getFeatures().supportsAndroidHardwareBuffer)
{
enabledDeviceExtensions.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
enabledDeviceExtensions.push_back(
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
InitExternalMemoryHardwareBufferANDROIDFunctions(mInstance);
}
#else
ASSERT(!getFeatures().supportsAndroidHardwareBuffer);
#endif
std::sort(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(), StrLess);
ANGLE_VK_TRY(displayVk, VerifyExtensionsPresent(deviceExtensionNames, enabledDeviceExtensions));
......@@ -1181,6 +1193,11 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
{
mFeatures.supportsIncrementalPresent = true;
}
#if defined(ANGLE_PLATFORM_ANDROID)
mFeatures.supportsAndroidHardwareBuffer = ExtensionFound(
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, deviceExtensionNames);
#endif
}
void RendererVk::initPipelineCacheVkKey()
......
......@@ -688,6 +688,17 @@ angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
const vk::Format &format = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
ANGLE_TRY(initImageViews(contextVk, format, 1));
// Transfer the image to this queue if needed
uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
{
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
mImage->changeLayoutAndQueue(VK_IMAGE_ASPECT_COLOR_BIT,
vk::ImageLayout::FragmentShaderReadOnly,
rendererQueueFamilyIndex, commandBuffer);
}
return angle::Result::Continue;
}
......
......@@ -14,6 +14,7 @@
#include <vulkan/vulkan.h>
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.h"
#include "libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.h"
#include "libANGLE/renderer/vulkan/vk_caps_utils.h"
......@@ -58,6 +59,38 @@ bool DisplayVkAndroid::checkConfigSupport(egl::Config *config)
return true;
}
egl::Error DisplayVkAndroid::validateImageClientBuffer(const gl::Context *context,
EGLenum target,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const
{
switch (target)
{
case EGL_NATIVE_BUFFER_ANDROID:
return HardwareBufferImageSiblingVkAndroid::ValidateHardwareBuffer(mRenderer,
clientBuffer);
default:
return DisplayVk::validateImageClientBuffer(context, target, clientBuffer, attribs);
}
}
ExternalImageSiblingImpl *DisplayVkAndroid::createExternalImageSibling(
const gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
{
switch (target)
{
case EGL_NATIVE_BUFFER_ANDROID:
return new HardwareBufferImageSiblingVkAndroid(buffer);
default:
return DisplayVk::createExternalImageSibling(context, target, buffer, attribs);
}
}
const char *DisplayVkAndroid::getWSIExtension() const
{
return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
......
......@@ -31,6 +31,16 @@ class DisplayVkAndroid : public DisplayVk
egl::ConfigSet generateConfigs() override;
bool checkConfigSupport(egl::Config *config) override;
egl::Error validateImageClientBuffer(const gl::Context *context,
EGLenum target,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const override;
ExternalImageSiblingImpl *createExternalImageSibling(const gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs) override;
const char *getWSIExtension() const override;
};
......
//
// Copyright 2019 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.
//
// HardwareBufferImageSiblingVkAndroid.cpp: Implements HardwareBufferImageSiblingVkAndroid.
#include "libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.h"
#include "common/android_util.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
namespace rx
{
HardwareBufferImageSiblingVkAndroid::HardwareBufferImageSiblingVkAndroid(EGLClientBuffer buffer)
: mBuffer(buffer),
mFormat(GL_NONE),
mRenderable(false),
mTextureable(false),
mSamples(0),
mImage(nullptr)
{}
HardwareBufferImageSiblingVkAndroid::~HardwareBufferImageSiblingVkAndroid() {}
// Static
egl::Error HardwareBufferImageSiblingVkAndroid::ValidateHardwareBuffer(RendererVk *renderer,
EGLClientBuffer buffer)
{
struct ANativeWindowBuffer *windowBuffer =
angle::android::ClientBufferToANativeWindowBuffer(buffer);
struct AHardwareBuffer *hardwareBuffer =
angle::android::ANativeWindowBufferToAHardwareBuffer(windowBuffer);
VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties = {};
bufferFormatProperties.sType =
VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
bufferFormatProperties.pNext = nullptr;
VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {};
bufferProperties.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
bufferProperties.pNext = &bufferFormatProperties;
VkDevice device = renderer->getDevice();
VkResult result =
vkGetAndroidHardwareBufferPropertiesANDROID(device, hardwareBuffer, &bufferProperties);
if (result != VK_SUCCESS)
{
return egl::EglBadParameter() << "Failed to query AHardwareBuffer properties";
}
if (!HasFullTextureFormatSupport(renderer, bufferFormatProperties.format))
{
return egl::EglBadParameter()
<< "AHardwareBuffer format does not support enough features to use as a texture.";
}
return egl::NoError();
}
egl::Error HardwareBufferImageSiblingVkAndroid::initialize(const egl::Display *display)
{
DisplayVk *displayVk = vk::GetImpl(display);
return angle::ToEGL(initImpl(displayVk), displayVk, EGL_BAD_PARAMETER);
}
angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk)
{
RendererVk *renderer = displayVk->getRenderer();
struct ANativeWindowBuffer *windowBuffer =
angle::android::ClientBufferToANativeWindowBuffer(mBuffer);
int pixelFormat = 0;
angle::android::GetANativeWindowBufferProperties(windowBuffer, &mSize.width, &mSize.height,
&mSize.depth, &pixelFormat);
GLenum internalFormat = angle::android::NativePixelFormatToGLInternalFormat(pixelFormat);
mFormat = gl::Format(internalFormat);
struct AHardwareBuffer *hardwareBuffer =
angle::android::ANativeWindowBufferToAHardwareBuffer(windowBuffer);
VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties;
bufferFormatProperties.sType =
VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
bufferFormatProperties.pNext = nullptr;
VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {};
bufferProperties.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
bufferProperties.pNext = &bufferFormatProperties;
VkDevice device = renderer->getDevice();
ANGLE_VK_TRY(displayVk, vkGetAndroidHardwareBufferPropertiesANDROID(device, hardwareBuffer,
&bufferProperties));
const vk::Format &vkFormat = renderer->getFormat(internalFormat);
const angle::Format &textureFormat = vkFormat.textureFormat();
bool isDepthOrStencilFormat = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0;
const VkImageUsageFlags usage =
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT |
(textureFormat.redBits > 0 ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0) |
(isDepthOrStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0);
VkExternalFormatANDROID externalFormat = {};
externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
externalFormat.externalFormat = 0;
if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED)
{
externalFormat.externalFormat = bufferFormatProperties.externalFormat;
}
VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
externalMemoryImageCreateInfo.pNext = &externalFormat;
externalMemoryImageCreateInfo.handleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
mImage = new vk::ImageHelper();
ANGLE_TRY(mImage->initExternal(displayVk, gl::TextureType::_2D, mSize, vkFormat, 1, usage,
vk::ImageLayout::ExternalPreInitialized,
&externalMemoryImageCreateInfo, 1, 1));
VkImportAndroidHardwareBufferInfoANDROID importHardwareBufferInfo = {};
importHardwareBufferInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
importHardwareBufferInfo.buffer = hardwareBuffer;
VkMemoryDedicatedAllocateInfo dedicatedAllocInfo = {};
dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
dedicatedAllocInfo.pNext = &importHardwareBufferInfo;
dedicatedAllocInfo.image = mImage->getImage().getHandle();
dedicatedAllocInfo.buffer = VK_NULL_HANDLE;
VkMemoryRequirements externalMemoryRequirements = {};
externalMemoryRequirements.size = bufferProperties.allocationSize;
externalMemoryRequirements.alignment = 0;
externalMemoryRequirements.memoryTypeBits = bufferProperties.memoryTypeBits;
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(mImage->initExternalMemory(displayVk, renderer->getMemoryProperties(),
externalMemoryRequirements, &dedicatedAllocInfo,
VK_QUEUE_FAMILY_FOREIGN_EXT, flags));
constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
constexpr uint32_t kDepthStencilRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
mRenderable = renderer->hasTextureFormatFeatureBits(vkFormat.vkTextureFormat,
kColorRenderableRequiredBits) ||
renderer->hasTextureFormatFeatureBits(vkFormat.vkTextureFormat,
kDepthStencilRenderableRequiredBits);
constexpr uint32_t kTextureableRequiredBits =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
mTextureable =
renderer->hasTextureFormatFeatureBits(vkFormat.vkTextureFormat, kTextureableRequiredBits);
return angle::Result::Continue;
}
void HardwareBufferImageSiblingVkAndroid::onDestroy(const egl::Display *display)
{
DisplayVk *displayVk = vk::GetImpl(display);
RendererVk *renderer = displayVk->getRenderer();
if (mImage != nullptr)
{
mImage->releaseImage(renderer);
mImage->releaseStagingBuffer(renderer);
SafeDelete(mImage);
}
}
gl::Format HardwareBufferImageSiblingVkAndroid::getFormat() const
{
return mFormat;
}
bool HardwareBufferImageSiblingVkAndroid::isRenderable(const gl::Context *context) const
{
return mRenderable;
}
bool HardwareBufferImageSiblingVkAndroid::isTexturable(const gl::Context *context) const
{
return mTextureable;
}
gl::Extents HardwareBufferImageSiblingVkAndroid::getSize() const
{
return mSize;
}
size_t HardwareBufferImageSiblingVkAndroid::getSamples() const
{
return mSamples;
}
// ExternalImageSiblingVk interface
vk::ImageHelper *HardwareBufferImageSiblingVkAndroid::getImage() const
{
return mImage;
}
} // namespace rx
//
// Copyright 2019 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.
//
// HardwareBufferImageSiblingVkAndroid.h: Defines the HardwareBufferImageSiblingVkAndroid to wrap
// EGL images created from AHardwareBuffer objects
#ifndef LIBANGLE_RENDERER_VULKAN_ANDROID_HARDWAREBUFFERIMAGESIBLINGVKANDROID_H_
#define LIBANGLE_RENDERER_VULKAN_ANDROID_HARDWAREBUFFERIMAGESIBLINGVKANDROID_H_
#include "libANGLE/renderer/vulkan/ImageVk.h"
namespace rx
{
class HardwareBufferImageSiblingVkAndroid : public ExternalImageSiblingVk
{
public:
HardwareBufferImageSiblingVkAndroid(EGLClientBuffer buffer);
~HardwareBufferImageSiblingVkAndroid() override;
static egl::Error ValidateHardwareBuffer(RendererVk *renderer, EGLClientBuffer buffer);
egl::Error initialize(const egl::Display *display) override;
void onDestroy(const egl::Display *display) override;
// ExternalImageSiblingImpl interface
gl::Format getFormat() const override;
bool isRenderable(const gl::Context *context) const override;
bool isTexturable(const gl::Context *context) const override;
gl::Extents getSize() const override;
size_t getSamples() const override;
// ExternalImageSiblingVk interface
vk::ImageHelper *getImage() const override;
private:
angle::Result initImpl(DisplayVk *displayVk);
EGLClientBuffer mBuffer;
gl::Extents mSize;
gl::Format mFormat;
bool mRenderable;
bool mTextureable;
size_t mSamples;
vk::ImageHelper *mImage;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_ANDROID_HARDWAREBUFFERIMAGESIBLINGVKANDROID_H_
......@@ -65,17 +65,6 @@ void FillTextureFormatCaps(RendererVk *renderer, VkFormat format, gl::TextureCap
}
}
bool HasFullTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat)
{
constexpr uint32_t kBitsColor = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
return renderer->hasTextureFormatFeatureBits(vkFormat, kBitsColor) ||
renderer->hasTextureFormatFeatureBits(vkFormat, kBitsDepth);
}
bool HasFullBufferFormatSupport(RendererVk *renderer, VkFormat vkFormat)
{
return renderer->hasBufferFormatFeatureBits(vkFormat, VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
......@@ -203,6 +192,17 @@ void FormatTable::initialize(RendererVk *renderer,
}
} // namespace vk
bool HasFullTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat)
{
constexpr uint32_t kBitsColor = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
return renderer->hasTextureFormatFeatureBits(vkFormat, kBitsColor) ||
renderer->hasTextureFormatFeatureBits(vkFormat, kBitsDepth);
}
size_t GetVertexInputAlignment(const vk::Format &format)
{
const angle::Format &bufferFormat = format.bufferFormat();
......
......@@ -121,6 +121,9 @@ const VkFormatProperties &GetMandatoryFormatSupport(VkFormat vkFormat);
} // namespace vk
// Checks if a vkFormat supports all the features needed to use it as a GL texture format
bool HasFullTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat);
// Returns the alignment for a buffer to be used with the vertex input stage in Vulkan. This
// calculation is listed in the Vulkan spec at the end of the section 'Vertex Input Description'.
size_t GetVertexInputAlignment(const vk::Format &format);
......
......@@ -68,15 +68,15 @@ constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemory
},
},
{
ImageLayout::PreInitialized,
ImageLayout::ExternalPreInitialized,
{
VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
// Transition to: we don't expect to transition into PreInitialized.
0,
// Transition from: all writes must finish before barrier.
VK_ACCESS_HOST_WRITE_BIT,
VK_ACCESS_MEMORY_WRITE_BIT,
false,
},
},
......@@ -1068,8 +1068,8 @@ angle::Result BufferHelper::init(Context *context,
{
mSize = createInfo.size;
ANGLE_VK_TRY(context, mBuffer.init(context->getDevice(), createInfo));
return vk::AllocateBufferMemory(context, memoryPropertyFlags, &mMemoryPropertyFlags, &mBuffer,
&mDeviceMemory);
return vk::AllocateBufferMemory(context, memoryPropertyFlags, &mMemoryPropertyFlags, nullptr,
&mBuffer, &mDeviceMemory);
}
void BufferHelper::destroy(VkDevice device)
......@@ -1219,6 +1219,7 @@ ImageHelper::ImageHelper()
mFormat(nullptr),
mSamples(0),
mCurrentLayout(ImageLayout::Undefined),
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
mLayerCount(0),
mLevelCount(0),
mStagingBuffer(kStagingBufferFlags, kStagingBufferSize, true)
......@@ -1232,6 +1233,7 @@ ImageHelper::ImageHelper(ImageHelper &&other)
mFormat(other.mFormat),
mSamples(other.mSamples),
mCurrentLayout(other.mCurrentLayout),
mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex),
mLayerCount(other.mLayerCount),
mLevelCount(other.mLevelCount),
mStagingBuffer(std::move(other.mStagingBuffer)),
......@@ -1263,6 +1265,21 @@ angle::Result ImageHelper::init(Context *context,
uint32_t mipLevels,
uint32_t layerCount)
{
return initExternal(context, textureType, extents, format, samples, usage,
ImageLayout::Undefined, nullptr, mipLevels, layerCount);
}
angle::Result ImageHelper::initExternal(Context *context,
gl::TextureType textureType,
const gl::Extents &extents,
const Format &format,
GLint samples,
VkImageUsageFlags usage,
ImageLayout initialLayout,
const void *externalImageCreateInfo,
uint32_t mipLevels,
uint32_t layerCount)
{
ASSERT(!valid());
// Validate that the input layerCount is compatible with the texture type
......@@ -1279,6 +1296,7 @@ angle::Result ImageHelper::init(Context *context,
VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.pNext = externalImageCreateInfo;
imageInfo.flags = GetImageCreateFlags(textureType);
imageInfo.imageType = gl_vk::GetImageType(textureType);
imageInfo.format = format.vkTextureFormat;
......@@ -1293,9 +1311,9 @@ angle::Result ImageHelper::init(Context *context,
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.queueFamilyIndexCount = 0;
imageInfo.pQueueFamilyIndices = nullptr;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.initialLayout = kImageMemoryBarrierData[initialLayout].layout;
mCurrentLayout = ImageLayout::Undefined;
mCurrentLayout = initialLayout;
ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
......@@ -1329,7 +1347,23 @@ angle::Result ImageHelper::initMemory(Context *context,
VkMemoryPropertyFlags flags)
{
// TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
ANGLE_TRY(AllocateImageMemory(context, flags, &mImage, &mDeviceMemory));
ANGLE_TRY(AllocateImageMemory(context, flags, nullptr, &mImage, &mDeviceMemory));
mCurrentQueueFamilyIndex = context->getRenderer()->getQueueFamilyIndex();
return angle::Result::Continue;
}
angle::Result ImageHelper::initExternalMemory(Context *context,
const MemoryProperties &memoryProperties,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
uint32_t currentQueueFamilyIndex,
VkMemoryPropertyFlags flags)
{
// TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
ANGLE_TRY(AllocateImageMemoryWithRequirements(context, flags, memoryRequirements,
extraAllocationInfo, &mImage, &mDeviceMemory));
mCurrentQueueFamilyIndex = currentQueueFamilyIndex;
return angle::Result::Continue;
}
......@@ -1496,7 +1530,7 @@ VkImageLayout ImageHelper::getCurrentLayout() const
return kImageMemoryBarrierData[mCurrentLayout].layout;
}
bool ImageHelper::isLayoutChangeNecessary(ImageLayout newLayout)
bool ImageHelper::isLayoutChangeNecessary(ImageLayout newLayout) const
{
const ImageMemoryBarrierData &layoutData = kImageMemoryBarrierData[mCurrentLayout];
......@@ -1515,6 +1549,24 @@ void ImageHelper::changeLayout(VkImageAspectFlags aspectMask,
return;
}
forceChangeLayoutAndQueue(aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer);
}
void ImageHelper::changeLayoutAndQueue(VkImageAspectFlags aspectMask,
ImageLayout newLayout,
uint32_t newQueueFamilyIndex,
CommandBuffer *commandBuffer)
{
ASSERT(isQueueChangeNeccesary(newQueueFamilyIndex));
forceChangeLayoutAndQueue(aspectMask, newLayout, newQueueFamilyIndex, commandBuffer);
}
void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
ImageLayout newLayout,
uint32_t newQueueFamilyIndex,
CommandBuffer *commandBuffer)
{
const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
const ImageMemoryBarrierData &transitionTo = kImageMemoryBarrierData[newLayout];
......@@ -1524,8 +1576,8 @@ void ImageHelper::changeLayout(VkImageAspectFlags aspectMask,
imageMemoryBarrier.dstAccessMask = transitionTo.dstAccessMask;
imageMemoryBarrier.oldLayout = transitionFrom.layout;
imageMemoryBarrier.newLayout = transitionTo.layout;
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.srcQueueFamilyIndex = mCurrentQueueFamilyIndex;
imageMemoryBarrier.dstQueueFamilyIndex = newQueueFamilyIndex;
imageMemoryBarrier.image = mImage.getHandle();
// TODO(jmadill): Is this needed for mipped/layer images?
......@@ -1539,6 +1591,7 @@ void ImageHelper::changeLayout(VkImageAspectFlags aspectMask,
nullptr, 0, nullptr, 1, &imageMemoryBarrier);
mCurrentLayout = newLayout;
mCurrentQueueFamilyIndex = newQueueFamilyIndex;
}
void ImageHelper::clearColor(const VkClearColorValue &color,
......
......@@ -504,7 +504,7 @@ class BufferHelper final : public CommandGraphResource
enum class ImageLayout
{
Undefined = 0,
PreInitialized = 1,
ExternalPreInitialized = 1,
TransferSrc = 2,
TransferDst = 3,
ComputeShaderReadOnly = 4,
......@@ -535,9 +535,25 @@ class ImageHelper final : public CommandGraphResource
VkImageUsageFlags usage,
uint32_t mipLevels,
uint32_t layerCount);
angle::Result initExternal(Context *context,
gl::TextureType textureType,
const gl::Extents &extents,
const Format &format,
GLint samples,
VkImageUsageFlags usage,
ImageLayout initialLayout,
const void *externalImageCreateInfo,
uint32_t mipLevels,
uint32_t layerCount);
angle::Result initMemory(Context *context,
const MemoryProperties &memoryProperties,
VkMemoryPropertyFlags flags);
angle::Result initExternalMemory(Context *context,
const MemoryProperties &memoryProperties,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
uint32_t currentQueueFamilyIndex,
VkMemoryPropertyFlags flags);
angle::Result initLayerImageView(Context *context,
gl::TextureType textureType,
VkImageAspectFlags aspectMask,
......@@ -671,13 +687,28 @@ class ImageHelper final : public CommandGraphResource
// changeLayout automatically skips the layout change if it's unnecessary. This function can be
// used to prevent creating a command graph node and subsequently a command buffer for the sole
// purpose of performing a transition (which may then not be issued).
bool isLayoutChangeNecessary(ImageLayout newLayout);
bool isLayoutChangeNecessary(ImageLayout newLayout) const;
void changeLayout(VkImageAspectFlags aspectMask,
ImageLayout newLayout,
CommandBuffer *commandBuffer);
bool isQueueChangeNeccesary(uint32_t newQueueFamilyIndex) const
{
return mCurrentQueueFamilyIndex != newQueueFamilyIndex;
}
void changeLayoutAndQueue(VkImageAspectFlags aspectMask,
ImageLayout newLayout,
uint32_t newQueueFamilyIndex,
CommandBuffer *commandBuffer);
private:
void forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
ImageLayout newLayout,
uint32_t newQueueFamilyIndex,
CommandBuffer *commandBuffer);
struct SubresourceUpdate
{
SubresourceUpdate();
......@@ -729,6 +760,7 @@ class ImageHelper final : public CommandGraphResource
// Current state.
ImageLayout mCurrentLayout;
uint32_t mCurrentQueueFamilyIndex;
// Cached properties.
uint32_t mLayerCount;
......
......@@ -100,6 +100,7 @@ angle::Result FindAndAllocateCompatibleMemory(vk::Context *context,
VkMemoryPropertyFlags requestedMemoryPropertyFlags,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
vk::DeviceMemory *deviceMemoryOut)
{
uint32_t memoryTypeIndex = 0;
......@@ -109,6 +110,7 @@ angle::Result FindAndAllocateCompatibleMemory(vk::Context *context,
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.pNext = extraAllocationInfo;
allocInfo.memoryTypeIndex = memoryTypeIndex;
allocInfo.allocationSize = memoryRequirements.size;
......@@ -117,22 +119,39 @@ angle::Result FindAndAllocateCompatibleMemory(vk::Context *context,
}
template <typename T>
angle::Result AllocateAndBindBufferOrImageMemory(vk::Context *context,
VkMemoryPropertyFlags requestedMemoryPropertyFlags,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
T *bufferOrImage,
vk::DeviceMemory *deviceMemoryOut)
{
const vk::MemoryProperties &memoryProperties = context->getRenderer()->getMemoryProperties();
ANGLE_TRY(FindAndAllocateCompatibleMemory(
context, memoryProperties, requestedMemoryPropertyFlags, memoryPropertyFlagsOut,
memoryRequirements, extraAllocationInfo, deviceMemoryOut));
ANGLE_VK_TRY(context, bufferOrImage->bindMemory(context->getDevice(), *deviceMemoryOut));
return angle::Result::Continue;
}
template <typename T>
angle::Result AllocateBufferOrImageMemory(vk::Context *context,
VkMemoryPropertyFlags requestedMemoryPropertyFlags,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const void *extraAllocationInfo,
T *bufferOrImage,
vk::DeviceMemory *deviceMemoryOut)
{
const vk::MemoryProperties &memoryProperties = context->getRenderer()->getMemoryProperties();
// Call driver to determine memory requirements.
VkMemoryRequirements memoryRequirements;
bufferOrImage->getMemoryRequirements(context->getDevice(), &memoryRequirements);
ANGLE_TRY(FindAndAllocateCompatibleMemory(context, memoryProperties,
requestedMemoryPropertyFlags, memoryPropertyFlagsOut,
memoryRequirements, deviceMemoryOut));
ANGLE_VK_TRY(context, bufferOrImage->bindMemory(context->getDevice(), *deviceMemoryOut));
ANGLE_TRY(AllocateAndBindBufferOrImageMemory(
context, requestedMemoryPropertyFlags, memoryPropertyFlagsOut, memoryRequirements,
extraAllocationInfo, bufferOrImage, deviceMemoryOut));
return angle::Result::Continue;
}
......@@ -335,7 +354,7 @@ angle::Result StagingBuffer::init(Context *context, VkDeviceSize size, StagingUs
ANGLE_VK_TRY(context, mBuffer.init(context->getDevice(), createInfo));
VkMemoryPropertyFlags flagsOut = 0;
ANGLE_TRY(AllocateBufferMemory(context, flags, &flagsOut, &mBuffer, &mDeviceMemory));
ANGLE_TRY(AllocateBufferMemory(context, flags, &flagsOut, nullptr, &mBuffer, &mDeviceMemory));
mSize = static_cast<size_t>(size);
return angle::Result::Continue;
}
......@@ -349,21 +368,37 @@ void StagingBuffer::dumpResources(Serial serial, std::vector<vk::GarbageObject>
angle::Result AllocateBufferMemory(vk::Context *context,
VkMemoryPropertyFlags requestedMemoryPropertyFlags,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const void *extraAllocationInfo,
Buffer *buffer,
DeviceMemory *deviceMemoryOut)
{
return AllocateBufferOrImageMemory(context, requestedMemoryPropertyFlags,
memoryPropertyFlagsOut, buffer, deviceMemoryOut);
memoryPropertyFlagsOut, extraAllocationInfo, buffer,
deviceMemoryOut);
}
angle::Result AllocateImageMemory(vk::Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,
const void *extraAllocationInfo,
Image *image,
DeviceMemory *deviceMemoryOut)
{
VkMemoryPropertyFlags memoryPropertyFlagsOut = 0;
return AllocateBufferOrImageMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut, image,
deviceMemoryOut);
return AllocateBufferOrImageMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut,
extraAllocationInfo, image, deviceMemoryOut);
}
angle::Result AllocateImageMemoryWithRequirements(vk::Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
Image *image,
DeviceMemory *deviceMemoryOut)
{
VkMemoryPropertyFlags memoryPropertyFlagsOut = 0;
return AllocateAndBindBufferOrImageMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut,
memoryRequirements, extraAllocationInfo, image,
deviceMemoryOut);
}
angle::Result InitShaderAndSerial(Context *context,
......@@ -519,6 +554,17 @@ void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance)
}
#endif
#if defined(ANGLE_PLATFORM_ANDROID)
PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID =
nullptr;
PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID = nullptr;
void InitExternalMemoryHardwareBufferANDROIDFunctions(VkInstance instance)
{
GET_FUNC(vkGetAndroidHardwareBufferPropertiesANDROID);
GET_FUNC(vkGetMemoryAndroidHardwareBufferANDROID);
}
#endif
#undef GET_FUNC
namespace gl_vk
......
......@@ -259,13 +259,21 @@ class ObjectAndSerial final : angle::NonCopyable
angle::Result AllocateBufferMemory(vk::Context *context,
VkMemoryPropertyFlags requestedMemoryPropertyFlags,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const void *extraAllocationInfo,
Buffer *buffer,
DeviceMemory *deviceMemoryOut);
angle::Result AllocateImageMemory(vk::Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,
const void *extraAllocationInfo,
Image *image,
DeviceMemory *deviceMemoryOut);
angle::Result AllocateImageMemoryWithRequirements(vk::Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,
const VkMemoryRequirements &memoryRequirements,
const void *extraAllocationInfo,
Image *image,
DeviceMemory *deviceMemoryOut);
using ShaderAndSerial = ObjectAndSerial<ShaderModule>;
......@@ -401,6 +409,13 @@ extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA;
void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance);
#endif
#if defined(ANGLE_PLATFORM_ANDROID)
// VK_ANDROID_external_memory_android_hardware_buffer
extern PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID;
extern PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID;
void InitExternalMemoryHardwareBufferANDROIDFunctions(VkInstance instance);
#endif
namespace gl_vk
{
VkRect2D GetRect(const gl::Rectangle &source);
......
......@@ -84,6 +84,13 @@ if (is_win) {
angle_system_utils_sources += [ "src/common/system_utils_win.cpp" ]
}
if (is_android) {
angle_system_utils_sources += [
"src/common/android_util.cpp",
"src/common/android_util.h",
]
}
libangle_image_util_sources = [
"src/image_util/copyimage.cpp",
"src/image_util/copyimage.h",
......@@ -727,8 +734,6 @@ libangle_gl_ozone_sources = [
]
libangle_gl_egl_android_sources = [
"src/libANGLE/renderer/gl/egl/android/android_util.cpp",
"src/libANGLE/renderer/gl/egl/android/android_util.h",
"src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp",
"src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h",
"src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.cpp",
......@@ -817,6 +822,8 @@ libangle_vulkan_sources = [
libangle_vulkan_android_sources = [
"src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.cpp",
"src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.h",
"src/libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.cpp",
"src/libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.h",
"src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.cpp",
"src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.h",
]
......
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