Add ability to generate images with the reference renderer

*Separate DrawContext into a DrawContext and DrawContextState to reflect
  graphics API's are split between state and action parts
* Add abstract DrawContext class

Test: Test clipping and synchronization primitives

Change-Id: I9f3945c6c3de169325fadea7bf70a9d5d7bfd932
diff --git a/external/vulkancts/modules/vulkan/clipping/vktClippingTests.cpp b/external/vulkancts/modules/vulkan/clipping/vktClippingTests.cpp
index 7fb1fca..8bb6878 100644
--- a/external/vulkancts/modules/vulkan/clipping/vktClippingTests.cpp
+++ b/external/vulkancts/modules/vulkan/clipping/vktClippingTests.cpp
@@ -46,6 +46,17 @@
 using tcu::IVec2;
 using namespace drawutil;
 
+enum TestConstants
+{
+	RENDER_SIZE								= 16,
+	RENDER_SIZE_LARGE						= 128,
+	NUM_RENDER_PIXELS						= RENDER_SIZE * RENDER_SIZE,
+	NUM_PATCH_CONTROL_POINTS				= 3,
+	MAX_CLIP_DISTANCES						= 8,
+	MAX_CULL_DISTANCES						= 8,
+	MAX_COMBINED_CLIP_AND_CULL_DISTANCES	= 8,
+};
+
 enum FeatureFlagBits
 {
 	FEATURE_TESSELLATION_SHADER							= 1u << 0,
@@ -382,7 +393,11 @@
 		log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage;
 
 		const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 0.0f);
-		DrawContext drawContext(context, shaders, vertices, topology);
+		DrawState			drawState		(topology, RENDER_SIZE, RENDER_SIZE);
+		DrawCallData		drawCallData	(vertices);
+		VulkanProgram		vulkanProgram	(shaders);
+
+		VulkanDrawContext	drawContext(context, drawState, drawCallData, vulkanProgram);
 		drawContext.draw();
 
 		const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
@@ -420,7 +435,11 @@
 		log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage;
 
 		const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 0.0f);
-		DrawContext drawContext(context, shaders, vertices, topology);
+		DrawState				drawState		(topology, RENDER_SIZE, RENDER_SIZE);
+		DrawCallData			drawCallData	(vertices);
+		VulkanProgram			vulkanProgram	(shaders);
+
+		VulkanDrawContext		drawContext(context, drawState, drawCallData, vulkanProgram);
 		drawContext.draw();
 
 		// All pixels must be black -- nothing is drawn.
@@ -500,7 +519,13 @@
 		log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage;
 
 		const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 1.0f);
-		DrawContext drawContext(context, shaders, vertices, topology, static_cast<deUint32>(RENDER_SIZE), cases[caseNdx].depthClampEnable);
+
+		DrawState					drawState		(topology, RENDER_SIZE, RENDER_SIZE);
+		DrawCallData				drawCallData	(vertices);
+		VulkanProgram				vulkanProgram	(shaders);
+		drawState.depthClampEnable = cases[caseNdx].depthClampEnable;
+
+		VulkanDrawContext			drawContext(context, drawState, drawCallData, vulkanProgram);
 		drawContext.draw();
 
 		const int numPixels = countPixels(drawContext.getColorPixels(), cases[caseNdx].regionOffset, regionSize, cases[caseNdx].color, Vec4());
@@ -542,7 +567,11 @@
 
 	log << tcu::TestLog::Message << "Drawing several large points just outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage;
 
-	DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
+	DrawState			drawState		(VK_PRIMITIVE_TOPOLOGY_POINT_LIST, RENDER_SIZE, RENDER_SIZE);
+	DrawCallData		drawCallData	(vertices);
+	VulkanProgram		vulkanProgram	(shaders);
+
+	VulkanDrawContext	drawContext(context, drawState, drawCallData, vulkanProgram);
 	drawContext.draw();
 
 	// All pixels must be black -- nothing is drawn.
@@ -605,7 +634,12 @@
 	log << tcu::TestLog::Message << "Drawing several wide lines just outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage
 		<< tcu::TestLog::Message << "Line width is " << lineWidth << "." << tcu::TestLog::EndMessage;
 
-	DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, static_cast<deUint32>(RENDER_SIZE), false, false, lineWidth);
+	DrawState					drawState		(VK_PRIMITIVE_TOPOLOGY_LINE_LIST, RENDER_SIZE, RENDER_SIZE);
+	DrawCallData				drawCallData	(vertices);
+	VulkanProgram				vulkanProgram	(shaders);
+	drawState.lineWidth			= lineWidth;
+
+	VulkanDrawContext			drawContext(context, drawState, drawCallData, vulkanProgram);
 	drawContext.draw();
 
 	// All pixels must be black -- nothing is drawn.
@@ -929,7 +963,14 @@
 		<< tcu::TestLog::Message << "Using " << caseDef.numClipDistances << " ClipDistance(s) and " << caseDef.numCullDistances << " CullDistance(s)" << tcu::TestLog::EndMessage
 		<< tcu::TestLog::Message << "Expecting upper half of the clipped bars to be black." << tcu::TestLog::EndMessage;
 
-	DrawContext drawContext(context, shaders, vertices, caseDef.topology);
+	DrawState			drawState		(caseDef.topology, RENDER_SIZE, RENDER_SIZE);
+	DrawCallData		drawCallData	(vertices);
+	VulkanProgram		vulkanProgram	(shaders);
+
+	if (caseDef.enableTessellation)
+		drawState.numPatchControlPoints = NUM_PATCH_CONTROL_POINTS;
+
+	VulkanDrawContext	drawContext(context, drawState, drawCallData, vulkanProgram);
 	drawContext.draw();
 
 	// Count black pixels in the whole image.
@@ -1050,7 +1091,12 @@
 		<< tcu::TestLog::Message << "Using " << numClipDistances << " clipping plane(s), one of them possibly having negative values." << tcu::TestLog::EndMessage
 		<< tcu::TestLog::Message << "Expecting a uniform gray area, no missing (black) nor overlapped (white) pixels." << tcu::TestLog::EndMessage;
 
-	DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, static_cast<deUint32>(RENDER_SIZE_LARGE), false, true);
+	DrawState					drawState		(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, RENDER_SIZE_LARGE, RENDER_SIZE_LARGE);
+	DrawCallData				drawCallData	(vertices);
+	VulkanProgram				vulkanProgram	(shaders);
+	drawState.blendEnable		= true;
+
+	VulkanDrawContext			drawContext(context, drawState, drawCallData, vulkanProgram);
 	drawContext.draw();
 
 	const int numGrayPixels		= countPixels(drawContext.getColorPixels(), Vec4(0.5f, 0.5f, 0.5f, 1.0f), Vec4(0.02f, 0.02f, 0.02f, 0.0f));
diff --git a/external/vulkancts/modules/vulkan/vktDrawUtil.cpp b/external/vulkancts/modules/vulkan/vktDrawUtil.cpp
index a261952..f140052 100644
--- a/external/vulkancts/modules/vulkan/vktDrawUtil.cpp
+++ b/external/vulkancts/modules/vulkan/vktDrawUtil.cpp
@@ -23,9 +23,14 @@
  *//*--------------------------------------------------------------------*/
 
 #include "vktDrawUtil.hpp"
+#include "rrMultisamplePixelBufferAccess.hpp"
 #include "vkBufferWithMemory.hpp"
 #include "vkImageWithMemory.hpp"
 #include "vkTypeUtil.hpp"
+#include "rrRenderer.hpp"
+#include "rrPrimitiveTypes.hpp"
+#include "tcuTextureUtil.hpp"
+#include "deArrayUtil.hpp"
 
 namespace vkt
 {
@@ -36,6 +41,25 @@
 using namespace tcu;
 using namespace vk;
 
+rr::PrimitiveType mapVkPrimitiveToRRPrimitive(const vk::VkPrimitiveTopology& primitiveTopology)
+{
+	static const rr::PrimitiveType primitiveTypeTable[] =
+	{
+		rr::PRIMITIVETYPE_POINTS,
+		rr::PRIMITIVETYPE_LINES,
+		rr::PRIMITIVETYPE_LINE_STRIP,
+		rr::PRIMITIVETYPE_TRIANGLES,
+		rr::PRIMITIVETYPE_TRIANGLE_STRIP,
+		rr::PRIMITIVETYPE_TRIANGLE_FAN,
+		rr::PRIMITIVETYPE_LINES_ADJACENCY,
+		rr::PRIMITIVETYPE_LINE_STRIP_ADJACENCY,
+		rr::PRIMITIVETYPE_TRIANGLES_ADJACENCY,
+		rr::PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY
+	};
+
+	return de::getSizedArrayElement<vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST>(primitiveTypeTable, primitiveTopology);
+}
+
 VkBufferCreateInfo makeBufferCreateInfo (const VkDeviceSize			bufferSize,
 										 const VkBufferUsageFlags	usage)
 {
@@ -211,10 +235,10 @@
 {
 	const VkCommandBufferBeginInfo info =
 	{
-		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// VkStructureType                          sType;
-		DE_NULL,										// const void*                              pNext;
-		VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,	// VkCommandBufferUsageFlags                flags;
-		DE_NULL,										// const VkCommandBufferInheritanceInfo*    pInheritanceInfo;
+		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// VkStructureType							sType;
+		DE_NULL,										// const void*								pNext;
+		VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,	// VkCommandBufferUsageFlags				flags;
+		DE_NULL,										// const VkCommandBufferInheritanceInfo*	pInheritanceInfo;
 	};
 	VK_CHECK(vk.beginCommandBuffer(commandBuffer, &info));
 }
@@ -239,15 +263,15 @@
 
 	const VkSubmitInfo submitInfo =
 	{
-		VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType                sType;
-		DE_NULL,							// const void*                    pNext;
-		0u,									// uint32_t                       waitSemaphoreCount;
-		DE_NULL,							// const VkSemaphore*             pWaitSemaphores;
-		DE_NULL,							// const VkPipelineStageFlags*    pWaitDstStageMask;
-		1u,									// uint32_t                       commandBufferCount;
-		&commandBuffer,						// const VkCommandBuffer*         pCommandBuffers;
-		0u,									// uint32_t                       signalSemaphoreCount;
-		DE_NULL,							// const VkSemaphore*             pSignalSemaphores;
+		VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType					sType;
+		DE_NULL,							// const void*						pNext;
+		0u,									// uint32_t							waitSemaphoreCount;
+		DE_NULL,							// const VkSemaphore*				pWaitSemaphores;
+		DE_NULL,							// const VkPipelineStageFlags*		pWaitDstStageMask;
+		1u,									// uint32_t							commandBufferCount;
+		&commandBuffer,						// const VkCommandBuffer*			pCommandBuffers;
+		0u,									// uint32_t							signalSemaphoreCount;
+		DE_NULL,							// const VkSemaphore*				pSignalSemaphores;
 	};
 	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
 	VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
@@ -258,66 +282,109 @@
 	std::string name(getPrimitiveTopologyName(topology));
 	return de::toLower(name.substr(22));
 }
-DrawContext::DrawContext (Context&						context,
-						  const std::vector<Shader>&	shaders,
-						  const std::vector<Vec4>&		vertices,
-						  const VkPrimitiveTopology		primitiveTopology,
-						  const deUint32				renderSize,
-						  const bool					depthClampEnable,
-						  const bool					blendEnable,
-						  const float					lineWidth)
-	: m_context					(context)
-	, m_colorFormat				(VK_FORMAT_R8G8B8A8_UNORM)
-	, m_depthFormat				(VK_FORMAT_D32_SFLOAT)
-	, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
-	, m_depthSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u))
-	, m_renderSize				(renderSize, renderSize)
-	, m_imageExtent				(makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u))
-	, m_primitiveTopology		(primitiveTopology)
-	, m_depthClampEnable		(depthClampEnable)
-	, m_blendEnable				(blendEnable)
-	, m_numVertices				(static_cast<deUint32>(vertices.size()))
-	, m_lineWidth				(lineWidth)
-	, m_numPatchControlPoints	(NUM_PATCH_CONTROL_POINTS)		// we're treating patches as triangles
+
+DrawState::DrawState(const vk::VkPrimitiveTopology topology_, deUint32 renderWidth_, deUint32 renderHeight_)
+	: topology				(topology_)
+	, colorFormat			(VK_FORMAT_R8G8B8A8_UNORM)
+	, depthFormat			(VK_FORMAT_D32_SFLOAT)
+	, renderSize			(tcu::UVec2(renderWidth_, renderHeight_))
+	, depthClampEnable		(false)
+	, blendEnable			(false)
+	, lineWidth				(1.0)
+	, numPatchControlPoints	(0)
 {
-	const DeviceInterface&	vk			= m_context.getDeviceInterface();
-	const VkDevice			device		= m_context.getDevice();
-	Allocator&				allocator	= m_context.getDefaultAllocator();
+	DE_ASSERT(renderSize.x() != 0 && renderSize.y() != 0);
+}
+
+ReferenceDrawContext::~ReferenceDrawContext (void)
+{
+}
+
+void ReferenceDrawContext::draw (void)
+{
+	m_refImage.setStorage(vk::mapVkFormat(m_drawState.colorFormat), m_drawState.renderSize.x(), m_drawState.renderSize.y());
+	tcu::clear(m_refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+
+	{
+		const rr::Program						program(&m_vertexShader, &m_fragmentShader);
+		const rr::MultisamplePixelBufferAccess	referenceColorBuffer = rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(m_refImage.getAccess());
+		const rr::RenderTarget					renderTarget(referenceColorBuffer);
+		const rr::RenderState					renderState((rr::ViewportState(referenceColorBuffer)), rr::VIEWPORTORIENTATION_UPPER_LEFT);
+		const rr::Renderer						renderer;
+		const rr::VertexAttrib					vertexAttrib[] =
+		{
+			rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &m_drawCallData.vertices[0])
+		};
+
+		renderer.draw(rr::DrawCommand(	renderState,
+										renderTarget,
+										program,
+										DE_LENGTH_OF_ARRAY(vertexAttrib),
+										&vertexAttrib[0],
+										rr::PrimitiveList(mapVkPrimitiveToRRPrimitive(m_drawState.topology), (int)m_drawCallData.vertices.size(), 0)));
+
+	}
+
+}
+
+tcu::ConstPixelBufferAccess ReferenceDrawContext::getColorPixels (void) const
+{
+	return tcu::ConstPixelBufferAccess( m_refImage.getAccess().getFormat(),
+										m_refImage.getAccess().getWidth(),
+										m_refImage.getAccess().getHeight(),
+										m_refImage.getAccess().getDepth(),
+										m_refImage.getAccess().getDataPtr());
+}
+
+VulkanDrawContext::VulkanDrawContext (  Context&				context,
+										const DrawState&		drawState,
+										const DrawCallData&		drawCallData,
+										const VulkanProgram&	vulkanProgram)
+	: DrawContext						(drawState, drawCallData)
+	, m_context							(context)
+	, m_program							(vulkanProgram)
+{
+	const DeviceInterface&	vk						= m_context.getDeviceInterface();
+	const VkDevice			device					= m_context.getDevice();
+	Allocator&				allocator				= m_context.getDefaultAllocator();
+	VkImageSubresourceRange	colorSubresourceRange;
+	VkImageSubresourceRange	depthSubresourceRange;
 
 	// Command buffer
 	{
-		m_cmdPool	= makeCommandPool(vk, device, m_context.getUniversalQueueFamilyIndex());
-		m_cmdBuffer	= makeCommandBuffer(vk, device, *m_cmdPool);
+		m_cmdPool			= makeCommandPool(vk, device, m_context.getUniversalQueueFamilyIndex());
+		m_cmdBuffer			= makeCommandBuffer(vk, device, *m_cmdPool);
 	}
 
 	// Color attachment image
 	{
 		const VkImageUsageFlags usage			= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+		colorSubresourceRange					= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
 		const VkImageCreateInfo	imageCreateInfo	=
 		{
-			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType          sType;
-			DE_NULL,									// const void*              pNext;
-			(VkImageCreateFlags)0,						// VkImageCreateFlags       flags;
-			VK_IMAGE_TYPE_2D,							// VkImageType              imageType;
-			m_colorFormat,								// VkFormat                 format;
-			m_imageExtent,								// VkExtent3D               extent;
-			1u,											// uint32_t                 mipLevels;
-			1u,											// uint32_t                 arrayLayers;
-			VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits    samples;
-			VK_IMAGE_TILING_OPTIMAL,					// VkImageTiling            tiling;
-			usage,										// VkImageUsageFlags        usage;
-			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode            sharingMode;
-			VK_QUEUE_FAMILY_IGNORED,					// uint32_t                 queueFamilyIndexCount;
-			DE_NULL,									// const uint32_t*          pQueueFamilyIndices;
-			VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout            initialLayout;
+			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType			sType;
+			DE_NULL,																	// const void*				pNext;
+			(VkImageCreateFlags)0,														// VkImageCreateFlags		flags;
+			VK_IMAGE_TYPE_2D,															// VkImageType				imageType;
+			m_drawState.colorFormat,													// VkFormat					format;
+			makeExtent3D(m_drawState.renderSize.x(), m_drawState.renderSize.y(), 1u),	// VkExtent3D				extent;
+			1u,																			// uint32_t					mipLevels;
+			1u,																			// uint32_t					arrayLayers;
+			VK_SAMPLE_COUNT_1_BIT,														// VkSampleCountFlagBits	samples;
+			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling			tiling;
+			usage,																		// VkImageUsageFlags		usage;
+			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode			sharingMode;
+			VK_QUEUE_FAMILY_IGNORED,													// uint32_t					queueFamilyIndexCount;
+			DE_NULL,																	// const uint32_t*			pQueueFamilyIndices;
+			VK_IMAGE_LAYOUT_UNDEFINED,													// VkImageLayout			initialLayout;
 		};
 
 		m_colorImage = MovePtr<ImageWithMemory>(new ImageWithMemory(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
-		m_colorImageView = makeImageView(vk, device, **m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
+		m_colorImageView = makeImageView(vk, device, **m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_drawState.colorFormat, colorSubresourceRange);
 
 		// Buffer to copy attachment data after rendering
 
-		const VkDeviceSize bitmapSize = tcu::getPixelSize(mapVkFormat(m_colorFormat)) * m_renderSize.x() * m_renderSize.y();
+		const VkDeviceSize bitmapSize = tcu::getPixelSize(mapVkFormat(m_drawState.colorFormat)) * m_drawState.renderSize.x() * m_drawState.renderSize.y();
 		m_colorAttachmentBuffer = MovePtr<BufferWithMemory>(new BufferWithMemory(
 			vk, device, allocator, makeBufferCreateInfo(bitmapSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible));
 
@@ -330,37 +397,38 @@
 
 	// Depth attachment image
 	{
+		depthSubresourceRange					= makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u);
 		const VkImageCreateInfo imageCreateInfo	=
 		{
-			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType
-			DE_NULL,										// const void*				pNext
-			0u,												// VkImageCreateFlags		flags
-			VK_IMAGE_TYPE_2D,								// VkImageType				imageType
-			m_depthFormat,									// VkFormat					depthFormat
-			{ m_renderSize.x(), m_renderSize.y(), 1u },		// VkExtent3D				externt
-			1u,												// deUint32					mipLevels
-			1u,												// deUint32					arrayLayers
-			VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples
-			VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling
-			VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,	// VkImageUsageFlags		usage
-			VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode
-			0u,												// deUint32					queueFamilyIndexCount
-			DE_NULL,										// const deUint32*			pQueueFamilyIndices
-			VK_IMAGE_LAYOUT_UNDEFINED						// VkImageLayout			initialLayout
+			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,						// VkStructureType			sType
+			DE_NULL,													// const void*				pNext
+			0u,															// VkImageCreateFlags		flags
+			VK_IMAGE_TYPE_2D,											// VkImageType				imageType
+			m_drawState.depthFormat,									// VkFormat					depthFormat
+			{ m_drawState.renderSize.x(), m_drawState.renderSize.y(), 1u },		// VkExtent3D				externt
+			1u,															// deUint32					mipLevels
+			1u,															// deUint32					arrayLayers
+			VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits	samples
+			VK_IMAGE_TILING_OPTIMAL,									// VkImageTiling			tiling
+			VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,				// VkImageUsageFlags		usage
+			VK_SHARING_MODE_EXCLUSIVE,									// VkSharingMode			sharingMode
+			0u,															// deUint32					queueFamilyIndexCount
+			DE_NULL,													// const deUint32*			pQueueFamilyIndices
+			VK_IMAGE_LAYOUT_UNDEFINED									// VkImageLayout			initialLayout
 		};
 
-		m_depthImage = MovePtr<ImageWithMemory>(new ImageWithMemory(vk, device, allocator, imageCreateInfo, MemoryRequirement::HostVisible));
-		m_depthImageView = makeImageView(vk, device, **m_depthImage, VK_IMAGE_VIEW_TYPE_2D, m_depthFormat, m_depthSubresourceRange);
+		m_depthImage = MovePtr<ImageWithMemory>(new ImageWithMemory(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
+		m_depthImageView = makeImageView(vk, device, **m_depthImage, VK_IMAGE_VIEW_TYPE_2D, m_drawState.depthFormat, depthSubresourceRange);
 	}
 
 	// Vertex buffer
 	{
-		const VkDeviceSize bufferSize = vertices.size() * sizeof(vertices[0]);
+		const VkDeviceSize bufferSize = m_drawCallData.vertices.size() * sizeof(m_drawCallData.vertices[0]);
 		m_vertexBuffer = MovePtr<BufferWithMemory>(new BufferWithMemory(
 			vk, device, allocator, makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible));
 
 		const Allocation& alloc = m_vertexBuffer->getAllocation();
-		deMemcpy(alloc.getHostPtr(), &vertices[0], (size_t)bufferSize);
+		deMemcpy(alloc.getHostPtr(), &m_drawCallData.vertices[0], (size_t)bufferSize);
 		flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), bufferSize);
 	}
 
@@ -374,7 +442,7 @@
 		const VkAttachmentDescription colorAttachmentDescription =
 		{
 			(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
-			m_colorFormat,										// VkFormat							format;
+			m_drawState.colorFormat,							// VkFormat							format;
 			VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
 			VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
 			VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
@@ -435,15 +503,15 @@
 		};
 
 		const VkFramebufferCreateInfo framebufferInfo = {
-			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		// VkStructureType                             sType;
-			DE_NULL,										// const void*                                 pNext;
-			(VkFramebufferCreateFlags)0,					// VkFramebufferCreateFlags                    flags;
-			*m_renderPass,									// VkRenderPass                                renderPass;
-			DE_LENGTH_OF_ARRAY(attachmentBindInfos),		// uint32_t                                    attachmentCount;
-			attachmentBindInfos,							// const VkImageView*                          pAttachments;
-			m_renderSize.x(),								// uint32_t                                    width;
-			m_renderSize.y(),								// uint32_t                                    height;
-			1u,												// uint32_t                                    layers;
+			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		// VkStructureType						sType;
+			DE_NULL,										// const void*							pNext;
+			(VkFramebufferCreateFlags)0,					// VkFramebufferCreateFlags				flags;
+			*m_renderPass,									// VkRenderPass							renderPass;
+			DE_LENGTH_OF_ARRAY(attachmentBindInfos),		// uint32_t								attachmentCount;
+			attachmentBindInfos,							// const VkImageView*					pAttachments;
+			m_drawState.renderSize.x(),						// uint32_t								width;
+			m_drawState.renderSize.y(),						// uint32_t								height;
+			1u,												// uint32_t								layers;
 		};
 
 		m_framebuffer = createFramebuffer(vk, device, &framebufferInfo);
@@ -454,6 +522,8 @@
 		const deUint32	vertexStride	= sizeof(Vec4);
 		const VkFormat	vertexFormat	= VK_FORMAT_R32G32B32A32_SFLOAT;
 
+		DE_ASSERT(m_drawState.topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST || m_drawState.numPatchControlPoints > 0);
+
 		const VkVertexInputBindingDescription bindingDesc =
 		{
 			0u,									// uint32_t				binding;
@@ -470,60 +540,60 @@
 
 		const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
 		{
-			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
-			DE_NULL,														// const void*                                 pNext;
-			(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
-			1u,																// uint32_t                                    vertexBindingDescriptionCount;
-			&bindingDesc,													// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
-			1u,																// uint32_t                                    vertexAttributeDescriptionCount;
-			&attributeDesc,													// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
+			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType								sType;
+			DE_NULL,														// const void*									pNext;
+			(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags		flags;
+			1u,																// uint32_t										vertexBindingDescriptionCount;
+			&bindingDesc,													// const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
+			1u,																// uint32_t										vertexAttributeDescriptionCount;
+			&attributeDesc,													// const VkVertexInputAttributeDescription*		pVertexAttributeDescriptions;
 		};
 
 		const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
 		{
-			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
-			DE_NULL,														// const void*                                 pNext;
-			(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
-			m_primitiveTopology,											// VkPrimitiveTopology                         topology;
-			VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
+			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType								sType;
+			DE_NULL,														// const void*									pNext;
+			(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags		flags;
+			m_drawState.topology,											// VkPrimitiveTopology							topology;
+			VK_FALSE,														// VkBool32										primitiveRestartEnable;
 		};
 
 		const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo =
 		{
-			VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,		// VkStructureType                             sType;
-			DE_NULL,														// const void*                                 pNext;
-			(VkPipelineTessellationStateCreateFlags)0,						// VkPipelineTessellationStateCreateFlags      flags;
-			m_numPatchControlPoints,										// uint32_t                                    patchControlPoints;
+			VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,		// VkStructureType								sType;
+			DE_NULL,														// const void*									pNext;
+			(VkPipelineTessellationStateCreateFlags)0,						// VkPipelineTessellationStateCreateFlags		flags;
+			m_drawState.numPatchControlPoints,								// uint32_t										patchControlPoints;
 		};
 
 		const VkViewport viewport = makeViewport(
 			0.0f, 0.0f,
-			static_cast<float>(m_renderSize.x()), static_cast<float>(m_renderSize.y()),
+			static_cast<float>(m_drawState.renderSize.x()), static_cast<float>(m_drawState.renderSize.y()),
 			0.0f, 1.0f);
 
 		const VkRect2D scissor = {
 			makeOffset2D(0, 0),
-			makeExtent2D(m_renderSize.x(), m_renderSize.y()),
+			makeExtent2D(m_drawState.renderSize.x(), m_drawState.renderSize.y()),
 		};
 
 		const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
 		{
-			VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,	// VkStructureType                             sType;
-			DE_NULL,												// const void*                                 pNext;
-			(VkPipelineViewportStateCreateFlags)0,					// VkPipelineViewportStateCreateFlags          flags;
-			1u,														// uint32_t                                    viewportCount;
-			&viewport,												// const VkViewport*                           pViewports;
-			1u,														// uint32_t                                    scissorCount;
-			&scissor,												// const VkRect2D*                             pScissors;
+			VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,	// VkStructureType									sType;
+			DE_NULL,												// const void*										pNext;
+			(VkPipelineViewportStateCreateFlags)0,					// VkPipelineViewportStateCreateFlags				flags;
+			1u,														// uint32_t											viewportCount;
+			&viewport,												// const VkViewport*								pViewports;
+			1u,														// uint32_t											scissorCount;
+			&scissor,												// const VkRect2D*									pScissors;
 		};
 
 		const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
 		{
-			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
-			DE_NULL,														// const void*                              pNext;
-			(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
-			m_depthClampEnable,												// VkBool32                                 depthClampEnable;
-			VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
+			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType							sType;
+			DE_NULL,														// const void*								pNext;
+			(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags	flags;
+			m_drawState.depthClampEnable,									// VkBool32									depthClampEnable;
+			VK_FALSE,														// VkBool32									rasterizerDiscardEnable;
 			VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
 			VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
 			VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
@@ -531,7 +601,7 @@
 			0.0f,															// float									depthBiasConstantFactor;
 			0.0f,															// float									depthBiasClamp;
 			0.0f,															// float									depthBiasSlopeFactor;
-			m_lineWidth,													// float									lineWidth;
+			m_drawState.lineWidth,											// float									lineWidth;
 		};
 
 		const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
@@ -575,7 +645,7 @@
 		const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
 		const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
 		{
-			m_blendEnable,						// VkBool32					blendEnable;
+			m_drawState.blendEnable,			// VkBool32					blendEnable;
 			VK_BLEND_FACTOR_SRC_ALPHA,			// VkBlendFactor			srcColorBlendFactor;
 			VK_BLEND_FACTOR_ONE,				// VkBlendFactor			dstColorBlendFactor;
 			VK_BLEND_OP_ADD,					// VkBlendOp				colorBlendOp;
@@ -602,31 +672,31 @@
 		std::vector<VkPipelineShaderStageCreateInfo>	shaderStages;
 		VkShaderStageFlags								stageFlags = (VkShaderStageFlags)0;
 
-		DE_ASSERT(shaders.size() <= MAX_NUM_SHADER_MODULES);
-		for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx)
+		DE_ASSERT(m_program.shaders.size() <= MAX_NUM_SHADER_MODULES);
+		for (deUint32 shaderNdx = 0; shaderNdx < m_program.shaders.size(); ++shaderNdx)
 		{
-			m_shaderModules[shaderNdx] = createShaderModule(vk, device, *shaders[shaderNdx].binary, (VkShaderModuleCreateFlags)0);
+			m_shaderModules[shaderNdx] = createShaderModule(vk, device, *m_program.shaders[shaderNdx].binary, (VkShaderModuleCreateFlags)0);
 
 			const VkPipelineShaderStageCreateInfo pipelineShaderStageInfo =
 			{
 				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType						sType;
 				DE_NULL,												// const void*							pNext;
 				(VkPipelineShaderStageCreateFlags)0,					// VkPipelineShaderStageCreateFlags		flags;
-				shaders[shaderNdx].stage,								// VkShaderStageFlagBits				stage;
+				m_program.shaders[shaderNdx].stage,						// VkShaderStageFlagBits				stage;
 				*m_shaderModules[shaderNdx],							// VkShaderModule						module;
 				"main",													// const char*							pName;
 				DE_NULL,												// const VkSpecializationInfo*			pSpecializationInfo;
 			};
 
 			shaderStages.push_back(pipelineShaderStageInfo);
-			stageFlags |= shaders[shaderNdx].stage;
+			stageFlags |= m_program.shaders[shaderNdx].stage;
 		}
 
 		DE_ASSERT(
-			(m_primitiveTopology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) ||
+			(m_drawState.topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) ||
 			(stageFlags & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)));
 
-		const bool tessellationEnabled = (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
+		const bool tessellationEnabled = (m_drawState.topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
 		const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
 		{
 			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,						// VkStructureType									sType;
@@ -665,17 +735,17 @@
 			const VkRect2D		renderArea =
 			{
 				makeOffset2D(0, 0),
-				makeExtent2D(m_renderSize.x(), m_renderSize.y())
+				makeExtent2D(m_drawState.renderSize.x(), m_drawState.renderSize.y())
 			};
 
 			const VkRenderPassBeginInfo renderPassBeginInfo = {
-				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
-				DE_NULL,										// const void*             pNext;
-				*m_renderPass,									// VkRenderPass            renderPass;
-				*m_framebuffer,									// VkFramebuffer           framebuffer;
-				renderArea,										// VkRect2D                renderArea;
-				1u,												// uint32_t                clearValueCount;
-				&clearValue,									// const VkClearValue*     pClearValues;
+				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,							// VkStructureType								sType;
+				DE_NULL,															// const void*									pNext;
+				*m_renderPass,														// VkRenderPass									renderPass;
+				*m_framebuffer,														// VkFramebuffer								framebuffer;
+				renderArea,															// VkRect2D										renderArea;
+				1u,																	// uint32_t										clearValueCount;
+				&clearValue,														// const VkClearValue*							pClearValues;
 			};
 
 			vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
@@ -684,7 +754,7 @@
 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
 		vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &(**m_vertexBuffer), &zeroOffset);
 
-		vk.cmdDraw(*m_cmdBuffer, m_numVertices, 1u, 0u, 1u);
+		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_drawCallData.vertices.size()), 1u, 0u, 1u);
 		vk.cmdEndRenderPass(*m_cmdBuffer);
 
 		// Barrier: draw -> copy from image
@@ -692,14 +762,15 @@
 			const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(
 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-				**m_colorImage, m_colorSubresourceRange);
+				**m_colorImage, colorSubresourceRange);
 
 			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0,
 				0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
 		}
 
 		{
-			const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), m_imageExtent);
+			const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),
+					makeExtent3D(m_drawState.renderSize.x(), m_drawState.renderSize.y(), 1u));
 			vk.cmdCopyImageToBuffer(*m_cmdBuffer, **m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_colorAttachmentBuffer, 1u, &copyRegion);
 		}
 
@@ -717,7 +788,11 @@
 	}
 }
 
-void DrawContext::draw (void)
+VulkanDrawContext::~VulkanDrawContext (void)
+{
+}
+
+void VulkanDrawContext::draw (void)
 {
 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
 	const VkDevice			device		= m_context.getDevice();
@@ -729,7 +804,7 @@
 	log << tcu::LogImageSet("attachments", "") << tcu::LogImage("color0", "", getColorPixels()) << tcu::TestLog::EndImageSet;
 }
 
-tcu::ConstPixelBufferAccess DrawContext::getColorPixels (void) const
+tcu::ConstPixelBufferAccess VulkanDrawContext::getColorPixels (void) const
 {
 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
 	const VkDevice			device		= m_context.getDevice();
@@ -737,7 +812,7 @@
 	const Allocation& alloc = m_colorAttachmentBuffer->getAllocation();
 	invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE);
 
-	return tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), m_imageExtent.width, m_imageExtent.height, m_imageExtent.depth, alloc.getHostPtr());
+	return tcu::ConstPixelBufferAccess(mapVkFormat(m_drawState.colorFormat), m_drawState.renderSize.x(), m_drawState.renderSize.y(), 1u, alloc.getHostPtr());
 }
 } // drawutil
 } // vkt
diff --git a/external/vulkancts/modules/vulkan/vktDrawUtil.hpp b/external/vulkancts/modules/vulkan/vktDrawUtil.hpp
index 9a74092..4cb00c2 100644
--- a/external/vulkancts/modules/vulkan/vktDrawUtil.hpp
+++ b/external/vulkancts/modules/vulkan/vktDrawUtil.hpp
@@ -32,24 +32,14 @@
 #include "vkImageUtil.hpp"
 #include "vkPrograms.hpp"
 #include "vktTestCase.hpp"
+#include "vkTypeUtil.hpp"
+#include "rrRenderer.hpp"
 
 namespace vkt
 {
 namespace drawutil
 {
 
-enum Constants
-{
-	RENDER_SIZE								= 16,
-	RENDER_SIZE_LARGE						= 128,
-	NUM_RENDER_PIXELS						= RENDER_SIZE * RENDER_SIZE,
-	NUM_PATCH_CONTROL_POINTS				= 3,
-	MAX_NUM_SHADER_MODULES					= 5,
-	MAX_CLIP_DISTANCES						= 8,
-	MAX_CULL_DISTANCES						= 8,
-	MAX_COMBINED_CLIP_AND_CULL_DISTANCES	= 8,
-};
-
 struct Shader
 {
 	vk::VkShaderStageFlagBits	stage;
@@ -61,39 +51,102 @@
 	{
 	}
 };
+
+struct DrawState
+{
+	const vk::VkPrimitiveTopology	topology;
+	const vk::VkFormat				colorFormat;
+	const vk::VkFormat				depthFormat;
+	tcu::UVec2						renderSize;
+	bool							depthClampEnable;
+	bool							blendEnable;
+	float							lineWidth;
+	deUint32						numPatchControlPoints;
+
+	DrawState (const vk::VkPrimitiveTopology topology_, deUint32 renderWidth_, deUint32 renderHeight_);
+};
+
+struct DrawCallData
+{
+	const std::vector<tcu::Vec4>&	vertices;
+
+	DrawCallData		(const std::vector<tcu::Vec4>&	vertices_)
+		: vertices		(vertices_)
+	{
+	}
+};
+
 //! Sets up a graphics pipeline and enables simple draw calls to predefined attachments.
 //! Clip volume uses wc = 1.0, which gives clip coord ranges: x = [-1, 1], y = [-1, 1], z = [0, 1]
 //! Clip coords (-1,-1) map to viewport coords (0, 0).
 class DrawContext
 {
 public:
-									DrawContext		(Context&						context,
-													 const std::vector<Shader>&		shaders,
-													 const std::vector<tcu::Vec4>&	vertices,
-													 const vk::VkPrimitiveTopology	primitiveTopology,
-													 const deUint32					renderSize			= static_cast<deUint32>(RENDER_SIZE),
-													 const bool						depthClampEnable	= false,
-													 const bool						blendEnable			= false,
-													 const float					lineWidth			= 1.0f);
+											DrawContext				(const DrawState&		drawState,
+																	 const DrawCallData&	drawCallData)
+		: m_drawState						(drawState)
+		, m_drawCallData					(drawCallData)
+	{
+	}
+	virtual									~DrawContext			(void)
+	{
+	}
 
-	void							draw			(void);
-	tcu::ConstPixelBufferAccess		getColorPixels	(void) const;
+	virtual void							draw					(void) = 0;
+	virtual tcu::ConstPixelBufferAccess		getColorPixels			(void) const = 0;
+protected:
+		const DrawState						m_drawState;
+		const DrawCallData					m_drawCallData;
+};
 
+class ReferenceDrawContext : public DrawContext
+{
+public:
+											ReferenceDrawContext	(const DrawState&			drawState,
+																	 const DrawCallData&		drawCallData,
+																	 const rr::VertexShader&	vertexShader,
+																	 const rr::FragmentShader&	fragmentShader)
+		: DrawContext						(drawState, drawCallData)
+		, m_vertexShader					(vertexShader)
+		, m_fragmentShader					(fragmentShader)
+	{
+	}
+	virtual									~ReferenceDrawContext	(void);
+	virtual void							draw					(void);
+	virtual tcu::ConstPixelBufferAccess		getColorPixels			(void) const;
 private:
+	const rr::VertexShader&					m_vertexShader;
+	const rr::FragmentShader&				m_fragmentShader;
+	tcu::TextureLevel						m_refImage;
+};
+
+struct VulkanProgram
+{
+	const std::vector<Shader>&				shaders;
+
+	VulkanProgram		(const std::vector<Shader>&			shaders_)
+		: shaders		(shaders_)
+	{
+	}
+};
+
+class VulkanDrawContext : public DrawContext
+{
+public:
+											VulkanDrawContext	(Context&				context,
+																 const DrawState&		drawState,
+																 const DrawCallData&	drawCallData,
+																 const VulkanProgram&	vulkanProgram);
+	virtual									~VulkanDrawContext	(void);
+	virtual void							draw				(void);
+	virtual tcu::ConstPixelBufferAccess		getColorPixels		(void) const;
+private:
+	enum Contants
+	{
+		MAX_NUM_SHADER_MODULES					= 5,
+	};
 	Context&									m_context;
-	const vk::VkFormat							m_colorFormat;
-	const vk::VkFormat							m_depthFormat;
-	const vk::VkImageSubresourceRange			m_colorSubresourceRange;
-	const vk::VkImageSubresourceRange			m_depthSubresourceRange;
-	const tcu::UVec2							m_renderSize;
-	const vk::VkExtent3D						m_imageExtent;
-	const vk::VkPrimitiveTopology				m_primitiveTopology;
-	const bool									m_depthClampEnable;
-	const bool									m_blendEnable;
-	const deUint32								m_numVertices;
-	const float									m_lineWidth;
-	const deUint32								m_numPatchControlPoints;
-	de::MovePtr<vk::BufferWithMemory>			m_vertexBuffer;
+	VulkanProgram								m_program;
 	de::MovePtr<vk::ImageWithMemory>			m_colorImage;
 	de::MovePtr<vk::ImageWithMemory>			m_depthImage;
 	de::MovePtr<vk::BufferWithMemory>			m_colorAttachmentBuffer;
@@ -106,10 +159,9 @@
 	vk::refdetails::Move<vk::VkCommandPool>		m_cmdPool;
 	vk::refdetails::Move<vk::VkCommandBuffer>	m_cmdBuffer;
 	vk::refdetails::Move<vk::VkShaderModule>	m_shaderModules[MAX_NUM_SHADER_MODULES];
-
-									DrawContext		(const DrawContext&);	// "deleted"
-	DrawContext&					operator=		(const DrawContext&);	// "deleted"
+	de::MovePtr<vk::BufferWithMemory>			m_vertexBuffer;
 };
+
 std::string getPrimitiveTopologyShortName (const vk::VkPrimitiveTopology topology);
 
 } // drwwutil
diff --git a/framework/referencerenderer/rrRasterizer.cpp b/framework/referencerenderer/rrRasterizer.cpp
index df5b412..247a195 100644
--- a/framework/referencerenderer/rrRasterizer.cpp
+++ b/framework/referencerenderer/rrRasterizer.cpp
@@ -446,12 +446,13 @@
 } // LineRasterUtil
 
 TriangleRasterizer::TriangleRasterizer (const tcu::IVec4& viewport, const int numSamples, const RasterizationState& state)
-	: m_viewport		(viewport)
-	, m_numSamples		(numSamples)
-	, m_winding			(state.winding)
-	, m_horizontalFill	(state.horizontalFill)
-	, m_verticalFill	(state.verticalFill)
-	, m_face			(FACETYPE_LAST)
+	: m_viewport				(viewport)
+	, m_numSamples				(numSamples)
+	, m_winding					(state.winding)
+	, m_horizontalFill			(state.horizontalFill)
+	, m_verticalFill			(state.verticalFill)
+	, m_face					(FACETYPE_LAST)
+	, m_viewportOrientation		(state.viewportOrientation)
 {
 }
 
@@ -493,7 +494,11 @@
 	// Determine face.
 	const deInt64	s				= evaluateEdge(m_edge01, x2, y2);
 	const bool		positiveArea	= (m_winding == WINDING_CCW) ? (s > 0) : (s < 0);
-	m_face = positiveArea ? FACETYPE_FRONT : FACETYPE_BACK;
+
+	if (m_viewportOrientation == VIEWPORTORIENTATION_UPPER_LEFT)
+		m_face = positiveArea ? FACETYPE_BACK : FACETYPE_FRONT;
+	else
+		m_face = positiveArea ? FACETYPE_FRONT : FACETYPE_BACK;
 
 	if (!positiveArea)
 	{
diff --git a/framework/referencerenderer/rrRasterizer.hpp b/framework/referencerenderer/rrRasterizer.hpp
index dee7c15..bfb2624 100644
--- a/framework/referencerenderer/rrRasterizer.hpp
+++ b/framework/referencerenderer/rrRasterizer.hpp
@@ -155,10 +155,11 @@
 	EdgeFunction			m_edge01;
 	EdgeFunction			m_edge12;
 	EdgeFunction			m_edge20;
-	FaceType				m_face;			//!< Triangle orientation, eg. visible face.
-	tcu::IVec2				m_bboxMin;		//!< Bounding box min (inclusive).
-	tcu::IVec2				m_bboxMax;		//!< Bounding box max (inclusive).
-	tcu::IVec2				m_curPos;		//!< Current rasterization position.
+	FaceType				m_face;					//!< Triangle orientation, eg. visible face.
+	tcu::IVec2				m_bboxMin;				//!< Bounding box min (inclusive).
+	tcu::IVec2				m_bboxMax;				//!< Bounding box max (inclusive).
+	tcu::IVec2				m_curPos;				//!< Current rasterization position.
+	ViewportOrientation		m_viewportOrientation;	//!< Direction of +x+y axis
 } DE_WARN_UNUSED_TYPE;
 
 
diff --git a/framework/referencerenderer/rrRenderState.hpp b/framework/referencerenderer/rrRenderState.hpp
index 671d4da..315225e 100644
--- a/framework/referencerenderer/rrRenderState.hpp
+++ b/framework/referencerenderer/rrRenderState.hpp
@@ -63,18 +63,29 @@
 	CULLMODE_LAST
 };
 
+//! Viewport Orientation of renderer this will be compared against
+enum ViewportOrientation
+{
+	VIEWPORTORIENTATION_LOWER_LEFT = 0,	//<! Corresponds to GL
+	VIEWPORTORIENTATION_UPPER_LEFT,		//<! Corresponds to Vulkan
+
+	VIEWPORTORIENTATION_LAST
+};
+
 struct RasterizationState
 {
 	RasterizationState (void)
-		: winding			(WINDING_CCW)
-		, horizontalFill	(FILL_LEFT)
-		, verticalFill		(FILL_BOTTOM)
+		: winding				(WINDING_CCW)
+		, horizontalFill		(FILL_LEFT)
+		, verticalFill			(FILL_BOTTOM)
+		, viewportOrientation	(VIEWPORTORIENTATION_LAST)
 	{
 	}
 
-	Winding			winding;
-	HorizontalFill	horizontalFill;
-	VerticalFill	verticalFill;
+	Winding					winding;
+	HorizontalFill			horizontalFill;
+	VerticalFill			verticalFill;
+	ViewportOrientation		viewportOrientation;
 };
 
 enum TestFunc
@@ -348,11 +359,13 @@
 
 struct RenderState
 {
-	explicit RenderState (const ViewportState& viewport_)
+	explicit RenderState (const ViewportState& viewport_, ViewportOrientation viewportOrientation_ = VIEWPORTORIENTATION_LOWER_LEFT)
 		: cullMode					(CULLMODE_NONE)
 		, provokingVertexConvention	(PROVOKINGVERTEX_LAST)
 		, viewport					(viewport_)
+		, viewportOrientation		(viewportOrientation_)
 	{
+		rasterization.viewportOrientation = viewportOrientation;
 	}
 
 	CullMode					cullMode;
@@ -363,6 +376,7 @@
 	ViewportState				viewport;
 	LineState					line;
 	RestartState				restart;
+	ViewportOrientation			viewportOrientation;
 };
 
 } // rr
diff --git a/framework/referencerenderer/rrRenderer.cpp b/framework/referencerenderer/rrRenderer.cpp
index fc5e075..5dd13be 100644
--- a/framework/referencerenderer/rrRenderer.cpp
+++ b/framework/referencerenderer/rrRenderer.cpp
@@ -1117,7 +1117,7 @@
 		return;
 
 	// Shading context
-	FragmentShadingContext shadingContext(triangle.v0->outputs, triangle.v1->outputs, triangle.v2->outputs, &buffers.shaderOutputs[0], buffers.fragmentDepthBuffer, triangle.v2->primitiveID, (int)program.fragmentShader->getOutputs().size(), numSamples);
+	FragmentShadingContext shadingContext(triangle.v0->outputs, triangle.v1->outputs, triangle.v2->outputs, &buffers.shaderOutputs[0], buffers.fragmentDepthBuffer, triangle.v2->primitiveID, (int)program.fragmentShader->getOutputs().size(), numSamples, rasterizer.getVisibleFace());
 
 	// Polygon offset
 	if (buffers.fragmentDepthBuffer && state.fragOps.polygonOffsetEnabled)
@@ -1174,7 +1174,7 @@
 	const float					depthClampMin		= de::min(state.viewport.zn, state.viewport.zf);
 	const float					depthClampMax		= de::max(state.viewport.zn, state.viewport.zf);
 	const bool					msaa				= numSamples > 1;
-	FragmentShadingContext		shadingContext		(line.v0->outputs, line.v1->outputs, DE_NULL, &buffers.shaderOutputs[0], buffers.fragmentDepthBuffer, line.v1->primitiveID, (int)program.fragmentShader->getOutputs().size(), numSamples);
+	FragmentShadingContext		shadingContext		(line.v0->outputs, line.v1->outputs, DE_NULL, &buffers.shaderOutputs[0], buffers.fragmentDepthBuffer, line.v1->primitiveID, (int)program.fragmentShader->getOutputs().size(), numSamples, FACETYPE_FRONT);
 	SingleSampleLineRasterizer	aliasedRasterizer	(renderTargetRect);
 	MultiSampleLineRasterizer	msaaRasterizer		(numSamples, renderTargetRect);
 
@@ -1240,7 +1240,7 @@
 	rasterizer2.init(w0, w2, w3);
 
 	// Shading context
-	FragmentShadingContext shadingContext(point.v0->outputs, DE_NULL, DE_NULL, &buffers.shaderOutputs[0], buffers.fragmentDepthBuffer, point.v0->primitiveID, (int)program.fragmentShader->getOutputs().size(), numSamples);
+	FragmentShadingContext shadingContext(point.v0->outputs, DE_NULL, DE_NULL, &buffers.shaderOutputs[0], buffers.fragmentDepthBuffer, point.v0->primitiveID, (int)program.fragmentShader->getOutputs().size(), numSamples, FACETYPE_FRONT);
 
 	// Execute rasterize - shade - write loop
 	for (;;)
diff --git a/framework/referencerenderer/rrShadingContext.cpp b/framework/referencerenderer/rrShadingContext.cpp
index 3262739..261970a 100644
--- a/framework/referencerenderer/rrShadingContext.cpp
+++ b/framework/referencerenderer/rrShadingContext.cpp
@@ -26,12 +26,13 @@
 namespace rr
 {
 
-FragmentShadingContext::FragmentShadingContext (const GenericVec4* varying0, const GenericVec4* varying1, const GenericVec4* varying2, GenericVec4* outputArray_, float* fragmentDepths_, int primitiveID_, int numFragmentOutputs_, int numSamples_)
+FragmentShadingContext::FragmentShadingContext (const GenericVec4* varying0, const GenericVec4* varying1, const GenericVec4* varying2, GenericVec4* outputArray_, float* fragmentDepths_, int primitiveID_, int numFragmentOutputs_, int numSamples_, FaceType visibleFace_)
 	: outputArray			(outputArray_)
 	, primitiveID			(primitiveID_)
 	, numFragmentOutputs	(numFragmentOutputs_)
 	, numSamples			(numSamples_)
 	, fragmentDepths		(fragmentDepths_)
+	, visibleFace			(visibleFace_)
 {
 	varyings[0] = varying0;
 	varyings[1] = varying1;
diff --git a/framework/referencerenderer/rrShadingContext.hpp b/framework/referencerenderer/rrShadingContext.hpp
index 635d396..b506dd1 100644
--- a/framework/referencerenderer/rrShadingContext.hpp
+++ b/framework/referencerenderer/rrShadingContext.hpp
@@ -37,7 +37,7 @@
  *//*--------------------------------------------------------------------*/
 struct FragmentShadingContext
 {
-								FragmentShadingContext (const GenericVec4* varying0, const GenericVec4* varying1, const GenericVec4* varying2, GenericVec4* outputArray, float* fragmentDepths, int primitiveID, int numFragmentOutputs, int numSamples);
+								FragmentShadingContext (const GenericVec4* varying0, const GenericVec4* varying1, const GenericVec4* varying2, GenericVec4* outputArray, float* fragmentDepths, int primitiveID, int numFragmentOutputs, int numSamples, FaceType visibleFace_);
 
 	const GenericVec4*			varyings[3];		//!< Vertex shader outputs. Pointer will be NULL if there is no such vertex.
 	GenericVec4* const			outputArray;		//!< Fragment output array
@@ -45,6 +45,7 @@
 	const int					numFragmentOutputs;	//!< Fragment output count
 	const int					numSamples;			//!< Number of samples
 	float*						fragmentDepths;		//!< Fragment packet depths. Pointer will be NULL if there is no depth buffer. Each sample has per-sample depth values
+	FaceType					visibleFace;		//!< Which face (front or back) is visible
 };
 
 // Write output