CommandBuffer and NonDispatchable objects code cleanup

Cleaned up items include:
- Sanitized parameter names in Command constructors
- Commands no longer hold Vk types for members if they
  can be cast to an internal type in the constructor
- Commands members are private
- VertexInputBinding contains a Buffer instead of a VkBuffer
- Removed the Fence default constructor
- Image functions now receive Image and Buffer objects
  instead of VkImage and VkBuffer handles.
- Removed the VkNonDispatchableHandle default constructor
- DeviceMemory::getOffsetPointer() is now const
- Refactored PresentImage so that it no longer contains
  VkImage and VkDeviceMemory handles, but proper Image
  and DeviceMemory objects instead and replaced duplicate
  code which releases these objects with a clear() function.
- SwapchainKHR no longer holds on to a VkSwapchainCreateInfoKHR
  structure, which was dangerous, since it contains pointers
  which were not deep copied, but only holds on to a SurfaceKHR
  object, which is the only thing it really needs.
- SwapchainKHR::images never changes size, so it was changed
  from a vector to an array so that we can better control its
  memory allocation.
- SurfaceKHR had a VkSwapchainKHR member, changed it for a
  SwapchainKHR* instead
- Removed surfaceFormats and presentModes, which were
  unnecessarily bloating the SurfaceKHR class and moved
  them to an unnamed namespace in VkSurfaceKHR.cpp.

Change-Id: If21e5ba1319759a204e562aef92aaf96d5a12b1f
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/32489
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Sean Risser <srisser@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index 90d1afa..398d20f 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -95,8 +95,6 @@
 
 		executionState.renderPass->nextSubpass();
 	}
-
-private:
 };
 
 class EndRenderPass : public CommandBuffer::Command
@@ -122,52 +120,50 @@
 		executionState.renderPass = nullptr;
 		executionState.renderPassFramebuffer = nullptr;
 	}
-
-private:
 };
 
 class ExecuteCommands : public CommandBuffer::Command
 {
 public:
-	ExecuteCommands(const VkCommandBuffer& commandBuffer) : commandBuffer(commandBuffer)
+	ExecuteCommands(const VkCommandBuffer& commandBuffer) : commandBuffer(Cast(commandBuffer))
 	{
 	}
 
 protected:
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(commandBuffer)->submitSecondary(executionState);
+		commandBuffer->submitSecondary(executionState);
 	}
 
 private:
-	const VkCommandBuffer commandBuffer;
+	const CommandBuffer* commandBuffer;
 };
 
 class PipelineBind : public CommandBuffer::Command
 {
 public:
-	PipelineBind(VkPipelineBindPoint pPipelineBindPoint, VkPipeline pPipeline) :
-		pipelineBindPoint(pPipelineBindPoint), pipeline(pPipeline)
+	PipelineBind(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) :
+		pipelineBindPoint(pipelineBindPoint), pipeline(Cast(pipeline))
 	{
 	}
 
 protected:
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		executionState.pipelineState[pipelineBindPoint].pipeline = Cast(pipeline);
+		executionState.pipelineState[pipelineBindPoint].pipeline = pipeline;
 	}
 
 private:
 	VkPipelineBindPoint pipelineBindPoint;
-	VkPipeline pipeline;
+	Pipeline* pipeline;
 };
 
 class Dispatch : public CommandBuffer::Command
 {
 public:
-	Dispatch(uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t pGroupCountX, uint32_t pGroupCountY, uint32_t pGroupCountZ) :
+	Dispatch(uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) :
 			baseGroupX(baseGroupX), baseGroupY(baseGroupY), baseGroupZ(baseGroupZ),
-			groupCountX(pGroupCountX), groupCountY(pGroupCountY), groupCountZ(pGroupCountZ)
+			groupCountX(groupCountX), groupCountY(groupCountY), groupCountZ(groupCountZ)
 	{
 	}
 
@@ -197,14 +193,14 @@
 {
 public:
 	DispatchIndirect(VkBuffer buffer, VkDeviceSize offset) :
-			buffer(buffer), offset(offset)
+			buffer(Cast(buffer)), offset(offset)
 	{
 	}
 
 protected:
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		auto cmd = reinterpret_cast<VkDispatchIndirectCommand const *>(Cast(buffer)->getOffsetPointer(offset));
+		auto cmd = reinterpret_cast<VkDispatchIndirectCommand const *>(buffer->getOffsetPointer(offset));
 
 		auto const &pipelineState = executionState.pipelineState[VK_PIPELINE_BIND_POINT_COMPUTE];
 
@@ -216,14 +212,14 @@
 	}
 
 private:
-	VkBuffer buffer;
+	const Buffer* buffer;
 	VkDeviceSize offset;
 };
 
 struct VertexBufferBind : public CommandBuffer::Command
 {
-	VertexBufferBind(uint32_t pBinding, const VkBuffer pBuffer, const VkDeviceSize pOffset) :
-		binding(pBinding), buffer(pBuffer), offset(pOffset)
+	VertexBufferBind(uint32_t binding, const VkBuffer buffer, const VkDeviceSize offset) :
+		binding(binding), buffer(Cast(buffer)), offset(offset)
 	{
 	}
 
@@ -232,26 +228,28 @@
 		executionState.vertexInputBindings[binding] = { buffer, offset };
 	}
 
+private:
 	uint32_t binding;
-	const VkBuffer buffer;
+	Buffer* buffer;
 	const VkDeviceSize offset;
 };
 
 struct IndexBufferBind : public CommandBuffer::Command
 {
 	IndexBufferBind(const VkBuffer buffer, const VkDeviceSize offset, const VkIndexType indexType) :
-		buffer(buffer), offset(offset), indexType(indexType)
+		buffer(Cast(buffer)), offset(offset), indexType(indexType)
 	{
 
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		executionState.indexBufferBinding = {buffer, offset};
+		executionState.indexBufferBinding = { buffer, offset };
 		executionState.indexType = indexType;
 	}
 
-	const VkBuffer buffer;
+private:
+	Buffer* buffer;
 	const VkDeviceSize offset;
 	const VkIndexType indexType;
 };
@@ -268,6 +266,7 @@
 		executionState.dynamicState.viewport = viewport;
 	}
 
+private:
 	const VkViewport viewport;
 	uint32_t viewportID;
 };
@@ -284,6 +283,7 @@
 		executionState.dynamicState.scissor = scissor;
 	}
 
+private:
 	const VkRect2D scissor;
 	uint32_t scissorID;
 };
@@ -302,6 +302,7 @@
 		executionState.dynamicState.depthBiasSlopeFactor = depthBiasSlopeFactor;
 	}
 
+private:
 	float depthBiasConstantFactor;
 	float depthBiasClamp;
 	float depthBiasSlopeFactor;
@@ -319,6 +320,7 @@
 		memcpy(&(executionState.dynamicState.blendConstants[0]), blendConstants, sizeof(blendConstants));
 	}
 
+private:
 	float blendConstants[4];
 };
 
@@ -335,6 +337,7 @@
 		executionState.dynamicState.maxDepthBounds = maxDepthBounds;
 	}
 
+private:
 	float minDepthBounds;
 	float maxDepthBounds;
 };
@@ -357,6 +360,7 @@
 		}
 	}
 
+private:
 	VkStencilFaceFlags faceMask;
 	uint32_t compareMask;
 };
@@ -380,6 +384,7 @@
 		}
 	}
 
+private:
 	VkStencilFaceFlags faceMask;
 	uint32_t writeMask;
 };
@@ -403,6 +408,7 @@
 		}
 	}
 
+private:
 	VkStencilFaceFlags faceMask;
 	uint32_t reference;
 };
@@ -415,8 +421,7 @@
 		if (attrib.count)
 		{
 			const auto &vertexInput = vertexInputBindings[attrib.binding];
-			Buffer *buffer = Cast(vertexInput.buffer);
-			attrib.buffer = buffer ? buffer->getOffsetPointer(
+			attrib.buffer = vertexInput.buffer ? vertexInput.buffer->getOffsetPointer(
 					attrib.offset + vertexInput.offset + attrib.vertexStride * firstVertex + attrib.instanceStride * firstInstance) : nullptr;
 		}
 	}
@@ -567,7 +572,7 @@
 		std::vector<std::pair<uint32_t, void*>> indexBuffers;
 		if(indexed)
 		{
-			void* indexBuffer = Cast(executionState.indexBufferBinding.buffer)->getOffsetPointer(
+			void* indexBuffer = executionState.indexBufferBinding.buffer->getOffsetPointer(
 				executionState.indexBufferBinding.offset + first * bytesPerIndex(executionState));
 			if(pipeline->hasPrimitiveRestartEnable())
 			{
@@ -621,6 +626,7 @@
 		draw(executionState, false, vertexCount, instanceCount, 0, firstVertex, firstInstance);
 	}
 
+private:
 	uint32_t vertexCount;
 	uint32_t instanceCount;
 	uint32_t firstVertex;
@@ -639,6 +645,7 @@
 		draw(executionState, true, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
 	}
 
+private:
 	uint32_t indexCount;
 	uint32_t instanceCount;
 	uint32_t firstIndex;
@@ -649,7 +656,7 @@
 struct DrawIndirect : public DrawBase
 {
 	DrawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride)
-			: buffer(buffer), offset(offset), drawCount(drawCount), stride(stride)
+			: buffer(Cast(buffer)), offset(offset), drawCount(drawCount), stride(stride)
 	{
 	}
 
@@ -657,12 +664,13 @@
 	{
 		for (auto drawId = 0u; drawId < drawCount; drawId++)
 		{
-			auto cmd = reinterpret_cast<VkDrawIndirectCommand const *>(Cast(buffer)->getOffsetPointer(offset + drawId * stride));
+			auto cmd = reinterpret_cast<VkDrawIndirectCommand const *>(buffer->getOffsetPointer(offset + drawId * stride));
 			draw(executionState, false, cmd->vertexCount, cmd->instanceCount, 0, cmd->firstVertex, cmd->firstInstance);
 		}
 	}
 
-	VkBuffer buffer;
+private:
+	const Buffer* buffer;
 	VkDeviceSize offset;
 	uint32_t drawCount;
 	uint32_t stride;
@@ -671,7 +679,7 @@
 struct DrawIndexedIndirect : public DrawBase
 {
 	DrawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride)
-			: buffer(buffer), offset(offset), drawCount(drawCount), stride(stride)
+			: buffer(Cast(buffer)), offset(offset), drawCount(drawCount), stride(stride)
 	{
 	}
 
@@ -679,12 +687,13 @@
 	{
 		for (auto drawId = 0u; drawId < drawCount; drawId++)
 		{
-			auto cmd = reinterpret_cast<VkDrawIndexedIndirectCommand const *>(Cast(buffer)->getOffsetPointer(offset + drawId * stride));
+			auto cmd = reinterpret_cast<VkDrawIndexedIndirectCommand const *>(buffer->getOffsetPointer(offset + drawId * stride));
 			draw(executionState, true, cmd->indexCount, cmd->instanceCount, cmd->firstIndex, cmd->vertexOffset, cmd->firstInstance);
 		}
 	}
 
-	VkBuffer buffer;
+private:
+	const Buffer* buffer;
 	VkDeviceSize offset;
 	uint32_t drawCount;
 	uint32_t stride;
@@ -692,90 +701,90 @@
 
 struct ImageToImageCopy : public CommandBuffer::Command
 {
-	ImageToImageCopy(VkImage pSrcImage, VkImage pDstImage, const VkImageCopy& pRegion) :
-		srcImage(pSrcImage), dstImage(pDstImage), region(pRegion)
+	ImageToImageCopy(VkImage srcImage, VkImage dstImage, const VkImageCopy& region) :
+		srcImage(Cast(srcImage)), dstImage(Cast(dstImage)), region(region)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(srcImage)->copyTo(dstImage, region);
+		srcImage->copyTo(dstImage, region);
 	}
 
 private:
-	VkImage srcImage;
-	VkImage dstImage;
+	Image* srcImage;
+	Image* dstImage;
 	const VkImageCopy region;
 };
 
 struct BufferToBufferCopy : public CommandBuffer::Command
 {
-	BufferToBufferCopy(VkBuffer pSrcBuffer, VkBuffer pDstBuffer, const VkBufferCopy& pRegion) :
-		srcBuffer(pSrcBuffer), dstBuffer(pDstBuffer), region(pRegion)
+	BufferToBufferCopy(VkBuffer srcBuffer, VkBuffer dstBuffer, const VkBufferCopy& region) :
+		srcBuffer(Cast(srcBuffer)), dstBuffer(Cast(dstBuffer)), region(region)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(srcBuffer)->copyTo(Cast(dstBuffer), region);
+		srcBuffer->copyTo(dstBuffer, region);
 	}
 
 private:
-	VkBuffer srcBuffer;
-	VkBuffer dstBuffer;
+	Buffer* srcBuffer;
+	Buffer* dstBuffer;
 	const VkBufferCopy region;
 };
 
 struct ImageToBufferCopy : public CommandBuffer::Command
 {
-	ImageToBufferCopy(VkImage pSrcImage, VkBuffer pDstBuffer, const VkBufferImageCopy& pRegion) :
-		srcImage(pSrcImage), dstBuffer(pDstBuffer), region(pRegion)
+	ImageToBufferCopy(VkImage srcImage, VkBuffer dstBuffer, const VkBufferImageCopy& region) :
+		srcImage(Cast(srcImage)), dstBuffer(Cast(dstBuffer)), region(region)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(srcImage)->copyTo(dstBuffer, region);
+		srcImage->copyTo(dstBuffer, region);
 	}
 
 private:
-	VkImage srcImage;
-	VkBuffer dstBuffer;
+	Image* srcImage;
+	Buffer* dstBuffer;
 	const VkBufferImageCopy region;
 };
 
 struct BufferToImageCopy : public CommandBuffer::Command
 {
-	BufferToImageCopy(VkBuffer pSrcBuffer, VkImage pDstImage, const VkBufferImageCopy& pRegion) :
-		srcBuffer(pSrcBuffer), dstImage(pDstImage), region(pRegion)
+	BufferToImageCopy(VkBuffer srcBuffer, VkImage dstImage, const VkBufferImageCopy& region) :
+		srcBuffer(Cast(srcBuffer)), dstImage(Cast(dstImage)), region(region)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(dstImage)->copyFrom(srcBuffer, region);
+		dstImage->copyFrom(srcBuffer, region);
 	}
 
 private:
-	VkBuffer srcBuffer;
-	VkImage dstImage;
+	Buffer* srcBuffer;
+	Image* dstImage;
 	const VkBufferImageCopy region;
 };
 
 struct FillBuffer : public CommandBuffer::Command
 {
 	FillBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) :
-		dstBuffer(dstBuffer), dstOffset(dstOffset), size(size), data(data)
+		dstBuffer(Cast(dstBuffer)), dstOffset(dstOffset), size(size), data(data)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(dstBuffer)->fill(dstOffset, size, data);
+		dstBuffer->fill(dstOffset, size, data);
 	}
 
 private:
-	VkBuffer dstBuffer;
+	Buffer* dstBuffer;
 	VkDeviceSize dstOffset;
 	VkDeviceSize size;
 	uint32_t data;
@@ -784,17 +793,17 @@
 struct UpdateBuffer : public CommandBuffer::Command
 {
 	UpdateBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint8_t* pData) :
-		dstBuffer(dstBuffer), dstOffset(dstOffset), data(pData, &pData[dataSize])
+		dstBuffer(Cast(dstBuffer)), dstOffset(dstOffset), data(pData, &pData[dataSize])
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(dstBuffer)->update(dstOffset, data.size(), data.data());
+		dstBuffer->update(dstOffset, data.size(), data.data());
 	}
 
 private:
-	VkBuffer dstBuffer;
+	Buffer* dstBuffer;
 	VkDeviceSize dstOffset;
 	std::vector<uint8_t> data; // FIXME (b/119409619): replace this vector by an allocator so we can control all memory allocations
 };
@@ -802,17 +811,17 @@
 struct ClearColorImage : public CommandBuffer::Command
 {
 	ClearColorImage(VkImage image, const VkClearColorValue& color, const VkImageSubresourceRange& range) :
-		image(image), color(color), range(range)
+		image(Cast(image)), color(color), range(range)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(image)->clear(color, range);
+		image->clear(color, range);
 	}
 
 private:
-	VkImage image;
+	Image* image;
 	const VkClearColorValue color;
 	const VkImageSubresourceRange range;
 };
@@ -820,17 +829,17 @@
 struct ClearDepthStencilImage : public CommandBuffer::Command
 {
 	ClearDepthStencilImage(VkImage image, const VkClearDepthStencilValue& depthStencil, const VkImageSubresourceRange& range) :
-		image(image), depthStencil(depthStencil), range(range)
+		image(Cast(image)), depthStencil(depthStencil), range(range)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(image)->clear(depthStencil, range);
+		image->clear(depthStencil, range);
 	}
 
 private:
-	VkImage image;
+	Image* image;
 	const VkClearDepthStencilValue depthStencil;
 	const VkImageSubresourceRange range;
 };
@@ -859,18 +868,18 @@
 struct BlitImage : public CommandBuffer::Command
 {
 	BlitImage(VkImage srcImage, VkImage dstImage, const VkImageBlit& region, VkFilter filter) :
-		srcImage(srcImage), dstImage(dstImage), region(region), filter(filter)
+		srcImage(Cast(srcImage)), dstImage(Cast(dstImage)), region(region), filter(filter)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(srcImage)->blit(dstImage, region, filter);
+		srcImage->blit(dstImage, region, filter);
 	}
 
 private:
-	VkImage srcImage;
-	VkImage dstImage;
+	const Image* srcImage;
+	Image* dstImage;
 	VkImageBlit region;
 	VkFilter filter;
 };
@@ -878,18 +887,18 @@
 struct ResolveImage : public CommandBuffer::Command
 {
 	ResolveImage(VkImage srcImage, VkImage dstImage, const VkImageResolve& region) :
-		srcImage(srcImage), dstImage(dstImage), region(region)
+		srcImage(Cast(srcImage)), dstImage(Cast(dstImage)), region(region)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(srcImage)->resolve(dstImage, region);
+		srcImage->resolve(dstImage, region);
 	}
 
 private:
-	VkImage srcImage;
-	VkImage dstImage;
+	const Image* srcImage;
+	Image* dstImage;
 	VkImageResolve region;
 };
 
@@ -916,51 +925,51 @@
 
 struct SignalEvent : public CommandBuffer::Command
 {
-	SignalEvent(VkEvent ev, VkPipelineStageFlags stageMask) : ev(ev), stageMask(stageMask)
+	SignalEvent(VkEvent ev, VkPipelineStageFlags stageMask) : ev(Cast(ev)), stageMask(stageMask)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
 		executionState.renderer->synchronize();
-		Cast(ev)->signal();
+		ev->signal();
 	}
 
 private:
-	VkEvent ev;
+	Event* ev;
 	VkPipelineStageFlags stageMask; // FIXME(b/117835459) : We currently ignore the flags and signal the event at the last stage
 };
 
 struct ResetEvent : public CommandBuffer::Command
 {
-	ResetEvent(VkEvent ev, VkPipelineStageFlags stageMask) : ev(ev), stageMask(stageMask)
+	ResetEvent(VkEvent ev, VkPipelineStageFlags stageMask) : ev(Cast(ev)), stageMask(stageMask)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
-		Cast(ev)->reset();
+		ev->reset();
 	}
 
 private:
-	VkEvent ev;
+	Event* ev;
 	VkPipelineStageFlags stageMask; // FIXME(b/117835459) : We currently ignore the flags and reset the event at the last stage
 };
 
 struct WaitEvent : public CommandBuffer::Command
 {
-	WaitEvent(VkEvent ev) : ev(ev)
+	WaitEvent(VkEvent ev) : ev(Cast(ev))
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState) override
 	{
 		executionState.renderer->synchronize();
-		Cast(ev)->wait();
+		ev->wait();
 	}
 
 private:
-	VkEvent ev;
+	Event* ev;
 };
 
 struct BindDescriptorSet : public CommandBuffer::Command
@@ -992,11 +1001,11 @@
 
 private:
 	VkPipelineBindPoint pipelineBindPoint;
-	vk::PipelineLayout *pipelineLayout;
+	PipelineLayout *pipelineLayout;
 	uint32_t set;
 	const VkDescriptorSet descriptorSet;
 	uint32_t dynamicOffsetCount;
-	vk::DescriptorSet::DynamicOffsets dynamicOffsets;
+	DescriptorSet::DynamicOffsets dynamicOffsets;
 };
 
 struct SetPushConstants : public CommandBuffer::Command
@@ -1024,18 +1033,18 @@
 struct BeginQuery : public CommandBuffer::Command
 {
 	BeginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags)
-		: queryPool(queryPool), query(query), flags(flags)
+		: queryPool(Cast(queryPool)), query(query), flags(flags)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState)
 	{
-		executionState.renderer->addQuery(Cast(queryPool)->getQuery(query));
-		Cast(queryPool)->begin(query, flags);
+		executionState.renderer->addQuery(queryPool->getQuery(query));
+		queryPool->begin(query, flags);
 	}
 
 private:
-	VkQueryPool queryPool;
+	QueryPool* queryPool;
 	uint32_t query;
 	VkQueryControlFlags flags;
 };
@@ -1043,35 +1052,35 @@
 struct EndQuery : public CommandBuffer::Command
 {
 	EndQuery(VkQueryPool queryPool, uint32_t query)
-		: queryPool(queryPool), query(query)
+		: queryPool(Cast(queryPool)), query(query)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState)
 	{
-		executionState.renderer->removeQuery(Cast(queryPool)->getQuery(query));
-		Cast(queryPool)->end(query);
+		executionState.renderer->removeQuery(queryPool->getQuery(query));
+		queryPool->end(query);
 	}
 
 private:
-	VkQueryPool queryPool;
+	QueryPool* queryPool;
 	uint32_t query;
 };
 
 struct ResetQueryPool : public CommandBuffer::Command
 {
 	ResetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount)
-		: queryPool(queryPool), firstQuery(firstQuery), queryCount(queryCount)
+		: queryPool(Cast(queryPool)), firstQuery(firstQuery), queryCount(queryCount)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState)
 	{
-		Cast(queryPool)->reset(firstQuery, queryCount);
+		queryPool->reset(firstQuery, queryCount);
 	}
 
 private:
-	VkQueryPool queryPool;
+	QueryPool* queryPool;
 	uint32_t firstQuery;
 	uint32_t queryCount;
 };
@@ -1079,17 +1088,17 @@
 struct WriteTimeStamp : public CommandBuffer::Command
 {
 	WriteTimeStamp(VkQueryPool queryPool, uint32_t query)
-		: queryPool(queryPool), query(query)
+		: queryPool(Cast(queryPool)), query(query)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState)
 	{
-		Cast(queryPool)->writeTimestamp(query);
+		queryPool->writeTimestamp(query);
 	}
 
 private:
-	VkQueryPool queryPool;
+	QueryPool* queryPool;
 	uint32_t query;
 };
 
@@ -1097,20 +1106,20 @@
 {
 	CopyQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
 		VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags)
-		: queryPool(queryPool), firstQuery(firstQuery), queryCount(queryCount), dstBuffer(dstBuffer),
-		  dstOffset(dstOffset), stride(stride), flags(flags)
+		: queryPool(Cast(queryPool)), firstQuery(firstQuery), queryCount(queryCount),
+		  dstBuffer(dstBuffer), dstOffset(dstOffset), stride(stride), flags(flags)
 	{
 	}
 
 	void play(CommandBuffer::ExecutionState& executionState)
 	{
 		vk::Buffer* buffer = Cast(dstBuffer);
-		Cast(queryPool)->getResults(firstQuery, queryCount, buffer->getSize() - dstOffset,
-		                            buffer->getOffsetPointer(dstOffset), stride, flags);
+		queryPool->getResults(firstQuery, queryCount, buffer->getSize() - dstOffset,
+		                      buffer->getOffsetPointer(dstOffset), stride, flags);
 	}
 
 private:
-	VkQueryPool queryPool;
+	QueryPool* queryPool;
 	uint32_t firstQuery;
 	uint32_t queryCount;
 	VkBuffer dstBuffer;
diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp
index df99cd8..1fc81cd 100644
--- a/src/Vulkan/VkCommandBuffer.hpp
+++ b/src/Vulkan/VkCommandBuffer.hpp
@@ -33,6 +33,7 @@
 namespace vk
 {
 
+class Buffer;
 class Framebuffer;
 class Pipeline;
 class RenderPass;
@@ -160,7 +161,7 @@
 
 		struct VertexInputBinding
 		{
-			VkBuffer buffer;
+			Buffer* buffer;
 			VkDeviceSize offset;
 		};
 		VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {};
diff --git a/src/Vulkan/VkDeviceMemory.cpp b/src/Vulkan/VkDeviceMemory.cpp
index 921e72f..3e9a952 100644
--- a/src/Vulkan/VkDeviceMemory.cpp
+++ b/src/Vulkan/VkDeviceMemory.cpp
@@ -63,7 +63,7 @@
 	return size;
 }
 
-void* DeviceMemory::getOffsetPointer(VkDeviceSize pOffset)
+void* DeviceMemory::getOffsetPointer(VkDeviceSize pOffset) const
 {
 	ASSERT(buffer);
 
diff --git a/src/Vulkan/VkDeviceMemory.hpp b/src/Vulkan/VkDeviceMemory.hpp
index 88f71cb..e50b21d 100644
--- a/src/Vulkan/VkDeviceMemory.hpp
+++ b/src/Vulkan/VkDeviceMemory.hpp
@@ -31,7 +31,7 @@
 	VkResult allocate();
 	VkResult map(VkDeviceSize offset, VkDeviceSize size, void** ppData);
 	VkDeviceSize getCommittedMemoryInBytes() const;
-	void* getOffsetPointer(VkDeviceSize pOffset);
+	void* getOffsetPointer(VkDeviceSize pOffset) const;
 	uint32_t getMemoryTypeIndex() const { return memoryTypeIndex; }
 
 private:
diff --git a/src/Vulkan/VkFence.hpp b/src/Vulkan/VkFence.hpp
index 7b990ef..2a043e6 100644
--- a/src/Vulkan/VkFence.hpp
+++ b/src/Vulkan/VkFence.hpp
@@ -24,8 +24,6 @@
 class Fence : public Object<Fence, VkFence>, public sw::TaskEvents
 {
 public:
-	Fence() : signaled(sw::Event::ClearMode::Manual, false) {}
-
 	Fence(const VkFenceCreateInfo* pCreateInfo, void* mem) :
 		signaled(sw::Event::ClearMode::Manual, (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) != 0) {}
 
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index 91043c9..7374a84 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -128,11 +128,10 @@
 	pLayout->arrayPitch = getLayerSize(aspect);
 }
 
-void Image::copyTo(VkImage dstImage, const VkImageCopy& pRegion)
+void Image::copyTo(Image* dstImage, const VkImageCopy& pRegion) const
 {
 	// 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);
 
 	if (!((pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
 	      (pRegion.srcSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) ||
@@ -158,7 +157,7 @@
 	VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(pRegion.dstSubresource.aspectMask);
 
 	Format srcFormat = getFormat(srcAspect);
-	Format dstFormat = dst->getFormat(dstAspect);
+	Format dstFormat = dstImage->getFormat(dstAspect);
 
 	if(((samples > VK_SAMPLE_COUNT_1_BIT) && (imageType == VK_IMAGE_TYPE_2D) && !format.isNonNormalizedInteger()) ||
 		srcFormat.hasQuadLayout() || dstFormat.hasQuadLayout())
@@ -177,22 +176,22 @@
 		region.dstOffsets[1].y = region.dstOffsets[0].y + pRegion.extent.height;
 		region.dstOffsets[1].z = region.dstOffsets[0].z + pRegion.extent.depth;
 
-		return device->getBlitter()->blit(this, dst, region, VK_FILTER_NEAREST);
+		return device->getBlitter()->blit(this, dstImage, region, VK_FILTER_NEAREST);
 	}
 
 	int srcBytesPerBlock = srcFormat.bytesPerBlock();
 	ASSERT(srcBytesPerBlock == dstFormat.bytesPerBlock());
 
 	const uint8_t* srcMem = static_cast<const uint8_t*>(getTexelPointer(pRegion.srcOffset, pRegion.srcSubresource));
-	uint8_t* dstMem = static_cast<uint8_t*>(dst->getTexelPointer(pRegion.dstOffset, pRegion.dstSubresource));
+	uint8_t* dstMem = static_cast<uint8_t*>(dstImage->getTexelPointer(pRegion.dstOffset, pRegion.dstSubresource));
 
 	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);
+	int dstRowPitchBytes = dstImage->rowPitchBytes(dstAspect, pRegion.dstSubresource.mipLevel);
+	int dstSlicePitchBytes = dstImage->slicePitchBytes(dstAspect, pRegion.dstSubresource.mipLevel);
 
 	VkExtent3D srcExtent = getMipLevelExtent(srcAspect, pRegion.srcSubresource.mipLevel);
-	VkExtent3D dstExtent = dst->getMipLevelExtent(dstAspect, pRegion.dstSubresource.mipLevel);
+	VkExtent3D dstExtent = dstImage->getMipLevelExtent(dstAspect, pRegion.dstSubresource.mipLevel);
 	VkExtent3D copyExtent = imageExtentInBlocks(pRegion.extent, srcAspect);
 
 	bool isSinglePlane = (copyExtent.depth == 1);
@@ -223,21 +222,21 @@
 	{
 		size_t copySize = copyExtent.width * srcBytesPerBlock;
 		ASSERT((srcMem + copySize) < end());
-		ASSERT((dstMem + copySize) < dst->end());
+		ASSERT((dstMem + copySize) < dstImage->end());
 		memcpy(dstMem, srcMem, copySize);
 	}
 	else if(isEntireLine && isSinglePlane) // Copy one plane
 	{
 		size_t copySize = copyExtent.height * srcRowPitchBytes;
 		ASSERT((srcMem + copySize) < end());
-		ASSERT((dstMem + copySize) < dst->end());
+		ASSERT((dstMem + copySize) < dstImage->end());
 		memcpy(dstMem, srcMem, copySize);
 	}
 	else if(isEntirePlane) // Copy multiple planes
 	{
 		size_t copySize = copyExtent.depth * srcSlicePitchBytes;
 		ASSERT((srcMem + copySize) < end());
-		ASSERT((dstMem + copySize) < dst->end());
+		ASSERT((dstMem + copySize) < dstImage->end());
 		memcpy(dstMem, srcMem, copySize);
 	}
 	else if(isEntireLine) // Copy plane by plane
@@ -247,7 +246,7 @@
 		for(uint32_t z = 0; z < copyExtent.depth; z++, dstMem += dstSlicePitchBytes, srcMem += srcSlicePitchBytes)
 		{
 			ASSERT((srcMem + copySize) < end());
-			ASSERT((dstMem + copySize) < dst->end());
+			ASSERT((dstMem + copySize) < dstImage->end());
 			memcpy(dstMem, srcMem, copySize);
 		}
 	}
@@ -260,14 +259,14 @@
 			for(uint32_t y = 0; y < copyExtent.height; y++, dstMem += dstRowPitchBytes, srcMem += srcRowPitchBytes)
 			{
 				ASSERT((srcMem + copySize) < end());
-				ASSERT((dstMem + copySize) < dst->end());
+				ASSERT((dstMem + copySize) < dstImage->end());
 				memcpy(dstMem, srcMem, copySize);
 			}
 		}
 	}
 }
 
-void Image::copy(VkBuffer buf, const VkBufferImageCopy& region, bool bufferIsSource)
+void Image::copy(Buffer* buffer, const VkBufferImageCopy& region, bool bufferIsSource)
 {
 	switch(region.imageSubresource.aspectMask)
 	{
@@ -292,7 +291,6 @@
 	int bufferRowPitchBytes = bufferExtent.width * bytesPerBlock;
 	int bufferSlicePitchBytes = bufferExtent.height * bufferRowPitchBytes;
 
-	Buffer* buffer = Cast(buf);
 	uint8_t* bufferMemory = static_cast<uint8_t*>(buffer->getOffsetPointer(region.bufferOffset));
 
 	if (copyFormat.hasQuadLayout())
@@ -415,12 +413,12 @@
 	}
 }
 
-void Image::copyTo(VkBuffer dstBuffer, const VkBufferImageCopy& region)
+void Image::copyTo(Buffer* dstBuffer, const VkBufferImageCopy& region)
 {
 	copy(dstBuffer, region, false);
 }
 
-void Image::copyFrom(VkBuffer srcBuffer, const VkBufferImageCopy& region)
+void Image::copyFrom(Buffer* srcBuffer, const VkBufferImageCopy& region)
 {
 	copy(srcBuffer, region, true);
 }
@@ -730,12 +728,12 @@
 	return (decompressedImage && isImageViewCompressed) ? decompressedImage : this;
 }
 
-void Image::blit(VkImage dstImage, const VkImageBlit& region, VkFilter filter)
+void Image::blit(Image* dstImage, const VkImageBlit& region, VkFilter filter) const
 {
-	device->getBlitter()->blit(this, Cast(dstImage), region, filter);
+	device->getBlitter()->blit(this, dstImage, region, filter);
 }
 
-void Image::resolve(VkImage dstImage, const VkImageResolve& region)
+void Image::resolve(Image* dstImage, const VkImageResolve& region) const
 {
 	VkImageBlit blitRegion;
 
@@ -752,7 +750,7 @@
 	blitRegion.srcSubresource = region.srcSubresource;
 	blitRegion.dstSubresource = region.dstSubresource;
 
-	device->getBlitter()->blit(this, Cast(dstImage), blitRegion, VK_FILTER_NEAREST);
+	device->getBlitter()->blit(this, dstImage, blitRegion, VK_FILTER_NEAREST);
 }
 
 VkFormat Image::getClearFormat() const
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp
index 9872585..f31209d 100644
--- a/src/Vulkan/VkImage.hpp
+++ b/src/Vulkan/VkImage.hpp
@@ -21,6 +21,7 @@
 namespace vk
 {
 
+class Buffer;
 class Device;
 class DeviceMemory;
 
@@ -35,12 +36,12 @@
 	const VkMemoryRequirements getMemoryRequirements() const;
 	void getSubresourceLayout(const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) const;
 	void bind(VkDeviceMemory pDeviceMemory, VkDeviceSize pMemoryOffset);
-	void copyTo(VkImage dstImage, const VkImageCopy& pRegion);
-	void copyTo(VkBuffer dstBuffer, const VkBufferImageCopy& region);
-	void copyFrom(VkBuffer srcBuffer, const VkBufferImageCopy& region);
+	void copyTo(Image* dstImage, const VkImageCopy& pRegion) const;
+	void copyTo(Buffer* dstBuffer, const VkBufferImageCopy& region);
+	void copyFrom(Buffer* srcBuffer, const VkBufferImageCopy& region);
 
-	void blit(VkImage dstImage, const VkImageBlit& region, VkFilter filter);
-	void resolve(VkImage dstImage, const VkImageResolve& region);
+	void blit(Image* dstImage, const VkImageBlit& region, VkFilter filter) const;
+	void resolve(Image* dstImage, const VkImageResolve& region) const;
 	void clear(const VkClearValue& clearValue, const vk::Format& viewFormat, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange);
 	void clear(const VkClearColorValue& color, const VkImageSubresourceRange& subresourceRange);
 	void clear(const VkClearDepthStencilValue& color, const VkImageSubresourceRange& subresourceRange);
@@ -67,7 +68,7 @@
 	const Image*             getSampledImage(const vk::Format& imageViewFormat) const;
 
 private:
-	void copy(VkBuffer buffer, const VkBufferImageCopy& region, bool bufferIsSource);
+	void copy(Buffer* buffer, const VkBufferImageCopy& region, bool bufferIsSource);
 	VkDeviceSize getStorageSize(VkImageAspectFlags flags) const;
 	VkDeviceSize getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
 	VkDeviceSize getMultiSampledLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp
index c8e1f65..94b56d5 100644
--- a/src/Vulkan/VkImageView.cpp
+++ b/src/Vulkan/VkImageView.cpp
@@ -181,7 +181,7 @@
 	region.extent = image->getMipLevelExtent(static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask),
 	                                         subresourceRange.baseMipLevel);
 
-	image->copyTo(*(resolveAttachment->image), region);
+	image->copyTo(resolveAttachment->image, region);
 }
 
 const Image* ImageView::getImage(Usage usage) const
diff --git a/src/Vulkan/VulkanPlatform.h b/src/Vulkan/VulkanPlatform.h
index cdbda52..1b309be 100644
--- a/src/Vulkan/VulkanPlatform.h
+++ b/src/Vulkan/VulkanPlatform.h
@@ -98,10 +98,6 @@
 template<typename T> class VkNonDispatchableHandle : public VkNonDispatchableHandleBase<T>
 {
 public:
-	VkNonDispatchableHandle() : VkNonDispatchableHandleBase<T>(nullptr)
-	{
-	}
-
 	VkNonDispatchableHandle(typename VkNonDispatchableHandleBase<T>::HandleType handle) : VkNonDispatchableHandleBase<T>(handle)
 	{
 		static_assert(sizeof(VkNonDispatchableHandle) == sizeof(uint64_t), "Size is not 64 bits!");
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 0c8d06d..dbba77b 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -2652,7 +2652,7 @@
 		vk::Cast(pCreateInfo->oldSwapchain)->retire();
 	}
 
-	if(vk::Cast(pCreateInfo->surface)->getAssociatedSwapchain() != VK_NULL_HANDLE)
+	if(vk::Cast(pCreateInfo->surface)->hasAssociatedSwapchain())
 	{
 		return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
 	}
@@ -2664,7 +2664,7 @@
 		return status;
 	}
 
-	status = vk::Cast(*pSwapchain)->createImages(device);
+	status = vk::Cast(*pSwapchain)->createImages(device, pCreateInfo);
 
 	if(status != VK_SUCCESS)
 	{
diff --git a/src/WSI/VkSurfaceKHR.cpp b/src/WSI/VkSurfaceKHR.cpp
index ba121b7..74c0e40 100644
--- a/src/WSI/VkSurfaceKHR.cpp
+++ b/src/WSI/VkSurfaceKHR.cpp
@@ -14,11 +14,98 @@
 
 #include "VkSurfaceKHR.hpp"
 
+#include "Vulkan/VkDestroy.h"
+
 #include <algorithm>
 
+namespace
+{
+
+static const VkSurfaceFormatKHR surfaceFormats[] =
+{
+	{VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+};
+
+static const VkPresentModeKHR presentModes[] =
+{
+	VK_PRESENT_MODE_FIFO_KHR,
+};
+
+}
+
 namespace vk
 {
 
+VkResult PresentImage::allocateImage(VkDevice device, const VkImageCreateInfo& createInfo)
+{
+	VkImage* vkImagePtr = reinterpret_cast<VkImage*>(allocate(sizeof(VkImage), REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY));
+	if(!vkImagePtr)
+	{
+		return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+	}
+
+	VkResult status = vkCreateImage(device, &createInfo, nullptr, vkImagePtr);
+	if(status != VK_SUCCESS)
+	{
+		deallocate(vkImagePtr, DEVICE_MEMORY);
+		return status;
+	}
+
+	image = Cast(*vkImagePtr);
+	deallocate(vkImagePtr, DEVICE_MEMORY);
+
+	return status;
+}
+
+VkResult PresentImage::allocateAndBindImageMemory(VkDevice device, const VkMemoryAllocateInfo& allocateInfo)
+{
+	ASSERT(image);
+
+	VkDeviceMemory* vkDeviceMemoryPtr = reinterpret_cast<VkDeviceMemory*>(
+		allocate(sizeof(VkDeviceMemory), REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY));
+	if(!vkDeviceMemoryPtr)
+	{
+		return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+	}
+
+	VkResult status = vkAllocateMemory(device, &allocateInfo, nullptr, vkDeviceMemoryPtr);
+	if(status != VK_SUCCESS)
+	{
+		deallocate(vkDeviceMemoryPtr, DEVICE_MEMORY);
+		return status;
+	}
+
+	imageMemory = Cast(*vkDeviceMemoryPtr);
+	vkBindImageMemory(device, *image, *vkDeviceMemoryPtr, 0);
+
+	imageStatus = AVAILABLE;
+	deallocate(vkDeviceMemoryPtr, DEVICE_MEMORY);
+
+	return status;
+}
+
+void PresentImage::clear()
+{
+	if(imageMemory)
+	{
+		vk::destroy(static_cast<VkDeviceMemory>(*imageMemory), nullptr);
+		imageMemory = nullptr;
+	}
+
+	if(image)
+	{
+		vk::destroy(static_cast<VkImage>(*image), nullptr);
+		image = nullptr;
+	}
+
+	imageStatus = NONEXISTENT;
+}
+
+VkImage PresentImage::asVkImage() const
+{
+	return image ? static_cast<VkImage>(*image) : VK_NULL_HANDLE;
+}
+
 void SurfaceKHR::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const
 {
 	pSurfaceCapabilities->minImageCount = 1;
@@ -34,7 +121,7 @@
 
 uint32_t SurfaceKHR::getSurfaceFormatsCount() const
 {
-	return static_cast<uint32_t>(surfaceFormats.size());
+	return static_cast<uint32_t>(sizeof(surfaceFormats) / sizeof(surfaceFormats[0]));
 }
 
 VkResult SurfaceKHR::getSurfaceFormats(uint32_t *pSurfaceFormatCount, VkSurfaceFormatKHR *pSurfaceFormats) const
@@ -49,7 +136,7 @@
 
 	*pSurfaceFormatCount = i;
 
-	if (*pSurfaceFormatCount < count)
+	if(*pSurfaceFormatCount < count)
 	{
 		return VK_INCOMPLETE;
 	}
@@ -59,10 +146,9 @@
 
 uint32_t SurfaceKHR::getPresentModeCount() const
 {
-	return static_cast<uint32_t>(presentModes.size());
+	return static_cast<uint32_t>(sizeof(presentModes) / sizeof(presentModes[0]));
 }
 
-
 VkResult SurfaceKHR::getPresentModes(uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) const
 {
 	uint32_t count = getPresentModeCount();
@@ -75,7 +161,7 @@
 
 	*pPresentModeCount = i;
 
-	if (*pPresentModeCount < count)
+	if(*pPresentModeCount < count)
 	{
 		return VK_INCOMPLETE;
 	}
@@ -85,17 +171,17 @@
 
 void SurfaceKHR::associateSwapchain(VkSwapchainKHR swapchain)
 {
-	associatedSwapchain = swapchain;
+	associatedSwapchain = Cast(swapchain);
 }
 
 void SurfaceKHR::disassociateSwapchain()
 {
-	associatedSwapchain = VK_NULL_HANDLE;
+	associatedSwapchain = nullptr;
 }
 
-VkSwapchainKHR SurfaceKHR::getAssociatedSwapchain()
+bool SurfaceKHR::hasAssociatedSwapchain()
 {
-	return associatedSwapchain;
+	return (associatedSwapchain != nullptr);
 }
 
 }
\ No newline at end of file
diff --git a/src/WSI/VkSurfaceKHR.hpp b/src/WSI/VkSurfaceKHR.hpp
index 616cbcc..7fb1591 100644
--- a/src/WSI/VkSurfaceKHR.hpp
+++ b/src/WSI/VkSurfaceKHR.hpp
@@ -30,11 +30,28 @@
 	PRESENTING,
 };
 
-struct PresentImage
+class DeviceMemory;
+class Image;
+class SwapchainKHR;
+
+class PresentImage
 {
-	VkImage image;
-	VkDeviceMemory imageMemory;
-	PresentImageStatus imageStatus;
+public:
+	VkResult allocateImage(VkDevice device, const VkImageCreateInfo& createInfo);
+	VkResult allocateAndBindImageMemory(VkDevice device, const VkMemoryAllocateInfo& allocateInfo);
+	void clear();
+	VkImage asVkImage() const;
+
+	const Image* getImage() const { return image; }
+	const DeviceMemory* getImageMemory() const { return imageMemory; }
+	bool isAvailable() const { return (imageStatus == AVAILABLE); }
+	bool exists() const { return (imageStatus != NONEXISTENT); }
+	void setStatus(PresentImageStatus status) { imageStatus = status; }
+
+private:
+	Image* image = nullptr;
+	DeviceMemory* imageMemory = nullptr;
+	PresentImageStatus imageStatus = NONEXISTENT;
 };
 
 class SurfaceKHR
@@ -68,21 +85,10 @@
 
 	void associateSwapchain(VkSwapchainKHR swapchain);
 	void disassociateSwapchain();
-	VkSwapchainKHR getAssociatedSwapchain();
-
+	bool hasAssociatedSwapchain();
 
 private:
-	VkSwapchainKHR associatedSwapchain;
-
-	const std::vector<VkSurfaceFormatKHR> surfaceFormats =
-	{
-		{VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-	};
-
-	const std::vector<VkPresentModeKHR> presentModes =
-	{
-		VK_PRESENT_MODE_FIFO_KHR,
-	};
+	SwapchainKHR* associatedSwapchain = nullptr;
 };
 
 static inline SurfaceKHR* Cast(VkSurfaceKHR object)
diff --git a/src/WSI/VkSwapchainKHR.cpp b/src/WSI/VkSwapchainKHR.cpp
index bdd459e..d265141 100644
--- a/src/WSI/VkSwapchainKHR.cpp
+++ b/src/WSI/VkSwapchainKHR.cpp
@@ -14,46 +14,49 @@
 
 #include "VkSwapchainKHR.hpp"
 
-#include "Vulkan/VkImage.hpp"
 #include "Vulkan/VkDeviceMemory.hpp"
-#include "Vulkan/VkDestroy.h"
+#include "Vulkan/VkFence.hpp"
+#include "Vulkan/VkImage.hpp"
+#include "Vulkan/VkSemaphore.hpp"
 
 #include <algorithm>
+#include <cstring>
 
 namespace vk
 {
 
 SwapchainKHR::SwapchainKHR(const VkSwapchainCreateInfoKHR *pCreateInfo, void *mem) :
-	createInfo(*pCreateInfo),
+	surface(Cast(pCreateInfo->surface)),
+	images(reinterpret_cast<PresentImage*>(mem)),
+	imageCount(pCreateInfo->minImageCount),
 	retired(false)
 {
-	images.resize(pCreateInfo->minImageCount);
-	resetImages();
+	memset(images, 0, imageCount * sizeof(PresentImage));
 }
 
 void SwapchainKHR::destroy(const VkAllocationCallbacks *pAllocator)
 {
-	for(auto& currentImage : images)
+	for(uint32_t i = 0; i < imageCount; i++)
 	{
-		if (currentImage.imageStatus != NONEXISTENT)
+		PresentImage& currentImage = images[i];
+		if(currentImage.exists())
 		{
-			vk::Cast(createInfo.surface)->detachImage(&currentImage);
-			vk::destroy(currentImage.imageMemory, nullptr);
-			vk::destroy(currentImage.image, nullptr);
-
-			currentImage.imageStatus = NONEXISTENT;
+			surface->detachImage(&currentImage);
+			currentImage.clear();
 		}
 	}
 
 	if(!retired)
 	{
-		vk::Cast(createInfo.surface)->disassociateSwapchain();
+		surface->disassociateSwapchain();
 	}
+
+	vk::deallocate(images, pAllocator);
 }
 
 size_t SwapchainKHR::ComputeRequiredAllocationSize(const VkSwapchainCreateInfoKHR *pCreateInfo)
 {
-	return 0;
+	return pCreateInfo->minImageCount * sizeof(PresentImage);
 }
 
 void SwapchainKHR::retire()
@@ -61,17 +64,15 @@
 	if(!retired)
 	{
 		retired = true;
-		vk::Cast(createInfo.surface)->disassociateSwapchain();
+		surface->disassociateSwapchain();
 
-		for(auto& currentImage : images)
+		for(uint32_t i = 0; i < imageCount; i++)
 		{
-			if(currentImage.imageStatus == AVAILABLE)
+			PresentImage& currentImage = images[i];
+			if(currentImage.isAvailable())
 			{
-				vk::Cast(createInfo.surface)->detachImage(&currentImage);
-				vk::destroy(currentImage.imageMemory, nullptr);
-				vk::destroy(currentImage.image, nullptr);
-
-				currentImage.imageStatus = NONEXISTENT;
+				surface->detachImage(&currentImage);
+				currentImage.clear();
 			}
 		}
 	}
@@ -79,73 +80,69 @@
 
 void SwapchainKHR::resetImages()
 {
-	for(auto& currentImage : images)
+	for(uint32_t i = 0; i < imageCount; i++)
 	{
-		currentImage.image = VK_NULL_HANDLE;
-		currentImage.imageMemory = VK_NULL_HANDLE;
-		currentImage.imageStatus = NONEXISTENT;
+		images[i].clear();
 	}
 }
 
-VkResult SwapchainKHR::createImages(VkDevice device)
+VkResult SwapchainKHR::createImages(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo)
 {
 	resetImages();
 
 	VkImageCreateInfo imageInfo = {};
 	imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
 
-	if(createInfo.flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR)
+	if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR)
 	{
 		imageInfo.flags |= VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT;
 	}
 
-	if(createInfo.flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR)
+	if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR)
 	{
 		imageInfo.flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
 	}
 
 	imageInfo.imageType = VK_IMAGE_TYPE_2D;
-	imageInfo.format = createInfo.imageFormat;
-	imageInfo.extent.height = createInfo.imageExtent.height;
-	imageInfo.extent.width = createInfo.imageExtent.width;
+	imageInfo.format = pCreateInfo->imageFormat;
+	imageInfo.extent.height = pCreateInfo->imageExtent.height;
+	imageInfo.extent.width = pCreateInfo->imageExtent.width;
 	imageInfo.extent.depth = 1;
 	imageInfo.mipLevels = 1;
-	imageInfo.arrayLayers = createInfo.imageArrayLayers;
+	imageInfo.arrayLayers = pCreateInfo->imageArrayLayers;
 	imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
 	imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
-	imageInfo.usage = createInfo.imageUsage;
-	imageInfo.sharingMode = createInfo.imageSharingMode;
-	imageInfo.pQueueFamilyIndices = createInfo.pQueueFamilyIndices;
-	imageInfo.queueFamilyIndexCount = createInfo.queueFamilyIndexCount;
+	imageInfo.usage = pCreateInfo->imageUsage;
+	imageInfo.sharingMode = pCreateInfo->imageSharingMode;
+	imageInfo.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices;
+	imageInfo.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount;
 	imageInfo.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
 
+	VkMemoryAllocateInfo allocInfo = {};
+	allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+	allocInfo.allocationSize = 0;
+	allocInfo.memoryTypeIndex = 0;
+
 	VkResult status;
-	for(auto& currentImage : images)
+	for(uint32_t i = 0; i < imageCount; i++)
 	{
-		status = vkCreateImage(device, &imageInfo, nullptr, &currentImage.image);
+		PresentImage& currentImage = images[i];
+
+		status = currentImage.allocateImage(device, imageInfo);
 		if(status != VK_SUCCESS)
 		{
 			return status;
 		}
 
-		VkMemoryRequirements memRequirements = vk::Cast(currentImage.image)->getMemoryRequirements();
+		allocInfo.allocationSize = currentImage.getImage()->getMemoryRequirements().size;
 
-		VkMemoryAllocateInfo allocInfo = {};
-		allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
-		allocInfo.allocationSize = memRequirements.size;
-		allocInfo.memoryTypeIndex = 0;
-
-		status = vkAllocateMemory(device, &allocInfo, nullptr, &currentImage.imageMemory);
+		status = currentImage.allocateAndBindImageMemory(device, allocInfo);
 		if(status != VK_SUCCESS)
 		{
 			return status;
 		}
 
-		vkBindImageMemory(device, currentImage.image, currentImage.imageMemory, 0);
-
-		currentImage.imageStatus = AVAILABLE;
-
-		vk::Cast(createInfo.surface)->attachImage(&currentImage);
+		surface->attachImage(&currentImage);
 	}
 
 	return VK_SUCCESS;
@@ -153,22 +150,20 @@
 
 uint32_t SwapchainKHR::getImageCount() const
 {
-	return static_cast<uint32_t >(images.size());
+	return imageCount;
 }
 
 VkResult SwapchainKHR::getImages(uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) const
 {
-	uint32_t count = getImageCount();
-
 	uint32_t i;
-	for (i = 0; i < std::min(*pSwapchainImageCount, count); i++)
+	for(i = 0; i < std::min(*pSwapchainImageCount, imageCount); i++)
 	{
-		pSwapchainImages[i] = images[i].image;
+		pSwapchainImages[i] = images[i].asVkImage();
 	}
 
 	*pSwapchainImageCount = i;
 
-	if (*pSwapchainImageCount < count)
+	if(*pSwapchainImageCount < imageCount)
 	{
 		return VK_INCOMPLETE;
 	}
@@ -178,12 +173,12 @@
 
 VkResult SwapchainKHR::getNextImage(uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex)
 {
-	for(uint32_t i = 0; i < getImageCount(); i++)
+	for(uint32_t i = 0; i < imageCount; i++)
 	{
 		PresentImage& currentImage = images[i];
-		if(currentImage.imageStatus == AVAILABLE)
+		if(currentImage.isAvailable())
 		{
-			currentImage.imageStatus = DRAWING;
+			currentImage.setStatus(DRAWING);
 			*pImageIndex = i;
 
 			if(semaphore)
@@ -206,17 +201,14 @@
 void SwapchainKHR::present(uint32_t index)
 {
 	auto & image = images[index];
-	image.imageStatus = PRESENTING;
-	vk::Cast(createInfo.surface)->present(&image);
-	image.imageStatus = AVAILABLE;
+	image.setStatus(PRESENTING);
+	surface->present(&image);
+	image.setStatus(AVAILABLE);
 
 	if(retired)
 	{
-		vk::Cast(createInfo.surface)->detachImage(&image);
-		vk::destroy(image.imageMemory, nullptr);
-		vk::destroy(image.image, nullptr);
-
-		image.imageStatus = NONEXISTENT;
+		surface->detachImage(&image);
+		image.clear();
 	}
 }
 
diff --git a/src/WSI/VkSwapchainKHR.hpp b/src/WSI/VkSwapchainKHR.hpp
index c5b0166..d9fc725 100644
--- a/src/WSI/VkSwapchainKHR.hpp
+++ b/src/WSI/VkSwapchainKHR.hpp
@@ -36,7 +36,7 @@
 
 	void retire();
 
-	VkResult createImages(VkDevice device);
+	VkResult createImages(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo);
 
 	uint32_t getImageCount() const;
 	VkResult getImages(uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) const;
@@ -46,9 +46,10 @@
 	void present(uint32_t index);
 
 private:
-	VkSwapchainCreateInfoKHR createInfo;
-	std::vector<PresentImage> images;
-	bool retired;
+	SurfaceKHR* surface = nullptr;
+	PresentImage* images = nullptr;
+	uint32_t imageCount = 0;
+	bool retired = false;
 
 	void resetImages();
 };
diff --git a/src/WSI/XlibSurfaceKHR.cpp b/src/WSI/XlibSurfaceKHR.cpp
index c512245..0891c22 100644
--- a/src/WSI/XlibSurfaceKHR.cpp
+++ b/src/WSI/XlibSurfaceKHR.cpp
@@ -12,14 +12,15 @@
 #include "XlibSurfaceKHR.hpp"
 
 #include "Vulkan/VkDeviceMemory.hpp"
+#include "Vulkan/VkImage.hpp"
 
 #include <string.h>
 
 namespace vk {
 
 XlibSurfaceKHR::XlibSurfaceKHR(const VkXlibSurfaceCreateInfoKHR *pCreateInfo, void *mem) :
-		pDisplay(pCreateInfo->dpy),
-		window(pCreateInfo->window)
+	pDisplay(pCreateInfo->dpy),
+	window(pCreateInfo->window)
 {
 	int screen = DefaultScreen(pDisplay);
 	gc = libX11->XDefaultGC(pDisplay, screen);
@@ -58,10 +59,10 @@
 	XWindowAttributes attr;
 	libX11->XGetWindowAttributes(pDisplay, window, &attr);
 
-	VkExtent3D extent = vk::Cast(image->image)->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+	VkExtent3D extent = image->getImage()->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
 
-	int bytes_per_line = vk::Cast(image->image)->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
-	char* buffer = static_cast<char*>(vk::Cast(image->imageMemory)->getOffsetPointer(0));
+	int bytes_per_line = image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+	char* buffer = static_cast<char*>(image->getImageMemory()->getOffsetPointer(0));
 
 	XImage* xImage = libX11->XCreateImage(pDisplay, visual, attr.depth, ZPixmap, 0, buffer, extent.width, extent.height, 32, bytes_per_line);
 
@@ -89,7 +90,7 @@
 
 		if(xImage->data)
 		{
-			VkExtent3D extent = vk::Cast(image->image)->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+			VkExtent3D extent = image->getImage()->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
 			libX11->XPutImage(pDisplay, window, gc, xImage, 0, 0, 0, 0, extent.width, extent.height);
 		}
 	}
diff --git a/src/WSI/XlibSurfaceKHR.hpp b/src/WSI/XlibSurfaceKHR.hpp
index dd07ea2..c923a32 100644
--- a/src/WSI/XlibSurfaceKHR.hpp
+++ b/src/WSI/XlibSurfaceKHR.hpp
@@ -16,7 +16,6 @@
 #define SWIFTSHADER_XLIBSURFACEKHR_HPP
 
 #include "Vulkan/VkObject.hpp"
-#include "Vulkan/VkImage.hpp"
 #include "libX11.hpp"
 #include "VkSurfaceKHR.hpp"
 #include "vulkan/vulkan_xlib.h"