Browse Source

Add an option to discard buffer contents upon writing

Marko Pintera 12 years ago
parent
commit
a1f31053f5

+ 8 - 2
CamelotCore/Include/CmCoreThreadAccessor.h

@@ -218,15 +218,21 @@ namespace CamelotFramework
 		/**
 		 * @copydoc RenderSystem::writeSubresource()
 		 *
+		 * @param discardEntireBuffer When true the existing contents of the resource you are updating will be discarded. This can make the
+		 * 							  operation faster. Resources with certain buffer types might require this flag to be in a specific state
+		 * 							  otherwise the operation will fail. 
+		 *
 		 * @note Resource is updated with data from "data" parameter when the async operation completes. 
 		 * 		 Until the async operation completes "data" is owned by the core thread and you won't
 		 * 		 be able to access it. 
+		 * 		 
+		 *		Normally dynamic buffers will require you to enable "discardEntireBuffer" flag, while static buffers require it disabled.
 		 */
-		AsyncOp writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceDataPtr& data)
+		AsyncOp writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceDataPtr& data, bool discardEntireBuffer = false)
 		{
 			data->lock();
 
-			return mCommandQueue->queueReturn(boost::bind(&RenderSystem::writeSubresource, RenderSystem::instancePtr(), resource, subresourceIdx, data, _1));
+			return mCommandQueue->queueReturn(boost::bind(&RenderSystem::writeSubresource, RenderSystem::instancePtr(), resource, subresourceIdx, data, discardEntireBuffer, _1));
 		}
 
 		/**

+ 1 - 1
CamelotCore/Include/CmGpuResource.h

@@ -14,7 +14,7 @@ namespace CamelotFramework
 		 * 			
 		 * @note	Call only from core thread.
 		 */
-		virtual void writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data) = 0;
+		virtual void writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data, bool discardEntireBuffer) = 0;
 
 		/**
 		 * @brief	Reads a part of the current resource into the provided "data" parameter.

+ 1 - 1
CamelotCore/Include/CmMesh.h

@@ -46,7 +46,7 @@ namespace CamelotFramework
 		/**
 		 * @copydoc GpuResource::writeSubresource
 		 */
-		virtual void writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data);
+		virtual void writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data, bool discardEntireBuffer);
 
 		/**
 		 * @copydoc GpuResource::readSubresource

+ 1 - 1
CamelotCore/Include/CmRenderSystem.h

@@ -292,7 +292,7 @@ namespace CamelotFramework
 		/**
 		 * @brief	Updates the resource with the specified data.
 		 */
-		void writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceDataPtr& data, AsyncOp& asyncOp);
+		void writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceDataPtr& data, bool discardEntireBuffer, AsyncOp& asyncOp);
 
 		/**
 		 * @brief	Reads data from a resource into a pre-allocated GpuResourceData instance.

+ 1 - 1
CamelotCore/Include/CmTexture.h

@@ -148,7 +148,7 @@ namespace CamelotFramework {
 		/**
 		 * @copydoc GpuResource::writeSubresource
 		 */
-		virtual void writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data);
+		virtual void writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data, bool discardEntireBuffer);
 
 		/**
 		 * @copydoc GpuResource::readSubresource

+ 22 - 5
CamelotCore/Source/CmMesh.cpp

@@ -35,13 +35,30 @@ namespace CamelotFramework
 	{
 	}
 
-	void Mesh::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data)
+	void Mesh::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data, bool discardEntireBuffer)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
 		if(data.getTypeId() != TID_MeshData)
 			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only MeshData is supported.");
 
+		if(discardEntireBuffer)
+		{
+			if(mBufferType == MeshBufferType::Static)
+			{
+				LOGWRN("Buffer discard was set but buffer was created as static.");
+				discardEntireBuffer = false;
+			}
+		}
+		else
+		{
+			if(mBufferType == MeshBufferType::Dynamic)
+			{
+				LOGWRN("Buffer discard was not set but buffer was created as dynamic.");
+				discardEntireBuffer = true;
+			}
+		}
+
 		const MeshData& meshData = static_cast<const MeshData&>(data);
 
 		// Indices
@@ -52,7 +69,7 @@ namespace CamelotFramework
 		if((indexOffset + indicesSize) > mIndexData->indexBuffer->getSizeInBytes())
 			CM_EXCEPT(InvalidParametersException, "Index buffer values are being written out of valid range.");
 
-		mIndexData->indexBuffer->writeData(indexOffset, indicesSize, srcIdxData);
+		mIndexData->indexBuffer->writeData(indexOffset, indicesSize, srcIdxData, discardEntireBuffer);
 
 		// Vertices
 		for(UINT32 i = 0; i <= meshData.getVertexDesc()->getMaxStreamIdx(); i++)
@@ -94,13 +111,13 @@ namespace CamelotFramework
 					}
 				}
 
-				vertexBuffer->writeData(bufferOffset, bufferSize, bufferCopy);
+				vertexBuffer->writeData(bufferOffset, bufferSize, bufferCopy, discardEntireBuffer);
 
 				cm_free(bufferCopy);
 			}
 			else
 			{
-				vertexBuffer->writeData(bufferOffset, bufferSize, srcVertBufferData);
+				vertexBuffer->writeData(bufferOffset, bufferSize, srcVertBufferData, discardEntireBuffer);
 			}
 		}
 
@@ -288,7 +305,7 @@ namespace CamelotFramework
 		// buffer data upon buffer construction, instead of setting it in a second step like I do here
 		if(mTempInitialMeshData != nullptr)
 		{
-			writeSubresource(0, *mTempInitialMeshData);
+			writeSubresource(0, *mTempInitialMeshData, mBufferType == MeshBufferType::Dynamic);
 
 			mTempInitialMeshData = nullptr;
 		}

+ 2 - 2
CamelotCore/Source/CmRenderSystem.cpp

@@ -252,13 +252,13 @@ namespace CamelotFramework {
 		target->swapBuffers();
 	}
 
-	void RenderSystem::writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceDataPtr& data, AsyncOp& asyncOp)
+	void RenderSystem::writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceDataPtr& data, bool discardEntireBuffer, AsyncOp& asyncOp)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
 		gProfiler().beginSample("writeSubresource");
 
-		resource->writeSubresource(subresourceIdx, *data);
+		resource->writeSubresource(subresourceIdx, *data, discardEntireBuffer);
 
 		gProfiler().endSample("writeSubresource");
 

+ 8 - 2
CamelotCore/Source/CmTexture.cpp

@@ -86,20 +86,26 @@ namespace CamelotFramework {
 		return getTextureType() == TEX_TYPE_CUBE_MAP ? 6 : 1;
 	}
 
-	void Texture::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data)
+	void Texture::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data, bool discardEntireBuffer)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
 		if(data.getTypeId() != TID_PixelData)
 			CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only PixelData is supported.");
 
+		if(!discardEntireBuffer) // TODO - Textures can currently only be dynamic
+		{
+			LOGWRN("Buffer discard was not set but buffer was created as dynamic.");
+			discardEntireBuffer = true;
+		}
+
 		const PixelData& pixelData = static_cast<const PixelData&>(data);
 
 		UINT32 face = 0;
 		UINT32 mip = 0;
 		mapFromSubresourceIdx(subresourceIdx, face, mip);
 
-		PixelData myData = lock(GBL_WRITE_ONLY_DISCARD, mip, face);
+		PixelData myData = lock(discardEntireBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_WRITE_ONLY, mip, face);
 		PixelUtil::bulkPixelConversion(pixelData, myData);
 		unlock();
 	}

+ 1 - 1
CamelotCore/Source/CmTextureManager.cpp

@@ -58,7 +58,7 @@ namespace CamelotFramework
 		data->setColorAt(Color::Red, 1, 1);
 
 		AsyncOp op;
-		RenderSystem::instance().writeSubresource(mDummyTexture.getInternalPtr(), mDummyTexture->mapToSubresourceIdx(0, 0), data, op);
+		RenderSystem::instance().writeSubresource(mDummyTexture.getInternalPtr(), mDummyTexture->mapToSubresourceIdx(0, 0), data, true, op);
 	}
 
     TexturePtr TextureManager::createTexture(TextureType texType, UINT32 width, UINT32 height, UINT32 depth, int numMipmaps,

+ 0 - 2
Opts.txt

@@ -26,8 +26,6 @@ When optimizing UpdateLayout make sure to mark elements that are fully culled as
  Mesh
   - GUIManager needs to be refactored so it knows to enlarge the Mesh when it runs out
  - writeSubresource
-  - add size and offset fields in MeshData which tell the method where exactly to write data and how much data is used
-    - Ensure that writeSubresource compares buffer sizes/offsets and maybe even vertex desc?
   - add "discardEntireBuffer" flag
    - ensure buffer is compatible with the flag (I think it needs to be dynamic)