Commit f02a767d by Michael Spang Committed by Commit Bot

Vulkan: Implement glTexStorageMem2DEXT

This implements support for creating textures that alias vulkan images allocated inside external memory. Bug: angleproject:3289 Change-Id: Iad071f353a217793102ae737647c7cd572f7b0ad Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1552029Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Michael Spang <spang@chromium.org>
parent 422c94bd
......@@ -7151,7 +7151,12 @@ void Context::texStorageMem2D(TextureType target,
GLuint memory,
GLuint64 offset)
{
UNIMPLEMENTED();
MemoryObject *memoryObject = getMemoryObject(memory);
ASSERT(memoryObject);
Extents size(width, height, 1);
Texture *texture = getTextureByType(target);
ANGLE_CONTEXT_TRY(texture->setStorageExternalMemory(this, target, levels, internalFormat, size,
memoryObject, offset));
}
void Context::texStorageMem2DMultisample(TextureType target,
......
......@@ -32,6 +32,8 @@ class MemoryObject final : public RefCountObject
void onDestroy(const Context *context) override;
rx::MemoryObjectImpl *getImplementation() const { return mImplementation.get(); }
angle::Result importFd(Context *context, GLuint64 size, HandleType handleType, GLint fd);
private:
......
......@@ -1307,6 +1307,41 @@ angle::Result Texture::setStorageMultisample(Context *context,
return angle::Result::Continue;
}
angle::Result Texture::setStorageExternalMemory(Context *context,
TextureType type,
GLsizei levels,
GLenum internalFormat,
const Extents &size,
MemoryObject *memoryObject,
GLuint64 offset)
{
ASSERT(type == mState.mType);
// Release from previous calls to eglBindTexImage, to avoid calling the Impl after
ANGLE_TRY(releaseTexImageInternal(context));
ANGLE_TRY(orphanImages(context));
ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
memoryObject, offset));
mState.mImmutableFormat = true;
mState.mImmutableLevels = static_cast<GLuint>(levels);
mState.clearImageDescs();
mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
InitState::MayNeedInit);
// Changing the texture to immutable can trigger a change in the base and max levels:
// GLES 3.0.4 section 3.8.10 pg 158:
// "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
// clamped to the range[levelbase;levels].
mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
signalDirtyStorage(context, InitState::Initialized);
return angle::Result::Continue;
}
angle::Result Texture::generateMipmap(Context *context)
{
// Release from previous calls to eglBindTexImage, to avoid calling the Impl after
......
......@@ -43,6 +43,7 @@ class TextureGL;
namespace gl
{
class Framebuffer;
class MemoryObject;
class Sampler;
class State;
class Texture;
......@@ -389,6 +390,14 @@ class Texture final : public RefCountObject,
const Extents &size,
bool fixedSampleLocations);
angle::Result setStorageExternalMemory(Context *context,
TextureType type,
GLsizei levels,
GLenum internalFormat,
const Extents &size,
MemoryObject *memoryObject,
GLuint64 offset);
angle::Result setEGLImageTarget(Context *context, TextureType type, egl::Image *imageTarget);
angle::Result generateMipmap(Context *context);
......
......@@ -32,6 +32,7 @@ struct Extents;
struct Offset;
struct Rectangle;
class Framebuffer;
class MemoryObject;
struct PixelUnpackState;
class TextureState;
} // namespace gl
......@@ -147,6 +148,14 @@ class TextureImpl : public FramebufferAttachmentObjectImpl, public angle::Subjec
const gl::Extents &size,
bool fixedSampleLocations) = 0;
virtual angle::Result setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset) = 0;
virtual angle::Result setEGLImageTarget(const gl::Context *context,
gl::TextureType type,
egl::Image *image) = 0;
......
......@@ -92,6 +92,14 @@ class MockTextureImpl : public TextureImpl
MOCK_METHOD5(
setStorage,
angle::Result(const gl::Context *, gl::TextureType, size_t, GLenum, const gl::Extents &));
MOCK_METHOD7(setStorageExternalMemory,
angle::Result(const gl::Context *,
gl::TextureType,
size_t,
GLenum,
const gl::Extents &,
gl::MemoryObject *,
GLuint64));
MOCK_METHOD4(setImageExternal,
angle::Result(const gl::Context *,
gl::TextureType,
......
......@@ -184,6 +184,18 @@ angle::Result TextureD3D::setStorageMultisample(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result TextureD3D::setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset)
{
ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
return angle::Result::Continue;
}
bool TextureD3D::shouldUseSetData(const ImageD3D *image) const
{
if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
......
......@@ -66,6 +66,14 @@ class TextureD3D : public TextureImpl
const gl::Extents &size,
bool fixedSampleLocations) override;
angle::Result setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset) override;
bool isImmutable() const { return mImmutable; }
virtual angle::Result getRenderTarget(const gl::Context *context,
......
......@@ -1048,6 +1048,18 @@ angle::Result TextureGL::setStorageMultisample(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result TextureGL::setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset)
{
ANGLE_GL_UNREACHABLE(GetImplAs<ContextGL>(context));
return angle::Result::Stop;
}
angle::Result TextureGL::setImageExternal(const gl::Context *context,
gl::TextureType type,
egl::Stream *stream,
......
......@@ -147,6 +147,14 @@ class TextureGL : public TextureImpl
const gl::Extents &size,
bool fixedSampleLocations) override;
angle::Result setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset) override;
angle::Result setImageExternal(const gl::Context *context,
gl::TextureType type,
egl::Stream *stream,
......
......@@ -125,6 +125,17 @@ angle::Result TextureNULL::setStorage(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result TextureNULL::setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset)
{
return angle::Result::Continue;
}
angle::Result TextureNULL::setEGLImageTarget(const gl::Context *context,
gl::TextureType type,
egl::Image *image)
......
......@@ -92,6 +92,14 @@ class TextureNULL : public TextureImpl
GLenum internalFormat,
const gl::Extents &size) override;
angle::Result setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset) override;
angle::Result setEGLImageTarget(const gl::Context *context,
gl::TextureType type,
egl::Image *image) override;
......
......@@ -74,4 +74,57 @@ angle::Result MemoryObjectVk::importOpaqueFd(gl::Context *context, GLuint64 size
return angle::Result::Continue;
}
angle::Result MemoryObjectVk::createImage(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
GLuint64 offset,
vk::ImageHelper *image)
{
ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer();
const vk::Format &vkFormat = renderer->getFormat(internalFormat);
static constexpr VkImageUsageFlags kAllImageUsageFlags =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
// All supported usage flags must be specified.
// See EXT_external_objects issue 13.
// TODO(spang): Query supported usage for format via vkGetPhysicalDeviceFormatProperties.
// http://anglebug.com/3389
VkImageUsageFlags imageUsageFlags = kAllImageUsageFlags;
VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
ANGLE_TRY(image->initExternal(contextVk, type, size, vkFormat, 1, imageUsageFlags,
vk::ImageLayout::ExternalPreInitialized,
&externalMemoryImageCreateInfo, levels, 1));
VkMemoryRequirements externalMemoryRequirements;
image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
ASSERT(mFd != -1);
VkImportMemoryFdInfoKHR importMemoryFdInfo = {};
importMemoryFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
importMemoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
importMemoryFdInfo.fd = dup(mFd);
// TODO(jmadill, spang): Memory sub-allocation. http://anglebug.com/2162
ASSERT(offset == 0);
ASSERT(externalMemoryRequirements.size == mSize);
VkMemoryPropertyFlags flags = 0;
ANGLE_TRY(image->initExternalMemory(contextVk, renderer->getMemoryProperties(),
externalMemoryRequirements, &importMemoryFdInfo,
VK_QUEUE_FAMILY_EXTERNAL, flags));
return angle::Result::Continue;
}
} // namespace rx
......@@ -28,6 +28,14 @@ class MemoryObjectVk : public MemoryObjectImpl
gl::HandleType handleType,
GLint fd) override;
angle::Result createImage(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
GLuint64 offset,
vk::ImageHelper *image);
private:
angle::Result importOpaqueFd(gl::Context *context, GLuint64 size, GLint fd);
......
......@@ -14,10 +14,12 @@
#include "libANGLE/Config.h"
#include "libANGLE/Context.h"
#include "libANGLE/Image.h"
#include "libANGLE/MemoryObject.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/MemoryObjectVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/SurfaceVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
......@@ -778,6 +780,44 @@ angle::Result TextureVk::setStorage(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result TextureVk::setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset)
{
ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer();
MemoryObjectVk *memoryObjectVk = vk::GetImpl(memoryObject);
releaseAndDeleteImage(context, renderer);
const vk::Format &format = renderer->getFormat(internalFormat);
setImageHelper(renderer, new vk::ImageHelper(), mState.getType(), format, 0, 0, true);
ANGLE_TRY(
memoryObjectVk->createImage(context, type, levels, internalFormat, size, offset, mImage));
ANGLE_TRY(initImageViews(contextVk, format, levels));
// TODO(spang): This needs to be reworked when semaphores are added.
// http://anglebug.com/3289
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;
}
angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
gl::TextureType type,
egl::Image *image)
......
......@@ -96,6 +96,14 @@ class TextureVk : public TextureImpl
GLenum internalFormat,
const gl::Extents &size) override;
angle::Result setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset) override;
angle::Result setEGLImageTarget(const gl::Context *context,
gl::TextureType type,
egl::Image *image) override;
......
......@@ -25,6 +25,7 @@
PROC(Buffer) \
PROC(Context) \
PROC(Framebuffer) \
PROC(MemoryObject) \
PROC(Program) \
PROC(Texture) \
PROC(VertexArray)
......
......@@ -3157,8 +3157,15 @@ bool ValidateTexStorageMem2DEXT(Context *context,
return false;
}
UNIMPLEMENTED();
return false;
if (context->getClientMajorVersion() < 3)
{
return ValidateES2TexStorageParameters(context, target, levels, internalFormat, width,
height);
}
ASSERT(context->getClientMajorVersion() >= 3);
return ValidateES3TexStorage2DParameters(context, target, levels, internalFormat, width, height,
1);
}
bool ValidateTexStorageMem3DEXT(Context *context,
......
......@@ -55,7 +55,7 @@ class VulkanExternalImageTest : public ANGLETest
};
// glImportMemoryFdEXT must be able to import a valid opaque fd.
TEST_P(VulkanExternalImageTest, ShouldImportVulkanExternalOpaqueFd)
TEST_P(VulkanExternalImageTest, ShouldImportOpaqueFd)
{
ANGLE_SKIP_TEST_IF(!ensureExtensionEnabled("GL_EXT_memory_object_fd"));
......@@ -90,6 +90,56 @@ TEST_P(VulkanExternalImageTest, ShouldImportVulkanExternalOpaqueFd)
vkFreeMemory(helper.getDevice(), deviceMemory, nullptr);
}
// Test creating and clearing a simple RGBA8 texture in a opaque fd.
TEST_P(VulkanExternalImageTest, ShouldClearOpaqueFdRGBA8)
{
ANGLE_SKIP_TEST_IF(!ensureExtensionEnabled("GL_EXT_memory_object_fd"));
VulkanExternalHelper helper;
helper.initialize();
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
ANGLE_SKIP_TEST_IF(
!helper.canCreateImageOpaqueFd(format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL));
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
VkDeviceSize deviceMemorySize = 0;
VkExtent3D extent = {1, 1, 1};
VkResult result =
helper.createImage2DOpaqueFd(format, extent, &image, &deviceMemory, &deviceMemorySize);
EXPECT_EQ(result, VK_SUCCESS);
int fd = kInvalidFd;
result = helper.exportMemoryOpaqueFd(deviceMemory, &fd);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_NE(fd, kInvalidFd);
{
GLMemoryObject memoryObject;
glImportMemoryFdEXT(memoryObject, deviceMemorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_NEAR(0, 0, 128, 128, 128, 128, 1.0);
}
EXPECT_GL_NO_ERROR();
vkDestroyImage(helper.getDevice(), image, nullptr);
vkFreeMemory(helper.getDevice(), deviceMemory, nullptr);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(VulkanExternalImageTest,
......
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