//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #ifndef IMATERIALSYSTEMINTERNAL_H #define IMATERIALSYSTEMINTERNAL_H #ifdef _WIN32 #pragma once #endif #include "materialsystem/imaterialsystem.h" #include "tier1/callqueue.h" #include "tier1/memstack.h" #include "tier1/fmtstr.h" #include "tier0/vprof_telemetry.h" #include "tier0/perfstats.h" class IMaterialInternal; //----------------------------------------------------------------------------- // Special call queue that knows (a) single threaded access, and (b) all // functions called after last function added //----------------------------------------------------------------------------- class CMatCallQueue { public: CMatCallQueue() { static int nStackCount = 0; CFmtStr stackName( "CMatCallQueue.m_Allocator[%d]", nStackCount++ ); #ifdef DEDICATED m_Allocator.Init( (const char *)stackName, 2*1024, 0, 0, 4 ); #else m_Allocator.Init( (const char *)stackName, ( IsGameConsole() || IsPlatformPosix() ) ? 2*1024*1024 : 8*1024*1024, 64*1024, 256*1024, 4 ); #endif m_FunctorFactory.SetAllocator( &m_Allocator ); m_pHead = m_pTail = NULL; } size_t GetMemoryUsed() { return m_Allocator.GetUsed(); } int Count() { int i = 0; Elem_t *pCurrent = m_pHead; while ( pCurrent ) { i++; pCurrent = pCurrent->pNext; } return i; } template T &Copy( T &item ) { T *pCopy = (T *)m_Allocator.Alloc( sizeof(T) ); memcpy( pCopy, &item, sizeof(T) ); return *pCopy; } template T *CopyArray( T *p, int n ) { T *pCopy = (T *)m_Allocator.Alloc( sizeof(T) * n ); memcpy( (void *)pCopy, p, sizeof(T) * n ); return pCopy; } template const char *Copy( const char *psz ) { int len = V_strlen( psz ); char *pCopy = (char *)m_Allocator.Alloc( len + 1 ); memcpy( pCopy, psz, len + 1 ); return pCopy; } void CallQueued() { TM_ZONE_PLOT( TELEMETRY_LEVEL1, "RenderThread", TELEMETRY_ZONE_PLOT_SLOT_2 ); PERF_STATS_BLOCK( "RenderThread", PERF_STATS_SLOT_RENDERTHREAD ); if ( !m_pHead ) { return; } CFunctor *pFunctor; Elem_t *pCurrent = m_pHead; while ( pCurrent ) { pFunctor = pCurrent->GetFunctor(); #ifdef _DEBUG if ( pFunctor->m_nUserID == m_nBreakSerialNumber) { m_nBreakSerialNumber = (unsigned)-1; } #endif if ( pCurrent->pNext ) { PREFETCH360( pCurrent->pNext, 0 ); PREFETCH360( pCurrent->pNext, 128 ); } (*pFunctor)(); pFunctor->~CFunctor(); // no need to ref count, we're alone here... pCurrent = pCurrent->pNext; } #ifdef DEBUG_MATCALLQUEUE static int prevHigh = 0; if ( m_Allocator.GetUsed() > prevHigh ) { Msg( "***%d\n", m_Allocator.GetUsed() ); prevHigh = m_Allocator.GetUsed(); } #endif m_Allocator.FreeAll( false ); m_pHead = m_pTail = NULL; } void QueueFunctor( CFunctor *pFunctor ) { Assert( pFunctor ); m_Allocator.Alloc( sizeof(Elem_t) ); QueueFunctorInternal( m_FunctorFactory.CreateRefCountingFunctor( pFunctor, &CFunctor::operator() ) ); } void Flush() { if ( !m_pHead ) { return; } CFunctor *pFunctor; Elem_t *pCurrent = m_pHead; while ( pCurrent ) { pFunctor = pCurrent->GetFunctor(); pFunctor->Release(); pCurrent = pCurrent->pNext; } m_Allocator.FreeAll( false ); m_pHead = m_pTail = NULL; } #define DEFINE_MATCALLQUEUE_NONMEMBER_QUEUE_CALL(N) \ template \ void QueueCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ m_Allocator.Alloc( sizeof(Elem_t) ); \ QueueFunctorInternal( m_FunctorFactory.CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \ } //------------------------------------- #define DEFINE_MATCALLQUEUE_MEMBER_QUEUE_CALL(N) \ template \ void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ m_Allocator.Alloc( sizeof(Elem_t) ); \ QueueFunctorInternal( m_FunctorFactory.CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \ } //------------------------------------- #define DEFINE_MATCALLQUEUE_CONST_MEMBER_QUEUE_CALL(N) \ template \ void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ m_Allocator.Alloc( sizeof(Elem_t) ); \ QueueFunctorInternal( m_FunctorFactory.CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \ } //------------------------------------- FUNC_GENERATE_ALL( DEFINE_MATCALLQUEUE_NONMEMBER_QUEUE_CALL ); FUNC_GENERATE_ALL( DEFINE_MATCALLQUEUE_MEMBER_QUEUE_CALL ); FUNC_GENERATE_ALL( DEFINE_MATCALLQUEUE_CONST_MEMBER_QUEUE_CALL ); private: void QueueFunctorInternal( CFunctor *pFunctor ) { #ifdef _DEBUG pFunctor->m_nUserID = m_nCurSerialNumber++; #endif MEM_ALLOC_CREDIT_( "CMatCallQueue.m_Allocator" ); // Caller is expected to have preallocated Elem_t entry immediately prior to functor Elem_t *pNew = ((Elem_t *)pFunctor) - 1; if ( m_pTail ) { m_pTail->pNext = pNew; m_pTail = pNew; } else { m_pHead = m_pTail = pNew; } pNew->pNext = NULL; } struct Elem_t { Elem_t *pNext; CFunctor *GetFunctor() { return (CFunctor *)(this + 1 ); } }; Elem_t *m_pHead; Elem_t *m_pTail; CMemoryStack m_Allocator; CCustomizedFunctorFactory > > m_FunctorFactory; unsigned m_nCurSerialNumber; unsigned m_nBreakSerialNumber; }; #define MATCONFIG_FLAGS_SUPPORT_EDITOR ( 1 << 0 ) #define MATCONFIG_FLAGS_SUPPORT_GBUFFER ( 1 << 1 ) //----------------------------------------------------------------------------- // Additional interfaces used internally to the library //----------------------------------------------------------------------------- abstract_class IMaterialSystemInternal : public IMaterialSystem { public: // Returns the current material virtual IMaterial* GetCurrentMaterial() = 0; virtual int GetLightmapPage( void ) = 0; // Gets the maximum lightmap page size... virtual int GetLightmapWidth( int lightmap ) const = 0; virtual int GetLightmapHeight( int lightmap ) const = 0; virtual ITexture *GetLocalCubemap( void ) = 0; // virtual bool RenderZOnlyWithHeightClipEnabled( void ) = 0; virtual void ForceDepthFuncEquals( bool bEnable ) = 0; virtual enum MaterialHeightClipMode_t GetHeightClipMode( void ) = 0; // FIXME: Remove? Here for debugging shaders in CShaderSystem virtual void AddMaterialToMaterialList( IMaterialInternal *pMaterial ) = 0; virtual void RemoveMaterial( IMaterialInternal *pMaterial ) = 0; virtual void RemoveMaterialSubRect( IMaterialInternal *pMaterial ) = 0; virtual bool InFlashlightMode() const = 0; virtual bool IsCascadedShadowMapping() const = 0; // Can we use editor materials? virtual bool CanUseEditorMaterials() const = 0; virtual int GetConfigurationFlags( void ) const = 0; virtual const char *GetForcedTextureLoadPathID() = 0; virtual CMatCallQueue *GetRenderCallQueue() = 0; virtual void UnbindMaterial( IMaterial *pMaterial ) = 0; virtual uint GetRenderThreadId() const = 0 ; }; #endif // IMATERIALSYSTEMINTERNAL_H