Commit b5ba549a by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Shader path for texture copy when image is not initialized

This change implements staging image/texture copies when the destination image is not yet fully initialized. With this change, CPU readback for glCopyTex[Sub]Image2D and glCopy[Sub]TextureCHROMIUM should happen only if the texture formats don't allow a fragment-shader based copy. Bug: angleproject:2958 Change-Id: I04087e14ea8fb6fbc731598c5493e44651c22c01 Reviewed-on: https://chromium-review.googlesource.com/c/1393909 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 73397e8e
......@@ -205,7 +205,7 @@ void RecordableGraphResource::addReadDependency(RecordableGraphResource *reading
CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
ASSERT(readingNode);
if (hasChildlessWritingNode())
if (mCurrentWritingNode)
{
// Ensure 'readingNode' happens after the current writing node.
CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
......
......@@ -70,7 +70,7 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
(isDepthOrStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0);
gl::Extents extents(static_cast<int>(width), static_cast<int>(height), 1);
ANGLE_TRY(mImage.init(contextVk, gl::TextureType::_2D, extents, vkFormat, 1, usage, 1));
ANGLE_TRY(mImage.init(contextVk, gl::TextureType::_2D, extents, vkFormat, 1, usage, 1, 1));
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(mImage.initMemory(contextVk, renderer->getMemoryProperties(), flags));
......
......@@ -93,7 +93,7 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display
: kSurfaceVKColorImageUsageFlags;
gl::Extents extents(static_cast<int>(width), static_cast<int>(height), 1);
ANGLE_TRY(image.init(displayVk, gl::TextureType::_2D, extents, vkFormat, 1, usage, 1));
ANGLE_TRY(image.init(displayVk, gl::TextureType::_2D, extents, vkFormat, 1, usage, 1, 1));
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(image.initMemory(displayVk, renderer->getMemoryProperties(), flags));
......@@ -513,7 +513,7 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
const VkImageUsageFlags dsUsage = kSurfaceVKDepthStencilImageUsageFlags;
ANGLE_TRY(mDepthStencilImage.init(displayVk, gl::TextureType::_2D, extents, dsFormat, 1,
dsUsage, 1));
dsUsage, 1, 1));
ANGLE_TRY(mDepthStencilImage.initMemory(displayVk, renderer->getMemoryProperties(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
......
......@@ -26,7 +26,7 @@ class PixelBuffer final : angle::NonCopyable
void release(RendererVk *renderer);
void removeStagedUpdates(const gl::ImageIndex &index);
void removeStagedUpdates(RendererVk *renderer, const gl::ImageIndex &index);
angle::Result stageSubresourceUpdate(ContextVk *contextVk,
const gl::ImageIndex &index,
......@@ -52,6 +52,11 @@ class PixelBuffer final : angle::NonCopyable
const gl::InternalFormat &formatInfo,
FramebufferVk *framebufferVk);
void stageSubresourceUpdateFromImage(vk::ImageHelper *image,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::Extents &extents);
// This will use the underlying dynamic buffer to allocate some memory to be used as a src or
// dst.
angle::Result allocate(ContextVk *contextVk,
......@@ -73,10 +78,40 @@ class PixelBuffer final : angle::NonCopyable
{
SubresourceUpdate();
SubresourceUpdate(VkBuffer bufferHandle, const VkBufferImageCopy &copyRegion);
SubresourceUpdate(vk::ImageHelper *image, const VkImageCopy &copyRegion);
SubresourceUpdate(const SubresourceUpdate &other);
VkBuffer bufferHandle;
VkBufferImageCopy copyRegion;
void release(RendererVk *renderer);
const VkImageSubresourceLayers &dstSubresource() const
{
return updateSource == UpdateSource::Buffer ? buffer.copyRegion.imageSubresource
: image.copyRegion.dstSubresource;
}
bool isUpdateToLayerLevel(uint32_t layerIndex, uint32_t levelIndex) const;
enum class UpdateSource
{
Buffer,
Image,
};
struct BufferUpdate
{
VkBuffer bufferHandle;
VkBufferImageCopy copyRegion;
};
struct ImageUpdate
{
vk::ImageHelper *image;
VkImageCopy copyRegion;
};
UpdateSource updateSource;
union
{
BufferUpdate buffer;
ImageUpdate image;
};
};
vk::DynamicBuffer mStagingBuffer;
......@@ -258,6 +293,7 @@ class TextureVk : public TextureImpl
angle::Result copySubImageImplWithDraw(ContextVk *contextVk,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const vk::Format &destFormat,
size_t sourceLevel,
const gl::Rectangle &sourceArea,
bool isSrcFlipY,
......
......@@ -716,12 +716,16 @@ angle::Result UtilsVk::copyImage(vk::Context *context,
renderArea.height = params.srcExtents[1];
// Change source layout outside render pass
vk::CommandBuffer *srcLayoutChange;
ANGLE_TRY(src->recordCommands(context, &srcLayoutChange));
if (src->getCurrentLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
vk::CommandBuffer *srcLayoutChange;
ANGLE_TRY(src->recordCommands(context, &srcLayoutChange));
src->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, srcLayoutChange);
src->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, srcLayoutChange);
}
// Change destination layout outside render pass as well
vk::CommandBuffer *destLayoutChange;
......
......@@ -28,22 +28,6 @@ constexpr int kLineLoopDynamicBufferMinSize = 1024 * 1024;
// This is an arbitrary max. We can change this later if necessary.
constexpr uint32_t kDefaultDescriptorPoolMaxSets = 2048;
VkImageUsageFlags GetStagingImageUsageFlags(StagingUsage usage)
{
switch (usage)
{
case StagingUsage::Read:
return VK_IMAGE_USAGE_TRANSFER_DST_BIT;
case StagingUsage::Write:
return VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
case StagingUsage::Both:
return (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
default:
UNREACHABLE();
return 0;
}
}
// Gets access flags based on layout.
VkAccessFlags GetSrcLayoutAccessFlags(VkImageLayout layout)
{
......@@ -1119,14 +1103,21 @@ angle::Result ImageHelper::init(Context *context,
const Format &format,
GLint samples,
VkImageUsageFlags usage,
uint32_t mipLevels)
uint32_t mipLevels,
uint32_t layerCount)
{
ASSERT(!valid());
// Validate that the input layerCount is compatible with the texture type
ASSERT(textureType != gl::TextureType::_3D || layerCount == 1);
ASSERT(textureType != gl::TextureType::External || layerCount == 1);
ASSERT(textureType != gl::TextureType::Rectangle || layerCount == 1);
ASSERT(textureType != gl::TextureType::CubeMap || layerCount == gl::kCubeFaceCount);
mExtents = extents;
mFormat = &format;
mSamples = samples;
mLayerCount = GetImageLayerCount(textureType);
mLayerCount = layerCount;
mLevelCount = mipLevels;
VkImageCreateInfo imageInfo = {};
......@@ -1251,22 +1242,20 @@ void ImageHelper::init2DWeakReference(VkImage handle,
angle::Result ImageHelper::init2DStaging(Context *context,
const MemoryProperties &memoryProperties,
const Format &format,
const gl::Extents &extents,
StagingUsage usage)
const Format &format,
VkImageUsageFlags usage,
uint32_t layerCount)
{
ASSERT(!valid());
mExtents = extents;
mFormat = &format;
mSamples = 1;
mLayerCount = 1;
mLayerCount = layerCount;
mLevelCount = 1;
// Use Preinitialized for writable staging images - in these cases we want to map the memory
// before we do a copy. For readback images, use an undefined layout.
mCurrentLayout =
usage == StagingUsage::Read ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_PREINITIALIZED;
mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
......@@ -1277,10 +1266,10 @@ angle::Result ImageHelper::init2DStaging(Context *context,
imageInfo.extent.height = static_cast<uint32_t>(extents.height);
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.arrayLayers = mLayerCount;
imageInfo.samples = gl_vk::GetSamples(mSamples);
imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
imageInfo.usage = GetStagingImageUsageFlags(usage);
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.usage = usage;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.queueFamilyIndexCount = 0;
imageInfo.pQueueFamilyIndices = nullptr;
......@@ -1288,13 +1277,8 @@ angle::Result ImageHelper::init2DStaging(Context *context,
ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
// Allocate and bind host visible and coherent Image memory.
// TODO(ynovikov): better approach would be to request just visible memory,
// and call vkInvalidateMappedMemoryRanges if the allocated memory is not coherent.
// This would solve potential issues of:
// 1) not having (enough) coherent memory and 2) coherent memory being slower
VkMemoryPropertyFlags memoryPropertyFlags =
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
// Allocate and bind device-local memory.
VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(initMemory(context, memoryProperties, memoryPropertyFlags));
return angle::Result::Continue;
......
......@@ -475,7 +475,8 @@ class ImageHelper final : public RecordableGraphResource
const Format &format,
GLint samples,
VkImageUsageFlags usage,
uint32_t mipLevels);
uint32_t mipLevels,
uint32_t layerCount);
angle::Result initMemory(Context *context,
const MemoryProperties &memoryProperties,
VkMemoryPropertyFlags flags);
......@@ -494,11 +495,16 @@ class ImageHelper final : public RecordableGraphResource
const gl::SwizzleState &swizzleMap,
ImageView *imageViewOut,
uint32_t levelCount);
// Create a 2D[Array] for staging purposes. Used by:
//
// - TextureVk::copySubImageImplWithDraw
//
angle::Result init2DStaging(Context *context,
const MemoryProperties &memoryProperties,
const Format &format,
const gl::Extents &extent,
StagingUsage usage);
const Format &format,
VkImageUsageFlags usage,
uint32_t layerCount);
void release(RendererVk *renderer);
......
......@@ -138,18 +138,6 @@ angle::Result AllocateBufferOrImageMemory(vk::Context *context,
return angle::Result::Continue;
}
uint32_t GetImageLayerCount(gl::TextureType textureType)
{
if (textureType == gl::TextureType::CubeMap)
{
return gl::kCubeFaceCount;
}
else
{
return 1;
}
}
const char *g_VkLoaderLayersPathEnv = "VK_LAYER_PATH";
const char *g_VkICDPathEnv = "VK_ICD_FILENAMES";
......@@ -1484,9 +1472,13 @@ VkImageType GetImageType(gl::TextureType textureType)
switch (textureType)
{
case gl::TextureType::_2D:
return VK_IMAGE_TYPE_2D;
case gl::TextureType::_2DArray:
case gl::TextureType::_2DMultisample:
case gl::TextureType::_2DMultisampleArray:
case gl::TextureType::CubeMap:
return VK_IMAGE_TYPE_2D;
case gl::TextureType::_3D:
return VK_IMAGE_TYPE_3D;
default:
// We will need to implement all the texture types for ES3+.
UNIMPLEMENTED();
......@@ -1499,7 +1491,13 @@ VkImageViewType GetImageViewType(gl::TextureType textureType)
switch (textureType)
{
case gl::TextureType::_2D:
case gl::TextureType::_2DMultisample:
return VK_IMAGE_VIEW_TYPE_2D;
case gl::TextureType::_2DArray:
case gl::TextureType::_2DMultisampleArray:
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
case gl::TextureType::_3D:
return VK_IMAGE_VIEW_TYPE_3D;
case gl::TextureType::CubeMap:
return VK_IMAGE_VIEW_TYPE_CUBE;
default:
......
......@@ -77,8 +77,6 @@ bool GetAvailableValidationLayers(const std::vector<VkLayerProperties> &layerPro
const char *const **enabledLayerNames,
uint32_t *enabledLayerCount);
uint32_t GetImageLayerCount(gl::TextureType textureType);
extern const char *g_VkLoaderLayersPathEnv;
extern const char *g_VkICDPathEnv;
......
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