Quellcode durchsuchen

Various Vulkan fixes (#2408)

* Vulkan: query max anisotropy

...instead of hardcoding it to 4

* Vulkan: use BGFX_CONFIG_MIP_LOD_BIAS

* Vulkan: consider BGFX_CONFIG_PREFER_DISCRETE_GPU at device selection

* Vulkan: implement resizing for textures with backbuffer ratio size

* Vulkan: use correct framebuffer attachment layer and mip

* Vulkan: bind correct image mip

* Cleanup

* Vulkan: add indirect draw support

* Vulkan: add support for BGFX_DEBUG_WIREFRAME

* Vulkan: check all extensions and layers

... not just the first 64

* Vulkan: add support for VPRT

https://github.com/bkaradzic/bgfx/issues/2320
pezcode vor 4 Jahren
Ursprung
Commit
8d51de5c5d
2 geänderte Dateien mit 289 neuen und 227 gelöschten Zeilen
  1. 283 207
      src/renderer_vk.cpp
  2. 6 20
      src/renderer_vk.h

+ 283 - 207
src/renderer_vk.cpp

@@ -317,6 +317,7 @@ VK_IMPORT_DEVICE
 			EXT_debug_report,
 			EXT_memory_budget,
 			KHR_get_physical_device_properties2,
+			EXT_shader_viewport_index_layer,
 
 			Count
 		};
@@ -337,6 +338,7 @@ VK_IMPORT_DEVICE
 		{ "VK_EXT_debug_report",                    1, false, false, BGFX_CONFIG_DEBUG            , Layer::Count },
 		{ "VK_EXT_memory_budget",                   1, false, false, true                         , Layer::Count },
 		{ "VK_KHR_get_physical_device_properties2", 1, false, false, true                         , Layer::Count },
+		{ "VK_EXT_shader_viewport_index_layer",     1, false, false, true                         , Layer::Count }
 	};
 	BX_STATIC_ASSERT(Extension::Count == BX_COUNTOF(s_extension) );
 
@@ -667,8 +669,7 @@ VK_IMPORT_DEVICE
 			if (VK_SUCCESS == result
 			&&  0 < numExtensionProperties)
 			{
-				VkExtensionProperties extensionProperties[64];
-				numExtensionProperties = bx::min<uint32_t>(numExtensionProperties, BX_COUNTOF(extensionProperties) );
+				VkExtensionProperties* extensionProperties = (VkExtensionProperties*)BX_ALLOC(g_allocator, numExtensionProperties * sizeof(VkExtensionProperties) );
 				result = enumerateExtensionProperties(_physicalDevice
 					, NULL
 					, &numExtensionProperties
@@ -695,6 +696,8 @@ VK_IMPORT_DEVICE
 
 					BX_UNUSED(supported);
 				}
+
+				BX_FREE(g_allocator, extensionProperties);
 			}
 		}
 
@@ -705,8 +708,7 @@ VK_IMPORT_DEVICE
 		if (VK_SUCCESS == result
 		&&  0 < numLayerProperties)
 		{
-			VkLayerProperties layerProperties[64];
-			numLayerProperties = bx::min<uint32_t>(numLayerProperties, BX_COUNTOF(layerProperties) );
+			VkLayerProperties* layerProperties = (VkLayerProperties*)BX_ALLOC(g_allocator, numLayerProperties * sizeof(VkLayerProperties) );
 			result = enumerateLayerProperties(_physicalDevice, &numLayerProperties, layerProperties);
 
 			char indent = VK_NULL_HANDLE == _physicalDevice ? '\0' : '\t';
@@ -741,8 +743,7 @@ VK_IMPORT_DEVICE
 				if (VK_SUCCESS == result
 				&&  0 < numExtensionProperties)
 				{
-					VkExtensionProperties extensionProperties[64];
-					numExtensionProperties = bx::min<uint32_t>(numExtensionProperties, BX_COUNTOF(extensionProperties) );
+					VkExtensionProperties* extensionProperties = (VkExtensionProperties*)BX_ALLOC(g_allocator, numExtensionProperties * sizeof(VkExtensionProperties) );
 					result = enumerateExtensionProperties(_physicalDevice
 						, layerProperties[layer].layerName
 						, &numExtensionProperties
@@ -766,8 +767,12 @@ VK_IMPORT_DEVICE
 
 						BX_UNUSED(supported);
 					}
+
+					BX_FREE(g_allocator, extensionProperties);
 				}
 			}
+
+			BX_FREE(g_allocator, layerProperties);
 		}
 	}
 
@@ -1005,7 +1010,7 @@ VK_IMPORT_DEVICE
 			: m_allocatorCb(NULL)
 			, m_renderDocDll(NULL)
 			, m_vulkan1Dll(NULL)
-			, m_maxAnisotropy(1)
+			, m_maxAnisotropy(1.0f)
 			, m_depthClamp(false)
 			, m_wireframe(false)
 			, m_rtMsaa(false)
@@ -1595,6 +1600,7 @@ VK_IMPORT_INSTANCE
 					goto error;
 				}
 
+				VkPhysicalDevice fallbackPhysicalDevice = VK_NULL_HANDLE;
 				m_physicalDevice = VK_NULL_HANDLE;
 
 				for (uint32_t ii = 0; ii < numPhysicalDevices; ++ii)
@@ -1620,7 +1626,14 @@ VK_IMPORT_INSTANCE
 					&&   (BGFX_PCI_ID_NONE == g_caps.vendorId || pdp.vendorID == g_caps.vendorId)
 					&&   (0 == g_caps.deviceId                || pdp.deviceID == g_caps.deviceId) )
 					{
-						m_physicalDevice = physicalDevices[ii];
+						if (BX_ENABLED(BGFX_CONFIG_PREFER_DISCRETE_GPU) && (pdp.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) )
+						{
+							fallbackPhysicalDevice = physicalDevices[ii];
+						}
+						else
+						{
+							m_physicalDevice = physicalDevices[ii];
+						}
 					}
 
 					VkPhysicalDeviceMemoryProperties pdmp;
@@ -1653,7 +1666,10 @@ VK_IMPORT_INSTANCE
 
 				if (VK_NULL_HANDLE == m_physicalDevice)
 				{
-					m_physicalDevice = physicalDevices[0];
+					m_physicalDevice = VK_NULL_HANDLE == fallbackPhysicalDevice
+						? physicalDevices[0]
+						: fallbackPhysicalDevice
+						;
 				}
 
 				vkGetPhysicalDeviceProperties(m_physicalDevice, &m_deviceProperties);
@@ -1680,6 +1696,10 @@ VK_IMPORT_INSTANCE
 					| BGFX_CAPS_IMAGE_RW
 					);
 
+				g_caps.supported |= 0
+					| (s_extension[Extension::EXT_shader_viewport_index_layer].m_supported ? BGFX_CAPS_VIEWPORT_LAYER_ARRAY : 0)
+					;
+
 				g_caps.limits.maxTextureSize     = m_deviceProperties.limits.maxImageDimension2D;
 				g_caps.limits.maxTextureLayers   = m_deviceProperties.limits.maxImageArrayLayers;
 				g_caps.limits.maxFBAttachments   = bx::min(uint8_t(m_deviceProperties.limits.maxFragmentOutputAttachments), uint8_t(BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) );
@@ -2149,8 +2169,8 @@ VK_IMPORT_DEVICE
 					}
 				}
 
-				BX_ASSERT(surfaceFormatIdx < numSurfaceFormats, "Cannot find preferred surface format from supported surface formats");
-				BX_WARN(surfaceFormatSrgbIdx < numSurfaceFormats, "Cannot find preferred sRGB surface format from supported surface formats");
+				BX_ASSERT(surfaceFormatIdx < numSurfaceFormats, "Cannot find preferred surface format from supported surface formats.");
+				BX_WARN(surfaceFormatSrgbIdx < numSurfaceFormats, "Cannot find preferred sRGB surface format from supported surface formats.");
 
 				m_backBufferColorFormat     = surfaceFormats[surfaceFormatIdx];
 				m_backBufferColorFormatSrgb = surfaceFormatSrgbIdx < numSurfaceFormats
@@ -2202,7 +2222,11 @@ VK_IMPORT_DEVICE
 					? BGFX_CONFIG_MAX_BACK_BUFFERS
 					: bx::min<uint32_t>(surfaceCapabilities.maxImageCount, BGFX_CONFIG_MAX_BACK_BUFFERS)
 					;
-				BX_ASSERT(minSwapBufferCount <= maxSwapBufferCount, "Incompatible swapchain image count");
+				BX_ASSERT(minSwapBufferCount <= maxSwapBufferCount
+					, "Incompatible swapchain image count (min: %d, max: %d)."
+					, minSwapBufferCount
+					, maxSwapBufferCount
+					);
 
 				uint32_t swapBufferCount = bx::clamp<uint32_t>(_init.resolution.numBackBuffers, minSwapBufferCount, maxSwapBufferCount);
 
@@ -2450,6 +2474,7 @@ VK_IMPORT_DEVICE
 			m_descriptorSetLayoutCache.invalidate();
 			m_renderPassCache.invalidate();
 			m_samplerCache.invalidate();
+			m_storageImageViewCache.invalidate();
 
 			for (uint32_t ii = 0; ii < m_numFramesInFlight; ++ii)
 			{
@@ -2678,8 +2703,50 @@ VK_IMPORT_DEVICE
 			vkFreeMemory(m_device, stagingMemory, m_allocatorCb);
 		}
 
-		void resizeTexture(TextureHandle /*_handle*/, uint16_t /*_width*/, uint16_t /*_height*/, uint8_t /*_numMips*/, uint16_t /*_numLayers*/) override
+		void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height, uint8_t _numMips, uint16_t _numLayers) override
 		{
+			TextureVK& texture = m_textures[_handle.idx];
+
+			if (!!(texture.m_flags & BGFX_TEXTURE_RT_MASK) )
+			{
+				for (uint32_t ii = 0; ii < BX_COUNTOF(m_frameBuffers); ++ii)
+				{
+					if (VK_NULL_HANDLE != m_frameBuffers[ii].m_framebuffer)
+					{
+						for (uint8_t jj = 0, num = m_frameBuffers[ii].m_numTh; jj < num; ++jj)
+						{
+							if (_handle.idx == m_frameBuffers[ii].m_attachment[jj].handle.idx)
+							{
+								m_frameBuffers[ii].m_needRecreate = true;
+								break;
+							}
+						}
+					}
+				}
+			}
+
+			uint32_t size = sizeof(uint32_t) + sizeof(TextureCreate);
+			const Memory* mem = alloc(size);
+
+			bx::StaticMemoryBlockWriter writer(mem->data, mem->size);
+			uint32_t magic = BGFX_CHUNK_MAGIC_TEX;
+			bx::write(&writer, magic);
+
+			TextureCreate tc;
+			tc.m_width     = _width;
+			tc.m_height    = _height;
+			tc.m_depth     = 0;
+			tc.m_numLayers = _numLayers;
+			tc.m_numMips   = _numMips;
+			tc.m_format    = TextureFormat::Enum(texture.m_requestedFormat);
+			tc.m_cubeMap   = false;
+			tc.m_mem       = NULL;
+			bx::write(&writer, tc);
+
+			texture.destroy();
+			texture.create(m_commandBuffer, mem, texture.m_flags, 0);
+
+			bgfx::release(mem);
 		}
 
 		void overrideInternal(TextureHandle /*_handle*/, uintptr_t /*_ptr*/) override
@@ -2860,11 +2927,6 @@ VK_IMPORT_DEVICE
 					setDebugObjectName(m_device, m_textures[_handle.idx].m_textureImageView, "%.*s", _len, _name);
 				}
 
-				if (VK_NULL_HANDLE != m_textures[_handle.idx].m_textureImageStorageView)
-				{
-					setDebugObjectName(m_device, m_textures[_handle.idx].m_textureImageStorageView, "%.*s", _len, _name);
-				}
-
 				if (VK_NULL_HANDLE != m_textures[_handle.idx].m_textureImageDepthView)
 				{
 					setDebugObjectName(m_device, m_textures[_handle.idx].m_textureImageDepthView, "%.*s", _len, _name);
@@ -2884,7 +2946,10 @@ VK_IMPORT_DEVICE
 		template<typename Ty>
 		void release(Ty _object, VkDeviceMemory _memory = VK_NULL_HANDLE)
 		{
-			m_cmd.release(uint64_t(_object.vk), getType<Ty>() );
+			if (VK_NULL_HANDLE != _object)
+			{
+				m_cmd.release(uint64_t(_object.vk), getType<Ty>() );
+			}
 
 			if (VK_NULL_HANDLE != _memory)
 			{
@@ -3134,13 +3199,16 @@ VK_IMPORT_DEVICE
 
 		bool updateResolution(const Resolution& _resolution)
 		{
+			float maxAnisotropy = 1.0f;
 			if (!!(_resolution.reset & BGFX_RESET_MAXANISOTROPY) )
 			{
-				m_maxAnisotropy = UINT32_MAX;
+				maxAnisotropy = m_deviceProperties.limits.maxSamplerAnisotropy;
 			}
-			else
+
+			if (m_maxAnisotropy != maxAnisotropy)
 			{
-				m_maxAnisotropy = 1;
+				m_maxAnisotropy = maxAnisotropy;
+				m_samplerCache.invalidate();
 			}
 
 			bool depthClamp = !!(_resolution.reset & BGFX_RESET_DEPTH_CLAMP);
@@ -3324,7 +3392,13 @@ VK_IMPORT_DEVICE
 
 			if (isValid(_fbh) )
 			{
-				const FrameBufferVK& frameBuffer = m_frameBuffers[_fbh.idx];
+				FrameBufferVK& frameBuffer = m_frameBuffers[_fbh.idx];
+
+				if (frameBuffer.m_needRecreate)
+				{
+					frameBuffer.destroy();
+					frameBuffer.create(frameBuffer.m_numTh, frameBuffer.m_attachment);
+				}
 
 				for (uint8_t ii = 0, num = frameBuffer.m_num; ii < num; ++ii)
 				{
@@ -3349,6 +3423,15 @@ VK_IMPORT_DEVICE
 			m_rtMsaa = _msaa;
 		}
 
+		void setDebugWireframe(bool _wireframe)
+		{
+			if (m_wireframe != _wireframe)
+			{
+				m_wireframe = _wireframe;
+				m_pipelineStateCache.invalidate();
+			}
+		}
+
 		void setBlendState(VkPipelineColorBlendStateCreateInfo& _desc, uint64_t _state, uint32_t _rgba = 0)
 		{
 			VkPipelineColorBlendAttachmentState* bas = const_cast<VkPipelineColorBlendAttachmentState*>(_desc.pAttachments);
@@ -3714,9 +3797,9 @@ VK_IMPORT_DEVICE
 			sci.addressModeU     = s_textureAddress[(_samplerFlags&BGFX_SAMPLER_U_MASK)>>BGFX_SAMPLER_U_SHIFT];
 			sci.addressModeV     = s_textureAddress[(_samplerFlags&BGFX_SAMPLER_V_MASK)>>BGFX_SAMPLER_V_SHIFT];
 			sci.addressModeW     = s_textureAddress[(_samplerFlags&BGFX_SAMPLER_W_MASK)>>BGFX_SAMPLER_W_SHIFT];
-			sci.mipLodBias       = 0.0f;
+			sci.mipLodBias       = float(BGFX_CONFIG_MIP_LOD_BIAS);
 			sci.anisotropyEnable = VK_FALSE;
-			sci.maxAnisotropy    = 4.0f;
+			sci.maxAnisotropy    = m_maxAnisotropy;
 			sci.compareEnable    = 0 != cmpFunc;
 			sci.compareOp        = s_cmpFunc[cmpFunc];
 			sci.minLod           = 0.0f;
@@ -3749,6 +3832,29 @@ VK_IMPORT_DEVICE
 			return sampler;
 		}
 
+		VkImageView getStorageImageView(TextureHandle _handle, uint8_t _mip)
+		{
+			const TextureVK& texture = m_textures[_handle.idx];
+
+			bx::HashMurmur2A hash;
+			hash.begin();
+			hash.add(texture.m_textureImage);
+			hash.add(_mip);
+			uint32_t hashKey = hash.end();
+
+			VkImageView view = m_storageImageViewCache.find(hashKey);
+
+			if (VK_NULL_HANDLE != view)
+			{
+				return view;
+			}
+			
+			view = texture.createView(0, texture.m_numSides, _mip, 1);
+
+			m_storageImageViewCache.add(hashKey, view);
+			return view;
+		}
+
 		VkPipeline getPipeline(ProgramHandle _program)
 		{
 			ProgramVK& program = m_program[_program.idx];
@@ -3867,7 +3973,7 @@ VK_IMPORT_DEVICE
 			inputAssemblyState.primitiveRestartEnable = VK_FALSE;
 
 			VkPipelineRasterizationStateCreateInfo rasterizationState;
-			setRasterizerState(rasterizationState, _state);
+			setRasterizerState(rasterizationState, _state, m_wireframe);
 
 			VkPipelineDepthStencilStateCreateInfo depthStencilState;
 			setDepthStencilState(depthStencilState, _state, _stencil);
@@ -4052,7 +4158,7 @@ VK_IMPORT_DEVICE
 
 				// bgfx does not seem to forbid setting a texture to a stage that a program does not use
 				if (bind.m_type == Binding::Texture
-				&& !isValid(program.m_bindInfo[stage].uniformHandle) )
+				&& !isValid(bindInfo.uniformHandle) )
 				{
 					continue;
 				}
@@ -4078,10 +4184,7 @@ VK_IMPORT_DEVICE
 							texture.setImageMemoryBarrier(m_commandBuffer, VK_IMAGE_LAYOUT_GENERAL);
 
 							imageInfo[imageCount].imageLayout = texture.m_currentImageLayout;
-							imageInfo[imageCount].imageView   = VK_NULL_HANDLE != texture.m_textureImageStorageView
-								? texture.m_textureImageStorageView
-								: texture.m_textureImageView
-								;
+							imageInfo[imageCount].imageView = getStorageImageView({ bind.m_idx }, bind.m_mip);
 							imageInfo[imageCount].sampler     = VK_NULL_HANDLE;
 							wds[wdsCount].pImageInfo = &imageInfo[imageCount];
 							++imageCount;
@@ -4329,6 +4432,7 @@ VK_IMPORT_DEVICE
 			{
 				const FrameBufferVK& fb = m_frameBuffers[fbh.idx];
 				numMrt = fb.m_num;
+				rect[0].layerCount = fb.m_attachment[0].numLayers;
 			}
 
 			VkClearAttachment attachments[BGFX_CONFIG_MAX_FRAME_BUFFERS];
@@ -4435,7 +4539,10 @@ VK_IMPORT_DEVICE
 		{
 			const bool acquired = VK_NULL_HANDLE != m_lastImageAcquiredSemaphore;
 			const VkSemaphore waitSemaphore   = m_lastImageAcquiredSemaphore;
-			const VkSemaphore signalSemaphore = acquired ? m_lastImageRenderedSemaphore : VK_NULL_HANDLE;
+			const VkSemaphore signalSemaphore = acquired
+				? m_lastImageRenderedSemaphore
+				: VkSemaphore(VK_NULL_HANDLE)
+				;
 
 			m_lastImageAcquiredSemaphore = VK_NULL_HANDLE;
 
@@ -4606,9 +4713,10 @@ VK_IMPORT_DEVICE
 		StateCacheT<VkDescriptorSetLayout> m_descriptorSetLayoutCache;
 		StateCacheT<VkRenderPass> m_renderPassCache;
 		StateCacheT<VkSampler> m_samplerCache;
+		StateCacheT<VkImageView> m_storageImageViewCache;
 
 		Resolution m_resolution;
-		uint32_t m_maxAnisotropy;
+		float m_maxAnisotropy;
 		bool m_depthClamp;
 		bool m_wireframe;
 		bool m_rtMsaa;
@@ -4752,101 +4860,6 @@ VK_DESTROY
 		vkFlushMappedMemoryRanges(device, 1, &range);
 	}
 
-	VkResult ImageVK::create(VkFormat _format, const VkExtent3D& _extent)
-	{
-		VkResult result;
-
-		VkAllocationCallbacks* allocatorCb = s_renderVK->m_allocatorCb;
-		VkDevice device = s_renderVK->m_device;
-
-		VkImageCreateInfo ici;
-		ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
-		ici.pNext = NULL;
-		ici.flags = 0;
-		ici.imageType = VK_IMAGE_TYPE_2D;
-		ici.format = _format;
-		ici.extent = _extent;
-		ici.mipLevels   = 1;
-		ici.arrayLayers = 1;
-		ici.samples = VK_SAMPLE_COUNT_1_BIT;
-		ici.tiling  = VK_IMAGE_TILING_OPTIMAL;
-		ici.usage   = 0
-			| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
-			| VK_IMAGE_USAGE_TRANSFER_SRC_BIT
-			;
-		ici.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-		ici.queueFamilyIndexCount = 0;
-		ici.pQueueFamilyIndices   = 0;
-		ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-		result = vkCreateImage(device, &ici, allocatorCb, &m_image);
-
-		if (VK_SUCCESS != result)
-		{
-			BX_TRACE("vkCreateImage failed %d: %s.", result, getName(result) );
-			return result;
-		}
-
-		VkMemoryRequirements mr;
-		vkGetImageMemoryRequirements(device, m_image, &mr);
-
-		result = s_renderVK->allocateMemory(&mr, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &m_memory);
-
-		if (VK_SUCCESS != result)
-		{
-			BX_TRACE("vkAllocateMemory failed %d: %s.", result, getName(result) );
-			destroy();
-			return result;
-		}
-
-		result = vkBindImageMemory(device, m_image, m_memory, 0);
-
-		if (VK_SUCCESS != result)
-		{
-			BX_TRACE("vkBindImageMemory failed %d: %s.", result, getName(result) );
-			destroy();
-			return result;
-		}
-
-		VkImageViewCreateInfo ivci;
-		ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-		ivci.pNext = NULL;
-		ivci.flags = 0;
-		ivci.image    = m_image;
-		ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
-		ivci.format   = _format;
-		ivci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ivci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ivci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ivci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ivci.subresourceRange.aspectMask = 0
-			| VK_IMAGE_ASPECT_DEPTH_BIT
-			| VK_IMAGE_ASPECT_STENCIL_BIT
-			;
-		ivci.subresourceRange.baseMipLevel   = 0;
-		ivci.subresourceRange.levelCount     = 1;
-		ivci.subresourceRange.baseArrayLayer = 0;
-		ivci.subresourceRange.layerCount     = 1;
-		result = vkCreateImageView(device, &ivci, allocatorCb, &m_imageView);
-
-		if (VK_SUCCESS != result)
-		{
-			BX_TRACE("vkCreateImageView failed %d: %s.", result, getName(result) );
-			destroy();
-			return result;
-		}
-
-		return VK_SUCCESS;
-	}
-
-	void ImageVK::destroy()
-	{
-		s_renderVK->release(m_imageView);
-		s_renderVK->release(m_image, m_memory);
-		m_imageView = VK_NULL_HANDLE;
-		m_image     = VK_NULL_HANDLE;
-		m_memory    = VK_NULL_HANDLE;
-	}
-
 	void BufferVK::create(VkCommandBuffer _commandBuffer, uint32_t _size, void* _data, uint16_t _flags, bool _vertex, uint32_t _stride)
 	{
 		BX_UNUSED(_stride);
@@ -5427,23 +5440,11 @@ VK_DESTROY
 			, &bic
 			);
 
-		// Make changes to the buffer visible to host read
-		VkMemoryBarrier memBarrier;
-		memBarrier.sType         = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
-		memBarrier.pNext         = NULL;
-		memBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-		memBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
-		vkCmdPipelineBarrier(
-			  _commandBuffer
+		// Make changes to the buffer visible to the host
+		setMemoryBarrier(
+			_commandBuffer
 			, VK_PIPELINE_STAGE_TRANSFER_BIT
 			, VK_PIPELINE_STAGE_HOST_BIT
-			, 0
-			, 1
-			, &memBarrier
-			, 0
-			, NULL
-			, 0
-			, NULL
 			);
 
 		setImageMemoryBarrier(
@@ -5548,6 +5549,10 @@ VK_DESTROY
 			{
 				m_type = VK_IMAGE_VIEW_TYPE_3D;
 			}
+			else if (imageContainer.m_numLayers > 1)
+			{
+				m_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+			}
 			else
 			{
 				m_type = VK_IMAGE_VIEW_TYPE_2D;
@@ -5867,33 +5872,6 @@ VK_DESTROY
 					) );
 			}
 
-			// image view creation for storage if needed
-			if (m_flags & BGFX_TEXTURE_COMPUTE_WRITE)
-			{
-				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 == VK_IMAGE_VIEW_TYPE_CUBE
-					? VK_IMAGE_VIEW_TYPE_2D_ARRAY
-					: m_type
-					;
-				viewInfo.format     = m_format;
-				viewInfo.components = m_components;
-				viewInfo.subresourceRange.aspectMask     = m_aspectMask;
-				viewInfo.subresourceRange.baseMipLevel   = 0;
-				viewInfo.subresourceRange.levelCount     = m_numMips;
-				viewInfo.subresourceRange.baseArrayLayer = 0;
-				viewInfo.subresourceRange.layerCount     = m_numSides;
-				VK_CHECK(vkCreateImageView(
-					  device
-					, &viewInfo
-					, allocatorCb
-					, &m_textureImageStorageView
-					) );
-			}
-
 			if (needResolve)
 			{
 				{
@@ -5956,12 +5934,10 @@ VK_DESTROY
 
 		if (VK_NULL_HANDLE != m_textureImage)
 		{
-			s_renderVK->release(m_textureImageStorageView);
 			s_renderVK->release(m_textureImageDepthView);
 			s_renderVK->release(m_textureImageView);
 			s_renderVK->release(m_textureImage, m_textureDeviceMem);
 
-			m_textureImageStorageView = VK_NULL_HANDLE;
 			m_textureImageDepthView   = VK_NULL_HANDLE;
 			m_textureImageView        = VK_NULL_HANDLE;
 			m_textureImage            = VK_NULL_HANDLE;
@@ -6194,10 +6170,39 @@ VK_DESTROY
 		m_currentImageLayout = _newImageLayout;
 	}
 
+	VkImageView TextureVK::createView(uint32_t _layer, uint32_t _numLayers, uint32_t _mip, uint32_t _numMips) const
+	{
+		VkImageView view = VK_NULL_HANDLE;
+
+		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 == VK_IMAGE_VIEW_TYPE_CUBE
+			? VK_IMAGE_VIEW_TYPE_2D_ARRAY
+			: m_type
+			;
+		viewInfo.format     = m_format;
+		viewInfo.components = m_components;
+		viewInfo.subresourceRange.aspectMask     = m_aspectMask;
+		viewInfo.subresourceRange.baseMipLevel   = _mip;
+		viewInfo.subresourceRange.levelCount     = _numMips;
+		viewInfo.subresourceRange.baseArrayLayer = _layer;
+		viewInfo.subresourceRange.layerCount     = _numLayers;
+		VK_CHECK(vkCreateImageView(
+			  s_renderVK->m_device
+			, &viewInfo
+			, s_renderVK->m_allocatorCb
+			, &view
+			) );
+
+		return view;
+	}
+
 	void FrameBufferVK::create(uint8_t _num, const Attachment* _attachment)
 	{
-		// create frame buffer object
-		m_numAttachment = _num;
+		m_numTh = _num;
 		bx::memCopy(m_attachment, _attachment, sizeof(Attachment) * _num);
 
 		VkDevice device = s_renderVK->m_device;
@@ -6210,10 +6215,25 @@ VK_DESTROY
 		m_depth.idx = bx::kInvalidHandle;
 		m_num = 0;
 
-		for (uint8_t ii = 0; ii < m_numAttachment; ++ii)
+		uint16_t numLayers = m_attachment[0].numLayers;
+
+		for (uint8_t ii = 0; ii < m_numTh; ++ii)
 		{
 			const TextureVK& texture = s_renderVK->m_textures[m_attachment[ii].handle.idx];
-			textureImageViews[ii] = texture.m_textureImageView;
+
+			BX_ASSERT(numLayers == m_attachment[ii].numLayers
+				, "Mismatching framebuffer attachment layer counts (%d != %d)."
+				, m_attachment[ii].numLayers
+				, numLayers
+				);
+
+			m_textureImageViews[ii] = texture.createView(
+				  m_attachment[ii].layer
+				, m_attachment[ii].numLayers
+				, m_attachment[ii].mip
+				, 1
+				);
+			textureImageViews[ii] = m_textureImageViews[ii];
 
 			if (texture.m_aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
 			{
@@ -6226,42 +6246,52 @@ VK_DESTROY
 			}
 		}
 
+		m_width = firstTexture.m_width >> m_attachment[0].mip;
+		m_height = firstTexture.m_height >> m_attachment[0].mip;
+
 		VkFramebufferCreateInfo fci;
 		fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
 		fci.pNext = NULL;
 		fci.flags = 0;
 		fci.renderPass      = renderPass;
-		fci.attachmentCount = m_numAttachment;
+		fci.attachmentCount = m_numTh;
 		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;
+		fci.width  = m_width;
+		fci.height = m_height;
+		fci.layers = numLayers;
 		VK_CHECK( vkCreateFramebuffer(device, &fci, allocatorCb, &m_framebuffer) );
 
 		m_renderPass = renderPass;
+
+		m_needRecreate = false;
 	}
 
 	void FrameBufferVK::resolve()
 	{
-		if (0 < m_numAttachment)
+		for (uint32_t ii = 0; ii < m_numTh; ++ii)
 		{
-			for (uint32_t ii = 0; ii < m_numAttachment; ++ii)
-			{
-				const Attachment& at = m_attachment[ii];
+			const Attachment& at = m_attachment[ii];
 
-				if (isValid(at.handle) )
-				{
-					TextureVK& texture = s_renderVK->m_textures[at.handle.idx];
-					texture.resolve(s_renderVK->m_commandBuffer, at.resolve);
-				}
+			if (isValid(at.handle) )
+			{
+				TextureVK& texture = s_renderVK->m_textures[at.handle.idx];
+				texture.resolve(s_renderVK->m_commandBuffer, at.resolve);
 			}
 		}
 	}
 
 	void FrameBufferVK::destroy()
 	{
-		s_renderVK->release(m_framebuffer);
-		m_framebuffer = VK_NULL_HANDLE;
+		if (VK_NULL_HANDLE != m_framebuffer)
+		{
+			s_renderVK->release(m_framebuffer);
+			m_framebuffer = VK_NULL_HANDLE;
+
+			for (uint8_t ii = 0; ii < m_numTh; ++ii)
+			{
+				s_renderVK->release(m_textureImageViews[ii]);
+			}
+		}
 	}
 
 	void CommandQueueVK::init(uint32_t _queueFamily, VkQueue _queue, uint32_t _numFramesInFlight)
@@ -6620,8 +6650,8 @@ VK_DESTROY
 		static ViewState viewState;
 		viewState.reset(_render);
 
-// 		bool wireframe = !!(_render->m_debug&BGFX_DEBUG_WIREFRAME);
-// 		setDebugWireframe(wireframe);
+		bool wireframe = !!(_render->m_debug&BGFX_DEBUG_WIREFRAME);
+		setDebugWireframe(wireframe);
 
 		uint16_t currentSamplerStateIdx = kInvalidHandle;
 		ProgramHandle currentProgram    = BGFX_INVALID_HANDLE;
@@ -7253,6 +7283,20 @@ VK_DESTROY
 							);
 					}
 
+					VkBuffer bufferIndirect = VK_NULL_HANDLE;
+					uint32_t numDrawIndirect = 0;
+					uint32_t bufferOffsetIndirect = 0;
+					if (isValid(draw.m_indirectBuffer) )
+					{
+						const VertexBufferVK& vb = m_vertexBuffers[draw.m_indirectBuffer.idx];
+						bufferIndirect = vb.m_buffer;
+						numDrawIndirect = UINT16_MAX == draw.m_numIndirect
+							? vb.m_size / BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+							: draw.m_numIndirect
+							;
+						bufferOffsetIndirect = draw.m_startIndirect * BGFX_CONFIG_DRAW_INDIRECT_STRIDE;
+					}
+
 					if (!isValid(draw.m_indexBuffer) )
 					{
 						const VertexBufferVK& vertexBuffer = m_vertexBuffers[draw.m_stream[0].m_handle.idx];
@@ -7262,12 +7306,28 @@ VK_DESTROY
 							? vertexBuffer.m_size / layout->m_stride
 							: draw.m_numVertices
 							;
-						vkCmdDraw(m_commandBuffer
-							, numVertices
-							, draw.m_numInstances
-							, draw.m_stream[0].m_startVertex
-							, 0
-							);
+
+						if (isValid(draw.m_indirectBuffer) )
+						{
+							vkCmdDrawIndirect(
+								  m_commandBuffer
+								, bufferIndirect
+								, bufferOffsetIndirect
+								, numDrawIndirect
+								, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+								);
+						}
+						else
+						{
+							vkCmdDraw(
+								  m_commandBuffer
+								, numVertices
+								, draw.m_numInstances
+								, draw.m_stream[0].m_startVertex
+								, 0
+								);
+						}
+
 					}
 					else
 					{
@@ -7281,18 +7341,34 @@ VK_DESTROY
 							: draw.m_numIndices
 							;
 
-						vkCmdBindIndexBuffer(m_commandBuffer
+						vkCmdBindIndexBuffer(
+							  m_commandBuffer
 							, ib.m_buffer
 							, 0
 							, indexFormat
 							);
-						vkCmdDrawIndexed(m_commandBuffer
-							, numIndices
-							, draw.m_numInstances
-							, draw.m_startIndex
-							, draw.m_stream[0].m_startVertex
-							, 0
-							);
+
+						if (isValid(draw.m_indirectBuffer) )
+						{
+							vkCmdDrawIndexedIndirect(
+								  m_commandBuffer
+								, bufferIndirect
+								, bufferOffsetIndirect
+								, numDrawIndirect
+								, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+								);
+						}
+						else
+						{
+							vkCmdDrawIndexed(
+								  m_commandBuffer
+								, numIndices
+								, draw.m_numInstances
+								, draw.m_startIndex
+								, draw.m_stream[0].m_startVertex
+								, 0
+								);
+						}
 					}
 
 					uint32_t numPrimsSubmitted = numIndices / prim.m_div - prim.m_sub;

+ 6 - 20
src/renderer_vk.h

@@ -389,23 +389,6 @@ VK_DESTROY
 		uint32_t m_maxDescriptors;
 	};
 
-	struct ImageVK
-	{
-		ImageVK()
-			: m_memory(VK_NULL_HANDLE)
-			, m_image(VK_NULL_HANDLE)
-			, m_imageView(VK_NULL_HANDLE)
-		{
-		}
-
-		VkResult create(VkFormat _format, const VkExtent3D& _extent);
-		void destroy();
-
-		VkDeviceMemory m_memory;
-		VkImage        m_image;
-		VkImageView    m_imageView;
-	};
-
 	struct BufferVK
 	{
 		BufferVK()
@@ -610,7 +593,6 @@ VK_DESTROY
 			, m_textureDeviceMem(VK_NULL_HANDLE)
 			, m_textureImageView(VK_NULL_HANDLE)
 			, m_textureImageDepthView(VK_NULL_HANDLE)
-			, m_textureImageStorageView(VK_NULL_HANDLE)
 			, m_currentImageLayout(VK_IMAGE_LAYOUT_UNDEFINED)
 			, m_singleMsaaImage(VK_NULL_HANDLE)
 			, m_singleMsaaDeviceMem(VK_NULL_HANDLE)
@@ -626,6 +608,8 @@ VK_DESTROY
 		void copyBufferToTexture(VkCommandBuffer _commandBuffer, VkBuffer _stagingBuffer, uint32_t _bufferImageCopyCount, VkBufferImageCopy* _bufferImageCopy);
 		void setImageMemoryBarrier(VkCommandBuffer _commandBuffer, VkImageLayout _newImageLayout);
 
+		VkImageView createView(uint32_t _layer, uint32_t _numLayers, uint32_t _mip, uint32_t _numMips) const;
+
 		void*    m_directAccessPtr;
 		uint64_t m_flags;
 		uint32_t m_width;
@@ -648,7 +632,6 @@ VK_DESTROY
 		VkDeviceMemory m_textureDeviceMem;
 		VkImageView    m_textureImageView;
 		VkImageView    m_textureImageDepthView;
-		VkImageView    m_textureImageStorageView;
 		VkImageLayout  m_currentImageLayout;
 
 		VkImage        m_singleMsaaImage;
@@ -667,6 +650,7 @@ VK_DESTROY
 			, m_denseIdx(kInvalidHandle)
 			, m_num(0)
 			, m_numTh(0)
+			, m_needRecreate(false)
 			, m_framebuffer(VK_NULL_HANDLE)
 		{
 		}
@@ -682,8 +666,10 @@ VK_DESTROY
 		uint16_t m_denseIdx;
 		uint8_t m_num;
 		uint8_t m_numTh;
-		uint8_t m_numAttachment;
+		bool m_needRecreate;
 		Attachment m_attachment[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
+
+		VkImageView m_textureImageViews[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
 		VkFramebuffer m_framebuffer;
 		VkRenderPass m_renderPass;
 	};