Use UNIMPLEMENTED() for missing functionality we claim support for

The parent change replaced all UNIMPLEMENTED() with UNSUPPORTED(), since
we are now Vulkan 1.1 conformant and the majority of these
UNIMPLEMENTED() uses was for functionality that is not mandatory to
still implement and is instead part of a currently unsupported feature.

This change conservatively restores uses of UNIMPLEMENTED() for things
that we might hit with correctly behaving apps. Bugs will be filed for
each of these and tests will be added where necessary to provide
coverage of these code paths.

Bug: b/131243109
Change-Id: Iaf547983c8495ad8d6d0c783a4c656273d8c0195
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/40409
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Device/Blitter.cpp b/src/Device/Blitter.cpp
index 5333359..946eafc 100644
--- a/src/Device/Blitter.cpp
+++ b/src/Device/Blitter.cpp
@@ -1750,7 +1750,7 @@
 	if((region.srcSubresource.layerCount != region.dstSubresource.layerCount) ||
 	   (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask))
 	{
-		UNSUPPORTED("region");
+		UNIMPLEMENTED("region");
 	}
 
 	if(region.dstOffsets[0].x > region.dstOffsets[1].x)
@@ -1892,7 +1892,7 @@
 
 	if(state.srcSamples != 1)
 	{
-		UNSUPPORTED("state.srcSamples %d", state.srcSamples);
+		UNIMPLEMENTED("state.srcSamples %d", state.srcSamples);
 	}
 
 	CornerUpdateFunction function;
@@ -1924,8 +1924,8 @@
 {
 	if(image->getArrayLayers() < (subresourceLayers.baseArrayLayer + 6))
 	{
-		UNSUPPORTED("image->getArrayLayers() %d, baseArrayLayer %d",
-		            image->getArrayLayers(), subresourceLayers.baseArrayLayer);
+		UNIMPLEMENTED("image->getArrayLayers() %d, baseArrayLayer %d",
+		              image->getArrayLayers(), subresourceLayers.baseArrayLayer);
 	}
 
 	// From Vulkan 1.1 spec, section 11.5. Image Views:
@@ -1982,7 +1982,7 @@
 
 	if(samples != VK_SAMPLE_COUNT_1_BIT)
 	{
-		UNSUPPORTED("Multi-sampled cube: %d samples", static_cast<int>(samples));
+		UNIMPLEMENTED("Multi-sampled cube: %d samples", static_cast<int>(samples));
 	}
 
 	auto cornerUpdateRoutine = getCornerUpdateRoutine(state);
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 95457fb..c505ad7 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -272,7 +272,7 @@
 					}
 					case spv::StorageClassAtomicCounter:
 					case spv::StorageClassImage:
-						UNSUPPORTED("StorageClass %d not yet implemented", (int)storageClass);
+						UNSUPPORTED("StorageClass %d not yet supported", (int)storageClass);
 						break;
 
 					case spv::StorageClassCrossWorkgroup:
diff --git a/src/Pipeline/SpirvShaderControlFlow.cpp b/src/Pipeline/SpirvShaderControlFlow.cpp
index bcaa473..f70a29c 100644
--- a/src/Pipeline/SpirvShaderControlFlow.cpp
+++ b/src/Pipeline/SpirvShaderControlFlow.cpp
@@ -581,14 +581,16 @@
 		{
 			if(insnNumber > 1)
 			{
-				UNSUPPORTED("Function block number of instructions: %d", insnNumber);
+				UNIMPLEMENTED("Function block number of instructions: %d", insnNumber);
 				return EmitResult::Continue;
 			}
+
 			if(blockInsn.opcode() != wrapOpKill[insnNumber++])
 			{
-				UNSUPPORTED("Function block instruction %d : %s", insnNumber - 1, OpcodeName(blockInsn.opcode()).c_str());
+				UNIMPLEMENTED("Function block instruction %d : %s", insnNumber - 1, OpcodeName(blockInsn.opcode()).c_str());
 				return EmitResult::Continue;
 			}
+
 			if(blockInsn.opcode() == spv::OpKill)
 			{
 				EmitInstruction(blockInsn, state);
diff --git a/src/Pipeline/SpirvShaderMemory.cpp b/src/Pipeline/SpirvShaderMemory.cpp
index 031ae7c..8fcd939 100644
--- a/src/Pipeline/SpirvShaderMemory.cpp
+++ b/src/Pipeline/SpirvShaderMemory.cpp
@@ -225,8 +225,9 @@
 		Object::ID initializerId = insn.word(4);
 		if(getObject(initializerId).kind != Object::Kind::Constant)
 		{
-			UNSUPPORTED("Non-constant initializers not yet implemented");
+			UNIMPLEMENTED("Non-constant initializers not yet implemented");
 		}
+
 		switch(objectTy.storageClass)
 		{
 			case spv::StorageClassOutput:
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index 414e748..3e9aea5 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -547,26 +547,30 @@
 			context.depthBias = executionState.dynamicState.depthBiasConstantFactor;
 			context.slopeDepthBias = executionState.dynamicState.depthBiasSlopeFactor;
 		}
+
 		if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS) && context.depthBoundsTestEnable)
 		{
-			// Unless the VK_EXT_depth_range_unrestricted extension is enabled minDepthBounds and maxDepthBounds must be between 0.0 and 1.0, inclusive
+			// Unless the VK_EXT_depth_range_unrestricted extension is enabled, minDepthBounds and maxDepthBounds must be between 0.0 and 1.0, inclusive
 			ASSERT(executionState.dynamicState.minDepthBounds >= 0.0f &&
 			       executionState.dynamicState.minDepthBounds <= 1.0f);
 			ASSERT(executionState.dynamicState.maxDepthBounds >= 0.0f &&
 			       executionState.dynamicState.maxDepthBounds <= 1.0f);
 
-			UNSUPPORTED("depthBoundsTestEnable");
+			UNSUPPORTED("VkPhysicalDeviceFeatures::depthBounds");
 		}
+
 		if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) && context.stencilEnable)
 		{
 			context.frontStencil.compareMask = executionState.dynamicState.compareMask[0];
 			context.backStencil.compareMask = executionState.dynamicState.compareMask[1];
 		}
+
 		if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) && context.stencilEnable)
 		{
 			context.frontStencil.writeMask = executionState.dynamicState.writeMask[0];
 			context.backStencil.writeMask = executionState.dynamicState.writeMask[1];
 		}
+
 		if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE) && context.stencilEnable)
 		{
 			context.frontStencil.reference = executionState.dynamicState.reference[0];
@@ -593,7 +597,7 @@
 						processPrimitiveRestart(static_cast<uint32_t *>(indexBuffer), count, pipeline, indexBuffers);
 						break;
 					default:
-						UNSUPPORTED("executionState.indexType %d", int(executionState.indexType));
+						UNSUPPORTED("VkIndexType %d", int(executionState.indexType));
 				}
 			}
 			else
@@ -1319,6 +1323,17 @@
 
 	// pInheritanceInfo merely contains optimization hints, so we currently ignore it
 
+	// "pInheritanceInfo is a pointer to a VkCommandBufferInheritanceInfo structure, used if commandBuffer is a
+	//  secondary command buffer. If this is a primary command buffer, then this value is ignored."
+	if(level == VK_COMMAND_BUFFER_LEVEL_SECONDARY)
+	{
+		if(pInheritanceInfo->queryFlags != 0)
+		{
+			// "If the inherited queries feature is not enabled, queryFlags must be 0"
+			UNSUPPORTED("VkPhysicalDeviceFeatures::inheritedQueries");
+		}
+	}
+
 	if(state != INITIAL)
 	{
 		// Implicit reset
@@ -1427,7 +1442,7 @@
 			addCommand<::CmdPipelineBind>(pipelineBindPoint, pipeline);
 			break;
 		default:
-			UNSUPPORTED("pipelineBindPoint");
+			UNSUPPORTED("VkPipelineBindPoint %d", int(pipelineBindPoint));
 	}
 }
 
@@ -1476,7 +1491,7 @@
 {
 	if(firstViewport != 0 || viewportCount > 1)
 	{
-		UNSUPPORTED("viewport");
+		UNSUPPORTED("VkPhysicalDeviceFeatures::multiViewport");
 	}
 
 	for(uint32_t i = 0; i < viewportCount; i++)
@@ -1489,7 +1504,7 @@
 {
 	if(firstScissor != 0 || scissorCount > 1)
 	{
-		UNSUPPORTED("scissor");
+		UNSUPPORTED("VkPhysicalDeviceFeatures::multiViewport");
 	}
 
 	for(uint32_t i = 0; i < scissorCount; i++)
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index 901a511..c7af54c 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -93,7 +93,7 @@
 	if(pCreateInfo->enabledLayerCount)
 	{
 		// "The ppEnabledLayerNames and enabledLayerCount members of VkDeviceCreateInfo are deprecated and their values must be ignored by implementations."
-		UNSUPPORTED("enabledLayerCount");  // TODO(b/119321052): UNSUPPORTED() should be used only for features that must still be implemented. Use a more informational macro here.
+		UNSUPPORTED("enabledLayerCount");
 	}
 
 	// FIXME (b/119409619): use an allocator here so we can control all memory allocations
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
index 281773b..6cd2c93 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
@@ -55,7 +55,7 @@
 
 						if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
 						{
-							UNSUPPORTED("exportInfo->handleTypes");
+							UNIMPLEMENTED("exportInfo->handleTypes");
 						}
 						exportAhb = true;
 					}
@@ -146,7 +146,7 @@
 
 	static VkResult getAhbProperties(const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
 	{
-		UNSUPPORTED("getAhbProperties");
+		UNIMPLEMENTED("getAhbProperties");
 		return VK_SUCCESS;
 	}
 
diff --git a/src/Vulkan/VkDeviceMemoryExternalLinux.hpp b/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
index b85aecd..89dd4f9 100644
--- a/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
@@ -47,7 +47,7 @@
 
 						if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
 						{
-							UNSUPPORTED("importInfo->handleType");
+							UNIMPLEMENTED("importInfo->handleType");
 						}
 						importFd = true;
 						fd = importInfo->fd;
@@ -59,7 +59,7 @@
 
 						if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
 						{
-							UNSUPPORTED("exportInfo->handleTypes");
+							UNIMPLEMENTED("exportInfo->handleTypes");
 						}
 						exportFd = true;
 					}
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index 0cdd5ca..2a462ca 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -894,7 +894,7 @@
 {
 	if(!(subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT))
 	{
-		UNSUPPORTED("aspectMask");
+		UNIMPLEMENTED("aspectMask");
 	}
 
 	device->getBlitter()->clear((void *)color.float32, getClearFormat(), this, format, subresourceRange);
@@ -905,7 +905,7 @@
 	if((subresourceRange.aspectMask & ~(VK_IMAGE_ASPECT_DEPTH_BIT |
 	                                    VK_IMAGE_ASPECT_STENCIL_BIT)) != 0)
 	{
-		UNSUPPORTED("aspectMask");
+		UNIMPLEMENTED("aspectMask");
 	}
 
 	if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
@@ -929,7 +929,7 @@
 	     (subresourceRange.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT |
 	                                     VK_IMAGE_ASPECT_STENCIL_BIT))))
 	{
-		UNSUPPORTED("subresourceRange");
+		UNIMPLEMENTED("subresourceRange");
 	}
 
 	if(subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT)
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp
index 8f065fe..3142cfb 100644
--- a/src/Vulkan/VkImageView.cpp
+++ b/src/Vulkan/VkImageView.cpp
@@ -120,12 +120,12 @@
 
 	if(!imageTypesMatch(image->getImageType()))
 	{
-		UNSUPPORTED("imageTypesMatch");
+		UNIMPLEMENTED("imageTypesMatch");
 	}
 
 	if(!format.isCompatible(image->getFormat()))
 	{
-		UNSUPPORTED("incompatible formats");
+		UNIMPLEMENTED("incompatible formats");
 	}
 
 	VkImageSubresourceRange sr = subresourceRange;
@@ -139,12 +139,12 @@
 
 	if(!imageTypesMatch(image->getImageType()))
 	{
-		UNSUPPORTED("imageTypesMatch");
+		UNIMPLEMENTED("imageTypesMatch");
 	}
 
 	if(!format.isCompatible(image->getFormat()))
 	{
-		UNSUPPORTED("incompatible formats");
+		UNIMPLEMENTED("incompatible formats");
 	}
 
 	VkImageSubresourceRange sr;
@@ -173,7 +173,7 @@
 {
 	if((subresourceRange.levelCount != 1) || (resolveAttachment->subresourceRange.levelCount != 1))
 	{
-		UNSUPPORTED("levelCount");
+		UNIMPLEMENTED("levelCount");
 	}
 
 	VkImageCopy region;
@@ -201,7 +201,7 @@
 {
 	if((subresourceRange.levelCount != 1) || (resolveAttachment->subresourceRange.levelCount != 1))
 	{
-		UNSUPPORTED("levelCount");
+		UNIMPLEMENTED("levelCount");
 	}
 
 	VkImageCopy region;
@@ -244,7 +244,7 @@
 		case SAMPLING:
 			return image->getSampledImage(format);
 		default:
-			UNSUPPORTED("usage %d", int(usage));
+			UNREACHABLE("usage %d", int(usage));
 			return nullptr;
 	}
 }
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 19ab8a3..9937dec 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -149,17 +149,27 @@
 {
 	context.robustBufferAccess = robustBufferAccess;
 
-	if(((pCreateInfo->flags &
-	     ~(VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT |
-	       VK_PIPELINE_CREATE_DERIVATIVE_BIT |
-	       VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) != 0) ||
-	   (pCreateInfo->pTessellationState != nullptr))
+	if((pCreateInfo->flags &
+	    ~(VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT |
+	      VK_PIPELINE_CREATE_DERIVATIVE_BIT |
+	      VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) != 0)
 	{
-		UNSUPPORTED("pCreateInfo settings");
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
+	}
+
+	if(pCreateInfo->pTessellationState != nullptr)
+	{
+		UNSUPPORTED("pCreateInfo->pTessellationState");
 	}
 
 	if(pCreateInfo->pDynamicState)
 	{
+		if(pCreateInfo->pDynamicState->flags != 0)
+		{
+			// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+			UNSUPPORTED("pCreateInfo->pDynamicState->flags %d", int(pCreateInfo->pDynamicState->flags));
+		}
+
 		for(uint32_t i = 0; i < pCreateInfo->pDynamicState->dynamicStateCount; i++)
 		{
 			VkDynamicState dynamicState = pCreateInfo->pDynamicState->pDynamicStates[i];
@@ -178,14 +188,16 @@
 					dynamicStateFlags |= (1 << dynamicState);
 					break;
 				default:
-					UNSUPPORTED("dynamic state");
+					UNSUPPORTED("VkDynamicState %d", int(dynamicState));
 			}
 		}
 	}
 
 	const VkPipelineVertexInputStateCreateInfo *vertexInputState = pCreateInfo->pVertexInputState;
+
 	if(vertexInputState->flags != 0)
 	{
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
 		UNSUPPORTED("vertexInputState->flags");
 	}
 
@@ -214,23 +226,30 @@
 		input.instanceStride = instanceStrides[desc.binding];
 	}
 
-	const VkPipelineInputAssemblyStateCreateInfo *assemblyState = pCreateInfo->pInputAssemblyState;
-	if(assemblyState->flags != 0)
+	const VkPipelineInputAssemblyStateCreateInfo *inputAssemblyState = pCreateInfo->pInputAssemblyState;
+
+	if(inputAssemblyState->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->pInputAssemblyState settings");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->pInputAssemblyState->flags %d", int(pCreateInfo->pInputAssemblyState->flags));
 	}
 
-	primitiveRestartEnable = (assemblyState->primitiveRestartEnable != VK_FALSE);
-	context.topology = assemblyState->topology;
+	primitiveRestartEnable = (inputAssemblyState->primitiveRestartEnable != VK_FALSE);
+	context.topology = inputAssemblyState->topology;
 
 	const VkPipelineViewportStateCreateInfo *viewportState = pCreateInfo->pViewportState;
 	if(viewportState)
 	{
-		if((viewportState->flags != 0) ||
-		   (viewportState->viewportCount != 1) ||
+		if(viewportState->flags != 0)
+		{
+			// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+			UNSUPPORTED("pCreateInfo->pViewportState->flags %d", int(pCreateInfo->pViewportState->flags));
+		}
+
+		if((viewportState->viewportCount != 1) ||
 		   (viewportState->scissorCount != 1))
 		{
-			UNSUPPORTED("pCreateInfo->pViewportState settings");
+			UNSUPPORTED("VkPhysicalDeviceFeatures::multiViewport");
 		}
 
 		if(!hasDynamicState(VK_DYNAMIC_STATE_SCISSOR))
@@ -245,10 +264,16 @@
 	}
 
 	const VkPipelineRasterizationStateCreateInfo *rasterizationState = pCreateInfo->pRasterizationState;
-	if((rasterizationState->flags != 0) ||
-	   (rasterizationState->depthClampEnable != VK_FALSE))
+
+	if(rasterizationState->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->pRasterizationState settings");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->pRasterizationState->flags %d", int(pCreateInfo->pRasterizationState->flags));
+	}
+
+	if(rasterizationState->depthClampEnable != VK_FALSE)
+	{
+		UNSUPPORTED("VkPhysicalDeviceFeatures::depthClamp");
 	}
 
 	context.rasterizerDiscard = (rasterizationState->rasterizerDiscardEnable != VK_FALSE);
@@ -290,6 +315,22 @@
 	const VkPipelineMultisampleStateCreateInfo *multisampleState = pCreateInfo->pMultisampleState;
 	if(multisampleState)
 	{
+		if(multisampleState->flags != 0)
+		{
+			// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+			UNSUPPORTED("pCreateInfo->pMultisampleState->flags %d", int(pCreateInfo->pMultisampleState->flags));
+		}
+
+		if(multisampleState->sampleShadingEnable != VK_FALSE)
+		{
+			UNSUPPORTED("VkPhysicalDeviceFeatures::sampleRateShading");
+		}
+
+		if(multisampleState->alphaToOneEnable != VK_FALSE)
+		{
+			UNSUPPORTED("VkPhysicalDeviceFeatures::alphaToOne");
+		}
+
 		switch(multisampleState->rasterizationSamples)
 		{
 			case VK_SAMPLE_COUNT_1_BIT:
@@ -308,13 +349,6 @@
 		}
 
 		context.alphaToCoverage = (multisampleState->alphaToCoverageEnable != VK_FALSE);
-
-		if((multisampleState->flags != 0) ||
-		   (multisampleState->sampleShadingEnable != VK_FALSE) ||
-		   (multisampleState->alphaToOneEnable != VK_FALSE))
-		{
-			UNSUPPORTED("multisampleState");
-		}
 	}
 	else
 	{
@@ -324,10 +358,15 @@
 	const VkPipelineDepthStencilStateCreateInfo *depthStencilState = pCreateInfo->pDepthStencilState;
 	if(depthStencilState)
 	{
-		if((depthStencilState->flags != 0) ||
-		   (depthStencilState->depthBoundsTestEnable != VK_FALSE))
+		if(depthStencilState->flags != 0)
 		{
-			UNSUPPORTED("depthStencilState");
+			// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+			UNSUPPORTED("pCreateInfo->pDepthStencilState->flags %d", int(pCreateInfo->pDepthStencilState->flags));
+		}
+
+		if(depthStencilState->depthBoundsTestEnable != VK_FALSE)
+		{
+			UNSUPPORTED("VkPhysicalDeviceFeatures::depthBounds");
 		}
 
 		context.depthBoundsTestEnable = (depthStencilState->depthBoundsTestEnable != VK_FALSE);
@@ -346,10 +385,15 @@
 	const VkPipelineColorBlendStateCreateInfo *colorBlendState = pCreateInfo->pColorBlendState;
 	if(colorBlendState)
 	{
-		if((colorBlendState->flags != 0) ||
-		   ((colorBlendState->logicOpEnable != VK_FALSE)))
+		if(pCreateInfo->pColorBlendState->flags != 0)
 		{
-			UNSUPPORTED("colorBlendState");
+			// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+			UNSUPPORTED("pCreateInfo->pColorBlendState->flags %d", int(pCreateInfo->pColorBlendState->flags));
+		}
+
+		if(colorBlendState->logicOpEnable != VK_FALSE)
+		{
+			UNSUPPORTED("VkPhysicalDeviceFeatures::logicOp");
 		}
 
 		if(!hasDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS))
@@ -427,7 +471,8 @@
 	{
 		if(pStage->flags != 0)
 		{
-			UNSUPPORTED("pStage->flags");
+			// Vulkan 1.2: "flags must be 0"
+			UNSUPPORTED("pStage->flags %d", int(pStage->flags));
 		}
 
 		const ShaderModule *module = vk::Cast(pStage->module);
@@ -479,7 +524,7 @@
 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
 			return std::max<uint32_t>(vertexCount, 2) - 2;
 		default:
-			UNSUPPORTED("context.topology %d", int(context.topology));
+			UNSUPPORTED("VkPrimitiveTopology %d", int(context.topology));
 	}
 
 	return 0;
diff --git a/src/Vulkan/VkQueryPool.cpp b/src/Vulkan/VkQueryPool.cpp
index 9330b08..07b29d7 100644
--- a/src/Vulkan/VkQueryPool.cpp
+++ b/src/Vulkan/VkQueryPool.cpp
@@ -92,7 +92,7 @@
     , type(pCreateInfo->queryType)
     , count(pCreateInfo->queryCount)
 {
-	// According to the Vulkan spec, section 34.1. Features:
+	// According to the Vulkan 1.2 spec, section 30. Features:
 	// "pipelineStatisticsQuery specifies whether the pipeline statistics
 	//  queries are supported. If this feature is not enabled, queries of
 	//  type VK_QUERY_TYPE_PIPELINE_STATISTICS cannot be created, and
@@ -100,7 +100,7 @@
 	//  pipelineStatistics member of the VkQueryPoolCreateInfo structure."
 	if(type == VK_QUERY_TYPE_PIPELINE_STATISTICS)
 	{
-		UNSUPPORTED("pCreateInfo->queryType");
+		UNSUPPORTED("VkPhysicalDeviceFeatures::pipelineStatisticsQuery");
 	}
 
 	// Construct all queries
@@ -189,7 +189,7 @@
 
 	if(flags != 0)
 	{
-		UNSUPPORTED("flags");
+		UNIMPLEMENTED("vkCmdBeginQuery::flags %d", int(flags));
 	}
 
 	pool[query].prepare(type);
diff --git a/src/Vulkan/VkQueue.cpp b/src/Vulkan/VkQueue.cpp
index 56434a9..ba08340 100644
--- a/src/Vulkan/VkQueue.cpp
+++ b/src/Vulkan/VkQueue.cpp
@@ -178,7 +178,7 @@
 				submitQueue(task);
 				break;
 			default:
-				UNSUPPORTED("task.type %d", static_cast<int>(task.type));
+				UNREACHABLE("task.type %d", static_cast<int>(task.type));
 				break;
 		}
 	}
diff --git a/src/Vulkan/VkSemaphore.cpp b/src/Vulkan/VkSemaphore.cpp
index efc6c4c..31eb5fd 100644
--- a/src/Vulkan/VkSemaphore.cpp
+++ b/src/Vulkan/VkSemaphore.cpp
@@ -56,7 +56,7 @@
 				exportSemaphore = true;
 				if(exportInfo->handleTypes != Semaphore::External::kExternalSemaphoreHandleType)
 				{
-					UNSUPPORTED("exportInfo->handleTypes");
+					UNIMPLEMENTED("exportInfo->handleTypes");
 				}
 				break;
 			}
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 1dfe97f..6478702 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -265,9 +265,15 @@
 
 	initializeLibrary();
 
-	if(pCreateInfo->enabledLayerCount)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->enabledLayerCount");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
+	}
+
+	if(pCreateInfo->enabledLayerCount != 0)
+	{
+		UNIMPLEMENTED("pCreateInfo->enabledLayerCount != 0");
 	}
 
 	uint32_t extensionPropertiesCount = sizeof(instanceExtensionProperties) / sizeof(instanceExtensionProperties[0]);
@@ -371,7 +377,7 @@
 			break;
 
 		default:
-			UNSUPPORTED("tiling");
+			UNSUPPORTED("VkImageTiling %d", int(tiling));
 			features = 0;
 	}
 
@@ -504,10 +510,16 @@
 	TRACE("(VkPhysicalDevice physicalDevice = %p, const VkDeviceCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkDevice* pDevice = %p)",
 	      physicalDevice, pCreateInfo, pAllocator, pDevice);
 
-	if(pCreateInfo->enabledLayerCount)
+	if(pCreateInfo->flags != 0)
+	{
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
+	}
+
+	if(pCreateInfo->enabledLayerCount != 0)
 	{
 		// "The ppEnabledLayerNames and enabledLayerCount members of VkDeviceCreateInfo are deprecated and their values must be ignored by implementations."
-		UNSUPPORTED("pCreateInfo->enabledLayerCount");
+		UNSUPPORTED("pCreateInfo->enabledLayerCount != 0");
 	}
 
 	uint32_t extensionPropertiesCount = sizeof(deviceExtensionProperties) / sizeof(deviceExtensionProperties[0]);
@@ -660,9 +672,9 @@
 	for(uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)
 	{
 		const VkDeviceQueueCreateInfo &queueCreateInfo = pCreateInfo->pQueueCreateInfos[i];
-		if(queueCreateInfo.flags)
+		if(queueCreateInfo.flags != 0)
 		{
-			UNSUPPORTED("queueCreateInfo.flags");
+			UNSUPPORTED("pCreateInfo->pQueueCreateInfos[%d]->flags %d", i, queueCreateInfo.flags);
 		}
 
 		auto extInfo = reinterpret_cast<VkBaseInStructure const *>(queueCreateInfo.pNext);
@@ -939,6 +951,12 @@
 	TRACE("(VkDevice device = %p, VkDeviceMemory memory = %p, VkDeviceSize offset = %d, VkDeviceSize size = %d, VkMemoryMapFlags flags = %d, void** ppData = %p)",
 	      device, static_cast<void *>(memory), int(offset), int(size), flags, ppData);
 
+	if(flags != 0)
+	{
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("flags %d", int(flags));
+	}
+
 	return vk::Cast(memory)->map(offset, size, ppData);
 }
 
@@ -1112,9 +1130,10 @@
 	TRACE("(VkDevice device = %p, const VkSemaphoreCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkSemaphore* pSemaphore = %p)",
 	      device, pCreateInfo, pAllocator, pSemaphore);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	return vk::Semaphore::Create(pAllocator, pCreateInfo, pSemaphore, pAllocator);
@@ -1136,7 +1155,7 @@
 
 	if(pGetFdInfo->handleType != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT)
 	{
-		UNSUPPORTED("pGetFdInfo->handleType");
+		UNSUPPORTED("pGetFdInfo->handleType %d", int(pGetFdInfo->handleType));
 	}
 
 	return vk::Cast(pGetFdInfo->semaphore)->exportFd(pFd);
@@ -1149,7 +1168,7 @@
 
 	if(pImportSemaphoreInfo->handleType != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT)
 	{
-		UNSUPPORTED("pImportSemaphoreInfo->handleType");
+		UNSUPPORTED("pImportSemaphoreInfo->handleType %d", int(pImportSemaphoreInfo->handleType));
 	}
 	bool temporaryImport = (pImportSemaphoreInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) != 0;
 
@@ -1167,7 +1186,7 @@
 
 	if(pImportSemaphoreZirconHandleInfo->handleType != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA)
 	{
-		UNSUPPORTED("pImportSemaphoreZirconHandleInfo->handleType");
+		UNSUPPORTED("pImportSemaphoreZirconHandleInfo->handleType %d", int(pImportSemaphoreZirconHandleInfo->handleType));
 	}
 	bool temporaryImport = (pImportSemaphoreZirconHandleInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) != 0;
 
@@ -1184,7 +1203,7 @@
 
 	if(pGetZirconHandleInfo->handleType != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA)
 	{
-		UNSUPPORTED("pGetZirconHandleInfo->handleType");
+		UNSUPPORTED("pGetZirconHandleInfo->handleType %d", int(pGetZirconHandleInfo->handleType));
 	}
 
 	return vk::Cast(pGetZirconHandleInfo->semaphore)->exportHandle(pZirconHandle);
@@ -1196,14 +1215,16 @@
 	TRACE("(VkDevice device = %p, const VkEventCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkEvent* pEvent = %p)",
 	      device, pCreateInfo, pAllocator, pEvent);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	auto extInfo = reinterpret_cast<VkBaseInStructure const *>(pCreateInfo->pNext);
 	while(extInfo)
 	{
+		// Vulkan 1.2: "pNext must be NULL"
 		WARN("pCreateInfo->pNext sType = %s", vk::Stringify(extInfo->sType).c_str());
 		extInfo = extInfo->pNext;
 	}
@@ -1249,9 +1270,10 @@
 	TRACE("(VkDevice device = %p, const VkQueryPoolCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkQueryPool* pQueryPool = %p)",
 	      device, pCreateInfo, pAllocator, pQueryPool);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	auto extInfo = reinterpret_cast<VkBaseInStructure const *>(pCreateInfo->pNext);
@@ -1316,9 +1338,10 @@
 	TRACE("(VkDevice device = %p, const VkBufferViewCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkBufferView* pView = %p)",
 	      device, pCreateInfo, pAllocator, pView);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	auto extInfo = reinterpret_cast<VkBaseInStructure const *>(pCreateInfo->pNext);
@@ -1450,9 +1473,9 @@
 	TRACE("(VkDevice device = %p, const VkImageViewCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkImageView* pView = %p)",
 	      device, pCreateInfo, pAllocator, pView);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
@@ -1506,9 +1529,10 @@
 	TRACE("(VkDevice device = %p, const VkShaderModuleCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkShaderModule* pShaderModule = %p)",
 	      device, pCreateInfo, pAllocator, pShaderModule);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	auto *nextInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
@@ -1534,9 +1558,10 @@
 	TRACE("(VkDevice device = %p, const VkPipelineCacheCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkPipelineCache* pPipelineCache = %p)",
 	      device, pCreateInfo, pAllocator, pPipelineCache);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	auto extInfo = reinterpret_cast<VkBaseInStructure const *>(pCreateInfo->pNext);
@@ -1650,9 +1675,10 @@
 	TRACE("(VkDevice device = %p, const VkPipelineLayoutCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkPipelineLayout* pPipelineLayout = %p)",
 	      device, pCreateInfo, pAllocator, pPipelineLayout);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	auto *nextInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
@@ -1678,9 +1704,9 @@
 	TRACE("(VkDevice device = %p, const VkSamplerCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkSampler* pSampler = %p)",
 	      device, pCreateInfo, pAllocator, pSampler);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
@@ -1776,9 +1802,10 @@
 	TRACE("(VkDevice device = %p, VkDescriptorPool descriptorPool = %p, VkDescriptorPoolResetFlags flags = 0x%x)",
 	      device, static_cast<void *>(descriptorPool), int(flags));
 
-	if(flags)
+	if(flags != 0)
 	{
-		UNSUPPORTED("flags");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("flags %d", int(flags));
 	}
 
 	return vk::Cast(descriptorPool)->reset();
@@ -1822,9 +1849,9 @@
 	TRACE("(VkDevice device = %p, const VkFramebufferCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkFramebuffer* pFramebuffer = %p)",
 	      device, pCreateInfo, pAllocator, pFramebuffer);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	auto *nextInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
@@ -1850,9 +1877,10 @@
 	TRACE("(VkDevice device = %p, const VkRenderPassCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkRenderPass* pRenderPass = %p)",
 	      device, pCreateInfo, pAllocator, pRenderPass);
 
-	if(pCreateInfo->flags)
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
 	}
 
 	const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
@@ -2502,7 +2530,7 @@
 	      device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
 
 	ASSERT(localDeviceIndex != remoteDeviceIndex);                 // "localDeviceIndex must not equal remoteDeviceIndex"
-	UNREACHABLE("remoteDeviceIndex: %d", int(remoteDeviceIndex));  // Only one physical device is supported, and since the device indexes can't be equal, this should never be called.
+	UNSUPPORTED("remoteDeviceIndex: %d", int(remoteDeviceIndex));  // Only one physical device is supported, and since the device indexes can't be equal, this should never be called.
 }
 
 VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask)
@@ -2973,6 +3001,12 @@
 	TRACE("(VkDevice device = %p, VkCommandPool commandPool = %p, VkCommandPoolTrimFlags flags = %d)",
 	      device, static_cast<void *>(commandPool), flags);
 
+	if(flags != 0)
+	{
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("flags %d", int(flags));
+	}
+
 	vk::Cast(commandPool)->trim(flags);
 }
 
@@ -2988,19 +3022,17 @@
 		extInfo = extInfo->pNext;
 	}
 
-	// The only flag that can be set here is VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT
-	// According to the Vulkan spec, 4.3.1. Queue Family Properties:
-	// "VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT specifies that the device queue is a
-	//  protected-capable queue. If the protected memory feature is not enabled,
-	//  the VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT bit of flags must not be set."
-	if(pQueueInfo->flags)
+	if(pQueueInfo->flags != 0)
 	{
-		*pQueue = VK_NULL_HANDLE;
+		// The only flag that can be set here is VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT
+		// According to the Vulkan 1.2.132 spec, 4.3.1. Queue Family Properties:
+		// "VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT specifies that the device queue is a
+		//  protected-capable queue. If the protected memory feature is not enabled,
+		//  the VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT bit of flags must not be set."
+		UNSUPPORTED("VkPhysicalDeviceVulkan11Features::protectedMemory");
 	}
-	else
-	{
-		vkGetDeviceQueue(device, pQueueInfo->queueFamilyIndex, pQueueInfo->queueIndex, pQueue);
-	}
+
+	vkGetDeviceQueue(device, pQueueInfo->queueFamilyIndex, pQueueInfo->queueIndex, pQueue);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSamplerYcbcrConversion *pYcbcrConversion)
@@ -3031,9 +3063,15 @@
 	TRACE("(VkDevice device = %p, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate = %p)",
 	      device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
 
-	if(pCreateInfo->flags || (pCreateInfo->templateType != VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET))
+	if(pCreateInfo->flags != 0)
 	{
-		UNSUPPORTED("pCreateInfo->flags || (pCreateInfo->templateType != VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET)");
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
+	}
+
+	if(pCreateInfo->templateType != VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET)
+	{
+		UNSUPPORTED("pCreateInfo->templateType %d", int(pCreateInfo->templateType));
 	}
 
 	auto extInfo = reinterpret_cast<VkBaseInStructure const *>(pCreateInfo->pNext);
@@ -3099,7 +3137,7 @@
 	TRACE("(VkCommandBuffer commandBuffer = %p, uint32_t lineStippleFactor = %u, uint16_t lineStipplePattern = %u",
 	      commandBuffer, lineStippleFactor, lineStipplePattern);
 
-	UNSUPPORTED("Line stipple not supported");
+	UNSUPPORTED("VkPhysicalDeviceLineRasterizationFeaturesEXT::stippled*Lines");
 }
 
 #ifdef VK_USE_PLATFORM_XCB_KHR