Implemented depth and stencil clear command

Added the ClearDepthStencilImage command and made some minor adjustments
to Image clear functions to make the depth and stencil clears work.

Passes all test in:
api.image_clearing.dedicated_allocation.clear_depth_stencil_image.*

Bug b/119620767

Change-Id: If4cfe6aa97b955c9bc7881bba89ab725897c36f9
Reviewed-on: https://swiftshader-review.googlesource.com/c/23728
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index 0d97a7e..57f9538 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -220,9 +220,9 @@
 	const VkBufferImageCopy region;
 };
 
-struct ClearImage : public CommandBuffer::Command
+struct ClearColorImage : public CommandBuffer::Command
 {
-	ClearImage(VkImage image, const VkClearColorValue& color, const VkImageSubresourceRange& range) :
+	ClearColorImage(VkImage image, const VkClearColorValue& color, const VkImageSubresourceRange& range) :
 		image(image), color(color), range(range)
 	{
 	}
@@ -238,6 +238,24 @@
 	const VkImageSubresourceRange range;
 };
 
+struct ClearDepthStencilImage : public CommandBuffer::Command
+{
+	ClearDepthStencilImage(VkImage image, const VkClearDepthStencilValue& depthStencil, const VkImageSubresourceRange& range) :
+		image(image), depthStencil(depthStencil), range(range)
+	{
+	}
+
+	void play(CommandBuffer::ExecutionState& executionState)
+	{
+		Cast(image)->clear(depthStencil, range);
+	}
+
+private:
+	VkImage image;
+	const VkClearDepthStencilValue depthStencil;
+	const VkImageSubresourceRange range;
+};
+
 struct BlitImage : public CommandBuffer::Command
 {
 	BlitImage(VkImage srcImage, VkImage dstImage, const VkImageBlit& region, VkFilter filter) :
@@ -619,14 +637,19 @@
 
 	for(uint32_t i = 0; i < rangeCount; i++)
 	{
-		commands->push_back(std::make_unique<ClearImage>(image, pColor[i], pRanges[i]));
+		commands->push_back(std::make_unique<ClearColorImage>(image, pColor[i], pRanges[i]));
 	}
 }
 
 void CommandBuffer::clearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil,
 	uint32_t rangeCount, const VkImageSubresourceRange* pRanges)
 {
-	UNIMPLEMENTED();
+	ASSERT(state == RECORDING);
+
+	for(uint32_t i = 0; i < rangeCount; i++)
+	{
+		commands->push_back(std::make_unique<ClearDepthStencilImage>(image, pDepthStencil[i], pRanges[i]));
+	}
 }
 
 void CommandBuffer::clearAttachments(uint32_t attachmentCount, const VkClearAttachment* pAttachments,
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index 5313120..39c941c 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -501,13 +501,8 @@
 	        mipLevels : (subresourceRange.baseMipLevel + subresourceRange.levelCount)) - 1;
 }
 
-void Image::clear(const VkClearColorValue& color, const VkImageSubresourceRange& subresourceRange)
+void Image::clear(void* pixelData, VkFormat format, const VkImageSubresourceRange& subresourceRange, VkImageAspectFlags aspectMask)
 {
-	if(!(subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT))
-	{
-		UNIMPLEMENTED();
-	}
-
 	uint32_t firstLayer = subresourceRange.baseArrayLayer;
 	uint32_t lastLayer = getLastLayerIndex(subresourceRange);
 	for(uint32_t layer = firstLayer; layer <= lastLayer; ++layer)
@@ -519,17 +514,48 @@
 			for(uint32_t s = 0; s < mipLevelExtent.depth; ++s)
 			{
 				const sw::SliceRect dRect(0, 0, mipLevelExtent.width, mipLevelExtent.height, s);
-				sw::Surface* surface = asSurface(subresourceRange.aspectMask, mipLevel, layer);
-				blitter->clear((void*)color.float32, getClearFormat(), surface, dRect, 0xF);
+				sw::Surface* surface = asSurface(aspectMask, mipLevel, layer);
+				blitter->clear(pixelData, format, surface, dRect, 0xF);
 				delete surface;
 			}
 		}
 	}
 }
 
+void Image::clear(const VkClearColorValue& color, const VkImageSubresourceRange& subresourceRange)
+{
+	if(!(subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT))
+	{
+		UNIMPLEMENTED();
+	}
+
+	clear((void*)color.float32, getClearFormat(), subresourceRange, VK_IMAGE_ASPECT_COLOR_BIT);
+}
+
+void Image::clear(const VkClearDepthStencilValue& color, const VkImageSubresourceRange& subresourceRange)
+{
+	if((subresourceRange.aspectMask & ~(VK_IMAGE_ASPECT_DEPTH_BIT |
+	                                    VK_IMAGE_ASPECT_STENCIL_BIT)) != 0)
+	{
+		UNIMPLEMENTED();
+	}
+
+	if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
+	{
+		clear((void*)(&color.depth), VK_FORMAT_D32_SFLOAT, subresourceRange, VK_IMAGE_ASPECT_DEPTH_BIT);
+	}
+
+	if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
+	{
+		clear((void*)(&color.stencil), VK_FORMAT_S8_UINT, subresourceRange, VK_IMAGE_ASPECT_STENCIL_BIT);
+	}
+}
+
 void Image::clear(const VkClearValue& clearValue, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange)
 {
-	if((subresourceRange.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) ||
+	if(!((subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
+	     (subresourceRange.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT |
+	                                     VK_IMAGE_ASPECT_STENCIL_BIT))) ||
 	   (subresourceRange.baseMipLevel != 0) ||
 	   (subresourceRange.levelCount != 1) ||
 	   (renderArea.offset.x != 0) ||
@@ -540,7 +566,14 @@
 		UNIMPLEMENTED();
 	}
 
-	clear(clearValue.color, subresourceRange);
+	if(subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT)
+	{
+		clear(clearValue.color, subresourceRange);
+	}
+	else
+	{
+		clear(clearValue.depthStencil, subresourceRange);
+	}
 }
 
 } // namespace vk
\ No newline at end of file
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp
index 8f1e95d..ae263e0 100644
--- a/src/Vulkan/VkImage.hpp
+++ b/src/Vulkan/VkImage.hpp
@@ -46,6 +46,7 @@
 	void blit(VkImage dstImage, const VkImageBlit& region, VkFilter filter);
 	void clear(const VkClearValue& clearValue, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange);
 	void clear(const VkClearColorValue& color, const VkImageSubresourceRange& subresourceRange);
+	void clear(const VkClearDepthStencilValue& color, const VkImageSubresourceRange& subresourceRange);
 
 	VkImageType              getImageType() const { return imageType; }
 	VkFormat                 getFormat() const { return format; }
@@ -70,6 +71,7 @@
 	uint32_t getLastLayerIndex(const VkImageSubresourceRange& subresourceRange) const;
 	uint32_t getLastMipLevel(const VkImageSubresourceRange& subresourceRange) const;
 	VkFormat getClearFormat() const;
+	void clear(void* pixelData, VkFormat format, const VkImageSubresourceRange& subresourceRange, VkImageAspectFlags aspectMask);
 	sw::Surface* asSurface(const VkImageAspectFlags& flags, uint32_t mipLevel, uint32_t layer) const;
 
 	DeviceMemory*            deviceMemory = nullptr;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 5684122..63230d7 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -472,9 +472,22 @@
 	TRACE("(VkDevice device = 0x%X, const VkMemoryAllocateInfo* pAllocateInfo = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X, VkDeviceMemory* pMemory = 0x%X)",
 		    device, pAllocateInfo, pAllocator, pMemory);
 
-	if(pAllocateInfo->pNext)
+	const VkBaseOutStructure* allocationInfo = reinterpret_cast<const VkBaseOutStructure*>(pAllocateInfo->pNext);
+	while(allocationInfo)
 	{
-		UNIMPLEMENTED();
+		switch(allocationInfo->sType)
+		{
+		case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
+			// This can safely be ignored, as the Vulkan spec mentions:
+			// "If the pNext chain includes a VkMemoryDedicatedAllocateInfo structure, then that structure
+			//  includes a handle of the sole buffer or image resource that the memory *can* be bound to."
+			break;
+		default:
+			UNIMPLEMENTED();
+			break;
+		}
+
+		allocationInfo = allocationInfo->pNext;
 	}
 
 	VkResult result = vk::DeviceMemory::Create(pAllocator, pAllocateInfo, pMemory);