Vulkan: Support Texture redefinition.

Because initializing the texture can queue a copy from a staging
vk::Image, we must ensure we're not in a render pass. To make this
easier we move the current render pass tracking into the RendererVk
from the FramebufferVk class. (Note: in the future we will have
deferred command submission and this will become unnecessary.)

BUG=angleproject:2200

Change-Id: Ide8d4d70b50efbd79bbfa7006ad75cbc57cdf4c7
Reviewed-on: https://chromium-review.googlesource.com/741549
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index d961981..0b15df5 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -49,11 +49,25 @@
                               const gl::PixelUnpackState &unpack,
                               const uint8_t *pixels)
 {
+    ContextVk *contextVk = GetImplAs<ContextVk>(context);
+    RendererVk *renderer = contextVk->getRenderer();
+
     // TODO(jmadill): support multi-level textures.
     ASSERT(level == 0);
 
-    // TODO(jmadill): support texture re-definition.
-    ASSERT(!mImage.valid());
+    if (mImage.valid())
+    {
+        const gl::ImageDesc &desc = mState.getImageDesc(target, level);
+
+        // TODO(jmadill): Consider comparing stored vk::Format.
+        if (desc.size != size ||
+            !gl::Format::SameSized(desc.format, gl::Format(internalFormat, type)))
+        {
+            renderer->releaseResource(*this, &mImage);
+            renderer->releaseResource(*this, &mDeviceMemory);
+            renderer->releaseResource(*this, &mImageView);
+        }
+    }
 
     // TODO(jmadill): support other types of textures.
     ASSERT(target == GL_TEXTURE_2D);
@@ -62,93 +76,99 @@
     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
     const vk::Format &vkFormat           = vk::Format::Get(formatInfo.sizedInternalFormat);
 
-    VkImageCreateInfo imageInfo;
-    imageInfo.sType         = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
-    imageInfo.pNext         = nullptr;
-    imageInfo.flags         = 0;
-    imageInfo.imageType     = VK_IMAGE_TYPE_2D;
-    imageInfo.format        = vkFormat.native;
-    imageInfo.extent.width  = size.width;
-    imageInfo.extent.height = size.height;
-    imageInfo.extent.depth  = size.depth;
-    imageInfo.mipLevels     = 1;
-    imageInfo.arrayLayers   = 1;
-    imageInfo.samples       = VK_SAMPLE_COUNT_1_BIT;
-    imageInfo.tiling        = VK_IMAGE_TILING_OPTIMAL;
+    VkDevice device = contextVk->getDevice();
 
-    // TODO(jmadill): Are all these image transfer bits necessary?
-    imageInfo.usage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
-                       VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
-    imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
-    imageInfo.queueFamilyIndexCount = 0;
-    imageInfo.pQueueFamilyIndices   = nullptr;
-    imageInfo.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
+    if (!mImage.valid())
+    {
+        ASSERT(!mDeviceMemory.valid() && !mImageView.valid());
 
-    ContextVk *contextVk = GetImplAs<ContextVk>(context);
-    VkDevice device      = contextVk->getDevice();
-    ANGLE_TRY(mImage.init(device, imageInfo));
+        VkImageCreateInfo imageInfo;
+        imageInfo.sType         = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+        imageInfo.pNext         = nullptr;
+        imageInfo.flags         = 0;
+        imageInfo.imageType     = VK_IMAGE_TYPE_2D;
+        imageInfo.format        = vkFormat.native;
+        imageInfo.extent.width  = size.width;
+        imageInfo.extent.height = size.height;
+        imageInfo.extent.depth  = size.depth;
+        imageInfo.mipLevels     = 1;
+        imageInfo.arrayLayers   = 1;
+        imageInfo.samples       = VK_SAMPLE_COUNT_1_BIT;
+        imageInfo.tiling        = VK_IMAGE_TILING_OPTIMAL;
 
-    // Allocate the device memory for the image.
-    // TODO(jmadill): Use more intelligent device memory allocation.
-    VkMemoryRequirements memoryRequirements;
-    mImage.getMemoryRequirements(device, &memoryRequirements);
+        // TODO(jmadill): Are all these image transfer bits necessary?
+        imageInfo.usage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+                           VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
+        imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
+        imageInfo.queueFamilyIndexCount = 0;
+        imageInfo.pQueueFamilyIndices   = nullptr;
+        imageInfo.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
 
-    RendererVk *renderer = contextVk->getRenderer();
+        ANGLE_TRY(mImage.init(device, imageInfo));
 
-    uint32_t memoryIndex = renderer->getMemoryProperties().findCompatibleMemoryIndex(
-        memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+        // Allocate the device memory for the image.
+        // TODO(jmadill): Use more intelligent device memory allocation.
+        VkMemoryRequirements memoryRequirements;
+        mImage.getMemoryRequirements(device, &memoryRequirements);
 
-    VkMemoryAllocateInfo allocateInfo;
-    allocateInfo.sType           = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
-    allocateInfo.pNext           = nullptr;
-    allocateInfo.allocationSize  = memoryRequirements.size;
-    allocateInfo.memoryTypeIndex = memoryIndex;
+        uint32_t memoryIndex = renderer->getMemoryProperties().findCompatibleMemoryIndex(
+            memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 
-    ANGLE_TRY(mDeviceMemory.allocate(device, allocateInfo));
-    ANGLE_TRY(mImage.bindMemory(device, mDeviceMemory));
+        VkMemoryAllocateInfo allocateInfo;
+        allocateInfo.sType           = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+        allocateInfo.pNext           = nullptr;
+        allocateInfo.allocationSize  = memoryRequirements.size;
+        allocateInfo.memoryTypeIndex = memoryIndex;
 
-    VkImageViewCreateInfo viewInfo;
-    viewInfo.sType                           = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-    viewInfo.pNext                           = nullptr;
-    viewInfo.flags                           = 0;
-    viewInfo.image                           = mImage.getHandle();
-    viewInfo.viewType                        = VK_IMAGE_VIEW_TYPE_2D;
-    viewInfo.format                          = vkFormat.native;
-    viewInfo.components.r                    = VK_COMPONENT_SWIZZLE_R;
-    viewInfo.components.g                    = VK_COMPONENT_SWIZZLE_G;
-    viewInfo.components.b                    = VK_COMPONENT_SWIZZLE_B;
-    viewInfo.components.a                    = VK_COMPONENT_SWIZZLE_A;
-    viewInfo.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
-    viewInfo.subresourceRange.baseMipLevel   = 0;
-    viewInfo.subresourceRange.levelCount     = 1;
-    viewInfo.subresourceRange.baseArrayLayer = 0;
-    viewInfo.subresourceRange.layerCount     = 1;
+        ANGLE_TRY(mDeviceMemory.allocate(device, allocateInfo));
+        ANGLE_TRY(mImage.bindMemory(device, mDeviceMemory));
 
-    ANGLE_TRY(mImageView.init(device, viewInfo));
+        VkImageViewCreateInfo viewInfo;
+        viewInfo.sType                           = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+        viewInfo.pNext                           = nullptr;
+        viewInfo.flags                           = 0;
+        viewInfo.image                           = mImage.getHandle();
+        viewInfo.viewType                        = VK_IMAGE_VIEW_TYPE_2D;
+        viewInfo.format                          = vkFormat.native;
+        viewInfo.components.r                    = VK_COMPONENT_SWIZZLE_R;
+        viewInfo.components.g                    = VK_COMPONENT_SWIZZLE_G;
+        viewInfo.components.b                    = VK_COMPONENT_SWIZZLE_B;
+        viewInfo.components.a                    = VK_COMPONENT_SWIZZLE_A;
+        viewInfo.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
+        viewInfo.subresourceRange.baseMipLevel   = 0;
+        viewInfo.subresourceRange.levelCount     = 1;
+        viewInfo.subresourceRange.baseArrayLayer = 0;
+        viewInfo.subresourceRange.layerCount     = 1;
 
-    // Create a simple sampler. Force basic parameter settings.
-    // TODO(jmadill): Sampler parameters.
-    VkSamplerCreateInfo samplerInfo;
-    samplerInfo.sType                   = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
-    samplerInfo.pNext                   = nullptr;
-    samplerInfo.flags                   = 0;
-    samplerInfo.magFilter               = VK_FILTER_NEAREST;
-    samplerInfo.minFilter               = VK_FILTER_NEAREST;
-    samplerInfo.mipmapMode              = VK_SAMPLER_MIPMAP_MODE_NEAREST;
-    samplerInfo.addressModeU            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
-    samplerInfo.addressModeV            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
-    samplerInfo.addressModeW            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
-    samplerInfo.mipLodBias              = 0.0f;
-    samplerInfo.anisotropyEnable        = VK_FALSE;
-    samplerInfo.maxAnisotropy           = 1.0f;
-    samplerInfo.compareEnable           = VK_FALSE;
-    samplerInfo.compareOp               = VK_COMPARE_OP_ALWAYS;
-    samplerInfo.minLod                  = 0.0f;
-    samplerInfo.maxLod                  = 1.0f;
-    samplerInfo.borderColor             = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
-    samplerInfo.unnormalizedCoordinates = VK_FALSE;
+        ANGLE_TRY(mImageView.init(device, viewInfo));
+    }
 
-    ANGLE_TRY(mSampler.init(device, samplerInfo));
+    if (!mSampler.valid())
+    {
+        // Create a simple sampler. Force basic parameter settings.
+        // TODO(jmadill): Sampler parameters.
+        VkSamplerCreateInfo samplerInfo;
+        samplerInfo.sType                   = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+        samplerInfo.pNext                   = nullptr;
+        samplerInfo.flags                   = 0;
+        samplerInfo.magFilter               = VK_FILTER_NEAREST;
+        samplerInfo.minFilter               = VK_FILTER_NEAREST;
+        samplerInfo.mipmapMode              = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+        samplerInfo.addressModeU            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+        samplerInfo.addressModeV            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+        samplerInfo.addressModeW            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+        samplerInfo.mipLodBias              = 0.0f;
+        samplerInfo.anisotropyEnable        = VK_FALSE;
+        samplerInfo.maxAnisotropy           = 1.0f;
+        samplerInfo.compareEnable           = VK_FALSE;
+        samplerInfo.compareOp               = VK_COMPARE_OP_ALWAYS;
+        samplerInfo.minLod                  = 0.0f;
+        samplerInfo.maxLod                  = 1.0f;
+        samplerInfo.borderColor             = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
+        samplerInfo.unnormalizedCoordinates = VK_FALSE;
+
+        ANGLE_TRY(mSampler.init(device, samplerInfo));
+    }
 
     mRenderTarget.image     = &mImage;
     mRenderTarget.imageView = &mImageView;
@@ -212,6 +232,10 @@
         ANGLE_TRY(contextVk->getStartedCommandBuffer(&commandBuffer));
         setQueueSerial(renderer->getCurrentQueueSerial());
 
+        // Ensure we aren't in a render pass.
+        // TODO(jmadill): Command reordering.
+        renderer->endRenderPass();
+
         stagingImage.getImage().changeLayoutTop(
             VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, commandBuffer);
         mImage.changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,