Wire up depth and stencil attachments to pipeline

- Fix broken use of VkImageCreateFlags in various places as an aspect mask
- Be consistent about layout of D+S images. Layout is now [aspect][layer][level].
- Allow fetching an offset into a particular aspect.

Fixes dEQP-VK.pipeline.depth.*

Bug: b/118619338
Change-Id: I46adc9c637882e7144945eaeacce9f087d53caf0
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/26011
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index e116de4..9634c10 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -159,6 +159,38 @@
 	const VkIndexType indexType;
 };
 
+void CommandBuffer::ExecutionState::bindAttachments()
+{
+	// Binds all the attachments for the current subpass
+	// Ideally this would be performed by BeginRenderPass and NextSubpass, but
+	// there is too much stomping of the renderer's state by setContext() in
+	// draws.
+
+	for (auto i = 0u; i < renderPass->getCurrentSubpass().colorAttachmentCount; i++)
+	{
+		auto attachmentReference = renderPass->getCurrentSubpass().pColorAttachments[i];
+		if (attachmentReference.attachment != VK_ATTACHMENT_UNUSED)
+		{
+			auto attachment = renderPassFramebuffer->getAttachment(attachmentReference.attachment);
+			renderer->setRenderTarget(i, attachment, 0);
+		}
+	}
+
+	auto attachmentReference = renderPass->getCurrentSubpass().pDepthStencilAttachment;
+	if (attachmentReference && attachmentReference->attachment != VK_ATTACHMENT_UNUSED)
+	{
+		auto attachment = renderPassFramebuffer->getAttachment(attachmentReference->attachment);
+		if (attachment->hasDepthAspect())
+		{
+			renderer->setDepthBuffer(attachment, 0);
+		}
+		if (attachment->hasStencilAspect())
+		{
+			renderer->setStencilBuffer(attachment, 0);
+		}
+	}
+}
+
 struct Draw : public CommandBuffer::Command
 {
 	Draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance)
@@ -189,15 +221,7 @@
 		executionState.renderer->setViewport(pipeline->getViewport());
 		executionState.renderer->setBlendConstant(pipeline->getBlendConstants());
 
-		for (auto i = 0u; i < executionState.renderPass->getCurrentSubpass().colorAttachmentCount; i++)
-		{
-			auto attachmentReference = executionState.renderPass->getCurrentSubpass().pColorAttachments[i];
-			if (attachmentReference.attachment != VK_ATTACHMENT_UNUSED)
-			{
-				auto attachment = executionState.renderPassFramebuffer->getAttachment(attachmentReference.attachment);
-				executionState.renderer->setRenderTarget(i, attachment, 0);
-			}
-		}
+		executionState.bindAttachments();
 
 		const uint32_t primitiveCount = pipeline->computePrimitiveCount(vertexCount);
 		const uint32_t lastInstance = firstInstance + instanceCount - 1;
@@ -247,15 +271,7 @@
 		executionState.renderer->setViewport(pipeline->getViewport());
 		executionState.renderer->setBlendConstant(pipeline->getBlendConstants());
 
-		for (auto i = 0u; i < executionState.renderPass->getCurrentSubpass().colorAttachmentCount; i++)
-		{
-			auto attachmentReference = executionState.renderPass->getCurrentSubpass().pColorAttachments[i];
-			if (attachmentReference.attachment != VK_ATTACHMENT_UNUSED)
-			{
-				auto attachment = executionState.renderPassFramebuffer->getAttachment(attachmentReference.attachment);
-				executionState.renderer->setRenderTarget(i, attachment, 0);
-			}
-		}
+		executionState.bindAttachments();
 
 		auto drawType = executionState.indexType == VK_INDEX_TYPE_UINT16
 				? (context.drawType | sw::DRAW_INDEXED16) : (context.drawType | sw::DRAW_INDEXED32);
diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp
index eb5f891..38d8e59 100644
--- a/src/Vulkan/VkCommandBuffer.hpp
+++ b/src/Vulkan/VkCommandBuffer.hpp
@@ -135,6 +135,8 @@
 		VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {};
 		VertexInputBinding indexBufferBinding;
 		VkIndexType indexType;
+
+		void bindAttachments();
 	};
 
 	void submit(CommandBuffer::ExecutionState& executionState);
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index 17c3213..463a8f7 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -19,6 +19,25 @@
 #include "Device/Surface.hpp"
 #include <cstring>
 
+namespace
+{
+	VkImageAspectFlags GetAspects(VkFormat format)
+	{
+		// TODO: probably just flatten this out to a full format list, and alter
+		// isDepth / isStencil etc to check for their aspect
+
+		VkImageAspectFlags aspects = 0;
+		if (sw::Surface::isDepth(format)) aspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
+		if (sw::Surface::isStencil(format)) aspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
+
+		// TODO: YCbCr planar formats have different aspects
+
+		// Anything else is "color".
+		if (!aspects) aspects |= VK_IMAGE_ASPECT_COLOR_BIT;
+		return aspects;
+	}
+}
+
 namespace vk
 {
 
@@ -55,7 +74,7 @@
 	VkMemoryRequirements memoryRequirements;
 	memoryRequirements.alignment = vk::REQUIRED_MEMORY_ALIGNMENT;
 	memoryRequirements.memoryTypeBits = vk::MEMORY_TYPE_GENERIC_BIT;
-	memoryRequirements.size = getStorageSize(flags);
+	memoryRequirements.size = getStorageSize(GetAspects(format));
 	return memoryRequirements;
 }
 
@@ -67,11 +86,19 @@
 
 void Image::getSubresourceLayout(const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) const
 {
-	pLayout->offset = getMemoryOffset(flags, pSubresource->mipLevel, pSubresource->arrayLayer);
-	pLayout->size = getMipLevelSize(flags, pSubresource->mipLevel);
-	pLayout->rowPitch = rowPitchBytes(flags, pSubresource->mipLevel);
-	pLayout->depthPitch = slicePitchBytes(flags, pSubresource->mipLevel);
-	pLayout->arrayPitch = getLayerSize(flags);
+	// By spec, aspectMask has a single bit set.
+	if (!((pSubresource->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
+		  (pSubresource->aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) ||
+		  (pSubresource->aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT)))
+	{
+		UNIMPLEMENTED();
+	}
+	auto aspect = static_cast<VkImageAspectFlagBits>(pSubresource->aspectMask);
+	pLayout->offset = getMemoryOffset(aspect, pSubresource->mipLevel, pSubresource->arrayLayer);
+	pLayout->size = getMipLevelSize(aspect, pSubresource->mipLevel);
+	pLayout->rowPitch = rowPitchBytes(aspect, pSubresource->mipLevel);
+	pLayout->depthPitch = slicePitchBytes(aspect, pSubresource->mipLevel);
+	pLayout->arrayPitch = getLayerSize(aspect);
 }
 
 void Image::copyTo(VkImage dstImage, const VkImageCopy& pRegion)
@@ -79,8 +106,6 @@
 	// Image copy does not perform any conversion, it simply copies memory from
 	// an image to another image that has the same number of bytes per pixel.
 	Image* dst = Cast(dstImage);
-	int srcBytesPerTexel = bytesPerTexel(pRegion.srcSubresource.aspectMask);
-	ASSERT(srcBytesPerTexel == dst->bytesPerTexel(pRegion.dstSubresource.aspectMask));
 
 	if(!((pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
 		 (pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) ||
@@ -100,13 +125,19 @@
 		UNIMPLEMENTED();
 	}
 
+	VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(pRegion.srcSubresource.aspectMask);
+	VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(pRegion.dstSubresource.aspectMask);
+
+	int srcBytesPerTexel = bytesPerTexel(srcAspect);
+	ASSERT(srcBytesPerTexel == dst->bytesPerTexel(dstAspect));
+
 	const char* srcMem = static_cast<const char*>(getTexelPointer(pRegion.srcOffset, pRegion.srcSubresource));
 	char* dstMem = static_cast<char*>(dst->getTexelPointer(pRegion.dstOffset, pRegion.dstSubresource));
 
-	int srcRowPitchBytes = rowPitchBytes(pRegion.srcSubresource.aspectMask, pRegion.srcSubresource.mipLevel);
-	int srcSlicePitchBytes = slicePitchBytes(pRegion.srcSubresource.aspectMask, pRegion.srcSubresource.mipLevel);
-	int dstRowPitchBytes = dst->rowPitchBytes(pRegion.dstSubresource.aspectMask, pRegion.dstSubresource.mipLevel);
-	int dstSlicePitchBytes = dst->slicePitchBytes(pRegion.dstSubresource.aspectMask, pRegion.dstSubresource.mipLevel);
+	int srcRowPitchBytes = rowPitchBytes(srcAspect, pRegion.srcSubresource.mipLevel);
+	int srcSlicePitchBytes = slicePitchBytes(srcAspect, pRegion.srcSubresource.mipLevel);
+	int dstRowPitchBytes = dst->rowPitchBytes(dstAspect, pRegion.dstSubresource.mipLevel);
+	int dstSlicePitchBytes = dst->slicePitchBytes(dstAspect, pRegion.dstSubresource.mipLevel);
 
 	VkExtent3D srcExtent = getMipLevelExtent(pRegion.srcSubresource.mipLevel);
 	VkExtent3D dstExtent = dst->getMipLevelExtent(pRegion.dstSubresource.mipLevel);
@@ -167,10 +198,12 @@
 		UNIMPLEMENTED();
 	}
 
+	VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(region.imageSubresource.aspectMask);
+
 	VkExtent3D mipLevelExtent = getMipLevelExtent(region.imageSubresource.mipLevel);
-	int imageBytesPerTexel = bytesPerTexel(region.imageSubresource.aspectMask);
-	int imageRowPitchBytes = rowPitchBytes(region.imageSubresource.aspectMask, region.imageSubresource.mipLevel);
-	int imageSlicePitchBytes = slicePitchBytes(region.imageSubresource.aspectMask, region.imageSubresource.mipLevel);
+	int imageBytesPerTexel = bytesPerTexel(aspect);
+	int imageRowPitchBytes = rowPitchBytes(aspect, region.imageSubresource.mipLevel);
+	int imageSlicePitchBytes = slicePitchBytes(aspect, region.imageSubresource.mipLevel);
 	int bufferRowPitchBytes = ((region.bufferRowLength == 0) ? region.imageExtent.width : region.bufferRowLength) *
 	                          imageBytesPerTexel;
 	int bufferSlicePitchBytes = (((region.bufferImageHeight == 0) || (region.bufferRowLength == 0))) ?
@@ -189,10 +222,10 @@
 	bool isEntirePlane = isEntireLine && (region.imageExtent.height == mipLevelExtent.height) &&
 	                     (imageSlicePitchBytes == bufferSlicePitchBytes);
 
-	VkDeviceSize layerSize = getLayerSize(flags);
+	VkDeviceSize layerSize = getLayerSize(aspect);
 	char* bufferMemory = static_cast<char*>(Cast(buffer)->getOffsetPointer(region.bufferOffset));
 	char* imageMemory = static_cast<char*>(deviceMemory->getOffsetPointer(
-	                    getMemoryOffset(region.imageSubresource.aspectMask, region.imageSubresource.mipLevel,
+	                    getMemoryOffset(aspect, region.imageSubresource.mipLevel,
 	                                    region.imageSubresource.baseArrayLayer) +
 	                    texelOffsetBytesInStorage(region.imageOffset, region.imageSubresource)));
 	char* srcMemory = bufferIsSource ? bufferMemory : imageMemory;
@@ -265,15 +298,17 @@
 
 void* Image::getTexelPointer(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const
 {
+	VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
 	return deviceMemory->getOffsetPointer(texelOffsetBytesInStorage(offset, subresource) +
-	       getMemoryOffset(flags, subresource.mipLevel, subresource.baseArrayLayer));
+	       getMemoryOffset(aspect, subresource.mipLevel, subresource.baseArrayLayer));
 }
 
 VkDeviceSize Image::texelOffsetBytesInStorage(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const
 {
-	return offset.z * slicePitchBytes(flags, subresource.mipLevel) +
-	       offset.y * rowPitchBytes(flags, subresource.mipLevel) +
-	       offset.x * bytesPerTexel(flags);
+	VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
+	return offset.z * slicePitchBytes(aspect, subresource.mipLevel) +
+	       offset.y * rowPitchBytes(aspect, subresource.mipLevel) +
+	       offset.x * bytesPerTexel(aspect);
 }
 
 VkExtent3D Image::getMipLevelExtent(uint32_t mipLevel) const
@@ -298,34 +333,34 @@
 	return mipLevelExtent;
 }
 
-int Image::rowPitchBytes(const VkImageAspectFlags& flags, uint32_t mipLevel) const
+int Image::rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
 {
 	// Depth and Stencil pitch should be computed separately
-	ASSERT((flags & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) !=
+	ASSERT((aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) !=
 	                (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
-	return sw::Surface::pitchB(getMipLevelExtent(mipLevel).width, isCube() ? 1 : 0, getFormat(flags), false);
+	return sw::Surface::pitchB(getMipLevelExtent(mipLevel).width, isCube() ? 1 : 0, getFormat(aspect), false);
 }
 
-int Image::slicePitchBytes(const VkImageAspectFlags& flags, uint32_t mipLevel) const
+int Image::slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
 {
 	// Depth and Stencil slice should be computed separately
-	ASSERT((flags & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) !=
+	ASSERT((aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) !=
 	                (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
 	VkExtent3D mipLevelExtent = getMipLevelExtent(mipLevel);
-	return sw::Surface::sliceB(mipLevelExtent.width, mipLevelExtent.height, isCube() ? 1 : 0, getFormat(flags), false);
+	return sw::Surface::sliceB(mipLevelExtent.width, mipLevelExtent.height, isCube() ? 1 : 0, getFormat(aspect), false);
 }
 
-int Image::bytesPerTexel(const VkImageAspectFlags& flags) const
+int Image::bytesPerTexel(VkImageAspectFlagBits aspect) const
 {
 	// Depth and Stencil bytes should be computed separately
-	ASSERT((flags & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) !=
+	ASSERT((aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) !=
 	                (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
-	return sw::Surface::bytes(getFormat(flags));
+	return sw::Surface::bytes(getFormat(aspect));
 }
 
-VkFormat Image::getFormat(const VkImageAspectFlags& flags) const
+VkFormat Image::getFormat(VkImageAspectFlagBits aspect) const
 {
-	switch(flags)
+	switch(aspect)
 	{
 	case VK_IMAGE_ASPECT_DEPTH_BIT:
 		switch(format)
@@ -363,14 +398,14 @@
 	return (flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && (imageType == VK_IMAGE_TYPE_2D);
 }
 
-VkDeviceSize Image::getMemoryOffset(const VkImageAspectFlags& flags) const
+VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect) const
 {
 	switch(format)
 	{
 	case VK_FORMAT_D16_UNORM_S8_UINT:
 	case VK_FORMAT_D24_UNORM_S8_UINT:
 	case VK_FORMAT_D32_SFLOAT_S8_UINT:
-		if(flags == VK_IMAGE_ASPECT_STENCIL_BIT)
+		if(aspect == VK_IMAGE_ASPECT_STENCIL_BIT)
 		{
 			// Offset by depth buffer to get to stencil buffer
 			return memoryOffset + getStorageSize(VK_IMAGE_ASPECT_DEPTH_BIT);
@@ -383,81 +418,64 @@
 	return memoryOffset;
 }
 
-VkDeviceSize Image::getMemoryOffset(const VkImageAspectFlags& flags, uint32_t mipLevel) const
+VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
 {
-	VkDeviceSize offset = getMemoryOffset(flags);
+	VkDeviceSize offset = getMemoryOffset(aspect);
 	for(uint32_t i = 0; i < mipLevel; ++i)
 	{
-		offset += getMipLevelSize(flags, i);
+		offset += getMipLevelSize(aspect, i);
 	}
 	return offset;
 }
 
-VkDeviceSize Image::getMemoryOffset(const VkImageAspectFlags& flags, uint32_t mipLevel, uint32_t layer) const
+VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const
 {
-	return layer * getLayerSize(flags) + getMemoryOffset(flags, mipLevel);
+	return layer * getLayerSize(aspect) + getMemoryOffset(aspect, mipLevel);
 }
 
-VkDeviceSize Image::getMipLevelSize(const VkImageAspectFlags& flags, uint32_t mipLevel) const
+VkDeviceSize Image::getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
 {
-	int slicePitchB = 0;
-	if(sw::Surface::isDepth(format) && sw::Surface::isStencil(format))
-	{
-		switch(flags)
-		{
-		case VK_IMAGE_ASPECT_DEPTH_BIT:
-		case VK_IMAGE_ASPECT_STENCIL_BIT:
-			slicePitchB = slicePitchBytes(flags, mipLevel);
-			break;
-		default:
-			// Allow allocating both depth and stencil contiguously
-			slicePitchB = (slicePitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, mipLevel) +
-			               slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, mipLevel));
-			break;
-		}
-	}
-	else
-	{
-		slicePitchB = slicePitchBytes(flags, mipLevel);
-	}
-
-	return getMipLevelExtent(mipLevel).depth * slicePitchB;
+	return getMipLevelExtent(mipLevel).depth * slicePitchBytes(aspect, mipLevel);
 }
 
-VkDeviceSize Image::getLayerSize(const VkImageAspectFlags& flags) const
+VkDeviceSize Image::getLayerSize(VkImageAspectFlagBits aspect) const
 {
 	VkDeviceSize layerSize = 0;
 
 	for(uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel)
 	{
-		layerSize += getMipLevelSize(flags, mipLevel);
+		layerSize += getMipLevelSize(aspect, mipLevel);
 	}
 
 	return layerSize;
 }
 
-VkDeviceSize Image::getStorageSize(const VkImageAspectFlags& flags) const
+VkDeviceSize Image::getStorageSize(VkImageAspectFlags aspectMask) const
 {
-	return arrayLayers * getLayerSize(flags);
+	if (aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT))
+	{
+		return arrayLayers * (getLayerSize(VK_IMAGE_ASPECT_DEPTH_BIT) + getLayerSize(VK_IMAGE_ASPECT_STENCIL_BIT));
+	}
+	return arrayLayers * getLayerSize(static_cast<VkImageAspectFlagBits>(aspectMask));
 }
 
-sw::Surface* Image::asSurface(const VkImageAspectFlags& flags, uint32_t mipLevel, uint32_t layer) const
+sw::Surface* Image::asSurface(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const
 {
 	VkExtent3D mipLevelExtent = getMipLevelExtent(mipLevel);
-	return sw::Surface::create(mipLevelExtent.width, mipLevelExtent.height, mipLevelExtent.depth, getFormat(flags),
-	                           deviceMemory->getOffsetPointer(getMemoryOffset(flags, mipLevel, layer)),
-	                           rowPitchBytes(flags, mipLevel), slicePitchBytes(flags, mipLevel));
+	return sw::Surface::create(mipLevelExtent.width, mipLevelExtent.height, mipLevelExtent.depth, getFormat(aspect),
+	                           deviceMemory->getOffsetPointer(getMemoryOffset(aspect, mipLevel, layer)),
+	                           rowPitchBytes(aspect, mipLevel), slicePitchBytes(aspect, mipLevel));
 }
 
 void Image::blit(VkImage dstImage, const VkImageBlit& region, VkFilter filter)
 {
-	VkImageAspectFlags srcFlags = region.srcSubresource.aspectMask;
-	VkImageAspectFlags dstFlags = region.dstSubresource.aspectMask;
+	VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(region.srcSubresource.aspectMask);
+	VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(region.dstSubresource.aspectMask);
 	if((region.srcSubresource.baseArrayLayer != 0) ||
 	   (region.dstSubresource.baseArrayLayer != 0) ||
 	   (region.srcSubresource.layerCount != 1) ||
 	   (region.dstSubresource.layerCount != 1) ||
-	   (srcFlags != dstFlags))
+	   (srcAspect != dstAspect))
 	{
 		UNIMPLEMENTED();
 	}
@@ -465,8 +483,8 @@
 	int32_t numSlices = (region.srcOffsets[1].z - region.srcOffsets[0].z);
 	ASSERT(numSlices == (region.dstOffsets[1].z - region.dstOffsets[0].z));
 
-	sw::Surface* srcSurface = asSurface(srcFlags, region.srcSubresource.mipLevel, 0);
-	sw::Surface* dstSurface = Cast(dstImage)->asSurface(dstFlags, region.dstSubresource.mipLevel, 0);
+	sw::Surface* srcSurface = asSurface(srcAspect, region.srcSubresource.mipLevel, 0);
+	sw::Surface* dstSurface = Cast(dstImage)->asSurface(dstAspect, region.dstSubresource.mipLevel, 0);
 
 	sw::SliceRectF sRect(static_cast<float>(region.srcOffsets[0].x), static_cast<float>(region.srcOffsets[0].y),
 	                     static_cast<float>(region.srcOffsets[1].x), static_cast<float>(region.srcOffsets[1].y),
@@ -478,7 +496,7 @@
 	for(int i = 0; i < numSlices; i++)
 	{
 		blitter->blit(srcSurface, sRect, dstSurface, dRect,
-		              {filter != VK_FILTER_NEAREST, srcFlags == VK_IMAGE_ASPECT_STENCIL_BIT, false});
+		              {filter != VK_FILTER_NEAREST, srcAspect == VK_IMAGE_ASPECT_STENCIL_BIT, false});
 		sRect.slice++;
 		dRect.slice++;
 	}
@@ -515,7 +533,7 @@
 	        mipLevels : (subresourceRange.baseMipLevel + subresourceRange.levelCount)) - 1;
 }
 
-void Image::clear(void* pixelData, VkFormat format, const VkImageSubresourceRange& subresourceRange, VkImageAspectFlags aspectMask)
+void Image::clear(void* pixelData, VkFormat format, const VkImageSubresourceRange& subresourceRange, VkImageAspectFlagBits aspect)
 {
 	uint32_t firstLayer = subresourceRange.baseArrayLayer;
 	uint32_t lastLayer = getLastLayerIndex(subresourceRange);
@@ -528,7 +546,7 @@
 			for(uint32_t s = 0; s < mipLevelExtent.depth; ++s)
 			{
 				const sw::SliceRect dRect(0, 0, mipLevelExtent.width, mipLevelExtent.height, s);
-				sw::Surface* surface = asSurface(aspectMask, mipLevel, layer);
+				sw::Surface* surface = asSurface(aspect, mipLevel, layer);
 				blitter->clear(pixelData, format, surface, dRect, 0xF);
 				delete surface;
 			}
@@ -536,7 +554,7 @@
 	}
 }
 
-void Image::clear(void* pixelData, VkFormat format, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange, VkImageAspectFlags aspectMask)
+void Image::clear(void* pixelData, VkFormat format, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange, VkImageAspectFlagBits aspect)
 {
 	if((subresourceRange.baseMipLevel != 0) ||
 	   (subresourceRange.levelCount != 1))
@@ -555,7 +573,7 @@
 		for(uint32_t s = 0; s < extent.depth; ++s)
 		{
 			dRect.slice = s;
-			sw::Surface* surface = asSurface(aspectMask, 0, layer);
+			sw::Surface* surface = asSurface(aspect, 0, layer);
 			blitter->clear(pixelData, format, surface, dRect, 0xF);
 			delete surface;
 		}
@@ -620,4 +638,4 @@
 	}
 }
 
-} // namespace vk
\ No newline at end of file
+} // namespace vk
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp
index 594091a..d3a77cd 100644
--- a/src/Vulkan/VkImage.hpp
+++ b/src/Vulkan/VkImage.hpp
@@ -53,29 +53,29 @@
 	VkFormat                 getFormat() const { return format; }
 	uint32_t                 getArrayLayers() const { return arrayLayers; }
 	VkSampleCountFlagBits    getSampleCountFlagBits() const { return samples; }
-	int                      rowPitchBytes(const VkImageAspectFlags& flags, uint32_t mipLevel) const;
-	int                      slicePitchBytes(const VkImageAspectFlags& flags, uint32_t mipLevel) const;
+	int                      rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
+	int                      slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
 	void*                    getTexelPointer(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const;
 	bool                     isCube() const;
 
 private:
-	sw::Surface* asSurface(const VkImageAspectFlags& flags, uint32_t mipLevel, uint32_t layer) const;
+	sw::Surface* asSurface(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const;
 	void copy(VkBuffer buffer, const VkBufferImageCopy& region, bool bufferIsSource);
-	VkDeviceSize getStorageSize(const VkImageAspectFlags& flags) const;
-	VkDeviceSize getMipLevelSize(const VkImageAspectFlags& flags, uint32_t mipLevel) const;
-	VkDeviceSize getLayerSize(const VkImageAspectFlags& flags) const;
-	VkDeviceSize getMemoryOffset(const VkImageAspectFlags& flags, uint32_t mipLevel) const;
-	VkDeviceSize getMemoryOffset(const VkImageAspectFlags& flags, uint32_t mipLevel, uint32_t layer) const;
+	VkDeviceSize getStorageSize(VkImageAspectFlags flags) const;
+	VkDeviceSize getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
+	VkDeviceSize getLayerSize(VkImageAspectFlagBits aspect) const;
+	VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
+	VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const;
 	VkDeviceSize texelOffsetBytesInStorage(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const;
-	VkDeviceSize getMemoryOffset(const VkImageAspectFlags& flags) const;
-	int bytesPerTexel(const VkImageAspectFlags& flags) const;
+	VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect) const;
+	int bytesPerTexel(VkImageAspectFlagBits flags) const;
 	VkExtent3D getMipLevelExtent(uint32_t mipLevel) const;
-	VkFormat getFormat(const VkImageAspectFlags& flags) const;
+	VkFormat getFormat(VkImageAspectFlagBits flags) const;
 	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);
-	void clear(void* pixelData, VkFormat format, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange, VkImageAspectFlags aspectMask);
+	void clear(void* pixelData, VkFormat format, const VkImageSubresourceRange& subresourceRange, VkImageAspectFlagBits aspect);
+	void clear(void* pixelData, VkFormat format, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange, VkImageAspectFlagBits aspect);
 
 	DeviceMemory*            deviceMemory = nullptr;
 	VkDeviceSize             memoryOffset = 0;
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp
index 367c602..34e4f93 100644
--- a/src/Vulkan/VkImageView.cpp
+++ b/src/Vulkan/VkImageView.cpp
@@ -119,17 +119,11 @@
 	image->clear(clearValue, renderArea.rect, sr);
 }
 
-void *ImageView::getPointer() const
-{
-	VkOffset3D noOffset = { 0, 0, 0 };
-	return getOffsetPointer(noOffset);
-}
-
-void *ImageView::getOffsetPointer(const VkOffset3D& offset) const
+void *ImageView::getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect) const
 {
 	VkImageSubresourceLayers imageSubresourceLayers =
 	{
-		subresourceRange.aspectMask,
+		aspect,
 		subresourceRange.baseMipLevel,
 		subresourceRange.baseArrayLayer,
 		subresourceRange.layerCount
@@ -137,4 +131,4 @@
 	return image->getTexelPointer(offset, imageSubresourceLayers);
 }
 
-}
\ No newline at end of file
+}
diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp
index 83fb289..89cc7a1 100644
--- a/src/Vulkan/VkImageView.hpp
+++ b/src/Vulkan/VkImageView.hpp
@@ -31,16 +31,17 @@
 
 	static size_t ComputeRequiredAllocationSize(const VkImageViewCreateInfo* pCreateInfo);
 
-	void clear(const VkClearValue& clearValues, const VkImageAspectFlags aspectMask, const VkRect2D& renderArea);
-	void clear(const VkClearValue& clearValue, const VkImageAspectFlags aspectMask, const VkClearRect& renderArea);
+	void clear(const VkClearValue& clearValues, VkImageAspectFlags aspectMask, const VkRect2D& renderArea);
+	void clear(const VkClearValue& clearValue, VkImageAspectFlags aspectMask, const VkClearRect& renderArea);
 
 	VkFormat getFormat() const { return format; }
-	int rowPitchBytes() const { return image->rowPitchBytes(subresourceRange.aspectMask, subresourceRange.baseMipLevel); }
-	int slicePitchBytes() const { return image->slicePitchBytes(subresourceRange.aspectMask, subresourceRange.baseMipLevel); }
 	int getSampleCount() const { return image->getSampleCountFlagBits(); }
+	int rowPitchBytes(VkImageAspectFlagBits aspect) const { return image->rowPitchBytes(aspect, subresourceRange.baseMipLevel); }
+	int slicePitchBytes(VkImageAspectFlagBits aspect) const { return image->slicePitchBytes(aspect, subresourceRange.baseMipLevel); }
 
-	void *getPointer() const;
-	void *getOffsetPointer(const VkOffset3D& offset) const;
+	void *getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect) const;
+	bool hasDepthAspect() const { return (subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; }
+	bool hasStencilAspect() const { return (subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; }
 
 private:
 	bool                       imageTypesMatch(VkImageType imageType) const;
@@ -59,4 +60,4 @@
 
 } // namespace vk
 
-#endif // VK_IMAGE_VIEW_HPP_
\ No newline at end of file
+#endif // VK_IMAGE_VIEW_HPP_