Browse Source

Build acceleration structures on mesh loading

Panagiotis Christopoulos Charitos 5 years ago
parent
commit
b5b9cf7cd1

+ 1 - 1
anki/gr/GrObject.cpp

@@ -15,7 +15,7 @@ GrObject::GrObject(GrManager* manager, GrObjectType type, CString name)
 	, m_refcount(0)
 	, m_type(type)
 {
-	if(!name || name.getLength() == 0)
+	if(name.getLength() == 0)
 	{
 		name = "N/A";
 	}

+ 12 - 0
anki/gr/vulkan/AccelerationStructureImpl.cpp

@@ -55,6 +55,18 @@ Error AccelerationStructureImpl::init(const AccelerationStructureInitInfo& inf)
 			geom.vertexFormat = convertFormat(m_bottomLevelInfo.m_positionsFormat);
 			geom.maxPrimitiveCount = m_bottomLevelInfo.m_indexCount / 3;
 			geom.maxVertexCount = m_bottomLevelInfo.m_positionCount;
+
+			VkFormatProperties2 formatProperties = {};
+			formatProperties.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
+			vkGetPhysicalDeviceFormatProperties2(getGrManagerImpl().getPhysicalDevice(), geom.vertexFormat,
+												 &formatProperties);
+
+			if(!(formatProperties.formatProperties.bufferFeatures
+				 & VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR))
+			{
+				ANKI_VK_LOGE("The positions format cannot be used in acceleration structures");
+				return Error::USER_DATA;
+			}
 		}
 		else
 		{

+ 86 - 77
anki/gr/vulkan/GrManagerImpl.cpp

@@ -410,11 +410,6 @@ Error GrManagerImpl::initInstance(const GrManagerInitInfo& init)
 	ANKI_VK_LOGI("GPU is %s. Vendor identified as %s", m_devProps.deviceName,
 				 &GPU_VENDOR_STR[m_capabilities.m_gpuVendor][0]);
 
-	vkGetPhysicalDeviceFeatures(m_physicalDevice, &m_devFeatures);
-	m_devFeatures.robustBufferAccess =
-		(init.m_config->getBool("gr_debugContext") && m_devFeatures.robustBufferAccess) ? true : false;
-	ANKI_VK_LOGI("Robust buffer access is %s", (m_devFeatures.robustBufferAccess) ? "enabled" : "disabled");
-
 	// Set limits
 	m_capabilities.m_uniformBufferBindOffsetAlignment =
 		max<U32>(ANKI_SAFE_ALIGNMENT, U32(m_devProps.limits.minUniformBufferOffsetAlignment));
@@ -482,7 +477,6 @@ Error GrManagerImpl::initDevice(const GrManagerInitInfo& init)
 	ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
 	ci.queueCreateInfoCount = 1;
 	ci.pQueueCreateInfos = &q;
-	ci.pEnabledFeatures = &m_devFeatures;
 
 	// Extensions
 	U32 extCount = 0;
@@ -546,100 +540,115 @@ Error GrManagerImpl::initDevice(const GrManagerInitInfo& init)
 			}
 		}
 
-		// Enable a few 1.2 features
+		ANKI_VK_LOGI("Will enable the following device extensions:");
+		for(U32 i = 0; i < extensionsToEnableCount; ++i)
 		{
-			m_12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
-
-			VkPhysicalDeviceFeatures2 features = {};
-			features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
-			features.pNext = &m_12Features;
+			ANKI_VK_LOGI("\t%s", extensionsToEnable[i]);
+		}
 
-			vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
+		ci.enabledExtensionCount = extensionsToEnableCount;
+		ci.ppEnabledExtensionNames = &extensionsToEnable[0];
+	}
 
-			// Descriptor indexing
-			if(!m_12Features.shaderSampledImageArrayNonUniformIndexing
-			   || !m_12Features.shaderStorageImageArrayNonUniformIndexing)
-			{
-				ANKI_VK_LOGE("Non uniform indexing is not supported by the device");
-				return Error::FUNCTION_FAILED;
-			}
+	// Enable/disable generic features
+	{
+		VkPhysicalDeviceFeatures2 devFeatures = {};
+		devFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+		vkGetPhysicalDeviceFeatures2(m_physicalDevice, &devFeatures);
+		m_devFeatures = devFeatures.features;
+		m_devFeatures.robustBufferAccess =
+			(init.m_config->getBool("gr_debugContext") && m_devFeatures.robustBufferAccess) ? true : false;
+		ANKI_VK_LOGI("Robust buffer access is %s", (m_devFeatures.robustBufferAccess) ? "enabled" : "disabled");
+
+		ci.pEnabledFeatures = &m_devFeatures;
+	}
 
-			if(!m_12Features.descriptorBindingSampledImageUpdateAfterBind
-			   || !m_12Features.descriptorBindingStorageImageUpdateAfterBind)
-			{
-				ANKI_VK_LOGE("Update descriptors after bind is not supported by the device");
-				return Error::FUNCTION_FAILED;
-			}
+	// Enable a few 1.2 features
+	{
+		m_12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
 
-			if(!m_12Features.descriptorBindingUpdateUnusedWhilePending)
-			{
-				ANKI_VK_LOGE("Update descriptors while cmd buffer is pending is not supported by the device");
-				return Error::FUNCTION_FAILED;
-			}
+		VkPhysicalDeviceFeatures2 features = {};
+		features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+		features.pNext = &m_12Features;
 
-			// Buffer address
-			if(!!(m_extensions & VulkanExtensions::KHR_RAY_TRACING))
-			{
-				if(!m_12Features.bufferDeviceAddress)
-				{
-					ANKI_VK_LOGE("Buffer device address is not supported by the device");
-					return Error::FUNCTION_FAILED;
-				}
+		vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
 
-				m_12Features.bufferDeviceAddressCaptureReplay =
-					m_12Features.bufferDeviceAddressCaptureReplay && init.m_config->getBool("gr_debugMarkers");
-				m_12Features.bufferDeviceAddressMultiDevice = false;
-			}
-			else
-			{
-				m_12Features.bufferDeviceAddress = false;
-				m_12Features.bufferDeviceAddressCaptureReplay = false;
-				m_12Features.bufferDeviceAddressMultiDevice = false;
-			}
+		// Descriptor indexing
+		if(!m_12Features.shaderSampledImageArrayNonUniformIndexing
+		   || !m_12Features.shaderStorageImageArrayNonUniformIndexing)
+		{
+			ANKI_VK_LOGE("Non uniform indexing is not supported by the device");
+			return Error::FUNCTION_FAILED;
+		}
 
-			// Scalar block layout
-			if(!m_12Features.scalarBlockLayout)
-			{
-				ANKI_VK_LOGE("Scalar block layout is not supported by the device");
-				return Error::FUNCTION_FAILED;
-			}
+		if(!m_12Features.descriptorBindingSampledImageUpdateAfterBind
+		   || !m_12Features.descriptorBindingStorageImageUpdateAfterBind)
+		{
+			ANKI_VK_LOGE("Update descriptors after bind is not supported by the device");
+			return Error::FUNCTION_FAILED;
+		}
 
-			ci.pNext = &m_12Features;
+		if(!m_12Features.descriptorBindingUpdateUnusedWhilePending)
+		{
+			ANKI_VK_LOGE("Update descriptors while cmd buffer is pending is not supported by the device");
+			return Error::FUNCTION_FAILED;
 		}
 
-		// Set RT features
+		// Buffer address
 		if(!!(m_extensions & VulkanExtensions::KHR_RAY_TRACING))
 		{
-			m_rtFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
-
-			VkPhysicalDeviceFeatures2 features = {};
-			features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
-			features.pNext = &m_rtFeatures;
-			vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
-
-			if(!m_rtFeatures.rayTracing || !m_rtFeatures.rayQuery)
+			if(!m_12Features.bufferDeviceAddress)
 			{
-				ANKI_VK_LOGE("Ray tracing and ray query are both required");
+				ANKI_VK_LOGE("Buffer device address is not supported by the device");
 				return Error::FUNCTION_FAILED;
 			}
 
-			// Only enable what's necessary
-			m_rtFeatures = {};
-			m_rtFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
-			m_rtFeatures.rayTracing = true;
-			m_rtFeatures.rayQuery = true;
+			m_12Features.bufferDeviceAddressCaptureReplay =
+				m_12Features.bufferDeviceAddressCaptureReplay && init.m_config->getBool("gr_debugMarkers");
+			m_12Features.bufferDeviceAddressMultiDevice = false;
+		}
+		else
+		{
+			m_12Features.bufferDeviceAddress = false;
+			m_12Features.bufferDeviceAddressCaptureReplay = false;
+			m_12Features.bufferDeviceAddressMultiDevice = false;
+		}
 
-			m_12Features.pNext = &m_rtFeatures;
+		// Scalar block layout
+		if(!m_12Features.scalarBlockLayout)
+		{
+			ANKI_VK_LOGE("Scalar block layout is not supported by the device");
+			return Error::FUNCTION_FAILED;
 		}
 
-		ANKI_VK_LOGI("Will enable the following device extensions:");
-		for(U32 i = 0; i < extensionsToEnableCount; ++i)
+		m_12Features.pNext = const_cast<void*>(ci.pNext);
+		ci.pNext = &m_12Features;
+	}
+
+	// Set RT features
+	if(!!(m_extensions & VulkanExtensions::KHR_RAY_TRACING))
+	{
+		m_rtFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
+
+		VkPhysicalDeviceFeatures2 features = {};
+		features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+		features.pNext = &m_rtFeatures;
+		vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
+
+		if(!m_rtFeatures.rayTracing || !m_rtFeatures.rayQuery)
 		{
-			ANKI_VK_LOGI("\t%s", extensionsToEnable[i]);
+			ANKI_VK_LOGE("Ray tracing and ray query are both required");
+			return Error::FUNCTION_FAILED;
 		}
 
-		ci.enabledExtensionCount = extensionsToEnableCount;
-		ci.ppEnabledExtensionNames = &extensionsToEnable[0];
+		// Only enable what's necessary
+		m_rtFeatures = {};
+		m_rtFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
+		m_rtFeatures.rayTracing = true;
+		m_rtFeatures.rayQuery = true;
+
+		m_rtFeatures.pNext = const_cast<void*>(ci.pNext);
+		ci.pNext = &m_rtFeatures;
 	}
 
 	ANKI_VK_CHECK(vkCreateDevice(m_physicalDevice, &ci, nullptr, &m_device));

+ 7 - 11
anki/importer/GltfImporter.cpp

@@ -606,16 +606,12 @@ Error GltfImporter::visitNode(const cgltf_node& node, const Transform& parentTrf
 				cgltf_material* m_mtl;
 				cgltf_skin* m_skin;
 				Bool m_selfCollision;
-				U32 m_lodCount;
-				F32 m_lodFactor;
 			};
 			Ctx* ctx = m_alloc.newInstance<Ctx>();
 			ctx->m_importer = this;
 			ctx->m_mesh = node.mesh;
 			ctx->m_mtl = node.mesh->primitives[0].material;
 			ctx->m_skin = node.skin;
-			ctx->m_lodCount = m_lodCount;
-			ctx->m_lodFactor = m_lodFactor;
 
 			HashMapAuto<CString, StringAuto>::Iterator it2;
 			const Bool selfCollision = (it2 = extras.find("collision_mesh")) != extras.getEnd() && *it2 == "self";
@@ -626,24 +622,24 @@ Error GltfImporter::visitNode(const cgltf_node& node, const Transform& parentTrf
 				Ctx& self = *static_cast<Ctx*>(userData);
 
 				// LOD 0
-				Error err = self.m_importer->writeMesh(*self.m_mesh, CString(), 1.0f);
+				Error err = self.m_importer->writeMesh(*self.m_mesh, CString(), self.m_importer->computeLodFactor(0));
 				U32 maxLod = 0;
 
 				// LOD 1
-				if(!err && self.m_lodCount > 1)
+				if(!err && self.m_importer->m_lodCount > 1 && !self.m_importer->skipMeshLod(*self.m_mesh, 1))
 				{
 					StringAuto name(self.m_importer->m_alloc);
 					name.sprintf("%s_lod1", self.m_mesh->name);
-					err = self.m_importer->writeMesh(*self.m_mesh, name, 1.0f - self.m_lodFactor);
+					err = self.m_importer->writeMesh(*self.m_mesh, name, self.m_importer->computeLodFactor(1));
 					maxLod = 1;
 				}
 
 				// LOD 2
-				if(!err && self.m_lodCount > 2)
+				if(!err && self.m_importer->m_lodCount > 2 && !self.m_importer->skipMeshLod(*self.m_mesh, 2))
 				{
 					StringAuto name(self.m_importer->m_alloc);
 					name.sprintf("%s_lod2", self.m_mesh->name);
-					err = self.m_importer->writeMesh(*self.m_mesh, name, 1.0f - self.m_lodFactor * 2.0f);
+					err = self.m_importer->writeMesh(*self.m_mesh, name, self.m_importer->computeLodFactor(2));
 					maxLod = 2;
 				}
 
@@ -767,14 +763,14 @@ Error GltfImporter::writeModel(const cgltf_mesh& mesh, CString skinName)
 
 	ANKI_CHECK(file.writeText("\t\t\t<mesh>%s%s.ankimesh</mesh>\n", m_rpath.cstr(), mesh.name));
 
-	if(m_lodCount > 1)
+	if(m_lodCount > 1 && !skipMeshLod(mesh, 1))
 	{
 		StringAuto name(m_alloc);
 		name.sprintf("%s_lod1", mesh.name);
 		ANKI_CHECK(file.writeText("\t\t\t<mesh1>%s%s.ankimesh</mesh1>\n", m_rpath.cstr(), name.cstr()));
 	}
 
-	if(m_lodCount > 2)
+	if(m_lodCount > 2 && !skipMeshLod(mesh, 2))
 	{
 		StringAuto name(m_alloc);
 		name.sprintf("%s_lod2", mesh.name);

+ 16 - 0
anki/importer/GltfImporter.h

@@ -73,6 +73,9 @@ private:
 	Bool m_optimizeMeshes = false;
 	StringAuto m_comment{m_alloc};
 
+	/// Don't generate LODs for meshes with less vertices than this number.
+	U32 m_skipLodVertexCountThreshold = 256;
+
 	// Misc
 	ANKI_USE_RESULT Error getExtras(const cgltf_extras& extras, HashMapAuto<CString, StringAuto>& out);
 	ANKI_USE_RESULT Error parseArrayOfNumbers(CString str, DynamicArrayAuto<F64>& out,
@@ -98,6 +101,19 @@ private:
 		return out;
 	}
 
+	F32 computeLodFactor(U32 lod) const
+	{
+		ANKI_ASSERT(lod < m_lodCount);
+		return 1.0f - m_lodFactor * F32(lod);
+	}
+
+	Bool skipMeshLod(const cgltf_mesh& mesh, U32 lod) const
+	{
+		return U32(computeLodFactor(lod) * F32(getMeshTotalVertexCount(mesh))) < m_skipLodVertexCountThreshold;
+	}
+
+	static U32 getMeshTotalVertexCount(const cgltf_mesh& mesh);
+
 	// Resources
 	ANKI_USE_RESULT Error writeMesh(const cgltf_mesh& mesh, CString nameOverride, F32 decimateFactor);
 	ANKI_USE_RESULT Error writeMaterial(const cgltf_material& mtl);

+ 14 - 0
anki/importer/GltfImporterMesh.cpp

@@ -249,6 +249,19 @@ static void decimateSubmesh(F32 factor, SubMesh& submesh, GenericMemoryPoolAlloc
 	submesh.m_verts = std::move(newVerts);
 }
 
+U32 GltfImporter::getMeshTotalVertexCount(const cgltf_mesh& mesh)
+{
+	U32 totalVertexCount = 0;
+
+	for(const cgltf_primitive* primitive = mesh.primitives; primitive < mesh.primitives + mesh.primitives_count;
+		++primitive)
+	{
+		totalVertexCount += U32(primitive->attributes[0].data->count);
+	}
+
+	return totalVertexCount;
+}
+
 Error GltfImporter::writeMesh(const cgltf_mesh& mesh, CString nameOverride, F32 decimateFactor)
 {
 	StringAuto fname(m_alloc);
@@ -694,6 +707,7 @@ Error GltfImporter::writeMesh(const cgltf_mesh& mesh, CString nameOverride, F32
 		header.m_indexType = IndexType::U16;
 		header.m_totalIndexCount = totalIndexCount;
 		header.m_totalVertexCount = totalVertexCount;
+		ANKI_ASSERT(header.m_totalVertexCount == getMeshTotalVertexCount(mesh));
 		header.m_subMeshCount = U32(submeshes.getSize());
 		header.m_aabbMin = aabbMin;
 		header.m_aabbMax = aabbMax;

+ 88 - 18
anki/resource/MeshResource.cpp

@@ -66,6 +66,12 @@ Error MeshResource::load(const ResourceFilename& filename, Bool async)
 	LoadContext* ctx;
 	LoadContext localCtx(this, getTempAllocator());
 
+	const Bool rayTracingEnabled = getManager().getGrManager().getDeviceCapabilities().m_rayTracingEnabled;
+	if(rayTracingEnabled)
+	{
+		async = false; // TODO Find a better way
+	}
+
 	if(async)
 	{
 		task = getManager().getAsyncLoader().newTask<LoadTask>(this);
@@ -99,11 +105,15 @@ Error MeshResource::load(const ResourceFilename& filename, Bool async)
 	ANKI_ASSERT((m_indexCount % 3) == 0 && "Expecting triangles");
 	m_indexType = header.m_indexType;
 
-	const PtrSize indexBuffSize = m_indexCount * ((m_indexType == IndexType::U32) ? 4 : 2);
+	const PtrSize indexBuffSize = PtrSize(m_indexCount) * ((m_indexType == IndexType::U32) ? 4 : 2);
 
+	BufferUsageBit indexBufferUsage = BufferUsageBit::INDEX | BufferUsageBit::TRANSFER_DESTINATION;
+	if(rayTracingEnabled)
+	{
+		indexBufferUsage |= BufferUsageBit::ACCELERATION_STRUCTURE_BUILD;
+	}
 	m_indexBuff = getManager().getGrManager().newBuffer(
-		BufferInitInfo(indexBuffSize, BufferUsageBit::INDEX | BufferUsageBit::TRANSFER_DESTINATION,
-					   BufferMapAccessBit::NONE, "MeshIdx"));
+		BufferInitInfo(indexBuffSize, indexBufferUsage, BufferMapAccessBit::NONE, "MeshIdx"));
 
 	// Vertex stuff
 	m_vertCount = header.m_totalVertexCount;
@@ -120,9 +130,13 @@ Error MeshResource::load(const ResourceFilename& filename, Bool async)
 		totalVertexBuffSize += m_vertCount * m_vertBufferInfos[i].m_stride;
 	}
 
+	BufferUsageBit vertexBufferUsage = BufferUsageBit::VERTEX | BufferUsageBit::TRANSFER_DESTINATION;
+	if(rayTracingEnabled)
+	{
+		vertexBufferUsage |= BufferUsageBit::ACCELERATION_STRUCTURE_BUILD;
+	}
 	m_vertBuff = getManager().getGrManager().newBuffer(
-		BufferInitInfo(totalVertexBuffSize, BufferUsageBit::VERTEX | BufferUsageBit::TRANSFER_DESTINATION,
-					   BufferMapAccessBit::NONE, "MeshVert"));
+		BufferInitInfo(totalVertexBuffSize, vertexBufferUsage, BufferMapAccessBit::NONE, "MeshVert"));
 
 	m_texChannelCount = !!header.m_vertexAttributes[VertexAttributeLocation::UV2].m_format ? 2 : 1;
 
@@ -147,17 +161,52 @@ Error MeshResource::load(const ResourceFilename& filename, Bool async)
 	m_obb = Obb(obbCenter.xyz0(), Mat3x4::getIdentity(), obbExtend.xyz0());
 
 	// Clear the buffers
-	CommandBufferInitInfo cmdbinit;
-	cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH;
-	CommandBufferPtr cmdb = getManager().getGrManager().newCommandBuffer(cmdbinit);
+	if(!async)
+	{
+		CommandBufferInitInfo cmdbinit;
+		cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH;
+		CommandBufferPtr cmdb = getManager().getGrManager().newCommandBuffer(cmdbinit);
 
-	cmdb->fillBuffer(m_vertBuff, 0, MAX_PTR_SIZE, 0);
-	cmdb->fillBuffer(m_indexBuff, 0, MAX_PTR_SIZE, 0);
+		cmdb->fillBuffer(m_vertBuff, 0, MAX_PTR_SIZE, 0);
+		cmdb->fillBuffer(m_indexBuff, 0, MAX_PTR_SIZE, 0);
 
-	cmdb->setBufferBarrier(m_vertBuff, BufferUsageBit::TRANSFER_DESTINATION, BufferUsageBit::VERTEX, 0, MAX_PTR_SIZE);
-	cmdb->setBufferBarrier(m_indexBuff, BufferUsageBit::TRANSFER_DESTINATION, BufferUsageBit::INDEX, 0, MAX_PTR_SIZE);
+		cmdb->setBufferBarrier(m_vertBuff, BufferUsageBit::TRANSFER_DESTINATION, BufferUsageBit::VERTEX, 0,
+							   MAX_PTR_SIZE);
+		cmdb->setBufferBarrier(m_indexBuff, BufferUsageBit::TRANSFER_DESTINATION, BufferUsageBit::INDEX, 0,
+							   MAX_PTR_SIZE);
+
+		cmdb->flush();
+	}
 
-	cmdb->flush();
+	// Create the BLAS
+	if(rayTracingEnabled)
+	{
+		AccelerationStructureInitInfo inf("Mesh BLAS");
+		inf.m_type = AccelerationStructureType::BOTTOM_LEVEL;
+
+		inf.m_bottomLevel.m_indexBuffer = m_indexBuff;
+		inf.m_bottomLevel.m_indexBufferOffset = 0;
+		inf.m_bottomLevel.m_indexCount = m_indexCount;
+		inf.m_bottomLevel.m_indexType = m_indexType;
+
+		U32 bufferIdx;
+		Format format;
+		PtrSize relativeOffset;
+		getVertexAttributeInfo(VertexAttributeLocation::POSITION, bufferIdx, format, relativeOffset);
+
+		BufferPtr posBuffer;
+		PtrSize offset;
+		PtrSize stride;
+		getVertexBufferInfo(bufferIdx, posBuffer, offset, stride);
+
+		inf.m_bottomLevel.m_positionBuffer = posBuffer;
+		inf.m_bottomLevel.m_positionBufferOffset = offset;
+		inf.m_bottomLevel.m_positionStride = U32(stride);
+		inf.m_bottomLevel.m_positionsFormat = format;
+		inf.m_bottomLevel.m_positionCount = m_vertCount;
+
+		m_blas = getManager().getGrManager().newAccelerationStructure(inf);
+	}
 
 	// Submit the loading task
 	if(async)
@@ -208,9 +257,10 @@ Error MeshResource::loadAsync(MeshLoader& loader) const
 		for(U32 i = 0; i < m_vertBufferInfos.getSize(); ++i)
 		{
 			alignRoundUp(VERTEX_BUFFER_ALIGNMENT, offset);
-			ANKI_CHECK(loader.storeVertexBuffer(i, data + offset, m_vertBufferInfos[i].m_stride * m_vertCount));
+			ANKI_CHECK(
+				loader.storeVertexBuffer(i, data + offset, PtrSize(m_vertBufferInfos[i].m_stride) * m_vertCount));
 
-			offset += m_vertBufferInfos[i].m_stride * m_vertCount;
+			offset += PtrSize(m_vertBufferInfos[i].m_stride) * m_vertCount;
 		}
 
 		ANKI_ASSERT(offset == m_vertBuff->getSize());
@@ -219,9 +269,29 @@ Error MeshResource::loadAsync(MeshLoader& loader) const
 		cmdb->copyBufferToBuffer(handles[0].getBuffer(), handles[0].getOffset(), m_vertBuff, 0, handles[0].getRange());
 	}
 
-	// Set barriers
-	cmdb->setBufferBarrier(m_vertBuff, BufferUsageBit::TRANSFER_DESTINATION, BufferUsageBit::VERTEX, 0, MAX_PTR_SIZE);
-	cmdb->setBufferBarrier(m_indexBuff, BufferUsageBit::TRANSFER_DESTINATION, BufferUsageBit::INDEX, 0, MAX_PTR_SIZE);
+	// Build the BLAS
+	if(gr.getDeviceCapabilities().m_rayTracingEnabled)
+	{
+		cmdb->setBufferBarrier(m_vertBuff, BufferUsageBit::TRANSFER_DESTINATION,
+							   BufferUsageBit::ACCELERATION_STRUCTURE_BUILD | BufferUsageBit::VERTEX, 0, MAX_PTR_SIZE);
+		cmdb->setBufferBarrier(m_indexBuff, BufferUsageBit::TRANSFER_DESTINATION,
+							   BufferUsageBit::ACCELERATION_STRUCTURE_BUILD | BufferUsageBit::INDEX, 0, MAX_PTR_SIZE);
+
+		cmdb->setAccelerationStructureBarrier(m_blas, AccelerationStructureUsageBit::NONE,
+											  AccelerationStructureUsageBit::BUILD);
+
+		cmdb->buildAccelerationStructure(m_blas);
+
+		cmdb->setAccelerationStructureBarrier(m_blas, AccelerationStructureUsageBit::BUILD,
+											  AccelerationStructureUsageBit::ALL_READ);
+	}
+	else
+	{
+		cmdb->setBufferBarrier(m_vertBuff, BufferUsageBit::TRANSFER_DESTINATION, BufferUsageBit::VERTEX, 0,
+							   MAX_PTR_SIZE);
+		cmdb->setBufferBarrier(m_indexBuff, BufferUsageBit::TRANSFER_DESTINATION, BufferUsageBit::INDEX, 0,
+							   MAX_PTR_SIZE);
+	}
 
 	// Finalize
 	FencePtr fence;

+ 9 - 1
anki/resource/MeshResource.h

@@ -105,7 +105,13 @@ public:
 		return isVertexAttributePresent(VertexAttributeLocation::BONE_WEIGHTS);
 	}
 
-protected:
+	AccelerationStructurePtr getBottomLevelAccelerationStructure() const
+	{
+		ANKI_ASSERT(m_blas.isCreated());
+		return m_blas;
+	}
+
+private:
 	class LoadTask;
 	class LoadContext;
 
@@ -149,6 +155,8 @@ protected:
 	// Other
 	Obb m_obb;
 
+	AccelerationStructurePtr m_blas;
+
 	ANKI_USE_RESULT Error loadAsync(MeshLoader& loader) const;
 };
 /// @}

+ 1 - 1
anki/resource/ResourceObject.h

@@ -68,7 +68,7 @@ public:
 		m_uuid = uuid;
 	}
 
-	/// To check if 2 resource pointers are actually the same.
+	/// To check if 2 resource pointers are actually the same resource.
 	ANKI_INTERNAL U64 getUuid() const
 	{
 		ANKI_ASSERT(m_uuid > 0);

+ 2 - 0
anki/shaders/include/ModelTypes.h

@@ -44,6 +44,8 @@ struct GpuMesh
 	U64 m_boneInfoVertexBufferPtr; ///< Points to a buffer of BoneInfoVertex.
 	U32 m_indexCount;
 	U32 m_vertexCount;
+	Vec3 m_aabbMin;
+	Vec3 m_aabbMax;
 };
 
 const U32 TEXTURE_CHANNEL_DIFFUSE = 0;

BIN
samples/simple_scene/assets/column_lod1.ankimesh


BIN
samples/simple_scene/assets/column_lod2.ankimesh


+ 0 - 2
samples/simple_scene/assets/column_walls.ankimdl

@@ -2,8 +2,6 @@
 	<modelPatches>
 		<modelPatch>
 			<mesh>assets/column.ankimesh</mesh>
-			<mesh1>assets/column_lod1.ankimesh</mesh1>
-			<mesh2>assets/column_lod2.ankimesh</mesh2>
 			<material>assets/walls.ankimtl</material>
 		</modelPatch>
 	</modelPatches>

BIN
samples/simple_scene/assets/room_lod1.ankimesh


BIN
samples/simple_scene/assets/room_lod2.ankimesh


+ 0 - 2
samples/simple_scene/assets/room_walls.ankimdl

@@ -2,8 +2,6 @@
 	<modelPatches>
 		<modelPatch>
 			<mesh>assets/room.ankimesh</mesh>
-			<mesh1>assets/room_lod1.ankimesh</mesh1>
-			<mesh2>assets/room_lod2.ankimesh</mesh2>
 			<material>assets/walls.ankimtl</material>
 		</modelPatch>
 	</modelPatches>

+ 3 - 0
samples/simple_scene/assets/scene.lua

@@ -1,3 +1,4 @@
+-- Generated by: ../../../buildd/bin/gltf_importer simple_scene.gltf /home/godlike/src/anki/samples/simple_scene/assets -rpath assets -texrpath assets -lod-count 3
 local scene = getSceneGraph()
 local events = getEventManager()
 
@@ -5,6 +6,8 @@ node = scene:newPerspectiveCameraNode("Camera_Orientation")
 scene:setActiveCameraNode(node:getSceneNodeBase())
 frustumc = node:getSceneNodeBase():getFrustumComponent()
 frustumc:setPerspective(0.100000, 1000.000000, getMainRenderer():getAspectRatio() * 1.024779, 1.024779)
+frustumc:setShadowCascadesDistancePower(1.5)
+frustumc:setEffectiveShadowDistance(100.000000)
 trf = Transform.new()
 trf:setOrigin(Vec4.new(0.000000, 4.311547, 5.946665, 0))
 rot = Mat3x4.new()

BIN
samples/simple_scene/assets/simple_scene.blend


+ 3 - 3
samples/simple_scene/assets/walls.ankimtl

@@ -12,15 +12,15 @@
 	</mutation>
 
 	<inputs>
-
+		
 
 		<input shaderVar="m_diffColor" value="0.510773 0.800000 0.000000"/>
 		<input shaderVar="m_specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderVar="m_roughness" value="0.215909"/>
 		<input shaderVar="m_metallic" value="0.000000"/>
-
+		
 		<input shaderVar="m_emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderVar="m_subsurface" value="0.000000"/>
-
+		
 	</inputs>
 </material>