windowing/windowserver/nga/CLIENT/RBUFFER.CPP
changeset 0 5d03bc08d59c
child 26 15986eb6c500
child 36 01a6848ebfd7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nga/CLIENT/RBUFFER.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,465 @@
+// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// RWsBuffer class, handles buffering and flushing of window server commands
+// 
+//
+
+#include <e32std.h>
+#include "../SERVER/w32cmd.h"
+#include "CLIENT.H"
+#include "w32comm.h"
+
+// Global functions
+
+GLDEF_C void Assert(TW32Assert aAssert)
+	{
+	_LIT(KW32AssertCategory,"W32 Assert");
+	User::Panic(KW32AssertCategory,aAssert);
+	}
+
+GLDEF_C void Panic(TW32Panic aPanic)
+	{
+	_LIT(KW32PanicCategory,"W32");
+	User::Panic(KW32PanicCategory,aPanic);
+	}
+
+// Public functions
+
+RWsBuffer::RWsBuffer(RWsSession *aSession) : iSession(aSession), iManager(NULL),
+	#if defined(__AUTO_FLUSH)
+		iAutoFlush(ETrue),
+	#else
+		iAutoFlush(EFalse),
+	#endif
+	iBuf(NULL,0,0), iNext(NULL), iPreviousHandle(0), iBufSize(0), iMaxBufSize(EMinBufferSize),
+	iDirectAcessCount(0), iInvalidBitmapArray(EFalse), iWindowSizeCache(NULL)
+	{
+	}
+
+TInt WsFbsDestroyCallBack(TAny* aBitmapHandle)
+	{
+	TInt* bitmapHandle=static_cast<TInt*>(aBitmapHandle);
+	RWsBuffer::FlushAllBuffers(aBitmapHandle ? *bitmapHandle : 0);
+
+	return(0);
+	}
+
+void RWsBuffer::SetCallBack()
+	{
+	for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext)
+		if (buffer==this)
+			return;	// Already linked
+	iNext=(RWsBuffer *)Dll::Tls();
+	Dll::SetTls(this);
+	if (iNext==NULL)	// First connection so set callback
+		RFbsSession::GetSession()->SetCallBack(TCallBack(WsFbsDestroyCallBack,NULL));
+	}
+
+void RWsBuffer::CancelCallBack()
+	{
+	RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();
+	if (buffer==this)
+		{
+		Dll::SetTls(iNext);
+		if (iNext==NULL)
+			RFbsSession::GetSession()->ResetCallBack();	// Last connection closing so cancel the callback
+		}
+	else
+		{
+		RWsBuffer *prev;
+		while(buffer)
+			{
+			prev=buffer;
+			buffer=buffer->iNext;
+			if (buffer==this)
+				{
+				prev->iNext=iNext;
+				break;
+				}
+			}
+		}
+	}
+
+void RWsBuffer::Close()
+	{
+	User::Free((TAny *)iBuf.Ptr());
+	if (iWindowSizeCache)
+	    {
+	    iWindowSizeCache->Close();
+	    delete iWindowSizeCache;
+	    iWindowSizeCache = NULL;
+	    }
+	}
+
+void RWsBuffer::Destroy()
+	{
+	Flush();
+	Close();
+	delete this;
+	}
+
+
+TInt RWsBuffer::Flush(const TIpcArgs* aIpcArgs,TBool aRequestFinish)
+	{
+	iBitmapArray.Reset();
+	iInvalidBitmapArray=EFalse;
+	if (iBuf.Length()==0)
+		{
+		return(KErrNone);
+		}
+	TIpcArgs ipcArgs;
+	if (aIpcArgs!=NULL)
+		{
+		ipcArgs=*aIpcArgs;
+		// check that the caller hasn't used the first slot
+		ipcArgs.Set(KBufferMessageSlot,TIpcArgs::ENothing);
+		__ASSERT_ALWAYS(Mem::Compare(REINTERPRET_CAST(const TUint8*, &ipcArgs), sizeof(TIpcArgs), REINTERPRET_CAST(const TUint8*, aIpcArgs), sizeof(TIpcArgs))==0,Panic(EW32PanicUsingReservedIpcSlot));
+		}
+	ipcArgs.Set(KBufferMessageSlot,&iBuf);
+	TInt ret;
+	if(aRequestFinish)
+		ret=iSession->DoFlush(ipcArgs);
+	else
+		ret=iSession->DoSyncMsgBuf(ipcArgs);
+	iBuf.Zero();
+	iPreviousHandle=0;
+	return(ret);
+	}
+
+void RWsBuffer::FlushAllBuffers(TInt aBitmapHandle)
+	{
+	for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext)
+		{
+		if(!aBitmapHandle || buffer->iInvalidBitmapArray || (buffer->iBitmapArray.FindInOrder(aBitmapHandle)!=KErrNotFound))
+
+			buffer->Flush();
+		}
+	}
+
+inline void RWsBuffer::SetAndLimitMaxBufSize(TInt aMaxBufSize)
+	{ // apply upper & lower limits to input buffer size
+	if (aMaxBufSize < EMinBufferSize)
+		{
+		iMaxBufSize = EMinBufferSize;
+		}
+	else if	(aMaxBufSize > EMaxBufferSize)
+		{
+		iMaxBufSize = EMaxBufferSize;
+		}
+	else
+		{
+		iMaxBufSize = aMaxBufSize;
+		}
+	}
+
+void RWsBuffer::SetBufferSizeL(TInt aBufSize)
+	{
+	SetAndLimitMaxBufSize(aBufSize);
+	ReAllocBufferL(iMaxBufSize);
+	}
+
+void RWsBuffer::SetMaxBufferSizeL(TInt aMaxBufSize)
+	{
+	SetAndLimitMaxBufSize(aMaxBufSize);
+
+	if (iMaxBufSize < iBufSize)
+		{ // shrink to new maximum
+		ReAllocBufferL(iMaxBufSize);
+		}
+	else
+		{
+		 // initial allocation should be (at least) a quarter of the requested size
+		TInt minSize = Max( (iMaxBufSize + 3) >> 2, EMinBufferSize);
+		if (minSize > iBufSize)
+			{ // new or enlarged buffer
+			ReAllocBufferL(minSize);
+			}
+		}
+
+	__ASSERT_DEBUG((iBufSize >= EMinBufferSize) && (iBufSize <= iMaxBufSize), Assert(EW32AssertBufferLogic));
+	}
+
+// Flush() buffer, try to ReAlloc, Leave if the ReAlloc fails.
+void RWsBuffer::ReAllocBufferL(TInt aNewSize)
+	{
+	if (aNewSize != iBufSize)
+		{
+		Flush();
+		if (!ReAllocBuffer(aNewSize))
+			{
+			User::LeaveNoMemory();
+			}
+		}
+	}
+
+TBool RWsBuffer::ReAllocBuffer(TInt aNewSize)
+	{
+	TUint8* ptr = const_cast<TUint8*>(iBuf.Ptr());
+	__ASSERT_DEBUG((iBufSize == 0) || (ptr != NULL), Assert(EW32AssertBufferLogic));
+	const TInt len = iBuf.Length();
+	TUint8* newPtr = static_cast<TUint8*>(User::ReAlloc(ptr, aNewSize));
+	if (newPtr != NULL)
+		{ // realloc was successful
+		iBuf.Set(newPtr, len, aNewSize);
+		iBufSize = aNewSize;
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+/* Expand the buffer, to allow new drawing command to fit.
+ 
+ Called either when trying to store additional commands to queue for Wserv, or
+ the trying to send a command bigger than the current buffer size.
+
+ Failure to expand the buffer is a minor problem in the first case but a big 
+ problem in the second.
+
+ @param aRequiredSpace Size of buffer increase required.
+ @param aMsgSize If expanding the buffer fails then needs this value to know whether Flush() is good enough.
+ @return ETrue if there is enough space, EFalse if not.
+ */
+void RWsBuffer::GrowBuffer(TInt aRequiredSpace, TInt aMsgSize)
+	{
+	__ASSERT_DEBUG(iBufSize < iMaxBufSize, Assert(EW32AssertBufferLogic));
+	// maximum size will be big enough?
+	__ASSERT_ALWAYS(aMsgSize <= iMaxBufSize, Panic(EW32PanicDataExceedsBufferLength));
+	
+	 // double or quad the current size, then limit it
+	TInt newSize = Min((iBufSize >= aRequiredSpace) ? iBufSize << 1 : iBufSize << 2, iMaxBufSize);
+
+	if (!ReAllocBuffer(newSize))
+		{ // OOM error
+		Flush();
+		if (aMsgSize > iBufSize)
+			{ // message is too big for buffer
+			Panic(EW32PanicDataExceedsBufferLength);
+			}
+		}
+	}
+
+
+TBool RWsBuffer::SetAutoFlush(TBool aState)
+	{
+	TBool old;
+
+	old=iAutoFlush;
+#if defined(__AUTO_FLUSH)
+	if (aState)
+#else
+	iAutoFlush=aState;
+	if (iAutoFlush)
+#endif
+		Flush();
+	return(old);
+	}
+
+TInt RWsBuffer::DoWrite(TInt aHandle, TUint aOpcode, TBool aFlush, const TIpcArgs* aIpcArgs, const TAny* aData, TInt aLength, const TAny* aData2, TInt aLength2)
+	{
+	__ASSERT_DEBUG(((TUint32) aOpcode) < 0x8000, Assert(EW32AssertIllegalOpcode));
+	__ASSERT_DEBUG((aLength&0x3) == 0, Assert(EW32AssertOddLengthData));
+	TInt xtra(0);
+	if (aLength2 > 0)
+		{
+		xtra = 4 - (aLength2&0x3);		// Round data upto a multiple of 4
+		if (xtra==4)
+			{
+			xtra=0;
+			}
+		}
+
+	const TInt msgSize = aLength + aLength2 + xtra + static_cast<TInt>(sizeof(TWsCmdHeader));
+	TInt available = iBuf.MaxLength() - iBuf.Length();
+	if (msgSize > available)
+		{
+		if (iBufSize >= iMaxBufSize)
+			{ // buffer is maximum size already
+			Flush();
+			}
+		else
+			{ // try to grow buffer
+			 if ( (iBuf.Length() + msgSize) > iMaxBufSize)
+				{ // growing alone will not make enough extra space
+				Flush();
+				available = iBufSize;
+				}
+
+			const TInt requiredSpace = msgSize - available;
+			if (requiredSpace > 0)
+				{
+				GrowBuffer(requiredSpace, msgSize);
+				}
+			}
+		}
+
+	TWsCmdHeader cmdHeader;
+	cmdHeader.iBase.iOpcode = (TInt16)aOpcode;
+	cmdHeader.iBase.iCmdLength = (TInt16)(aLength + aLength2 + xtra);
+
+	// For performance reasons we only pass in the handle if it is different
+	// from the previous command
+	if (aHandle == iPreviousHandle)
+		{
+		iBuf.Append((TUint8 *)&cmdHeader.iBase,sizeof(cmdHeader.iBase));
+		}
+	else
+		{
+		iPreviousHandle = aHandle;
+		cmdHeader.iBase.iOpcode|=EWsOpcodeHandle;
+		cmdHeader.iDestHandle = aHandle;
+		iBuf.Append((TUint8 *)&cmdHeader,sizeof(cmdHeader));
+		}
+
+	if (aLength)
+		{
+		iBuf.Append((TUint8 *)aData, aLength);
+		}
+	if (aLength2 > 0)
+		{
+		iBuf.Append((TUint8 *)aData2, aLength2);
+		iBuf.AppendFill(0,xtra);
+		}
+
+	if (aFlush)
+		{
+		return Flush(aIpcArgs);
+		}
+	return KErrNone;
+	}
+
+void RWsBuffer::Write(TInt handle,TUint opcode)
+	{
+	DoWrite(handle, opcode, iAutoFlush, NULL);
+	}
+
+void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length)
+	{
+	DoWrite(handle, opcode, iAutoFlush, NULL, pData, length);
+	}
+
+void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length,const TAny *pData2, TInt length2)
+	{
+	DoWrite(handle, opcode, iAutoFlush, NULL, pData, length, pData2, length2);
+	}
+
+TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TIpcArgs* aIpcArgs)
+	{
+	return DoWrite(handle, opcode, ETrue, aIpcArgs);
+	}
+
+TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData, TInt length,const TIpcArgs* aIpcArgs)
+	{
+	return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length);
+	}
+	
+TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData,TInt length,const TAny *pData2,TInt length2,const TIpcArgs* aIpcArgs)
+	{
+	return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length, pData2, length2);
+	}
+
+TInt RWsBuffer::WriteReplyP(TInt aHandle, TUint aOpcode, const TWriteDescriptorType& aReplyBuffer)
+	{
+	TIpcArgs ipcArgs;
+	aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs);
+	return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs);
+	}
+
+TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData,TInt aLength,const TWriteDescriptorType& aReplyBuffer)
+	{
+	TIpcArgs ipcArgs;
+	aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs);
+	return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength);
+	}
+
+TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData1,TInt aLengthData1,const TAny *aData2,TInt aLengthData2,const TWriteDescriptorType& aReplyBuffer)
+	{
+	TIpcArgs ipcArgs;
+	aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs);
+	return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData1, aLengthData1, aData2, aLengthData2);
+	}
+
+TInt RWsBuffer::WriteReplyWs(TUint opcode)
+//
+// Do a WriteReply using the sessions handle
+//
+	{
+	return(iSession->WriteReply(opcode));
+	}
+
+TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, TUint aOpcode)
+//
+// Do a WriteReply using the sessions handle
+//
+	{
+	return(iSession->WriteReply(pData,aLength,aOpcode));
+	}
+
+TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, const TAny *pData2, TInt aLength2, TUint aOpcode)
+//
+// Do a WriteReply using the sessions handle
+//
+	{
+	return(iSession->WriteReply(pData,aLength,pData2,aLength2,aOpcode));
+	}
+
+TInt RWsBuffer::WriteReplyByProvidingRemoteReadAccess(TInt aHandle,TUint aOpcode,const TAny *aData, TInt aLength,const TReadDescriptorType& aRemoteReadBuffer)
+	{
+	TIpcArgs ipcArgs;
+	aRemoteReadBuffer.SetDescriptorOnIpcArgs(ipcArgs);
+	return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength);
+	}
+
+void RWsBuffer::AddToBitmapArray(TInt aBitmapHandle)
+	{
+	if(aBitmapHandle && !iInvalidBitmapArray)
+		{
+		if(iBitmapArray.InsertInOrder(aBitmapHandle)==KErrNoMemory)
+
+			iInvalidBitmapArray=ETrue;
+		}
+	}
+	
+void RWsBuffer::SetWsGraphicManager(CWsGraphic::CManager* aManager)
+	{
+	__ASSERT_DEBUG(!WsGraphicManager(),Panic(EW32PanicGraphicInternal));
+	iManager = aManager;
+	}
+
+CWsGraphic::CManager* RWsBuffer::WsGraphicManager()
+	{
+	for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext)
+		if (buffer->iManager)
+			return buffer->iManager;	
+	return NULL; // does not yet exist
+	}
+
+void RWsBuffer::AsyncRequest(TInt aHandle, TUint aOpcode, TRequestStatus& aStatus)
+	{
+	aStatus = KRequestPending;
+	__ASSERT_DEBUG((aOpcode&EWservMessAsynchronousService)==0, Assert(EW32AssertIllegalOpcode));
+	Flush(); 
+
+	const TInt function = EWservMessAsynchronousService | aOpcode;
+	TIpcArgs ipcArgs(aHandle);
+
+	iSession->SendReceive(function, ipcArgs, aStatus);
+	}
+
+void RWsBuffer::EnableWindowSizeCacheL()
+    {
+    if (iWindowSizeCache == NULL)
+        {
+        iWindowSizeCache = new (ELeave) RHashMap<TInt, TWindowSizeCacheEntry>();        
+        }
+    }