rsContext.h revision 8c401effb0837155fc39ca0364f57a882d127d38
10d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams/* 20d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * Copyright (C) 2009 The Android Open Source Project 30d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * 40d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * Licensed under the Apache License, Version 2.0 (the "License"); 50d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * you may not use this file except in compliance with the License. 60d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * You may obtain a copy of the License at 70d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * 80d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * http://www.apache.org/licenses/LICENSE-2.0 90d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * 100d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * Unless required by applicable law or agreed to in writing, software 110d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * distributed under the License is distributed on an "AS IS" BASIS, 120d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * See the License for the specific language governing permissions and 140d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams * limitations under the License. 150d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams */ 160d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 170d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#ifndef ANDROID_RS_CONTEXT_H 180d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#define ANDROID_RS_CONTEXT_H 190d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 200d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsUtils.h" 210d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 220d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include <ui/Surface.h> 230d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 240d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsThreadIO.h" 250d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsType.h" 260d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsMatrix.h" 270d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsAllocation.h" 280d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsSimpleMesh.h" 290d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsMesh.h" 300d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsDevice.h" 310d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsScriptC.h" 320d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsAllocation.h" 330d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsAdapter.h" 340d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsSampler.h" 350d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsLight.h" 360d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsProgramFragment.h" 370d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsProgramFragmentStore.h" 38f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes#include "rsProgramRaster.h" 39f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes#include "rsProgramVertex.h" 400d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 410d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsgApiStructs.h" 420d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#include "rsLocklessFifo.h" 430d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 440d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 450d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams// --------------------------------------------------------------------------- 460d6043caef208ee6c661eb17bcb376abfe90cd48Jason Samsnamespace android { 470d6043caef208ee6c661eb17bcb376abfe90cd48Jason Samsnamespace renderscript { 480d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 4980ef693674f69c0343c41564e30f80e7fb513b60Chris Wailesclass Context 500d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams{ 519ed79105cc6a8dbfaf959875249f36022cc2c798Chris Wailespublic: 5280ef693674f69c0343c41564e30f80e7fb513b60Chris Wailes Context(Device *, Surface *, bool useDepth); 530d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ~Context(); 549ed79105cc6a8dbfaf959875249f36022cc2c798Chris Wailes 5580ef693674f69c0343c41564e30f80e7fb513b60Chris Wailes static pthread_key_t gThreadTLSKey; 560d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams struct ScriptTLSStruct { 579ed79105cc6a8dbfaf959875249f36022cc2c798Chris Wailes Context * mContext; 580d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams Script * mScript; 590d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams }; 600d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 610d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 620d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams //StructuredAllocationContext mStateAllocation; 630d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ElementState mStateElement; 640d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams TypeState mStateType; 650d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams SamplerState mStateSampler; 660d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ProgramFragmentState mStateFragment; 670d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ProgramFragmentStoreState mStateFragmentStore; 680d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ProgramRasterState mStateRaster; 690d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ProgramVertexState mStateVertex; 700d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams LightState mStateLight; 710d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 720d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ScriptCState mScriptC; 730d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 740d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void swapBuffers(); 750d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void setRootScript(Script *); 760d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void setRaster(ProgramRaster *); 770d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void setVertex(ProgramVertex *); 780d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void setFragment(ProgramFragment *); 790d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void setFragmentStore(ProgramFragmentStore *); 800d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 810d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void updateSurface(void *sur); 820d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 830d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams const ProgramFragment * getFragment() {return mFragment.get();} 840d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams const ProgramFragmentStore * getFragmentStore() {return mFragmentStore.get();} 850d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams const ProgramRaster * getRaster() {return mRaster.get();} 860d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams const ProgramVertex * getVertex() {return mVertex.get();} 870d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 880d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void setupCheck(); 890d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void allocationCheck(const Allocation *); 900d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 910d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void pause(); 920d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void resume(); 930d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 940d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void assignName(ObjectBase *obj, const char *name, uint32_t len); 950d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void removeName(ObjectBase *obj); 960d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ObjectBase * lookupName(const char *name) const; 970d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void appendNameDefines(String8 *str) const; 980d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void appendVarDefines(String8 *str) const; 990d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1000d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint32_t getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait); 1010d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool waitForSpace); 1020d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1030d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void initToClient(); 1040d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void deinitToClient(); 1050d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1060d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ProgramFragment * getDefaultProgramFragment() const { 1070d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams return mStateFragment.mDefault.get(); 1080d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams } 1090d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ProgramVertex * getDefaultProgramVertex() const { 1100d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams return mStateVertex.mDefault.get(); 1110d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams } 1120d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ProgramFragmentStore * getDefaultProgramFragmentStore() const { 1130d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams return mStateFragmentStore.mDefault.get(); 1140d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams } 115ef05d4666eb87a924c8883e193fd505245101414Miao Wang ProgramRaster * getDefaultProgramRaster() const { 1160d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams return mStateRaster.mDefault.get(); 1170d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams } 1180d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1190d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void addInt32Define(const char* name, int32_t value) { 1200d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams mInt32Defines.add(String8(name), value); 1210d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams } 1220d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1230d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void addFloatDefine(const char* name, float value) { 1240d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams mFloatDefines.add(String8(name), value); 1250d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams } 1260d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1270d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint32_t getWidth() const {return mEGL.mWidth;} 1280d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint32_t getHeight() const {return mEGL.mHeight;} 1290d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1300d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1310d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ThreadIO mIO; 1320d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void objDestroyAdd(ObjectBase *); 1330d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1340d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams // Timers 1350d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams enum Timers { 1360d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams RS_TIMER_IDLE, 1370d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams RS_TIMER_INTERNAL, 1380d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams RS_TIMER_SCRIPT, 1390d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams RS_TIMER_CLEAR_SWAP, 1400d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams _RS_TIMER_TOTAL 1410d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams }; 1420d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint64_t getTime() const; 1430d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void timerInit(); 1440d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void timerReset(); 1450d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void timerSet(Timers); 1460d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void timerPrint(); 1470d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void timerFrame(); 1480d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1490d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool checkVersion1_1() const {return (mGL.mMajorVersion > 1) || (mGL.mMinorVersion >= 1); } 150ef05d4666eb87a924c8883e193fd505245101414Miao Wang bool checkVersion2_0() const {return mGL.mMajorVersion >= 2; } 1510d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1520d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams struct { 1530d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool mLogTimes; 1540d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool mLogScripts; 1550d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool mLogObjects; 1560d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams } props; 1570d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1580d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams mutable const ObjectBase * mObjHead; 1590d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1600d6043caef208ee6c661eb17bcb376abfe90cd48Jason Samsprotected: 1610d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams Device *mDev; 1620d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1630d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams struct { 1640d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams EGLint mNumConfigs; 1650d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams EGLint mMajorVersion; 1660d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams EGLint mMinorVersion; 1670d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams EGLConfig mConfig; 1680d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams EGLContext mContext; 1690d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams EGLSurface mSurface; 1700d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams EGLint mWidth; 1710d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams EGLint mHeight; 1720d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams EGLDisplay mDisplay; 1730d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams } mEGL; 174ef05d4666eb87a924c8883e193fd505245101414Miao Wang 1750d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams struct { 1760d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams const uint8_t * mVendor; 1770d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams const uint8_t * mRenderer; 17880ef693674f69c0343c41564e30f80e7fb513b60Chris Wailes const uint8_t * mVersion; 1790d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams const uint8_t * mExtensions; 1809ed79105cc6a8dbfaf959875249f36022cc2c798Chris Wailes 1810d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint32_t mMajorVersion; 1820d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint32_t mMinorVersion; 1830d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1840d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams } mGL; 1850d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1860d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool mRunning; 1870d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool mExit; 1880d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool mUseDepth; 1890d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool mPaused; 1900d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1910d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams pthread_t mThreadId; 1920d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1930d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ObjectBaseRef<Script> mRootScript; 1940d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ObjectBaseRef<ProgramFragment> mFragment; 1950d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ObjectBaseRef<ProgramVertex> mVertex; 1960d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ObjectBaseRef<ProgramFragmentStore> mFragmentStore; 1970d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ObjectBaseRef<ProgramRaster> mRaster; 1980d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 1990d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 2000d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams struct ObjDestroyOOB { 2010d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams pthread_mutex_t mMutex; 2020d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams Vector<ObjectBase *> mDestroyList; 2030d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool mNeedToEmpty; 2040d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams }; 2050d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams ObjDestroyOOB mObjDestroy; 2060d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool objDestroyOOBInit(); 2070d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void objDestroyOOBRun(); 2080d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void objDestroyOOBDestroy(); 2090d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 2100d6043caef208ee6c661eb17bcb376abfe90cd48Jason Samsprivate: 2110d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams Context(); 2120d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 2130d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams void initEGL(); 2140d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 2150d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool runScript(Script *s, uint32_t launchID); 2160d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams bool runRootScript(); 2170d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 21880ef693674f69c0343c41564e30f80e7fb513b60Chris Wailes static void * threadProc(void *); 2190d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 2209ed79105cc6a8dbfaf959875249f36022cc2c798Chris Wailes Surface *mWndSurface; 2210d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 2220d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams Vector<ObjectBase *> mNames; 2230d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams KeyedVector<String8,int> mInt32Defines; 2240d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams KeyedVector<String8,float> mFloatDefines; 2250d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 2260d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint64_t mTimers[_RS_TIMER_TOTAL]; 2270d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams Timers mTimerActive; 2280d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint64_t mTimeLast; 2290d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint64_t mTimeFrame; 2300d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams uint64_t mTimeLastFrame; 2310d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams}; 2320d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams 2330d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams} 2340d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams} 2350d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams#endif 2360d6043caef208ee6c661eb17bcb376abfe90cd48Jason Sams