Merge 1. Pull in cpp files in the performance enhanced Khronos RI OVG files which are newly added. I've ignored platform-specific cpp files for linux, macosx, and null operating systems because this local solution has its own platform glue (i.e. facility to target Bitmaps but no full windowing support). I've ignored sfEGLInterface.cpp because this is used as a bridge to go from EGL to Nokia's Platsim which offers an EGL service. That's not relevant to this implementation because this is ARM side code, not Intel side. I just left a comment to sfEGLInterface.cpp in case we need to pick up this later on. The current code compiles on winscw. Prior to this fix, the code works on winscw, and can launch the SVG tiger (tiger.exe). That takes about 20 seconds to render. I hope to always be able to show this icon on each commit, and the plan is for the render time to reduce with this series of submissions. On this commit, the tiger renders ok in 20 seconds.
// 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)
#ifdef SYMBIAN_GRAPHICS_FIXNATIVEORIENTATION
, iWindowNativeSizeCache(NULL)
#endif // SYMBIAN_GRAPHICS_FIXNATIVEORIENTATION
{
}
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;
}
#ifdef SYMBIAN_GRAPHICS_FIXNATIVEORIENTATION
if (iWindowNativeSizeCache)
{
iWindowNativeSizeCache->Close();
delete iWindowNativeSizeCache;
iWindowNativeSizeCache = NULL;
}
#endif // SYMBIAN_GRAPHICS_FIXNATIVEORIENTATION
}
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>();
}
}
#ifdef SYMBIAN_GRAPHICS_FIXNATIVEORIENTATION
void RWsBuffer::EnableWindowNativeSizeCacheL()
{
if (iWindowNativeSizeCache == NULL)
{
iWindowNativeSizeCache = new (ELeave) RHashMap<TInt, TWindowSizeCacheEntry>();
}
}
#endif // SYMBIAN_GRAPHICS_FIXNATIVEORIENTATION