os/graphics/windowing/windowserver/nonnga/CLIENT/RBUFFER.CPP
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// RWsBuffer class, handles buffering and flushing of window server commands
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include <e32std.h>
sl@0
    19
#include "../SERVER/w32cmd.h"
sl@0
    20
#include "CLIENT.H"
sl@0
    21
#include "w32comm.h"
sl@0
    22
sl@0
    23
// Global functions
sl@0
    24
sl@0
    25
GLDEF_C void Assert(TW32Assert aAssert)
sl@0
    26
	{
sl@0
    27
	_LIT(KW32AssertCategory,"W32 Assert");
sl@0
    28
	User::Panic(KW32AssertCategory,aAssert);
sl@0
    29
	}
sl@0
    30
sl@0
    31
GLDEF_C void Panic(TW32Panic aPanic)
sl@0
    32
	{
sl@0
    33
	_LIT(KW32PanicCategory,"W32");
sl@0
    34
	User::Panic(KW32PanicCategory,aPanic);
sl@0
    35
	}
sl@0
    36
sl@0
    37
// Public functions
sl@0
    38
sl@0
    39
RWsBuffer::RWsBuffer(RWsSession *aSession) : iSession(aSession), iManager(NULL),
sl@0
    40
	#if defined(__AUTO_FLUSH)
sl@0
    41
		iAutoFlush(ETrue),
sl@0
    42
	#else
sl@0
    43
		iAutoFlush(EFalse),
sl@0
    44
	#endif
sl@0
    45
	iBuf(NULL,0,0), iNext(NULL), iPreviousHandle(0), iBufSize(0), iMaxBufSize(EMinBufferSize),
sl@0
    46
	iDirectAcessCount(0), iInvalidBitmapArray(EFalse)
sl@0
    47
	{
sl@0
    48
	}
sl@0
    49
sl@0
    50
TInt WsFbsDestroyCallBack(TAny* aBitmapHandle)
sl@0
    51
	{
sl@0
    52
	TInt* bitmapHandle=static_cast<TInt*>(aBitmapHandle);
sl@0
    53
	RWsBuffer::FlushAllBuffers(aBitmapHandle ? *bitmapHandle : 0);
sl@0
    54
sl@0
    55
	return(0);
sl@0
    56
	}
sl@0
    57
sl@0
    58
void RWsBuffer::SetCallBack()
sl@0
    59
	{
sl@0
    60
	for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext)
sl@0
    61
		if (buffer==this)
sl@0
    62
			return;	// Already linked
sl@0
    63
	iNext=(RWsBuffer *)Dll::Tls();
sl@0
    64
	Dll::SetTls(this);
sl@0
    65
	if (iNext==NULL)	// First connection so set callback
sl@0
    66
		RFbsSession::GetSession()->SetCallBack(TCallBack(WsFbsDestroyCallBack,NULL));
sl@0
    67
	}
sl@0
    68
sl@0
    69
void RWsBuffer::CancelCallBack()
sl@0
    70
	{
sl@0
    71
	RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();
sl@0
    72
	if (buffer==this)
sl@0
    73
		{
sl@0
    74
		Dll::SetTls(iNext);
sl@0
    75
		if (iNext==NULL)
sl@0
    76
			RFbsSession::GetSession()->ResetCallBack();	// Last connection closing so cancel the callback
sl@0
    77
		}
sl@0
    78
	else
sl@0
    79
		{
sl@0
    80
		RWsBuffer *prev;
sl@0
    81
		while(buffer)
sl@0
    82
			{
sl@0
    83
			prev=buffer;
sl@0
    84
			buffer=buffer->iNext;
sl@0
    85
			if (buffer==this)
sl@0
    86
				{
sl@0
    87
				prev->iNext=iNext;
sl@0
    88
				break;
sl@0
    89
				}
sl@0
    90
			}
sl@0
    91
		}
sl@0
    92
	}
sl@0
    93
sl@0
    94
void RWsBuffer::Close()
sl@0
    95
	{
sl@0
    96
	User::Free((TAny *)iBuf.Ptr());
sl@0
    97
	}
sl@0
    98
sl@0
    99
void RWsBuffer::Destroy()
sl@0
   100
	{
sl@0
   101
	Flush();
sl@0
   102
	Close();
sl@0
   103
	delete this;
sl@0
   104
	}
sl@0
   105
sl@0
   106
sl@0
   107
TInt RWsBuffer::Flush(const TIpcArgs* aIpcArgs,TBool aRequestFinish)
sl@0
   108
	{
sl@0
   109
	iBitmapArray.Reset();
sl@0
   110
	iInvalidBitmapArray=EFalse;
sl@0
   111
	if (iBuf.Length()==0)
sl@0
   112
		{
sl@0
   113
		return(KErrNone);
sl@0
   114
		}
sl@0
   115
	TIpcArgs ipcArgs;
sl@0
   116
	if (aIpcArgs!=NULL)
sl@0
   117
		{
sl@0
   118
		ipcArgs=*aIpcArgs;
sl@0
   119
		// check that the caller hasn't used the first slot
sl@0
   120
		ipcArgs.Set(KBufferMessageSlot,TIpcArgs::ENothing);
sl@0
   121
		__ASSERT_ALWAYS(Mem::Compare(REINTERPRET_CAST(const TUint8*, &ipcArgs), sizeof(TIpcArgs), REINTERPRET_CAST(const TUint8*, aIpcArgs), sizeof(TIpcArgs))==0,Panic(EW32PanicUsingReservedIpcSlot));
sl@0
   122
		}
sl@0
   123
	ipcArgs.Set(KBufferMessageSlot,&iBuf);
sl@0
   124
	TInt ret;
sl@0
   125
	if(aRequestFinish)
sl@0
   126
		ret=iSession->DoFlush(ipcArgs);
sl@0
   127
	else
sl@0
   128
		ret=iSession->DoSyncMsgBuf(ipcArgs);
sl@0
   129
	iBuf.Zero();
sl@0
   130
	iPreviousHandle=0;
sl@0
   131
	return(ret);
sl@0
   132
	}
sl@0
   133
sl@0
   134
void RWsBuffer::FlushAllBuffers(TInt aBitmapHandle)
sl@0
   135
	{
sl@0
   136
	for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext)
sl@0
   137
		{
sl@0
   138
		if(!aBitmapHandle || buffer->iInvalidBitmapArray || (buffer->iBitmapArray.FindInOrder(aBitmapHandle)!=KErrNotFound))
sl@0
   139
sl@0
   140
			buffer->Flush();
sl@0
   141
		}
sl@0
   142
	}
sl@0
   143
sl@0
   144
inline void RWsBuffer::SetAndLimitMaxBufSize(TInt aMaxBufSize)
sl@0
   145
	{ // apply upper & lower limits to input buffer size
sl@0
   146
	if (aMaxBufSize < EMinBufferSize)
sl@0
   147
		{
sl@0
   148
		iMaxBufSize = EMinBufferSize;
sl@0
   149
		}
sl@0
   150
	else if	(aMaxBufSize > EMaxBufferSize)
sl@0
   151
		{
sl@0
   152
		iMaxBufSize = EMaxBufferSize;
sl@0
   153
		}
sl@0
   154
	else
sl@0
   155
		{
sl@0
   156
		iMaxBufSize = aMaxBufSize;
sl@0
   157
		}
sl@0
   158
	}
sl@0
   159
sl@0
   160
void RWsBuffer::SetBufferSizeL(TInt aBufSize)
sl@0
   161
	{
sl@0
   162
	SetAndLimitMaxBufSize(aBufSize);
sl@0
   163
	ReAllocBufferL(iMaxBufSize);
sl@0
   164
	}
sl@0
   165
sl@0
   166
void RWsBuffer::SetMaxBufferSizeL(TInt aMaxBufSize)
sl@0
   167
	{
sl@0
   168
	SetAndLimitMaxBufSize(aMaxBufSize);
sl@0
   169
sl@0
   170
	if (iMaxBufSize < iBufSize)
sl@0
   171
		{ // shrink to new maximum
sl@0
   172
		ReAllocBufferL(iMaxBufSize);
sl@0
   173
		}
sl@0
   174
	else
sl@0
   175
		{
sl@0
   176
		 // initial allocation should be (at least) a quarter of the requested size
sl@0
   177
		TInt minSize = Max( (iMaxBufSize + 3) >> 2, EMinBufferSize);
sl@0
   178
		if (minSize > iBufSize)
sl@0
   179
			{ // new or enlarged buffer
sl@0
   180
			ReAllocBufferL(minSize);
sl@0
   181
			}
sl@0
   182
		}
sl@0
   183
sl@0
   184
	__ASSERT_DEBUG((iBufSize >= EMinBufferSize) && (iBufSize <= iMaxBufSize), Assert(EW32AssertBufferLogic));
sl@0
   185
	}
sl@0
   186
sl@0
   187
// Flush() buffer, try to ReAlloc, Leave if the ReAlloc fails.
sl@0
   188
void RWsBuffer::ReAllocBufferL(TInt aNewSize)
sl@0
   189
	{
sl@0
   190
	if (aNewSize != iBufSize)
sl@0
   191
		{
sl@0
   192
		Flush();
sl@0
   193
		if (!ReAllocBuffer(aNewSize))
sl@0
   194
			{
sl@0
   195
			User::LeaveNoMemory();
sl@0
   196
			}
sl@0
   197
		}
sl@0
   198
	}
sl@0
   199
sl@0
   200
TBool RWsBuffer::ReAllocBuffer(TInt aNewSize)
sl@0
   201
	{
sl@0
   202
	TUint8* ptr = const_cast<TUint8*>(iBuf.Ptr());
sl@0
   203
	__ASSERT_DEBUG((iBufSize == 0) || (ptr != NULL), Assert(EW32AssertBufferLogic));
sl@0
   204
	const TInt len = iBuf.Length();
sl@0
   205
	TUint8* newPtr = static_cast<TUint8*>(User::ReAlloc(ptr, aNewSize));
sl@0
   206
	if (newPtr != NULL)
sl@0
   207
		{ // realloc was successful
sl@0
   208
		iBuf.Set(newPtr, len, aNewSize);
sl@0
   209
		iBufSize = aNewSize;
sl@0
   210
		return ETrue;
sl@0
   211
		}
sl@0
   212
	return EFalse;
sl@0
   213
	}
sl@0
   214
sl@0
   215
/* Expand the buffer, to allow new drawing command to fit.
sl@0
   216
 
sl@0
   217
 Called either when trying to store additional commands to queue for Wserv, or
sl@0
   218
 the trying to send a command bigger than the current buffer size.
sl@0
   219
sl@0
   220
 Failure to expand the buffer is a minor problem in the first case but a big 
sl@0
   221
 problem in the second.
sl@0
   222
sl@0
   223
 @param aRequiredSpace Size of buffer increase required.
sl@0
   224
 @param aMsgSize If expanding the buffer fails then needs this value to know whether Flush() is good enough.
sl@0
   225
 @return ETrue if there is enough space, EFalse if not.
sl@0
   226
 */
sl@0
   227
void RWsBuffer::GrowBuffer(TInt aRequiredSpace, TInt aMsgSize)
sl@0
   228
	{
sl@0
   229
	__ASSERT_DEBUG(iBufSize < iMaxBufSize, Assert(EW32AssertBufferLogic));
sl@0
   230
	// maximum size will be big enough?
sl@0
   231
	__ASSERT_ALWAYS(aMsgSize <= iMaxBufSize, Panic(EW32PanicDataExceedsBufferLength));
sl@0
   232
	
sl@0
   233
	 // double or quad the current size, then limit it
sl@0
   234
	TInt newSize = Min((iBufSize >= aRequiredSpace) ? iBufSize << 1 : iBufSize << 2, iMaxBufSize);
sl@0
   235
sl@0
   236
	if (!ReAllocBuffer(newSize))
sl@0
   237
		{ // OOM error
sl@0
   238
		Flush();
sl@0
   239
		if (aMsgSize > iBufSize)
sl@0
   240
			{ // message is too big for buffer
sl@0
   241
			Panic(EW32PanicDataExceedsBufferLength);
sl@0
   242
			}
sl@0
   243
		}
sl@0
   244
	}
sl@0
   245
sl@0
   246
sl@0
   247
TBool RWsBuffer::SetAutoFlush(TBool aState)
sl@0
   248
	{
sl@0
   249
	TBool old;
sl@0
   250
sl@0
   251
	old=iAutoFlush;
sl@0
   252
#if defined(__AUTO_FLUSH)
sl@0
   253
	if (aState)
sl@0
   254
#else
sl@0
   255
	iAutoFlush=aState;
sl@0
   256
	if (iAutoFlush)
sl@0
   257
#endif
sl@0
   258
		Flush();
sl@0
   259
	return(old);
sl@0
   260
	}
sl@0
   261
sl@0
   262
TInt RWsBuffer::DoWrite(TInt aHandle, TUint aOpcode, TBool aFlush, const TIpcArgs* aIpcArgs, const TAny* aData, TInt aLength, const TAny* aData2, TInt aLength2)
sl@0
   263
	{
sl@0
   264
	__ASSERT_DEBUG(((TUint32) aOpcode) < 0x8000, Assert(EW32AssertIllegalOpcode));
sl@0
   265
	__ASSERT_DEBUG((aLength&0x3) == 0, Assert(EW32AssertOddLengthData));
sl@0
   266
	TInt xtra(0);
sl@0
   267
	if (aLength2 > 0)
sl@0
   268
		{
sl@0
   269
		xtra = 4 - (aLength2&0x3);		// Round data upto a multiple of 4
sl@0
   270
		if (xtra==4)
sl@0
   271
			{
sl@0
   272
			xtra=0;
sl@0
   273
			}
sl@0
   274
		}
sl@0
   275
sl@0
   276
	const TInt msgSize = aLength + aLength2 + xtra + static_cast<TInt>(sizeof(TWsCmdHeader));
sl@0
   277
	TInt available = iBuf.MaxLength() - iBuf.Length();
sl@0
   278
	if (msgSize > available)
sl@0
   279
		{
sl@0
   280
		if (iBufSize >= iMaxBufSize)
sl@0
   281
			{ // buffer is maximum size already
sl@0
   282
			Flush();
sl@0
   283
			}
sl@0
   284
		else
sl@0
   285
			{ // try to grow buffer
sl@0
   286
			 if ( (iBuf.Length() + msgSize) > iMaxBufSize)
sl@0
   287
				{ // growing alone will not make enough extra space
sl@0
   288
				Flush();
sl@0
   289
				available = iBufSize;
sl@0
   290
				}
sl@0
   291
sl@0
   292
			const TInt requiredSpace = msgSize - available;
sl@0
   293
			if (requiredSpace > 0)
sl@0
   294
				{
sl@0
   295
				GrowBuffer(requiredSpace, msgSize);
sl@0
   296
				}
sl@0
   297
			}
sl@0
   298
		}
sl@0
   299
sl@0
   300
	TWsCmdHeader cmdHeader;
sl@0
   301
	cmdHeader.iBase.iOpcode = (TInt16)aOpcode;
sl@0
   302
	cmdHeader.iBase.iCmdLength = (TInt16)(aLength + aLength2 + xtra);
sl@0
   303
sl@0
   304
	// For performance reasons we only pass in the handle if it is different
sl@0
   305
	// from the previous command
sl@0
   306
	if (aHandle == iPreviousHandle)
sl@0
   307
		{
sl@0
   308
		iBuf.Append((TUint8 *)&cmdHeader.iBase,sizeof(cmdHeader.iBase));
sl@0
   309
		}
sl@0
   310
	else
sl@0
   311
		{
sl@0
   312
		iPreviousHandle = aHandle;
sl@0
   313
		cmdHeader.iBase.iOpcode|=EWsOpcodeHandle;
sl@0
   314
		cmdHeader.iDestHandle = aHandle;
sl@0
   315
		iBuf.Append((TUint8 *)&cmdHeader,sizeof(cmdHeader));
sl@0
   316
		}
sl@0
   317
sl@0
   318
	if (aLength)
sl@0
   319
		{
sl@0
   320
		iBuf.Append((TUint8 *)aData, aLength);
sl@0
   321
		}
sl@0
   322
	if (aLength2 > 0)
sl@0
   323
		{
sl@0
   324
		iBuf.Append((TUint8 *)aData2, aLength2);
sl@0
   325
		iBuf.AppendFill(0,xtra);
sl@0
   326
		}
sl@0
   327
sl@0
   328
	if (aFlush)
sl@0
   329
		{
sl@0
   330
		return Flush(aIpcArgs);
sl@0
   331
		}
sl@0
   332
	return KErrNone;
sl@0
   333
	}
sl@0
   334
sl@0
   335
void RWsBuffer::Write(TInt handle,TUint opcode)
sl@0
   336
	{
sl@0
   337
	DoWrite(handle, opcode, iAutoFlush, NULL);
sl@0
   338
	}
sl@0
   339
sl@0
   340
void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length)
sl@0
   341
	{
sl@0
   342
	DoWrite(handle, opcode, iAutoFlush, NULL, pData, length);
sl@0
   343
	}
sl@0
   344
sl@0
   345
void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length,const TAny *pData2, TInt length2)
sl@0
   346
	{
sl@0
   347
	DoWrite(handle, opcode, iAutoFlush, NULL, pData, length, pData2, length2);
sl@0
   348
	}
sl@0
   349
sl@0
   350
TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TIpcArgs* aIpcArgs)
sl@0
   351
	{
sl@0
   352
	return DoWrite(handle, opcode, ETrue, aIpcArgs);
sl@0
   353
	}
sl@0
   354
sl@0
   355
TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData, TInt length,const TIpcArgs* aIpcArgs)
sl@0
   356
	{
sl@0
   357
	return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length);
sl@0
   358
	}
sl@0
   359
	
sl@0
   360
TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData,TInt length,const TAny *pData2,TInt length2,const TIpcArgs* aIpcArgs)
sl@0
   361
	{
sl@0
   362
	return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length, pData2, length2);
sl@0
   363
	}
sl@0
   364
sl@0
   365
TInt RWsBuffer::WriteReplyP(TInt aHandle, TUint aOpcode, const TWriteDescriptorType& aReplyBuffer)
sl@0
   366
	{
sl@0
   367
	TIpcArgs ipcArgs;
sl@0
   368
	aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs);
sl@0
   369
	return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs);
sl@0
   370
	}
sl@0
   371
sl@0
   372
TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData,TInt aLength,const TWriteDescriptorType& aReplyBuffer)
sl@0
   373
	{
sl@0
   374
	TIpcArgs ipcArgs;
sl@0
   375
	aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs);
sl@0
   376
	return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength);
sl@0
   377
	}
sl@0
   378
sl@0
   379
TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData1,TInt aLengthData1,const TAny *aData2,TInt aLengthData2,const TWriteDescriptorType& aReplyBuffer)
sl@0
   380
	{
sl@0
   381
	TIpcArgs ipcArgs;
sl@0
   382
	aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs);
sl@0
   383
	return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData1, aLengthData1, aData2, aLengthData2);
sl@0
   384
	}
sl@0
   385
sl@0
   386
TInt RWsBuffer::WriteReplyWs(TUint opcode)
sl@0
   387
//
sl@0
   388
// Do a WriteReply using the sessions handle
sl@0
   389
//
sl@0
   390
	{
sl@0
   391
	return(iSession->WriteReply(opcode));
sl@0
   392
	}
sl@0
   393
sl@0
   394
TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, TUint aOpcode)
sl@0
   395
//
sl@0
   396
// Do a WriteReply using the sessions handle
sl@0
   397
//
sl@0
   398
	{
sl@0
   399
	return(iSession->WriteReply(pData,aLength,aOpcode));
sl@0
   400
	}
sl@0
   401
sl@0
   402
TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, const TAny *pData2, TInt aLength2, TUint aOpcode)
sl@0
   403
//
sl@0
   404
// Do a WriteReply using the sessions handle
sl@0
   405
//
sl@0
   406
	{
sl@0
   407
	return(iSession->WriteReply(pData,aLength,pData2,aLength2,aOpcode));
sl@0
   408
	}
sl@0
   409
sl@0
   410
TInt RWsBuffer::WriteReplyByProvidingRemoteReadAccess(TInt aHandle,TUint aOpcode,const TAny *aData, TInt aLength,const TReadDescriptorType& aRemoteReadBuffer)
sl@0
   411
	{
sl@0
   412
	TIpcArgs ipcArgs;
sl@0
   413
	aRemoteReadBuffer.SetDescriptorOnIpcArgs(ipcArgs);
sl@0
   414
	return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength);
sl@0
   415
	}
sl@0
   416
sl@0
   417
void RWsBuffer::AddToBitmapArray(TInt aBitmapHandle)
sl@0
   418
	{
sl@0
   419
	if(aBitmapHandle && !iInvalidBitmapArray)
sl@0
   420
		{
sl@0
   421
		if(iBitmapArray.InsertInOrder(aBitmapHandle)==KErrNoMemory)
sl@0
   422
sl@0
   423
			iInvalidBitmapArray=ETrue;
sl@0
   424
		}
sl@0
   425
	}
sl@0
   426
	
sl@0
   427
void RWsBuffer::SetWsGraphicManager(CWsGraphic::CManager* aManager)
sl@0
   428
	{
sl@0
   429
	__ASSERT_DEBUG(!WsGraphicManager(),Panic(EW32PanicGraphicInternal));
sl@0
   430
	iManager = aManager;
sl@0
   431
	}
sl@0
   432
sl@0
   433
CWsGraphic::CManager* RWsBuffer::WsGraphicManager()
sl@0
   434
	{
sl@0
   435
	for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext)
sl@0
   436
		if (buffer->iManager)
sl@0
   437
			return buffer->iManager;	
sl@0
   438
	return NULL; // does not yet exist
sl@0
   439
	}