Hash :
cb16fb5f
Author :
Date :
2019-08-29T16:53:55
Vulkan: Support texture base and max levels The Vulkan backend uses a vkImage that matches the number of effective levels in the GL texture. This is due to the fact that GL textures can have really strange layouts that only make sense when base level and max level are applied. For instance, take the following layout with disjoint mip levels: Level 0: 4x4 RGBA Level 1: 2x2 RGBA Level 2: 10x10 RGB If base level is set to zero and max level is set to 1, the image is still considered mip-complete: Level 0: 4x4 RGBA ==> Base Level 0 ==> Level 0: 4x4 RGBA Level 1: 2x2 RGBA ==> Max Level 1 ==> Level 1: 2x2 RGBA Level 2: 10x10 RGB If base and max level are then both set to 2, the texture is still considered complete, but of a different size and format: Level 0: 4x4 RGBA Level 1: 2x2 RGBA Level 2: 10x10 RGB ==> Base/Max Level 2 ==> Level 2: 10x10 RGB When the base or max level is changed, we must recreate the vkImage to match the new level count. To support that, we: - Stage updates from the current image to the new image - Only stage updates if there aren't already staged updates for a level - Free the current image and so it can be recreated at the next draw This CL does the following: - Refactors TextureVk::copyImageDataToBuffer to support staging updates without flush - Adds TextureVk::copyImageDataToBufferAndGetData to support previous use model - Adds TextureVk::changeLevels, triggered during syncState, which stages updates and releases the current image. - Updates ImageHelper::flushStagedUpdates to understand base/max levels - Updates TextureVk::ensureImageInitialized and TextureVk::generateMipmap to account for base/max level - Tracks base and max levels in ImageHelper - Adds ImageHelper::stageSubresourceUpdateFromBuffer to support this use case - Adds ImageHelper::isUpdateStaged to determine if changeLevels should propagate data - Makes gl::TextureTypeToTarget available for use outside of ImageIndex - Enables several deqp and end2end tests Bug: angleproject:3148 Test: dEQP-GLES3.functional.texture.mipmap.*base_level* Test: dEQP-GLES3.functional.texture.mipmap.*max_level* Change-Id: I14ca071c9c62eb310dfed7ef9290dc65fc3ff696 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1776933 Reviewed-by: Courtney Goeltzenleuchter <courtneygo@google.com> Commit-Queue: Cody Northrop <cnorthrop@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
// 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.
//
// MemoryObjectVk.cpp: Defines the class interface for MemoryObjectVk, implementing
// MemoryObjectImpl.
#include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
#include <vulkan/vulkan.h>
#include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#if !defined(ANGLE_PLATFORM_WINDOWS)
# include <unistd.h>
#else
# include <io.h>
#endif
namespace rx
{
namespace
{
constexpr int kInvalidFd = -1;
#if defined(ANGLE_PLATFORM_WINDOWS)
int close(int fd)
{
return _close(fd);
}
#endif
} // namespace
MemoryObjectVk::MemoryObjectVk() : mSize(0), mFd(kInvalidFd) {}
MemoryObjectVk::~MemoryObjectVk() = default;
void MemoryObjectVk::onDestroy(const gl::Context *context)
{
if (mFd != kInvalidFd)
{
close(mFd);
mFd = kInvalidFd;
}
}
angle::Result MemoryObjectVk::importFd(gl::Context *context,
GLuint64 size,
gl::HandleType handleType,
GLint fd)
{
switch (handleType)
{
case gl::HandleType::OpaqueFd:
return importOpaqueFd(context, size, fd);
default:
UNREACHABLE();
return angle::Result::Stop;
}
}
angle::Result MemoryObjectVk::importOpaqueFd(gl::Context *context, GLuint64 size, GLint fd)
{
ASSERT(mFd == kInvalidFd);
mFd = fd;
mSize = 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);
// All supported usage flags must be specified.
// See EXT_external_objects issue 13.
VkImageUsageFlags imageUsageFlags =
vk::GetMaximalImageUsageFlags(renderer, vkFormat.vkImageFormat);
VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
VkExtent3D vkExtents;
uint32_t layerCount;
gl_vk::GetExtentsAndLayerCount(type, size, &vkExtents, &layerCount);
ANGLE_TRY(image->initExternal(
contextVk, type, vkExtents, vkFormat, 1, imageUsageFlags,
vk::ImageLayout::ExternalPreInitialized, &externalMemoryImageCreateInfo, 0,
static_cast<uint32_t>(levels) - 1, static_cast<uint32_t>(levels), layerCount));
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