Browse Source

Updated texture read/write API so it may be executed on different GPU's and/or different GPU queues

BearishSun 9 years ago
parent
commit
9f08aa6622

+ 1 - 1
Source/BansheeCore/Include/BsMesh.h

@@ -316,7 +316,7 @@ namespace BansheeEngine
 		 * @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
+		 *									allows the GPU to perform write 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

+ 69 - 9
Source/BansheeCore/Include/BsTexture.h

@@ -343,8 +343,15 @@ namespace BansheeEngine
 		 *									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.
+		 * @param[in]	queueIdx			Device queue to perform the write operation on. Using a non-default queue index
+		 *									allows the GPU to perform write 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 writeSubresource(UINT32 subresourceIdx, const PixelData& data, bool discardEntireBuffer);
+		virtual void writeSubresource(UINT32 subresourceIdx, const PixelData& data, bool discardEntireBuffer,
+									  UINT32 queueIdx = 0);
 
 		/**
 		 * Reads a part of the current resource into the provided @p data parameter. Data buffer needs to be pre-allocated.
@@ -352,22 +359,43 @@ namespace BansheeEngine
 		 * @param[in]	subresourceIdx		Index of the subresource to update, if the texture 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, PixelData& data);
+		virtual void readSubresource(UINT32 subresourceIdx, PixelData& data, UINT32 deviceIdx = 0, UINT32 queueIdx = 0);
 
 		/**
 		 * Locks the buffer for reading or writing.
 		 *
 		 * @param[in]	options 	Options for controlling what you may do with the locked data.
 		 * @param[in]	mipLevel	(optional) Mipmap level to lock.
-		 * @param[in]	face		(optional) Texture face to lock.					
+		 * @param[in]	face		(optional) Texture face to lock.
+		 * @param[in]	deviceIdx	Index of the device whose memory to map. If the buffer doesn't exist on this device,
+		 *							the method returns null.
+		 * @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
+		 *							operations on the same time.
+		 *
+		 *							Note that when writing to a texture 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().
 		 * @return					Pointer to the buffer data. Only valid until you call unlock().
 		 * 			
 		 * @note	
 		 * If you are just reading or writing one block of data use readData()/writeData() methods as they can be much faster
 		 * in certain situations.
 		 */
-		PixelData lock(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0);
+		PixelData lock(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
+					   UINT32 queueIdx = 0);
 
 		/** 
 		 * Unlocks a previously locked buffer. After the buffer is unlocked, any data returned by lock becomes invalid. 
@@ -386,8 +414,18 @@ namespace BansheeEngine
 		 * @param[in]	srcSubresourceIdx	Index of the subresource to copy from.
 		 * @param[in]	destSubresourceIdx	Index of the subresource to copy to.
 		 * @param[in]	target				Texture that contains the destination subresource.
+		 * @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 operations on the same time.
+		 *
+		 *									Note that when writing to a texture 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().
 		 */
-		void copy(UINT32 srcSubresourceIdx, UINT32 destSubresourceIdx, const SPtr<TextureCore>& target);
+		void copy(UINT32 srcSubresourceIdx, UINT32 destSubresourceIdx, const SPtr<TextureCore>& target, UINT32 queueIdx = 0);
 
 		/**
 		 * Reads data from the texture buffer into the provided buffer.
@@ -395,8 +433,17 @@ namespace BansheeEngine
 		 * @param[out]	dest		Previously allocated buffer to read data into.
 		 * @param[in]	mipLevel	(optional) Mipmap level to read from.
 		 * @param[in]	face		(optional) Texture face to read from.
+		 * @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 readData(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0) = 0;
+		virtual void readData(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
+							  UINT32 queueIdx = 0) = 0;
 
 		/**
 		 * Writes data from the provided buffer into the texture buffer.
@@ -406,8 +453,19 @@ namespace BansheeEngine
 		 * @param[in]	face				(optional) Texture face to write into.
 		 * @param[in]	discardWholeBuffer	(optional) If true any existing texture data will be discard. This can improve 
 		 *									performance of the write operation.
+		 * @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 texture 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().
 		 */
-		virtual void writeData(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0, bool discardWholeBuffer = false) = 0;
+		virtual void writeData(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0, bool discardWholeBuffer = false,
+							   UINT32 queueIdx = 0) = 0;
 
 		/**	Returns properties that contain information about the texture. */
 		const TextureProperties& getProperties() const { return mProperties; }
@@ -459,7 +517,8 @@ namespace BansheeEngine
 		static SPtr<TextureCore> NORMAL;
 	protected:
 		/** @copydoc lock */
-		virtual PixelData lockImpl(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0) = 0;
+		virtual PixelData lockImpl(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
+								   UINT32 queueIdx = 0) = 0;
 
 		/** @copydoc unlock */
 		virtual void unlockImpl() = 0;
@@ -472,9 +531,10 @@ namespace BansheeEngine
 		 * @param[in]	destFace		Face index to copy to.
 		 * @param[in]	destMipLevel	Mip level to copy to.
 		 * @param[in]	target			Texture to copy to.
+		 * @param[in]	queueIdx		Global queue index to perform the copy on.
 		 */
 		virtual void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, 
-			const SPtr<TextureCore>& target) = 0;
+			const SPtr<TextureCore>& target, UINT32 queueIdx = 0) = 0;
 
 		/************************************************************************/
 		/* 								TEXTURE VIEW                      		*/

+ 12 - 9
Source/BansheeCore/Source/BsTexture.cpp

@@ -92,7 +92,8 @@ namespace BansheeEngine
 		}
 	}
 
-	void TextureCore::writeSubresource(UINT32 subresourceIdx, const PixelData& pixelData, bool discardEntireBuffer)
+	void TextureCore::writeSubresource(UINT32 subresourceIdx, const PixelData& pixelData, bool discardEntireBuffer, 
+		UINT32 queueIdx)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -109,10 +110,10 @@ namespace BansheeEngine
 		UINT32 mip = 0;
 		mProperties.mapFromSubresourceIdx(subresourceIdx, face, mip);
 
-		writeData(pixelData, mip, face, discardEntireBuffer);
+		writeData(pixelData, mip, face, discardEntireBuffer, queueIdx);
 	}
 
-	void TextureCore::readSubresource(UINT32 subresourceIdx, PixelData& data)
+	void TextureCore::readSubresource(UINT32 subresourceIdx, PixelData& data, UINT32 deviceIdx, UINT32 queueIdx)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -138,10 +139,10 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Provided buffer is not of valid dimensions or format in order to read from this texture.");
 		}
 
-		readData(pixelData, mip, face);
+		readData(pixelData, mip, face, deviceIdx, queueIdx);
 	}
 
-	PixelData TextureCore::lock(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
+	PixelData TextureCore::lock(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx, UINT32 queueIdx)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -151,7 +152,7 @@ namespace BansheeEngine
 		if (face >= mProperties.getNumFaces())
 			BS_EXCEPT(InvalidParametersException, "Invalid face index: " + toString(face) + ". Min is 0, max is " + toString(mProperties.getNumFaces()));
 
-		return lockImpl(options, mipLevel, face);
+		return lockImpl(options, mipLevel, face, deviceIdx, queueIdx);
 	}
 
 	void TextureCore::unlock()
@@ -161,7 +162,8 @@ namespace BansheeEngine
 		unlockImpl();
 	}
 
-	void TextureCore::copy(UINT32 srcSubresourceIdx, UINT32 destSubresourceIdx, const SPtr<TextureCore>& target)
+	void TextureCore::copy(UINT32 srcSubresourceIdx, UINT32 destSubresourceIdx, const SPtr<TextureCore>& target,
+						   UINT32 queueIdx)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -206,7 +208,7 @@ namespace BansheeEngine
 		if (srcMipWidth != dstMipWidth || srcMipHeight != dstMipHeight || srcMipDepth != dstMipDepth)
 			BS_EXCEPT(InvalidParametersException, "Source and destination sizes must match");
 
-		copyImpl(srcFace, srcMipLevel, destFace, destMipLevel, target);
+		copyImpl(srcFace, srcMipLevel, destFace, destMipLevel, target, queueIdx);
 	}
 
 	/************************************************************************/
@@ -223,7 +225,8 @@ namespace BansheeEngine
 		mTextureViews.clear();
 	}
 
-	SPtr<TextureView> TextureCore::requestView(const SPtr<TextureCore>& texture, UINT32 mostDetailMip, UINT32 numMips, UINT32 firstArraySlice, UINT32 numArraySlices, GpuViewUsage usage)
+	SPtr<TextureView> TextureCore::requestView(const SPtr<TextureCore>& texture, UINT32 mostDetailMip, UINT32 numMips,
+											   UINT32 firstArraySlice, UINT32 numArraySlices, GpuViewUsage usage)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 

+ 8 - 4
Source/BansheeD3D11RenderAPI/Include/BsD3D11Texture.h

@@ -41,19 +41,23 @@ namespace BansheeEngine
 		void initialize() override;
 
 		/** @copydoc TextureCore::lockImpl */
-		PixelData lockImpl(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0) override;
+		PixelData lockImpl(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
+						   UINT32 queueIdx = 0) override;
 
 		/** @copydoc TextureCore::unlockImpl */
 		void unlockImpl() override;
 
 		/** @copydoc TextureCore::copyImpl */
-		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target) override;
+		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
+					  const SPtr<TextureCore>& target, UINT32 queueIdx = 0) override;
 
 		/** @copydoc TextureCore::readData */
-		void readData(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0) override;
+		void readData(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
+					  UINT32 queueIdx = 0) override;
 
 		/** @copydoc TextureCore::writeData */
-		void writeData(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0, bool discardWholeBuffer = false) override;
+		void writeData(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0, bool discardWholeBuffer = false,
+					   UINT32 queueIdx = 0) override;
 
 		/**	Creates a blank DX11 1D texture object. */
 		void create1DTex();

+ 7 - 4
Source/BansheeD3D11RenderAPI/Source/BsD3D11Texture.cpp

@@ -58,7 +58,8 @@ namespace BansheeEngine
 		TextureCore::initialize();
 	}
 
-	void D3D11TextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target)
+	void D3D11TextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
+									const SPtr<TextureCore>& target, UINT32 queueIdx)
 	{
 		D3D11TextureCore* other = static_cast<D3D11TextureCore*>(target.get());
 
@@ -87,7 +88,8 @@ namespace BansheeEngine
 		}
 	}
 
-	PixelData D3D11TextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
+	PixelData D3D11TextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,
+										 UINT32 queueIdx)
 	{
 		if (mProperties.getNumSamples() > 1)
 			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
@@ -153,7 +155,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void D3D11TextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
+	void D3D11TextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx, UINT32 queueIdx)
 	{
 		if (mProperties.getNumSamples() > 1)
 			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
@@ -173,7 +175,8 @@ namespace BansheeEngine
 		unlock();
 	}
 
-	void D3D11TextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
+	void D3D11TextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer,
+									 UINT32 queueIdx)
 	{
 		PixelFormat format = mProperties.getFormat();
 

+ 8 - 4
Source/BansheeGLRenderAPI/Include/BsGLTexture.h

@@ -48,19 +48,23 @@ namespace BansheeEngine
 		void initialize() override;
 
 		/** @copydoc TextureCore::lock */
-		PixelData lockImpl(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0) override;
+		PixelData lockImpl(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
+						   UINT32 queueIdx = 0) override;
 
 		/** @copydoc TextureCore::unlock */
 		void unlockImpl() override;
 
 		/** @copydoc TextureCore::copyImpl */
-		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target) override;
+		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
+					  const SPtr<TextureCore>& target, UINT32 queueIdx = 0) override;
 
 		/** @copydoc TextureCore::readData */
-		void readData(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0) override;
+		void readData(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
+					  UINT32 queueIdx = 0) override;
 
 		/** @copydoc TextureCore::writeData */
-		void writeData(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0, bool discardWholeBuffer = false) override;
+		void writeData(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0, bool discardWholeBuffer = false,
+					   UINT32 queueIdx = 0) override;
 
 		/** Creates pixel buffers for each face and mip level. Texture must have been created previously. */
 		void createSurfaceList();

+ 7 - 4
Source/BansheeGLRenderAPI/Source/BsGLTexture.cpp

@@ -209,7 +209,8 @@ namespace BansheeEngine
 		return mTextureID;
 	}
 
-	PixelData GLTextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
+	PixelData GLTextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,
+									  UINT32 queueIdx)
 	{
 		if (mProperties.getNumSamples() > 1)
 			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
@@ -238,7 +239,7 @@ namespace BansheeEngine
 		mLockedBuffer = nullptr;
 	}
 
-	void GLTextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
+	void GLTextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx, UINT32 queueIdx)
 	{
 		if (mProperties.getNumSamples() > 1)
 			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
@@ -246,7 +247,8 @@ namespace BansheeEngine
 		getBuffer(face, mipLevel)->download(dest);
 	}
 
-	void GLTextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
+	void GLTextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer,
+								  UINT32 queueIdx)
 	{
 		if (mProperties.getNumSamples() > 1)
 			BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
@@ -254,7 +256,8 @@ namespace BansheeEngine
 		getBuffer(face, mipLevel)->upload(src, src.getExtents());
 	}
 
-	void GLTextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target)
+	void GLTextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
+								 const SPtr<TextureCore>& target, UINT32 queueIdx)
 	{
 		GLTextureCore* destTex = static_cast<GLTextureCore*>(target.get());
 		GLTextureBuffer *src = static_cast<GLTextureBuffer*>(getBuffer(srcFace, srcMipLevel).get());

+ 8 - 4
Source/BansheeVulkanRenderAPI/Include/BsVulkanTexture.h

@@ -88,19 +88,23 @@ namespace BansheeEngine
 		void initialize() override;
 
 		/** @copydoc TextureCore::lockImpl */
-		PixelData lockImpl(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0) override;
+		PixelData lockImpl(GpuLockOptions options, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
+						   UINT32 queueIdx = 0) override;
 
 		/** @copydoc TextureCore::unlockImpl */
 		void unlockImpl() override;
 
 		/** @copydoc TextureCore::copyImpl */
-		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target) override;
+		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
+					  const SPtr<TextureCore>& target, UINT32 queueIdx = 0) override;
 
 		/** @copydoc TextureCore::readData */
-		void readData(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0) override;
+		void readData(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,
+					  UINT32 queueIdx = 0) override;
 
 		/** @copydoc TextureCore::writeData */
-		void writeData(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0, bool discardWholeBuffer = false) override;
+		void writeData(const PixelData& src, UINT32 mipLevel = 0, UINT32 face = 0, bool discardWholeBuffer = false,
+					   UINT32 queueIdx = 0) override;
 
 	private:
 		/** Creates a new image for the specified device, matching the current properties. */

+ 7 - 4
Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp

@@ -265,12 +265,14 @@ namespace BansheeEngine
 		return mImages[deviceIdx]->getView(surface);
 	}
 
-	void VulkanTextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target)
+	void VulkanTextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
+									 const SPtr<TextureCore>& target, UINT32 queueIdx)
 	{
 		// TODO - Handle resolve here as well
 	}
 
-	PixelData VulkanTextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
+	PixelData VulkanTextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,
+										  UINT32 queueIdx)
 	{
 		PixelData lockedArea(1, 1, 1, mProperties.getFormat());
 	
@@ -284,12 +286,13 @@ namespace BansheeEngine
 		
 	}
 
-	void VulkanTextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face)
+	void VulkanTextureCore::readData(PixelData& dest, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx, UINT32 queueIdx)
 	{
 		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
 	}
 
-	void VulkanTextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer)
+	void VulkanTextureCore::writeData(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer,
+									  UINT32 queueIdx)
 	{
 		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
 	}