Explorar el Código

implement framebuffer / mipmap / cached sampler

- fix texture mipmap setting / texture update bug
- implement framebuffer
- fix image memory barrier bug
- vkstruct explicit initialization
- sampler caching
Rinthel hace 6 años
padre
commit
72abfdc8a4
Se han modificado 2 ficheros con 403 adiciones y 146 borrados
  1. 392 139
      src/renderer_vk.cpp
  2. 11 7
      src/renderer_vk.h

+ 392 - 139
src/renderer_vk.cpp

@@ -684,7 +684,7 @@ VK_IMPORT_DEVICE
 		}
 		}
 	}
 	}
 
 
-	void setImageMemoryBarrier(VkCommandBuffer _commandBuffer, VkImage _image, VkImageLayout _oldLayout, VkImageLayout _newLayout, uint32_t levelCount, uint32_t layerCount)
+	void setImageMemoryBarrier(VkCommandBuffer _commandBuffer, VkImage _image, VkImageAspectFlags _aspectMask, VkImageLayout _oldLayout, VkImageLayout _newLayout, uint32_t _levelCount, uint32_t _layerCount)
 	{
 	{
 		BX_CHECK(true
 		BX_CHECK(true
 			&& _newLayout != VK_IMAGE_LAYOUT_UNDEFINED
 			&& _newLayout != VK_IMAGE_LAYOUT_UNDEFINED
@@ -694,7 +694,6 @@ VK_IMPORT_DEVICE
 
 
 		VkAccessFlags srcAccessMask = 0;
 		VkAccessFlags srcAccessMask = 0;
 		VkAccessFlags dstAccessMask = 0;
 		VkAccessFlags dstAccessMask = 0;
-		VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
 
 		switch (_oldLayout)
 		switch (_oldLayout)
 		{
 		{
@@ -753,7 +752,7 @@ VK_IMPORT_DEVICE
 
 
 		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
 		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
 			dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
 			dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
-			aspectMask     = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+			// aspectMask     = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
 			break;
 			break;
 
 
 		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
 		case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
@@ -792,11 +791,11 @@ VK_IMPORT_DEVICE
 		imb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
 		imb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
 		imb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
 		imb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
 		imb.image = _image;
 		imb.image = _image;
-		imb.subresourceRange.aspectMask     = aspectMask;
+		imb.subresourceRange.aspectMask     = _aspectMask;
 		imb.subresourceRange.baseMipLevel   = 0;
 		imb.subresourceRange.baseMipLevel   = 0;
-		imb.subresourceRange.levelCount     = levelCount;
+		imb.subresourceRange.levelCount     = _levelCount;
 		imb.subresourceRange.baseArrayLayer = 0;
 		imb.subresourceRange.baseArrayLayer = 0;
-		imb.subresourceRange.layerCount     = layerCount;
+		imb.subresourceRange.layerCount     = _layerCount;
 		vkCmdPipelineBarrier(_commandBuffer
 		vkCmdPipelineBarrier(_commandBuffer
 			, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
 			, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
 			, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
 			, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
@@ -1189,7 +1188,7 @@ VK_IMPORT_INSTANCE
 					, NULL
 					, NULL
 					);
 					);
 
 
-				VkQueueFamilyProperties queueFamilyPropertices[10] = {};
+				VkQueueFamilyProperties queueFamilyPropertices[10];
 				queueFamilyPropertyCount = bx::min<uint32_t>(queueFamilyPropertyCount, BX_COUNTOF(queueFamilyPropertices) );
 				queueFamilyPropertyCount = bx::min<uint32_t>(queueFamilyPropertyCount, BX_COUNTOF(queueFamilyPropertices) );
 				vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice
 				vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice
 					, &queueFamilyPropertyCount
 					, &queueFamilyPropertyCount
@@ -1868,6 +1867,7 @@ VK_IMPORT_DEVICE
 				setImageMemoryBarrier(
 				setImageMemoryBarrier(
 					  commandBuffer
 					  commandBuffer
 					, m_backBufferDepthStencilImage
 					, m_backBufferDepthStencilImage
+					, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT
 					, VK_IMAGE_LAYOUT_UNDEFINED
 					, VK_IMAGE_LAYOUT_UNDEFINED
 					, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
 					, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
 					, 1
 					, 1
@@ -1879,6 +1879,7 @@ VK_IMPORT_DEVICE
 					setImageMemoryBarrier(
 					setImageMemoryBarrier(
 						  commandBuffer
 						  commandBuffer
 						, m_backBufferColorImage[ii]
 						, m_backBufferColorImage[ii]
+						, VK_IMAGE_ASPECT_COLOR_BIT
 						, VK_IMAGE_LAYOUT_UNDEFINED
 						, VK_IMAGE_LAYOUT_UNDEFINED
 						, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
 						, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
 						, 1
 						, 1
@@ -1892,6 +1893,7 @@ VK_IMPORT_DEVICE
 					setImageMemoryBarrier(
 					setImageMemoryBarrier(
 						  commandBuffer
 						  commandBuffer
 						, m_backBufferColorImage[ii]
 						, m_backBufferColorImage[ii]
+						, VK_IMAGE_ASPECT_COLOR_BIT
 						, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
 						, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
 						, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
 						, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
 						, 1
 						, 1
@@ -2108,6 +2110,8 @@ VK_IMPORT_DEVICE
 
 
 			m_pipelineStateCache.invalidate();
 			m_pipelineStateCache.invalidate();
 			m_descriptorSetLayoutCache.invalidate();
 			m_descriptorSetLayoutCache.invalidate();
+			m_renderPassCache.invalidate();
+			m_samplerCache.invalidate();
 
 
 			for (uint32_t ii = 0; ii < BX_COUNTOF(m_scratchBuffer); ++ii)
 			for (uint32_t ii = 0; ii < BX_COUNTOF(m_scratchBuffer); ++ii)
 			{
 			{
@@ -2346,16 +2350,18 @@ VK_IMPORT_DEVICE
 		    m_textures[_handle.idx].destroy();
 		    m_textures[_handle.idx].destroy();
 		}
 		}
 
 
-		void createFrameBuffer(FrameBufferHandle /*_handle*/, uint8_t /*_num*/, const Attachment* /*_attachment*/) override
+		void createFrameBuffer(FrameBufferHandle _handle, uint8_t _num, const Attachment* _attachment) override
 		{
 		{
+			m_frameBuffers[_handle.idx].create(_num, _attachment);
 		}
 		}
 
 
 		void createFrameBuffer(FrameBufferHandle /*_handle*/, void* /*_nwh*/, uint32_t /*_width*/, uint32_t /*_height*/, TextureFormat::Enum /*_format*/, TextureFormat::Enum /*_depthFormat*/) override
 		void createFrameBuffer(FrameBufferHandle /*_handle*/, void* /*_nwh*/, uint32_t /*_width*/, uint32_t /*_height*/, TextureFormat::Enum /*_format*/, TextureFormat::Enum /*_depthFormat*/) override
 		{
 		{
 		}
 		}
 
 
-		void destroyFrameBuffer(FrameBufferHandle /*_handle*/) override
+		void destroyFrameBuffer(FrameBufferHandle _handle) override
 		{
 		{
+			m_frameBuffers[_handle.idx].destroy();
 		}
 		}
 
 
 		void createUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name) override
 		void createUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name) override
@@ -2609,21 +2615,21 @@ VK_IMPORT_DEVICE
 				const FrameBufferVK& frameBuffer = m_frameBuffers[m_fbh.idx];
 				const FrameBufferVK& frameBuffer = m_frameBuffers[m_fbh.idx];
 				BX_UNUSED(frameBuffer);
 				BX_UNUSED(frameBuffer);
 
 
-//				for (uint8_t ii = 0, num = frameBuffer.m_num; ii < num; ++ii)
-//				{
-//					TextureVK& texture = m_textures[frameBuffer.m_texture[ii].idx];
-//					texture.setState(m_commandList, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
-//				}
-//
-//				if (isValid(frameBuffer.m_depth) )
-//				{
-//					TextureVK& texture = m_textures[frameBuffer.m_depth.idx];
-//					const bool writeOnly  = 0 != (texture.m_flags&BGFX_TEXTURE_RT_WRITE_ONLY);
-//					if (!writeOnly)
-//					{
-//						texture.setState(m_commandList, D3D12_RESOURCE_STATE_DEPTH_READ);
-//					}
-//				}
+				for (uint8_t ii = 0, num = frameBuffer.m_num; ii < num; ++ii)
+				{
+					TextureVK& texture = m_textures[frameBuffer.m_texture[ii].idx];
+					texture.setImageMemoryBarrier(m_commandBuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+				}
+
+				if (isValid(frameBuffer.m_depth) )
+				{
+					TextureVK& texture = m_textures[frameBuffer.m_depth.idx];
+					const bool writeOnly  = 0 != (texture.m_flags&BGFX_TEXTURE_RT_WRITE_ONLY);
+					if (!writeOnly)
+					{
+						texture.setImageMemoryBarrier(m_commandBuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+					}
+				}
 			}
 			}
 
 
 			if (!isValid(_fbh) )
 			if (!isValid(_fbh) )
@@ -2669,15 +2675,13 @@ VK_IMPORT_DEVICE
 				for (uint8_t ii = 0, num = frameBuffer.m_num; ii < num; ++ii)
 				for (uint8_t ii = 0, num = frameBuffer.m_num; ii < num; ++ii)
 				{
 				{
 					TextureVK& texture = m_textures[frameBuffer.m_texture[ii].idx];
 					TextureVK& texture = m_textures[frameBuffer.m_texture[ii].idx];
-					BX_UNUSED(texture);
-//					texture.setState(m_commandList, D3D12_RESOURCE_STATE_RENDER_TARGET);
+					texture.setImageMemoryBarrier(m_commandBuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
 				}
 				}
 
 
 				if (isValid(frameBuffer.m_depth) )
 				if (isValid(frameBuffer.m_depth) )
 				{
 				{
 					TextureVK& texture = m_textures[frameBuffer.m_depth.idx];
 					TextureVK& texture = m_textures[frameBuffer.m_depth.idx];
-					BX_UNUSED(texture);
-//					texture.setState(m_commandList, D3D12_RESOURCE_STATE_DEPTH_WRITE);
+					texture.setImageMemoryBarrier(m_commandBuffer, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
 				}
 				}
 
 
 //				m_commandList->OMSetRenderTargets(frameBuffer.m_num
 //				m_commandList->OMSetRenderTargets(frameBuffer.m_num
@@ -2691,8 +2695,8 @@ VK_IMPORT_DEVICE
 //			m_rtMsaa = _msaa;
 //			m_rtMsaa = _msaa;
 		}
 		}
 
 
-          		void setBlendState(VkPipelineColorBlendStateCreateInfo& _desc, uint64_t _state, uint32_t _rgba = 0)
-          		{
+		void setBlendState(VkPipelineColorBlendStateCreateInfo& _desc, uint64_t _state, uint32_t _rgba = 0)
+		{
 			VkPipelineColorBlendAttachmentState* bas = const_cast<VkPipelineColorBlendAttachmentState*>(_desc.pAttachments);
 			VkPipelineColorBlendAttachmentState* bas = const_cast<VkPipelineColorBlendAttachmentState*>(_desc.pAttachments);
 
 
 			uint8_t writeMask = 0;
 			uint8_t writeMask = 0;
@@ -2874,6 +2878,198 @@ VK_IMPORT_DEVICE
 			return num;
 			return num;
 		}
 		}
 
 
+		uint32_t getRenderPassHashkey(uint8_t _num, const Attachment* attachments)
+		{
+			if (_num == 0)
+				return 0;
+			bx::HashMurmur2A hash;
+			hash.begin(0);
+			for (uint8_t ii = 0; ii < _num; ++ii)
+			{
+				hash.add(attachments[ii].access);
+				hash.add(attachments[ii].layer);
+				hash.add(attachments[ii].mip);
+				hash.add(attachments[ii].resolve);
+
+				TextureVK& texture = m_textures[attachments[ii].handle.idx];
+				hash.add(texture.m_textureFormat);
+			}
+			return hash.end();
+		}
+
+		VkRenderPass getRenderPass(uint8_t _num, const Attachment* _attachments)
+		{
+			VkRenderPass renderPass = VK_NULL_HANDLE;
+			uint32_t hashKey = getRenderPassHashkey(_num, _attachments);
+			renderPass = (VkRenderPass)m_renderPassCache.find(hashKey);
+			if (renderPass != VK_NULL_HANDLE)
+				return renderPass;
+
+			// cache missed
+			VkAttachmentDescription ad[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
+			VkAttachmentReference colorAr[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
+			VkAttachmentReference resolveAr;
+			VkAttachmentReference depthAr;
+			uint32_t numColorAr = 0;
+
+			resolveAr.attachment = VK_ATTACHMENT_UNUSED;
+			resolveAr.layout     = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+			depthAr.attachment   = VK_ATTACHMENT_UNUSED;
+			depthAr.layout		 = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+			for (uint8_t ii = 0; ii < _num; ++ii)
+			{
+				TextureVK& texture = m_textures[_attachments[ii].handle.idx];
+				ad[ii].flags          = 0;
+				ad[ii].format         = texture.m_vkTextureFormat;
+				ad[ii].samples        = VK_SAMPLE_COUNT_1_BIT;
+				ad[ii].loadOp         = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+				ad[ii].storeOp        = VK_ATTACHMENT_STORE_OP_STORE;
+				ad[ii].stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+				ad[ii].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+				ad[ii].initialLayout  = VK_IMAGE_LAYOUT_UNDEFINED;
+
+				if (texture.m_vkTextureAspect & VK_IMAGE_ASPECT_COLOR_BIT)
+				{
+					ad[ii].finalLayout               = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+					colorAr[numColorAr].layout       = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+					colorAr[numColorAr].attachment   = ii;
+					numColorAr++;
+				}
+				else if (texture.m_vkTextureAspect & VK_IMAGE_ASPECT_DEPTH_BIT)
+				{
+					ad[ii].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+					depthAr.layout     = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+					depthAr.attachment = ii;
+				}
+			}
+
+			VkSubpassDescription sd[1];
+			sd[0].flags                   = 0;
+			sd[0].pipelineBindPoint       = VK_PIPELINE_BIND_POINT_GRAPHICS;
+			sd[0].inputAttachmentCount    = 0;
+			sd[0].pInputAttachments       = NULL;
+			sd[0].colorAttachmentCount    = numColorAr;
+			sd[0].pColorAttachments       = colorAr;
+			sd[0].pResolveAttachments     = &resolveAr;
+			sd[0].pDepthStencilAttachment = &depthAr;
+			sd[0].preserveAttachmentCount = 0;
+			sd[0].pPreserveAttachments    = NULL;
+
+			VkRenderPassCreateInfo rpi;
+			rpi.sType           = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+			rpi.pNext           = NULL;
+			rpi.flags           = 0;
+			rpi.attachmentCount = _num;
+			rpi.pAttachments    = ad;
+			rpi.subpassCount    = BX_COUNTOF(sd);
+			rpi.pSubpasses      = sd;
+			rpi.dependencyCount = 0;
+			rpi.pDependencies   = NULL;
+
+			VK_CHECK( vkCreateRenderPass(m_device, &rpi, m_allocatorCb, &renderPass) );
+
+			m_renderPassCache.add(hashKey, renderPass);
+			return renderPass;
+		}
+
+		VkSampler getSampler(uint32_t _samplerFlags, uint32_t _mipLevels)
+		{
+			bx::HashMurmur2A hash;
+			hash.add(_samplerFlags);
+			hash.add(_mipLevels);
+			uint32_t hashKey = hash.end();
+
+			VkSampler sampler = m_samplerCache.find(hashKey);
+			if (sampler != VK_NULL_HANDLE)
+				return sampler;
+
+			// set default sampler
+			VkSamplerCreateInfo samplerInfo;
+			samplerInfo.sType        = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+			samplerInfo.pNext		 = NULL;
+			samplerInfo.flags        = 0;
+			samplerInfo.magFilter    = VK_FILTER_LINEAR;
+			samplerInfo.minFilter    = VK_FILTER_LINEAR;
+			samplerInfo.mipmapMode   = VK_SAMPLER_MIPMAP_MODE_LINEAR;
+			samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+			samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+			samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+			samplerInfo.mipLodBias   = 0.0f;
+			samplerInfo.anisotropyEnable = VK_FALSE;
+			samplerInfo.maxAnisotropy = 0; // TODO
+			samplerInfo.compareEnable = VK_FALSE;
+			samplerInfo.compareOp    = VK_COMPARE_OP_ALWAYS;
+			samplerInfo.minLod       = 0.0f;
+			samplerInfo.maxLod       = (float)_mipLevels;
+			samplerInfo.borderColor  = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
+			samplerInfo.unnormalizedCoordinates = VK_FALSE;
+
+			if (0 == (_samplerFlags & BGFX_SAMPLER_INTERNAL_DEFAULT))
+			{
+				switch (_samplerFlags & BGFX_SAMPLER_MAG_MASK)
+				{
+					case BGFX_SAMPLER_MAG_POINT:       samplerInfo.magFilter = VK_FILTER_NEAREST; break;
+					case BGFX_SAMPLER_MAG_ANISOTROPIC: samplerInfo.anisotropyEnable = VK_TRUE;    break;
+				}
+
+				switch (_samplerFlags & BGFX_SAMPLER_MIN_MASK)
+				{
+					case BGFX_SAMPLER_MIN_POINT:       samplerInfo.minFilter = VK_FILTER_NEAREST; break;
+					case BGFX_SAMPLER_MIN_ANISOTROPIC: samplerInfo.anisotropyEnable = VK_TRUE;    break;
+				}
+
+				switch (_samplerFlags & BGFX_SAMPLER_U_MASK)
+				{
+					case BGFX_SAMPLER_U_MIRROR: samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; break;
+					case BGFX_SAMPLER_U_CLAMP:  samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;   break;
+					case BGFX_SAMPLER_U_BORDER: samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; break;
+				}
+
+				switch (_samplerFlags & BGFX_SAMPLER_V_MASK)
+				{
+					case BGFX_SAMPLER_V_MIRROR: samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; break;
+					case BGFX_SAMPLER_V_CLAMP:  samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;   break;
+					case BGFX_SAMPLER_V_BORDER: samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; break;
+				}
+
+				switch (_samplerFlags & BGFX_SAMPLER_W_MASK)
+				{
+					case BGFX_SAMPLER_W_MIRROR: samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; break;
+					case BGFX_SAMPLER_W_CLAMP:  samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;   break;
+					case BGFX_SAMPLER_W_BORDER: samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; break;
+				}
+
+				if (0 != (_samplerFlags & BGFX_SAMPLER_COMPARE_MASK))
+				{
+					samplerInfo.compareEnable = VK_TRUE;
+					switch (_samplerFlags & BGFX_SAMPLER_COMPARE_MASK)
+					{
+						case BGFX_SAMPLER_COMPARE_LESS:     samplerInfo.compareOp = VK_COMPARE_OP_LESS;             break;
+						case BGFX_SAMPLER_COMPARE_LEQUAL:   samplerInfo.compareOp = VK_COMPARE_OP_LESS_OR_EQUAL;    break;
+						case BGFX_SAMPLER_COMPARE_EQUAL:    samplerInfo.compareOp = VK_COMPARE_OP_EQUAL;            break;
+						case BGFX_SAMPLER_COMPARE_GEQUAL:   samplerInfo.compareOp = VK_COMPARE_OP_GREATER_OR_EQUAL; break;
+						case BGFX_SAMPLER_COMPARE_GREATER:  samplerInfo.compareOp = VK_COMPARE_OP_GREATER;          break;
+						case BGFX_SAMPLER_COMPARE_NOTEQUAL: samplerInfo.compareOp = VK_COMPARE_OP_NOT_EQUAL;        break;
+						case BGFX_SAMPLER_COMPARE_NEVER:    samplerInfo.compareOp = VK_COMPARE_OP_NEVER;            break;
+						case BGFX_SAMPLER_COMPARE_ALWAYS:   samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;           break;
+					}
+				}
+
+				uint32_t borderColor = ((_samplerFlags & BGFX_SAMPLER_BORDER_COLOR_MASK) >> BGFX_SAMPLER_BORDER_COLOR_SHIFT);
+				if (borderColor > 0)
+				{
+					// TODO: set borderColor properly
+					samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_WHITE;
+				}
+			}
+
+			VK_CHECK(vkCreateSampler(m_device, &samplerInfo, m_allocatorCb, &sampler));
+
+			m_samplerCache.add(hashKey, sampler);
+			return sampler;
+		}
+
 		VkPipeline getPipeline(ProgramHandle _program)
 		VkPipeline getPipeline(ProgramHandle _program)
 		{
 		{
 			BX_UNUSED(_program);
 			BX_UNUSED(_program);
@@ -3028,7 +3224,7 @@ VK_IMPORT_DEVICE
 			graphicsPipeline.pDynamicState       = &dynamicState;
 			graphicsPipeline.pDynamicState       = &dynamicState;
 //			graphicsPipeline.layout     = m_pipelineLayout;
 //			graphicsPipeline.layout     = m_pipelineLayout;
 			graphicsPipeline.layout     = program.m_pipelineLayout;
 			graphicsPipeline.layout     = program.m_pipelineLayout;
-			graphicsPipeline.renderPass = m_renderPass;
+			graphicsPipeline.renderPass = isValid(m_fbh) ? m_frameBuffers[m_fbh.idx].m_renderPass : m_renderPass;
 			graphicsPipeline.subpass    = 0;
 			graphicsPipeline.subpass    = 0;
 			graphicsPipeline.basePipelineHandle = VK_NULL_HANDLE;
 			graphicsPipeline.basePipelineHandle = VK_NULL_HANDLE;
 			graphicsPipeline.basePipelineIndex  = 0;
 			graphicsPipeline.basePipelineIndex  = 0;
@@ -3189,12 +3385,12 @@ VK_IMPORT_DEVICE
 			rect[0].layerCount     = 1;
 			rect[0].layerCount     = 1;
 
 
 			uint32_t numMrt = 1;
 			uint32_t numMrt = 1;
-//			FrameBufferHandle fbh = m_fbh;
-//			if (isValid(fbh) )
-//			{
-//				const FrameBufferVK& fb = m_frameBuffers[fbh.idx];
-//				numMrt = bx::max(1, fb.m_num);
-//			}
+			FrameBufferHandle fbh = m_fbh;
+			if (isValid(fbh) )
+			{
+				const FrameBufferVK& fb = m_frameBuffers[fbh.idx];
+				numMrt = bx::max((uint8_t)1, fb.m_num);
+			}
 
 
 			VkClearAttachment attachments[BGFX_CONFIG_MAX_FRAME_BUFFERS];
 			VkClearAttachment attachments[BGFX_CONFIG_MAX_FRAME_BUFFERS];
 			uint32_t mrt = 0;
 			uint32_t mrt = 0;
@@ -3246,12 +3442,15 @@ VK_IMPORT_DEVICE
 				++mrt;
 				++mrt;
 			}
 			}
 
 
-			vkCmdClearAttachments(m_commandBuffer
-				, mrt
-				, attachments
-				, BX_COUNTOF(rect)
-				, rect
-				);
+			if (mrt > 0)
+			{
+				vkCmdClearAttachments(m_commandBuffer
+					, mrt
+					, attachments
+					, BX_COUNTOF(rect)
+					, rect
+					);
+			}
 		}
 		}
 
 
 		uint64_t kick(VkSemaphore _wait = VK_NULL_HANDLE, VkSemaphore _signal = VK_NULL_HANDLE)
 		uint64_t kick(VkSemaphore _wait = VK_NULL_HANDLE, VkSemaphore _signal = VK_NULL_HANDLE)
@@ -3403,6 +3602,8 @@ VK_IMPORT_DEVICE
 
 
 		StateCacheT<VkPipeline> m_pipelineStateCache;
 		StateCacheT<VkPipeline> m_pipelineStateCache;
 		StateCacheT<VkDescriptorSetLayout> m_descriptorSetLayoutCache;
 		StateCacheT<VkDescriptorSetLayout> m_descriptorSetLayoutCache;
+		StateCacheT<VkRenderPass> m_renderPassCache;
+		StateCacheT<VkSampler> m_samplerCache;
 
 
 		Resolution m_resolution;
 		Resolution m_resolution;
 		uint32_t m_maxAnisotropy;
 		uint32_t m_maxAnisotropy;
@@ -3743,10 +3944,10 @@ VK_DESTROY
 			VkCommandBuffer commandBuffer = s_renderVK->beginNewCommand();
 			VkCommandBuffer commandBuffer = s_renderVK->beginNewCommand();
 			// copy buffer to buffer
 			// copy buffer to buffer
 			{
 			{
-				VkBufferCopy region = {};
+				VkBufferCopy region;
 				region.srcOffset = 0;
 				region.srcOffset = 0;
 				region.dstOffset = 0;
 				region.dstOffset = 0;
-				region.size = _size;
+				region.size      = _size;
 
 
 				vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_buffer, 1, &region);
 				vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_buffer, 1, &region);
 			}
 			}
@@ -3816,10 +4017,10 @@ VK_DESTROY
 		VkCommandBuffer commandBuffer = s_renderVK->beginNewCommand();
 		VkCommandBuffer commandBuffer = s_renderVK->beginNewCommand();
 		// copy buffer to buffer
 		// copy buffer to buffer
 		{
 		{
-			VkBufferCopy region = {};
+			VkBufferCopy region;
 			region.srcOffset = 0;
 			region.srcOffset = 0;
 			region.dstOffset = _offset;
 			region.dstOffset = _offset;
-			region.size = _size;
+			region.size      = _size;
 
 
 			vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_buffer, 1, &region);
 			vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_buffer, 1, &region);
 		}
 		}
@@ -3903,7 +4104,12 @@ VK_DESTROY
 
 
 		uint8_t fragmentBit = fragment ? BGFX_UNIFORM_FRAGMENTBIT : 0;
 		uint8_t fragmentBit = fragment ? BGFX_UNIFORM_FRAGMENTBIT : 0;
 
 
-		bx::memSet(m_sampler, 0, sizeof(SamplerInfo) * BX_COUNTOF(m_sampler));
+		for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_TEXTURE_SAMPLERS; ++ii)
+        {
+            m_sampler[ii].uniformHandle = {kInvalidHandle};
+            m_sampler[ii].imageBinding = 0;
+            m_sampler[ii].samplerBinding = 0;
+        }
 		if (0 < count)
 		if (0 < count)
 		{
 		{
 			for (uint32_t ii = 0; ii < count; ++ii)
 			for (uint32_t ii = 0; ii < count; ++ii)
@@ -3962,7 +4168,6 @@ VK_DESTROY
 					m_sampler[num].uniformHandle = info->m_handle;
 					m_sampler[num].uniformHandle = info->m_handle;
 					m_sampler[num].imageBinding = regIndex;	// regIndex is used for image binding index
 					m_sampler[num].imageBinding = regIndex;	// regIndex is used for image binding index
 					m_sampler[num].samplerBinding = regCount;	// regCount is used for sampler binding index
 					m_sampler[num].samplerBinding = regCount;	// regCount is used for sampler binding index
-					m_numSamplers++;
 
 
 					kind = "sampler";
 					kind = "sampler";
 				}
 				}
@@ -4206,11 +4411,13 @@ VK_DESTROY
 			m_textureFormat = uint8_t(getViableTextureFormat(imageContainer));
 			m_textureFormat = uint8_t(getViableTextureFormat(imageContainer));
 			const bool convert = m_textureFormat != m_requestedFormat;
 			const bool convert = m_textureFormat != m_requestedFormat;
 			const uint8_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_textureFormat));
 			const uint8_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_textureFormat));
-			VkImageAspectFlags aspectFlag = bimg::isDepth((bimg::TextureFormat::Enum)m_textureFormat)
+			m_vkTextureAspect = bimg::isDepth((bimg::TextureFormat::Enum)m_textureFormat)
 				? VK_IMAGE_ASPECT_DEPTH_BIT
 				? VK_IMAGE_ASPECT_DEPTH_BIT
 				: VK_IMAGE_ASPECT_COLOR_BIT
 				: VK_IMAGE_ASPECT_COLOR_BIT
 				;
 				;
-			VkFormat textureFormat = bimg::isDepth((bimg::TextureFormat::Enum)m_textureFormat)
+			if (m_textureFormat == TextureFormat::D0S8 || m_textureFormat == TextureFormat::D24S8)
+				m_vkTextureAspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
+			m_vkTextureFormat = bimg::isDepth((bimg::TextureFormat::Enum)m_textureFormat)
 				? s_textureFormat[m_textureFormat].m_fmtDsv
 				? s_textureFormat[m_textureFormat].m_fmtDsv
 				: s_textureFormat[m_textureFormat].m_fmt
 				: s_textureFormat[m_textureFormat].m_fmt
 				;
 				;
@@ -4229,6 +4436,7 @@ VK_DESTROY
 			}
 			}
 
 
 			m_numMips = ti.numMips;
 			m_numMips = ti.numMips;
+			m_numSides = ti.numLayers * (imageContainer.m_cubeMap ? 6 : 1);
 			const uint16_t numSides = ti.numLayers * (imageContainer.m_cubeMap ? 6 : 1);
 			const uint16_t numSides = ti.numLayers * (imageContainer.m_cubeMap ? 6 : 1);
 			const uint32_t numSrd = numSides * ti.numMips;
 			const uint32_t numSrd = numSides * ti.numMips;
 
 
@@ -4267,7 +4475,7 @@ VK_DESTROY
 
 
 			ImageInfo* imageInfos = (ImageInfo*)BX_ALLOC(g_allocator, sizeof(ImageInfo) * numSrd);
 			ImageInfo* imageInfos = (ImageInfo*)BX_ALLOC(g_allocator, sizeof(ImageInfo) * numSrd);
 			bx::memSet(imageInfos, 0, sizeof(ImageInfo) * numSrd);
 			bx::memSet(imageInfos, 0, sizeof(ImageInfo) * numSrd);
-			uint32_t alignment = 256;
+			uint32_t alignment = 1; // tightly aligned buffer
 			for (uint8_t side = 0; side < numSides; ++side)
 			for (uint8_t side = 0; side < numSides; ++side)
 			{
 			{
 				for (uint8_t lod = 0; lod < ti.numMips; ++lod)
 				for (uint8_t lod = 0; lod < ti.numMips; ++lod)
@@ -4360,15 +4568,17 @@ VK_DESTROY
 			VkBufferImageCopy* bufferCopyInfo = (VkBufferImageCopy*)BX_ALLOC(g_allocator, sizeof(VkBufferImageCopy) * numSrd);
 			VkBufferImageCopy* bufferCopyInfo = (VkBufferImageCopy*)BX_ALLOC(g_allocator, sizeof(VkBufferImageCopy) * numSrd);
 			for (uint32_t ii = 0; ii < numSrd; ++ii)
 			for (uint32_t ii = 0; ii < numSrd; ++ii)
 			{
 			{
-				bufferCopyInfo[ii].bufferOffset = totalMemSize;
-				bufferCopyInfo[ii].bufferImageHeight = 0;
-				bufferCopyInfo[ii].bufferRowLength = 0;
-				bufferCopyInfo[ii].imageOffset = { 0, 0, 0 };
-				bufferCopyInfo[ii].imageExtent = { imageInfos[ii].width, imageInfos[ii].height, imageInfos[ii].depth };
-				bufferCopyInfo[ii].imageSubresource.aspectMask = aspectFlag;
-				bufferCopyInfo[ii].imageSubresource.mipLevel = imageInfos[ii].mipLevel;
+				uint32_t idealWidth  = m_width  >> imageInfos[ii].mipLevel;
+				uint32_t idealHeight = m_height >> imageInfos[ii].mipLevel;
+				bufferCopyInfo[ii].bufferOffset      = totalMemSize;
+				bufferCopyInfo[ii].bufferRowLength   = 0; // assume that image data are tightly aligned
+				bufferCopyInfo[ii].bufferImageHeight = 0; // assume that image data are tightly aligned
+				bufferCopyInfo[ii].imageSubresource.aspectMask     = m_vkTextureAspect;
+				bufferCopyInfo[ii].imageSubresource.mipLevel       = imageInfos[ii].mipLevel;
 				bufferCopyInfo[ii].imageSubresource.baseArrayLayer = imageInfos[ii].layer;
 				bufferCopyInfo[ii].imageSubresource.baseArrayLayer = imageInfos[ii].layer;
-				bufferCopyInfo[ii].imageSubresource.layerCount = 1;
+				bufferCopyInfo[ii].imageSubresource.layerCount     = 1;
+				bufferCopyInfo[ii].imageOffset = { 0, 0, 0 };
+				bufferCopyInfo[ii].imageExtent = { idealWidth, idealHeight, imageInfos[ii].depth };
 				totalMemSize += imageInfos[ii].size;
 				totalMemSize += imageInfos[ii].size;
 			}
 			}
 
 
@@ -4432,11 +4642,19 @@ VK_DESTROY
 			ici.queueFamilyIndexCount = 0;
 			ici.queueFamilyIndexCount = 0;
 			ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 			ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 			ici.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 			ici.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-			ici.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+			ici.usage = 0
+				| VK_IMAGE_USAGE_TRANSFER_DST_BIT
+				| VK_IMAGE_USAGE_SAMPLED_BIT
+				| (_flags & BGFX_TEXTURE_RT_MASK ?
+					(bimg::isDepth((bimg::TextureFormat::Enum)m_textureFormat) ?
+					VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT :
+					VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
+					: 0)
+				;
 			ici.format = bimg::isDepth((bimg::TextureFormat::Enum)m_textureFormat) ? s_textureFormat[m_textureFormat].m_fmtDsv : s_textureFormat[m_textureFormat].m_fmt;
 			ici.format = bimg::isDepth((bimg::TextureFormat::Enum)m_textureFormat) ? s_textureFormat[m_textureFormat].m_fmtDsv : s_textureFormat[m_textureFormat].m_fmt;
 			ici.samples = VK_SAMPLE_COUNT_1_BIT;
 			ici.samples = VK_SAMPLE_COUNT_1_BIT;
 			ici.mipLevels = m_numMips;
 			ici.mipLevels = m_numMips;
-			ici.arrayLayers = (m_type == VK_IMAGE_VIEW_TYPE_CUBE ? 6 : m_numLayers);
+			ici.arrayLayers = m_numSides;
 			ici.extent.width = m_width;
 			ici.extent.width = m_width;
 			ici.extent.height = m_height;
 			ici.extent.height = m_height;
 			ici.extent.depth = m_depth;
 			ici.extent.depth = m_depth;
@@ -4461,25 +4679,14 @@ VK_DESTROY
 
 
 			if (stagingBuffer)
 			if (stagingBuffer)
 			{
 			{
-				/*VkBufferImageCopy region = {};
-				region.bufferOffset = 0;
-				region.bufferRowLength = 0;
-				region.bufferImageHeight = 0;
-				region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-				region.imageSubresource.mipLevel = 0;
-				region.imageSubresource.baseArrayLayer = 0;
-				region.imageSubresource.layerCount = 1;
-
-				region.imageOffset.x = 0;
-				region.imageOffset.y = 0;
-				region.imageOffset.z = 0;
-				region.imageExtent.width = m_width;
-				region.imageExtent.height = m_height;
-				region.imageExtent.depth = 1;
-
-				copyBufferToTexture(stagingBuffer, 1, &region);*/
 				copyBufferToTexture(stagingBuffer, numSrd, bufferCopyInfo);
 				copyBufferToTexture(stagingBuffer, numSrd, bufferCopyInfo);
 			}
 			}
+			else
+			{
+				VkCommandBuffer commandBuffer = s_renderVK->beginNewCommand();
+				setImageMemoryBarrier(commandBuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+				s_renderVK->submitCommandAndWait(commandBuffer);
+			}
 
 
 			vkFreeMemory(device, stagingDeviceMem, &s_allocationCb);
 			vkFreeMemory(device, stagingDeviceMem, &s_allocationCb);
 			vkDestroy(stagingBuffer);
 			vkDestroy(stagingBuffer);
@@ -4493,42 +4700,24 @@ VK_DESTROY
 
 
 			// image view creation
 			// image view creation
 			{
 			{
-				VkImageViewCreateInfo viewInfo = {};
-				viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-				viewInfo.image = m_textureImage;
-				viewInfo.viewType = m_type;
-				viewInfo.format = textureFormat;
-				viewInfo.subresourceRange.aspectMask = aspectFlag;
-				viewInfo.subresourceRange.baseMipLevel = 0;
-				viewInfo.subresourceRange.levelCount = 1; //m_numMips;
+				VkImageViewCreateInfo viewInfo;
+				viewInfo.sType        = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+				viewInfo.pNext        = NULL;
+				viewInfo.flags        = 0;
+				viewInfo.image        = m_textureImage;
+				viewInfo.viewType     = m_type;
+				viewInfo.format       = m_vkTextureFormat;
+				viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+				viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+				viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+				viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+				viewInfo.subresourceRange.aspectMask     = m_vkTextureAspect;
+				viewInfo.subresourceRange.baseMipLevel   = 0;
+				viewInfo.subresourceRange.levelCount     = m_numMips; //m_numMips;
 				viewInfo.subresourceRange.baseArrayLayer = 0;
 				viewInfo.subresourceRange.baseArrayLayer = 0;
-				viewInfo.subresourceRange.layerCount = 1; //(m_type == VK_IMAGE_VIEW_TYPE_CUBE ? 6 : m_numLayers);
-
+				viewInfo.subresourceRange.layerCount     = m_numSides; //(m_type == VK_IMAGE_VIEW_TYPE_CUBE ? 6 : m_numLayers);
 				VK_CHECK(vkCreateImageView(device, &viewInfo, &s_allocationCb, &m_textureImageView));
 				VK_CHECK(vkCreateImageView(device, &viewInfo, &s_allocationCb, &m_textureImageView));
 			}
 			}
-
-			// sampler creation
-			{
-				VkSamplerCreateInfo samplerInfo = {};
-				samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
-				samplerInfo.magFilter = VK_FILTER_LINEAR;
-				samplerInfo.minFilter = VK_FILTER_LINEAR;
-				samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
-				samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
-				samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
-				samplerInfo.anisotropyEnable = VK_FALSE; // TODO
-				samplerInfo.maxAnisotropy = 0;
-				samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
-				samplerInfo.unnormalizedCoordinates = VK_FALSE;
-				samplerInfo.compareEnable = VK_FALSE;
-				samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
-				samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
-				samplerInfo.mipLodBias = 0.0f;
-				samplerInfo.minLod = 0.0f;
-				samplerInfo.maxLod = 0.0f;
-
-				VK_CHECK(vkCreateSampler(device, &samplerInfo, &s_allocationCb, &m_textureSampler));
-			}
 		}
 		}
 
 
 		return m_directAccessPtr;
 		return m_directAccessPtr;
@@ -4541,7 +4730,6 @@ VK_DESTROY
 			VkDevice device = s_renderVK->m_device;
 			VkDevice device = s_renderVK->m_device;
 			vkFreeMemory(device, m_textureDeviceMem, &s_allocationCb);
 			vkFreeMemory(device, m_textureDeviceMem, &s_allocationCb);
 
 
-			vkDestroy(m_textureSampler);
 			vkDestroy(m_textureImageView);
 			vkDestroy(m_textureImageView);
 			vkDestroy(m_textureImage);
 			vkDestroy(m_textureImage);
 		}
 		}
@@ -4549,7 +4737,7 @@ VK_DESTROY
 
 
 	void TextureVK::update(VkCommandPool _commandPool, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem)
 	void TextureVK::update(VkCommandPool _commandPool, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem)
 	{
 	{
-		BX_UNUSED(_commandPool, _side, _mip, _pitch);
+		BX_UNUSED(_commandPool);
 		VkDevice device = s_renderVK->m_device;
 		VkDevice device = s_renderVK->m_device;
 
 
 		VkBuffer stagingBuffer = VK_NULL_HANDLE;
 		VkBuffer stagingBuffer = VK_NULL_HANDLE;
@@ -4560,7 +4748,7 @@ VK_DESTROY
 		bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
 		bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
 		bci.pNext = NULL;
 		bci.pNext = NULL;
 		bci.flags = 0;
 		bci.flags = 0;
-		bci.size = _rect.m_width * _rect.m_height * _depth * 4;
+		bci.size = (_pitch == UINT16_MAX ? _mem->size :_rect.m_height * _pitch * _depth);
 		bci.queueFamilyIndexCount = 0;
 		bci.queueFamilyIndexCount = 0;
 		bci.pQueueFamilyIndices = NULL;
 		bci.pQueueFamilyIndices = NULL;
 		bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 		bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@@ -4596,25 +4784,21 @@ VK_DESTROY
 
 
 		void* directAccessPtr = NULL;
 		void* directAccessPtr = NULL;
 		VK_CHECK(vkBindBufferMemory(device, stagingBuffer, stagingDeviceMem, 0));
 		VK_CHECK(vkBindBufferMemory(device, stagingBuffer, stagingDeviceMem, 0));
-		VK_CHECK(vkMapMemory(device, stagingDeviceMem, 0, ma.allocationSize, 0, (void**)& directAccessPtr));
-		bx::memCopy(directAccessPtr, _mem->data, _mem->size);
+		VK_CHECK(vkMapMemory(device, stagingDeviceMem, 0, ma.allocationSize, 0, (void**)&directAccessPtr));
+		bx::memCopy(directAccessPtr, _mem->data, bci.size);
 		vkUnmapMemory(device, stagingDeviceMem);
 		vkUnmapMemory(device, stagingDeviceMem);
 
 
-		VkBufferImageCopy region = {};
-		region.bufferOffset = 0;
-		region.bufferRowLength = 0;
+		const uint32_t bpp    = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_textureFormat) );
+		VkBufferImageCopy region;
+		region.bufferOffset      = 0;
+		region.bufferRowLength   = (_pitch == UINT16_MAX ? 0 : _pitch * 8 / bpp);
 		region.bufferImageHeight = 0;
 		region.bufferImageHeight = 0;
-		region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-		region.imageSubresource.mipLevel = 0;
-		region.imageSubresource.baseArrayLayer = 0;
-		region.imageSubresource.layerCount = 1;
-
-		region.imageOffset.x = _rect.m_x;
-		region.imageOffset.y = _rect.m_y;
-		region.imageOffset.z = _z;
-		region.imageExtent.width = _rect.m_width;
-		region.imageExtent.height = _rect.m_height;
-		region.imageExtent.depth = _depth;
+		region.imageSubresource.aspectMask     = m_vkTextureAspect;
+		region.imageSubresource.mipLevel       = _mip;
+		region.imageSubresource.baseArrayLayer = _side;
+		region.imageSubresource.layerCount     = 1;
+		region.imageOffset = { _rect.m_x, _rect.m_y, _z };
+		region.imageExtent = { _rect.m_width, _rect.m_height, _depth };
 
 
 		copyBufferToTexture(stagingBuffer, 1, &region);
 		copyBufferToTexture(stagingBuffer, 1, &region);
 
 
@@ -4626,19 +4810,76 @@ VK_DESTROY
 	{
 	{
 		VkCommandBuffer commandBuffer = s_renderVK->beginNewCommand();
 		VkCommandBuffer commandBuffer = s_renderVK->beginNewCommand();
 		// image Layout transition into destination optimal
 		// image Layout transition into destination optimal
-		setImageMemoryBarrier(commandBuffer, m_textureImage, m_currentImageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_numMips, m_numLayers);
+		setImageMemoryBarrier(commandBuffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
 
 
 		// copy buffer to image
 		// copy buffer to image
 		vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, m_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, bufferImageCopyCount, bufferImageCopy);
 		vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, m_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, bufferImageCopyCount, bufferImageCopy);
 
 
-		setImageMemoryBarrier(commandBuffer, m_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, m_numMips, m_numLayers);
+		setImageMemoryBarrier(commandBuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
 		s_renderVK->submitCommandAndWait(commandBuffer);
 		s_renderVK->submitCommandAndWait(commandBuffer);
-		m_currentImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 	}
 	}
 
 
+	void TextureVK::setImageMemoryBarrier(VkCommandBuffer commandBuffer, VkImageLayout newImageLayout)
+	{
+		if (m_currentImageLayout == newImageLayout)
+			return;
+		bgfx::vk::setImageMemoryBarrier(commandBuffer
+			, m_textureImage
+			, m_vkTextureAspect
+			, m_currentImageLayout
+			, newImageLayout
+			, m_numMips
+			, m_numSides
+			);
+		m_currentImageLayout = newImageLayout;
+	}
+
+	void FrameBufferVK::create(uint8_t _num, const Attachment* _attachment)
+	{
+		// create frame buffer object
+		m_numAttachment = _num;
+		bx::memCopy(m_attachment, _attachment, sizeof(Attachment) * _num);
+
+		VkDevice device = s_renderVK->m_device;
+		VkAllocationCallbacks* allocatorCb = s_renderVK->m_allocatorCb;
+		VkRenderPass renderPass = s_renderVK->getRenderPass(_num, _attachment);
+
+		TextureVK& firstTexture = s_renderVK->m_textures[m_attachment[0].handle.idx];
+		::VkImageView textureImageViews[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
+
+		m_num = 0;
+		for (uint8_t ii = 0; ii < m_numAttachment; ++ii)
+		{
+			TextureVK& texture = s_renderVK->m_textures[m_attachment[ii].handle.idx];
+			textureImageViews[ii] = texture.m_textureImageView;
+			if (texture.m_vkTextureAspect & VK_IMAGE_ASPECT_COLOR_BIT)
+			{
+				m_texture[m_num] = m_attachment[ii].handle;
+				m_num++;
+			}
+			else if (texture.m_vkTextureAspect & VK_IMAGE_ASPECT_DEPTH_BIT)
+			{
+				m_depth = m_attachment[ii].handle;
+			}
+		}
+
+		VkFramebufferCreateInfo fci;
+		fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+		fci.pNext = NULL;
+		fci.flags = 0;
+		fci.renderPass      = renderPass;
+		fci.attachmentCount = m_numAttachment;
+		fci.pAttachments    = textureImageViews;
+		fci.width  = firstTexture.m_width >> m_attachment[0].mip;
+		fci.height = firstTexture.m_height >> m_attachment[0].mip;
+		fci.layers = firstTexture.m_numSides;
+		VK_CHECK( vkCreateFramebuffer(device, &fci, allocatorCb, &m_framebuffer) );
+		m_renderPass = renderPass;
+	}
 
 
 	void FrameBufferVK::destroy()
 	void FrameBufferVK::destroy()
 	{
 	{
+		vkDestroy(m_framebuffer);
 	}
 	}
 
 
 	void RendererContextVK::submitBlit(BlitState& _bs, uint16_t _view)
 	void RendererContextVK::submitBlit(BlitState& _bs, uint16_t _view)
@@ -4750,6 +4991,7 @@ VK_DESTROY
 
 
 		setImageMemoryBarrier(m_commandBuffer
 		setImageMemoryBarrier(m_commandBuffer
 			, m_backBufferColorImage[m_backBufferColorIdx]
 			, m_backBufferColorImage[m_backBufferColorIdx]
+			, VK_IMAGE_ASPECT_COLOR_BIT
 			, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
 			, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
 			, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
 			, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
 			, 1, 1);
 			, 1, 1);
@@ -4817,6 +5059,7 @@ BX_UNUSED(currentSamplerStateIdx);
 					currentProgram         = BGFX_INVALID_HANDLE;
 					currentProgram         = BGFX_INVALID_HANDLE;
 					hasPredefined          = false;
 					hasPredefined          = false;
 
 
+					VK_CHECK(vkBeginCommandBuffer(m_commandBuffer, &cbbi) );
 					fbh = _render->m_view[view].m_fbh;
 					fbh = _render->m_view[view].m_fbh;
 					setFrameBuffer(fbh);
 					setFrameBuffer(fbh);
 
 
@@ -4826,11 +5069,12 @@ BX_UNUSED(currentSamplerStateIdx);
 					viewHasScissor  = !scissorRect.isZero();
 					viewHasScissor  = !scissorRect.isZero();
 					viewScissorRect = viewHasScissor ? scissorRect : rect;
 					viewScissorRect = viewHasScissor ? scissorRect : rect;
 
 
+					rpbi.framebuffer = isValid(m_fbh) ? m_frameBuffers[m_fbh.idx].m_framebuffer : m_backBufferColor[m_backBufferColorIdx];
+					rpbi.renderPass = isValid(m_fbh) ? m_frameBuffers[m_fbh.idx].m_renderPass : m_renderPass;
 					rpbi.renderArea.offset.x = rect.m_x;
 					rpbi.renderArea.offset.x = rect.m_x;
 					rpbi.renderArea.offset.y = rect.m_y;
 					rpbi.renderArea.offset.y = rect.m_y;
 					rpbi.renderArea.extent.width  = rect.m_width;
 					rpbi.renderArea.extent.width  = rect.m_width;
 					rpbi.renderArea.extent.height = rect.m_height;
 					rpbi.renderArea.extent.height = rect.m_height;
-					VK_CHECK(vkBeginCommandBuffer(m_commandBuffer, &cbbi) );
 
 
 					if (BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION) )
 					if (BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION) )
 					{
 					{
@@ -5337,12 +5581,20 @@ BX_UNUSED(currentSamplerStateIdx);
 						for (uint32_t stage = 0; stage < BGFX_CONFIG_MAX_TEXTURE_SAMPLERS; ++stage)
 						for (uint32_t stage = 0; stage < BGFX_CONFIG_MAX_TEXTURE_SAMPLERS; ++stage)
 						{
 						{
 							const Binding& bind = renderBind.m_bind[stage];
 							const Binding& bind = renderBind.m_bind[stage];
-							if (kInvalidHandle != bind.m_idx)
+							if (kInvalidHandle != bind.m_idx &&
+								isValid(program.m_fsh->m_sampler[stage].uniformHandle))
 							{
 							{
 								TextureVK& texture = m_textures[bind.m_idx];
 								TextureVK& texture = m_textures[bind.m_idx];
-								imageInfo[stage].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-								imageInfo[stage].imageView = texture.m_textureImageView;
-								imageInfo[stage].sampler = texture.m_textureSampler;
+								VkSampler sampler = getSampler(
+									(0 == (BGFX_SAMPLER_INTERNAL_DEFAULT & bind.m_samplerFlags)
+										? bind.m_samplerFlags
+										: (uint32_t)texture.m_flags
+									) & (BGFX_SAMPLER_BITS_MASK | BGFX_SAMPLER_BORDER_COLOR_MASK)
+									, (uint32_t)texture.m_numMips);
+
+								imageInfo[stage].imageLayout = texture.m_currentImageLayout;
+								imageInfo[stage].imageView   = texture.m_textureImageView;
+								imageInfo[stage].sampler     = sampler;
 
 
 								wds[wdsCount].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 								wds[wdsCount].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 								wds[wdsCount].pNext = NULL;
 								wds[wdsCount].pNext = NULL;
@@ -5789,6 +6041,7 @@ BX_UNUSED(presentMin, presentMax);
 
 
 		setImageMemoryBarrier(m_commandBuffer
 		setImageMemoryBarrier(m_commandBuffer
 			, m_backBufferColorImage[m_backBufferColorIdx]
 			, m_backBufferColorImage[m_backBufferColorIdx]
+			, VK_IMAGE_ASPECT_COLOR_BIT
 			, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
 			, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
 			, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
 			, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
 			, 1, 1);
 			, 1, 1);

+ 11 - 7
src/renderer_vk.h

@@ -390,7 +390,6 @@ VK_DESTROY
 			, m_hash(0)
 			, m_hash(0)
 			, m_numUniforms(0)
 			, m_numUniforms(0)
 			, m_numPredefined(0)
 			, m_numPredefined(0)
-			, m_numSamplers(0)
 			, m_numBindings(0)
 			, m_numBindings(0)
 		{
 		{
 		}
 		}
@@ -419,7 +418,6 @@ VK_DESTROY
 			uint32_t imageBinding;
 			uint32_t imageBinding;
 		};
 		};
 		SamplerInfo m_sampler[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
 		SamplerInfo m_sampler[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
-		uint16_t m_numSamplers;
 		uint16_t m_numBindings;
 		uint16_t m_numBindings;
 		VkDescriptorSetLayoutBinding m_bindings[32];
 		VkDescriptorSetLayoutBinding m_bindings[32];
 	};
 	};
@@ -450,10 +448,10 @@ VK_DESTROY
 	struct TextureVK
 	struct TextureVK
 	{
 	{
 		TextureVK()
 		TextureVK()
-			: m_textureImage(VK_NULL_HANDLE)
+			: m_vkTextureFormat(VK_FORMAT_UNDEFINED)
+			, m_textureImage(VK_NULL_HANDLE)
 			, m_textureDeviceMem(VK_NULL_HANDLE)
 			, m_textureDeviceMem(VK_NULL_HANDLE)
 			, m_textureImageView(VK_NULL_HANDLE)
 			, m_textureImageView(VK_NULL_HANDLE)
-			, m_textureSampler(VK_NULL_HANDLE)
 			, m_currentImageLayout(VK_IMAGE_LAYOUT_UNDEFINED)
 			, m_currentImageLayout(VK_IMAGE_LAYOUT_UNDEFINED)
 		{
 		{
 		}
 		}
@@ -463,6 +461,7 @@ VK_DESTROY
 		void update(VkCommandPool commandPool, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
 		void update(VkCommandPool commandPool, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
 
 
 		void copyBufferToTexture(VkBuffer stagingBuffer, uint32_t bufferImageCopyCount, VkBufferImageCopy* bufferImageCopy);
 		void copyBufferToTexture(VkBuffer stagingBuffer, uint32_t bufferImageCopyCount, VkBufferImageCopy* bufferImageCopy);
+		void setImageMemoryBarrier(VkCommandBuffer commandBuffer, VkImageLayout newImageLayout);
 
 
 		void* m_directAccessPtr;
 		void* m_directAccessPtr;
 		uint64_t m_flags;
 		uint64_t m_flags;
@@ -470,16 +469,17 @@ VK_DESTROY
 		uint32_t m_height;
 		uint32_t m_height;
 		uint32_t m_depth;
 		uint32_t m_depth;
 		uint32_t m_numLayers;
 		uint32_t m_numLayers;
-		uint16_t m_samplerIdx;
+		uint32_t m_numSides;
 		VkImageViewType m_type;
 		VkImageViewType m_type;
 		uint8_t m_requestedFormat;
 		uint8_t m_requestedFormat;
 		uint8_t m_textureFormat;
 		uint8_t m_textureFormat;
 		uint8_t m_numMips;
 		uint8_t m_numMips;
+		VkFormat m_vkTextureFormat;
+		VkImageAspectFlags  m_vkTextureAspect;
 
 
 		VkImage m_textureImage;
 		VkImage m_textureImage;
 		VkDeviceMemory m_textureDeviceMem;
 		VkDeviceMemory m_textureDeviceMem;
 		VkImageView m_textureImageView;
 		VkImageView m_textureImageView;
-		VkSampler m_textureSampler;
 		VkImageLayout m_currentImageLayout;
 		VkImageLayout m_currentImageLayout;
 	};
 	};
 
 
@@ -492,9 +492,10 @@ VK_DESTROY
 			, m_denseIdx(kInvalidHandle)
 			, m_denseIdx(kInvalidHandle)
 			, m_num(0)
 			, m_num(0)
 			, m_numTh(0)
 			, m_numTh(0)
+			, m_framebuffer(VK_NULL_HANDLE)
 		{
 		{
 		}
 		}
-
+		void create(uint8_t _num, const Attachment* _attachment);
 		void destroy();
 		void destroy();
 
 
 		TextureHandle m_texture[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
 		TextureHandle m_texture[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
@@ -505,7 +506,10 @@ VK_DESTROY
 		uint16_t m_denseIdx;
 		uint16_t m_denseIdx;
 		uint8_t m_num;
 		uint8_t m_num;
 		uint8_t m_numTh;
 		uint8_t m_numTh;
+		uint8_t m_numAttachment;
 		Attachment m_attachment[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
 		Attachment m_attachment[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
+		VkFramebuffer m_framebuffer;
+		VkRenderPass m_renderPass;
 	};
 	};
 
 
 } /* namespace bgfx */ } // namespace vk
 } /* namespace bgfx */ } // namespace vk