Kaynağa Gözat

Vulkan index, vertex, gpu and gpu param block buffer implementations

BearishSun 9 yıl önce
ebeveyn
işleme
5486740789

+ 0 - 1
Source/BansheeCore/Include/BsCorePrerequisites.h

@@ -230,7 +230,6 @@ namespace BansheeEngine
     class OcclusionQuery;
     class VertexBuffer;
 	class VertexBufferCore;
-	class PixelBuffer;
 	class GpuBuffer;
 	class HighLevelGpuProgram;
 	class GpuProgramManager;

+ 4 - 8
Source/BansheeCore/Include/BsHardwareBuffer.h

@@ -97,14 +97,10 @@ namespace BansheeEngine
 		 *							of the buffer (@p offset is only applied to the source).
 		 * @param[in]	deviceIdx	Index of the device whose memory to read. If the buffer doesn't exist on this device,
 		 *							no data will be read.		
-		 * @param[in]	queueIdx	Device queue to perform any read/write operations on. Using a non-default queue index
-		 *							allows the GPU to perform write or read operations while executing rendering or compute
+		 * @param[in]	queueIdx	Device queue to perform the read operation on. Using a non-default queue index
+		 *							allows the GPU to perform read operations while executing rendering or compute
 		 *							operations on the same time.
 		 *
-		 *							Note that when writing to a buffer that is being used on a command buffer with a
-		 *							different queue you must ensure to provide the command buffer with a valid sync mask
-		 *							so it knows to wait before the write operation completes.
-		 *
 		 *							This value is a global queue index which encodes both the queue type and queue index.
 		 *							Retrieve it from CommandSyncMask::getGlobalQueueIdx().
 		 */
@@ -118,8 +114,8 @@ namespace BansheeEngine
 		 * @param[in]	source		Source buffer containing the data to write. Data is read from the start of the buffer
 		 *							(@p offset is only applied to the destination).
 		 * @param[in]	writeFlags	Optional write flags that may affect performance.
-		 * @param[in]	queueIdx	Device queue to perform any read/write operations on. Using a non-default queue index
-		 *							allows the GPU to perform write or read operations while executing rendering or compute
+		 * @param[in]	queueIdx	Device queue to perform any write operations on. Using a non-default queue index
+		 *							allows the GPU to perform write operations while executing rendering or compute
 		 *							operations on the same time.
 		 *
 		 *							Note that when writing to a buffer that is being used on a command buffer with a

+ 17 - 2
Source/BansheeCore/Include/BsMesh.h

@@ -315,8 +315,15 @@ namespace BansheeEngine
 		 *									will fail.
 		 * @param[in]	updateBounds		If true the internal bounds of the mesh will be recalculated based on the 
 		 *									provided data.
+		 * @param[in]	queueIdx			Device queue to perform the write operation on. Using a non-default queue index
+		 *									allows the GPU to perform writeoperations while executing rendering or compute
+		 *									operations on the same time.
+		 *									
+		 *									This value is a global queue index which encodes both the queue type and queue
+		 *									index. Retrieve it from CommandSyncMask::getGlobalQueueIdx().
 		 */
-		virtual void writeSubresource(UINT32 subresourceIdx, const MeshData& data, bool discardEntireBuffer, bool updateBounds = true);
+		virtual void writeSubresource(UINT32 subresourceIdx, const MeshData& data, bool discardEntireBuffer, 
+			bool updateBounds = true, UINT32 queueIdx = 0);
 
 		/**
 		 * Reads a part of the current resource into the provided @p data parameter. Data buffer needs to be pre-allocated.
@@ -324,8 +331,16 @@ namespace BansheeEngine
 		 * @param[in]	subresourceIdx		Index of the subresource to update, if the mesh has more than one.
 		 * @param[out]	data				Buffer that will receive the data. Should be allocated with 
 		 *									allocateSubresourceBuffer() to ensure it is of valid type and size.
+		 * @param[in]	deviceIdx			Index of the device whose memory to read. If the buffer doesn't exist on this
+		 *									device, no data will be read.
+		 * @param[in]	queueIdx			Device queue to perform the read operation on. Using a non-default queue index
+		 *									allows the GPU to perform read operations while executing rendering or compute
+		 *									operations on the same time.
+		 *
+		 *									This value is a global queue index which encodes both the queue type and queue
+		 *									index. Retrieve it from CommandSyncMask::getGlobalQueueIdx().
 		 */
-		virtual void readSubresource(UINT32 subresourceIdx, MeshData& data);
+		virtual void readSubresource(UINT32 subresourceIdx, MeshData& data, UINT32 deviceIdx = 0, UINT32 queueIdx = 0);
 
 		/**
 		 * Creates a new empty mesh. Created mesh will have no sub-meshes.

+ 9 - 7
Source/BansheeCore/Source/BsMesh.cpp

@@ -101,7 +101,8 @@ namespace BansheeEngine
 		return mVertexDesc;
 	}
 
-	void MeshCore::writeSubresource(UINT32 subresourceIdx, const MeshData& meshData, bool discardEntireBuffer, bool performUpdateBounds)
+	void MeshCore::writeSubresource(UINT32 subresourceIdx, const MeshData& meshData, bool discardEntireBuffer, 
+		bool performUpdateBounds, UINT32 queueIdx)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -142,7 +143,7 @@ namespace BansheeEngine
 			LOGERR("Index buffer values are being written out of valid range.");
 		}
 
-		mIndexBuffer->writeData(0, indicesSize, srcIdxData, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL);
+		mIndexBuffer->writeData(0, indicesSize, srcIdxData, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL, queueIdx);
 
 		// Vertices
 		for (UINT32 i = 0; i <= mVertexDesc->getMaxStreamIdx(); i++)
@@ -197,13 +198,14 @@ namespace BansheeEngine
 					}
 				}
 
-				vertexBuffer->writeData(0, bufferSize, bufferCopy, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL);
+				vertexBuffer->writeData(0, bufferSize, bufferCopy, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL, queueIdx);
 
 				bs_free(bufferCopy);
 			}
 			else
 			{
-				vertexBuffer->writeData(0, bufferSize, srcVertBufferData, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL);
+				vertexBuffer->writeData(0, bufferSize, srcVertBufferData, discardEntireBuffer ? BWT_DISCARD : BWT_NORMAL, 
+					queueIdx);
 			}
 		}
 
@@ -211,7 +213,7 @@ namespace BansheeEngine
 			updateBounds(meshData);
 	}
 
-	void MeshCore::readSubresource(UINT32 subresourceIdx, MeshData& meshData)
+	void MeshCore::readSubresource(UINT32 subresourceIdx, MeshData& meshData, UINT32 deviceIdx, UINT32 queueIdx)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -236,7 +238,7 @@ namespace BansheeEngine
 				return;
 			}
 
-			UINT8* idxData = static_cast<UINT8*>(mIndexBuffer->lock(GBL_READ_ONLY));
+			UINT8* idxData = static_cast<UINT8*>(mIndexBuffer->lock(GBL_READ_ONLY, deviceIdx, queueIdx));
 			UINT32 idxElemSize = ibProps.getIndexSize();
 
 			UINT8* indices = nullptr;
@@ -293,7 +295,7 @@ namespace BansheeEngine
 					continue;
 				}
 
-				UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY));
+				UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY, deviceIdx, queueIdx));
 
 				UINT8* dest = meshData.getStreamData(streamIdx);
 				memcpy(dest, vertDataPtr, bufferSize);

+ 11 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanIndexBuffer.h

@@ -4,7 +4,6 @@
 
 #include "BsVulkanPrerequisites.h"
 #include "BsIndexBuffer.h"
-#include "BsVulkanHardwareBuffer.h"
 
 namespace BansheeEngine
 {
@@ -30,6 +29,12 @@ namespace BansheeEngine
 		void copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, UINT32 dstOffset, UINT32 length, 
 			bool discardWholeBuffer = false, UINT32 queueIdx = 0) override;
 
+		/** 
+		 * Gets the resource wrapping the buffer object, on the specified device. If GPU param block buffer's device mask
+		 * doesn't include the provided device, null is returned. 
+		 */
+		VulkanBuffer* getResource(UINT32 deviceIdx) const;
+
 	protected:
 		/** @copydoc IndexBufferCore::map */
 		void* map(UINT32 offset, UINT32 length, GpuLockOptions options, UINT32 deviceIdx, UINT32 queueIdx) override;
@@ -39,6 +44,11 @@ namespace BansheeEngine
 
 		/** @copydoc IndexBufferCore::initialize */
 		void initialize() override;
+
+	private:
+		VulkanHardwareBuffer* mBuffer;
+		GpuBufferUsage mUsage;
+		GpuDeviceFlags mDeviceMask;
 	};
 
 	/** @} */

+ 11 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanVertexBuffer.h

@@ -29,6 +29,12 @@ namespace BansheeEngine
 		void copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, UINT32 dstOffset, UINT32 length, 
 			bool discardWholeBuffer = false, UINT32 queueIdx = 0) override;
 
+		/** 
+		 * Gets the resource wrapping the buffer object, on the specified device. If GPU param block buffer's device mask
+		 * doesn't include the provided device, null is returned. 
+		 */
+		VulkanBuffer* getResource(UINT32 deviceIdx) const;
+
 	protected: 
 		/** @copydoc VertexBufferCore::map */
 		void* map(UINT32 offset, UINT32 length, GpuLockOptions options, UINT32 deviceIdx, UINT32 queueIdx) override;
@@ -38,6 +44,11 @@ namespace BansheeEngine
 
 		/** @copydoc VertexBufferCore::initialize */
 		void initialize() override;
+
+	private:
+		VulkanHardwareBuffer* mBuffer;
+		GpuBufferUsage mUsage;
+		GpuDeviceFlags mDeviceMask;
 	};
 
 	/** @} */

+ 7 - 3
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuBuffer.cpp

@@ -56,29 +56,33 @@ namespace BansheeEngine
 		}
 #endif
 
-		return nullptr;;
+		return mBuffer->lock(offset, length, options, deviceIdx, queueIdx);
 	}
 
 	void VulkanGpuBufferCore::unlock()
 	{
-		
+		mBuffer->unlock();
 	}
 
 	void VulkanGpuBufferCore::readData(UINT32 offset, UINT32 length, void* dest, UINT32 deviceIdx, UINT32 queueIdx)
 	{
+		mBuffer->readData(offset, length, dest, deviceIdx, queueIdx);
+
 		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuBuffer);
 	}
 
 	void VulkanGpuBufferCore::writeData(UINT32 offset, UINT32 length, const void* source, BufferWriteType writeFlags,
 										UINT32 queueIdx)
 	{
+		mBuffer->writeData(offset, length, source, writeFlags, queueIdx);
+
 		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuBuffer);
 	}
 
 	void VulkanGpuBufferCore::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset,
 		UINT32 dstOffset, UINT32 length, bool discardWholeBuffer, UINT32 queueIdx)
 	{
-
+		mBuffer->copyData(srcBuffer, srcOffset, dstOffset, length, discardWholeBuffer, queueIdx);
 	}
 
 	VulkanBuffer* VulkanGpuBufferCore::getResource(UINT32 deviceIdx) const

+ 3 - 1
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParamBlockBuffer.cpp

@@ -25,13 +25,15 @@ namespace BansheeEngine
 
 		GpuBufferUsage usage = mUsage == GPBU_STATIC ? GBU_STATIC : GBU_DYNAMIC;
 
-		mBuffer = bs_new<VulkanHardwareBuffer>(VulkanHardwareBuffer::BT_UNIFORM, BF_32X1F, usage, mSize, mDeviceMask);
+		mBuffer = bs_new<VulkanHardwareBuffer>(VulkanHardwareBuffer::BT_UNIFORM, BF_UNKNOWN, usage, mSize, mDeviceMask);
 
 		GpuParamBlockBufferCore::initialize();
 	}
 
 	void VulkanGpuParamBlockBufferCore::writeToGPU(const UINT8* data)
 	{
+		mBuffer->writeData(0, mSize, data, BWT_DISCARD);
+
 		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuParamBuffer);
 	}
 

+ 22 - 10
Source/BansheeVulkanRenderAPI/Source/BsVulkanIndexBuffer.cpp

@@ -1,23 +1,27 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanIndexBuffer.h"
+#include "BsVulkanHardwareBuffer.h"
 #include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
 	VulkanIndexBufferCore::VulkanIndexBufferCore(const INDEX_BUFFER_DESC& desc, GpuDeviceFlags deviceMask)
-		:IndexBufferCore(desc, deviceMask)
-	{
-		
-	}
+		:IndexBufferCore(desc, deviceMask), mBuffer(nullptr),  mUsage(desc.usage), mDeviceMask(deviceMask)
+	{ }
 
 	VulkanIndexBufferCore::~VulkanIndexBufferCore()
 	{
+		if (mBuffer != nullptr)
+			bs_delete(mBuffer);
+
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_IndexBuffer);
 	}
 
 	void VulkanIndexBufferCore::initialize()
 	{
+		mBuffer = bs_new<VulkanHardwareBuffer>(VulkanHardwareBuffer::BT_INDEX, BF_UNKNOWN, mUsage, mSize, mDeviceMask);
+
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_IndexBuffer);
 		IndexBufferCore::initialize();
 	}
@@ -30,34 +34,42 @@ namespace BansheeEngine
 			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_IndexBuffer);
 		}
 
-		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD 
-			|| options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
 		{
 			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_IndexBuffer);
 		}
 #endif
 
-		return nullptr;
+		return mBuffer->lock(offset, length, options, deviceIdx, queueIdx);
 	}
 
 	void VulkanIndexBufferCore::unmap()
 	{
-
+		mBuffer->unlock();
 	}
 
 	void VulkanIndexBufferCore::readData(UINT32 offset, UINT32 length, void* dest, UINT32 deviceIdx, UINT32 queueIdx)
 	{
+		mBuffer->readData(offset, length, dest, deviceIdx, queueIdx);
+
 		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_IndexBuffer);
 	}
 
-	void VulkanIndexBufferCore::writeData(UINT32 offset, UINT32 length, const void* pSource, BufferWriteType writeFlags, UINT32 queueIdx)
+	void VulkanIndexBufferCore::writeData(UINT32 offset, UINT32 length, const void* source, BufferWriteType writeFlags, UINT32 queueIdx)
 	{
+		mBuffer->writeData(offset, length, source, writeFlags, queueIdx);
+
 		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_IndexBuffer);
 	}
 
 	void VulkanIndexBufferCore::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset,
-		UINT32 dstOffset, UINT32 length, bool discardWholeBuffer, UINT32 queueIdx)
+										UINT32 dstOffset, UINT32 length, bool discardWholeBuffer, UINT32 queueIdx)
 	{
+		mBuffer->copyData(srcBuffer, srcOffset, dstOffset, length, discardWholeBuffer, queueIdx);
+	}
 
+	VulkanBuffer* VulkanIndexBufferCore::getResource(UINT32 deviceIdx) const
+	{
+		return mBuffer->getResource(deviceIdx);
 	}
 }

+ 22 - 7
Source/BansheeVulkanRenderAPI/Source/BsVulkanVertexBuffer.cpp

@@ -1,19 +1,31 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanVertexBuffer.h"
+#include "BsVulkanHardwareBuffer.h"
 #include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
 	VulkanVertexBufferCore::VulkanVertexBufferCore(const VERTEX_BUFFER_DESC& desc, GpuDeviceFlags deviceMask)
-		:VertexBufferCore(desc, deviceMask)
+		:VertexBufferCore(desc, deviceMask), mBuffer(nullptr), mUsage(desc.usage), mDeviceMask(deviceMask)
 	{ }
 
 	VulkanVertexBufferCore::~VulkanVertexBufferCore()
 	{
+		if (mBuffer != nullptr)
+			bs_delete(mBuffer);
+
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_VertexBuffer);
 	}
 
+	void VulkanVertexBufferCore::initialize()
+	{
+		mBuffer = bs_new<VulkanHardwareBuffer>(VulkanHardwareBuffer::BT_VERTEX, BF_UNKNOWN, mUsage, mSize, mDeviceMask);
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexBuffer);
+		VertexBufferCore::initialize();
+	}
+
 	void* VulkanVertexBufferCore::map(UINT32 offset, UINT32 length, GpuLockOptions options, UINT32 deviceIdx, UINT32 queueIdx)
 	{
 #if BS_PROFILING_ENABLED
@@ -28,34 +40,37 @@ namespace BansheeEngine
 		}
 #endif
 
-		return nullptr;
+		return mBuffer->lock(offset, length, options, deviceIdx, queueIdx);
 	}
 
 	void VulkanVertexBufferCore::unmap()
 	{
-
+		mBuffer->unlock();
 	}
 
 	void VulkanVertexBufferCore::readData(UINT32 offset, UINT32 length, void* dest, UINT32 deviceIdx, UINT32 queueIdx)
 	{
+		mBuffer->readData(offset, length, dest, deviceIdx, queueIdx);
+
 		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_VertexBuffer);
 	}
 
 	void VulkanVertexBufferCore::writeData(UINT32 offset, UINT32 length, const void* source, BufferWriteType writeFlags, 
 		UINT32 queueIdx)
 	{
+		mBuffer->writeData(offset, length, source, writeFlags, queueIdx);
+
 		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_VertexBuffer);
 	}
 
 	void VulkanVertexBufferCore::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset,
 		UINT32 dstOffset, UINT32 length, bool discardWholeBuffer, UINT32 queueIdx)
 	{
-
+		mBuffer->copyData(srcBuffer, srcOffset, dstOffset, length, discardWholeBuffer, queueIdx);
 	}
 
-	void VulkanVertexBufferCore::initialize()
+	VulkanBuffer* VulkanVertexBufferCore::getResource(UINT32 deviceIdx) const
 	{
-		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexBuffer);
-		VertexBufferCore::initialize();
+		return mBuffer->getResource(deviceIdx);
 	}
 }

+ 19 - 2
Source/ExampleProject/Source/Main.cpp

@@ -7,6 +7,7 @@
 #include "BsImporter.h"
 #include "BsResources.h"
 #include "BsTextureImportOptions.h"
+#include "BsMeshImportOptions.h"
 #include "BsMaterial.h"
 #include "BsShader.h"
 #include "BsVirtualInput.h"
@@ -170,6 +171,19 @@ namespace BansheeEngine
 		model = gResources().load<Mesh>(exampleModelAssetPath);
 		if(model == nullptr) // Mesh file doesn't exist, import from the source file.
 		{
+			// When importing you may specify optional import options that control how is the asset imported.
+			SPtr<ImportOptions> meshImportOptions = Importer::instance().createImportOptions(exampleModelPath);
+
+			// rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a
+			// non-mesh resource. This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
+			if (rtti_is_of_type<MeshImportOptions>(meshImportOptions))
+			{
+				MeshImportOptions* importOptions = static_cast<MeshImportOptions*>(meshImportOptions.get());
+
+				// Ensures we can save the mesh contents
+				importOptions->setCPUCached(true);
+			}
+
 			model = gImporter().import<Mesh>(exampleModelPath);
 
 			// Save for later use, so we don't have to import on the next run.
@@ -183,8 +197,8 @@ namespace BansheeEngine
 			// When importing you may specify optional import options that control how is the asset imported.
 			SPtr<ImportOptions> textureImportOptions = Importer::instance().createImportOptions(exampleTexturePath);
 
-			// rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a non-texture resource.
-			// This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
+			// rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a 
+			// non-texture resource. This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
 			if (rtti_is_of_type<TextureImportOptions>(textureImportOptions))
 			{
 				TextureImportOptions* importOptions = static_cast<TextureImportOptions*>(textureImportOptions.get());
@@ -194,6 +208,9 @@ namespace BansheeEngine
 
 				// The texture is in sRGB space
 				importOptions->setSRGB(true);
+
+				// Ensures we can save the texture contents
+				importOptions->setCPUCached(true);
 			}
 
 			// Import texture with specified import options