GLB_FORCEINLINE void Timer::getCorrectPerformanceValue (int64& nPerfCountElapsed) const { uint32 uiTicksElapsed; uint32 uiPerfCountElapsedMilli; int32 nLeapTest; // get performance counter value this->getPerformanceCount(nPerfCountElapsed, uiTicksElapsed); // prepare a workaround to compensate a potential performance counter leap nPerfCountElapsed -= m_nStart; uiPerfCountElapsedMilli = uint32(nPerfCountElapsed * 1000 / m_nFrequency); GLB_ASSERT((nPerfCountElapsed * 1000 / m_nFrequency) <= (LONGLONG)std::numeric_limits<uint32>::max()); GLB_ASSERT(uiPerfCountElapsedMilli <= (uint32)std::numeric_limits<int32>::max()); GLB_ASSERT(uiTicksElapsed <= (uint32)std::numeric_limits<int32>::max()); // if too great leap is detected, adjust start time and update state // accordingly before return nLeapTest = (int32)uiPerfCountElapsedMilli - (int32)uiTicksElapsed; if ((nLeapTest < -c_nMaxLeapThreshold) || (nLeapTest > c_nMaxLeapThreshold)) { LONGLONG nUpdate = std::min<LONGLONG>(LONGLONG(nLeapTest * m_nFrequency / 1000), (nPerfCountElapsed - m_nLastPerfCountElapsed)); #ifdef GLB_DEBUG //GLB_LOGWARN("Performance Counter leap detected (%d ms) !", nLeapTest); #endif m_nStart += nUpdate; nPerfCountElapsed -= nUpdate; } // update state m_nLastPerfCountElapsed = nPerfCountElapsed; }
//--------------------------------------------------------------------------- bool FileIterator::openDir (const char* pszDirectory, FileIterator::FileInfo& infoFirst) { this->close(); GLB_ASSERT(pszDirectory); if (!pszDirectory) return false; GLB_ASSERT(pszDirectory[0]); if (!pszDirectory[0]) return false; m_strDir = pszDirectory; while (m_strDir.pathHasTrailingSeparator()) m_strDir.erase(-1); if (!FileSystem::isDirectory(m_strDir)) { m_strDir.clear(); return false; } if ((infoFirst.fQueryFlags & QUERY_DIRS_AND_FILES) == 0) infoFirst.fQueryFlags |= QUERY_DIRS_AND_FILES; if (!this->getNext(infoFirst)) { m_bEmpty = true; return false; } return true; }
//--------------------------------------------------------------------------- void Timer::reset (void) { #if defined(GLB_PLATFORM_WINDOWS) { if (g_nPerfCounter > 0) { DWORD dwProcessAffinityMask; DWORD dwSystemAffinityMask; DWORD_PTR dwOldThreadAffinityMask; HANDLE hThread; // get current process affinity with processor cores ::GetProcessAffinityMask(::GetCurrentProcess(), (PDWORD_PTR)&dwProcessAffinityMask, (PDWORD_PTR)&dwSystemAffinityMask); // lazy init for the timer affinity mask // this is a common trick to find the first core used by the current process if (!m_dwTimerAffinityMask) { m_dwTimerAffinityMask = 1; while (!(m_dwTimerAffinityMask & dwProcessAffinityMask)) m_dwTimerAffinityMask <<= 1; } // setup our affinity to the desired processor core hThread = ::GetCurrentThread(); dwOldThreadAffinityMask = ::SetThreadAffinityMask(hThread, m_dwTimerAffinityMask); // init timer by getting frequency and start time (void)::QueryPerformanceFrequency((LARGE_INTEGER*)&m_nFrequency); (void)::QueryPerformanceCounter((LARGE_INTEGER*)&m_nStart); m_dwStartTicks = g_pfnTimeGetTime(); // reset affinity to be compliant with the calling environment (void)::SetThreadAffinityMask(hThread, dwOldThreadAffinityMask); // if frequency is not bound in a 32bit word, we'll get erroneous values // from Timer::Get*32() methods GLB_ASSERT(m_nFrequency <= (int64)std::numeric_limits<uint32>::max()); // reset other members m_nLastPerfCountElapsed = 0; } else { GLB_ASSERT(g_pfnTimeGetTime); m_dwStartTicks = g_pfnTimeGetTime(); } } #elif defined(GLB_PLATFORM_LINUX) { gettimeofday(&m_tvStart, NULL); } #endif }
//--------------------------------------------------------------------------- uint32 Timer::getMilliseconds32 (void) const { #if defined(GLB_PLATFORM_WINDOWS) { if (g_nPerfCounter > 0) { uint32 uiPerfCountElapsedMilli; this->getCorrectPerformanceValueMilli(uiPerfCountElapsedMilli); return uiPerfCountElapsedMilli; } else { DWORD dwTime; dwTime = g_pfnTimeGetTime(); GLB_ASSERT(dwTime > m_dwStartTicks); return (dwTime - m_dwStartTicks); } } #elif defined(GLB_PLATFORM_LINUX) { struct timeval tvNow; uint32 uiElapsed; gettimeofday(&tvNow, NULL); uiElapsed = uint32(tvNow.tv_sec - m_tvStart.tv_sec) * 1000; uiElapsed += uint32(tvNow.tv_usec - m_tvStart.tv_usec) / 1000; return uiElapsed; } #endif }
//--------------------------------------------------------------------------- D3DSURFACE_DESC Texture::getLevelDesc (uint uiLevel/*=0*/) { D3DSURFACE_DESC d3dSurfDesc; GLB_ASSERT(this->getRef()); GLB_DXTEST(this->getRef()->GetLevelDesc(uiLevel, &d3dSurfDesc)); return d3dSurfDesc; }
//--------------------------------------------------------------------------- D3DSURFACE_DESC Surface::getDesc (void) { D3DSURFACE_DESC d3dSurfDesc; GLB_ASSERT(this->getRef()); GLB_DXTEST(this->getRef()->GetDesc(&d3dSurfDesc)); return d3dSurfDesc; }
GLB_FORCEINLINE void Timer::getPerformanceCount (int64& nOutPerfCount, uint32& uiOutTicksElapsed) const { HANDLE hThread = ::GetCurrentThread(); DWORD_PTR dwOldThreadAffinityMask; GLB_ASSERT(g_nPerfCounter > 0); GLB_ASSERT(g_pfnTimeGetTime); dwOldThreadAffinityMask = ::SetThreadAffinityMask(hThread, m_dwTimerAffinityMask); (void)::QueryPerformanceCounter((LARGE_INTEGER*)&nOutPerfCount); uiOutTicksElapsed = g_pfnTimeGetTime(); (void)::SetThreadAffinityMask(hThread, dwOldThreadAffinityMask); GLB_ASSERT(uiOutTicksElapsed > m_dwStartTicks); uiOutTicksElapsed -= m_dwStartTicks; }
//--------------------------------------------------------------------------- Surface Texture::getLevel (uint uiLevel/*=0*/) { IDirect3DSurface9* pSurf; GLB_ASSERT(this->getRef()); GLB_DXTEST(this->getRef()->GetSurfaceLevel(uiLevel, &pSurf)); pSurf->Release(); // GetSurfaceLevel() incremented the ref counter return Surface(pSurf); }
//--------------------------------------------------------------------------- bool FileIterator::seekToFirst (FileIterator::FileInfo& info) { StringA strDir; GLB_ASSERT(this->isOpen()); if(!this->isOpen()) return false; // the problem : // * in the linux implementation, we could simply use the rewinddir() // function to simply seek read pointer to start, but this kind of // behavior is not allowed by the win32 api. // * so the only way to get same behavior between multiple platforms is to // close the handle before opening a new one. strDir = m_strDir; return this->openDir(strDir, info); }
//--------------------------------------------------------------------------- uint64 Timer::getMicroseconds (void) const { #if defined(GLB_PLATFORM_WINDOWS) { if (g_nPerfCounter > 0) { int64 nPerfCountElapsed; this->getCorrectPerformanceValue(nPerfCountElapsed); // scale by 1000000 in order to get microsecond precision nPerfCountElapsed *= 1000000; nPerfCountElapsed /= m_nFrequency; return nPerfCountElapsed; } else { DWORD dwTime; dwTime = g_pfnTimeGetTime(); GLB_ASSERT(dwTime > m_dwStartTicks); return uint64(dwTime - m_dwStartTicks) * 1000; } } #elif defined(GLB_PLATFORM_LINUX) { struct timeval tvNow; int64 nElapsed; gettimeofday(&tvNow, NULL); nElapsed = int64(tvNow.tv_sec - m_tvStart.tv_sec) * 1000000; nElapsed += int64(tvNow.tv_usec - m_tvStart.tv_usec); if (nElapsed < 0) nElapsed = 0; return (uint64)nElapsed; } #endif }
//--------------------------------------------------------------------------- float64 Timer::getSecondsFloat64 (void) const { #if defined(GLB_PLATFORM_WINDOWS) { if (g_nPerfCounter > 0) { int64 nPerfCountElapsed; this->getCorrectPerformanceValue(nPerfCountElapsed); return (float64)nPerfCountElapsed / (float64)m_nFrequency; } else { DWORD dwTime; float64 rTime; dwTime = g_pfnTimeGetTime(); GLB_ASSERT(dwTime > m_dwStartTicks); rTime = float64(dwTime - m_dwStartTicks); rTime *= float64(0.001); return rTime; } } #elif defined(GLB_PLATFORM_LINUX) { struct timeval tvNow; float64 rElapsed; gettimeofday(&tvNow, NULL); rElapsed = float64(tvNow.tv_sec - m_tvStart.tv_sec); rElapsed += float64(0.000001) * float64(tvNow.tv_usec - m_tvStart.tv_usec); if (rElapsed < float64(0.0)) rElapsed = float64(0.0); return rElapsed; } #endif }
//--------------------------------------------------------------------------- bool FileIterator::getNext (FileIterator::FileInfo& info) { GLB_ASSERT(this->isOpen()); if (!this->isOpen() || m_bEmpty) return false; info.fQueryFlags |= QUERY_TYPE; while (1) { if (!this->getNextImpl(info)) return false; if (info.eType == TYPE_DIRECTORY && (info.fQueryFlags & QUERY_DIRS)) return true; else if (info.eType != TYPE_DIRECTORY && (info.fQueryFlags & QUERY_FILES)) return true; } return true; }
GLBSampler* glbCreateSampler (int *errcode_ret) { int errcode; GLBSampler *sampler = malloc(sizeof(GLBSampler)); GLB_ASSERT(sampler, GLB_OUT_OF_MEMORY, ERROR); sampler->refcount = 1; sampler->magfilter = GLB_LINEAR; sampler->minfilter = GLB_LINEAR; sampler->minlod = -1000.0f; sampler->maxlod = 1000.0f; sampler->wrap_s = GLB_REPEAT; sampler->wrap_t = GLB_REPEAT; sampler->wrap_r = GLB_REPEAT; sampler->compare_mode = GLB_NONE; sampler->compare_func = GLB_LEQUAL; GLB_SET_ERROR(GLB_SUCCESS); return sampler; ERROR: GLB_SET_ERROR(errcode); return NULL; }
//--------------------------------------------------------------------------- bool FileIterator::getNextImpl (FileIterator::FileInfo& info) { bool bIsFirst = false; #ifdef GLB_PLATFORM_WINDOWS { WIN32_FIND_DATAA wfd; if (m_pHandle == INVALID_HANDLE_VALUE) { bIsFirst = true; m_strDir.pathAppend("*"); m_pHandle = ::FindFirstFileA(m_strDir.c_str(), &wfd); if (m_strDir.right(1) == "*") { m_strDir.erase(-1); while (m_strDir.pathHasTrailingSeparator()) m_strDir.erase(-1); } } else if (!::FindNextFileA(m_pHandle, &wfd)) { _FileIterator_ResetInfo(info); return false; } if (m_pHandle == INVALID_HANDLE_VALUE) { GLB_LOGERR("Error while trying to iterate in \"%s\" ! Error %lu : %s", m_strDir.c_str(), System::lastError(), System::lastErrorString()); _FileIterator_ResetInfo(info); return false; } else { // skip "." and ".." entries while (!strcmp((char*)&wfd.cFileName, ".") || !strcmp((char*)&wfd.cFileName, "..") || ((wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) && !(info.fQueryFlags & FileIterator::QUERY_HIDDEN))) { if (!::FindNextFileA(m_pHandle, &wfd)) { if (bIsFirst) m_bEmpty = true; // no valid entry found at all _FileIterator_ResetInfo(info); return false; } } // FindFirstFile() and FindNextFile() automatically convert non-utc // times into utc times _FileIterator_MapOsDataToFileInfo(info, m_strDir, wfd, true); } } #else { struct dirent* pDirEntry; if (!m_pHandle) { bIsFirst = true; m_pHandle = opendir(m_strDir.c_str()); if (!m_pHandle) { GLB_LOGERROR("Error while trying to iterate in \"%s\" ! Error %lu : %s", m_strDir.c_str(), System::lastError(), System::lastErrorString()); _FileIterator_ResetInfo(info); return false; } } GLB_ASSERT(m_pHandle); while ((pDirEntry = readdir((DIR*)m_pHandle)) != NULL) { if (strcmp((char*)&pDirEntry->d_name, ".") && strcmp((char*)&pDirEntry->d_name, "..")) { if (pDirEntry->d_name[0] != '.' || (info.fQueryFlags & FileIterator::QUERY_HIDDEN)) break; } } if (!pDirEntry) { if (bIsFirst) m_bEmpty = true; // no valid entry found at all _FileIterator_ResetInfo(info); return false; } _FileIterator_MapOsDataToFileInfo(info, m_strDir, (char*)&pDirEntry->d_name); } #endif return true; }
static void _FileIterator_MapOsDataToFileInfo (FileIterator::FileInfo& info, const StringA& strDir, const char* pszFileName) { #if defined(GLB_PLATFORM_CYGWIN) #define STATSTRUCT struct stat #define STATFUNC ::stat #else #define STATSTRUCT struct stat64 #define STATFUNC ::stat64 #endif STATSTRUCT stats; // name info.strName = pszFileName; // reset other members first info.eType = FileIterator::TYPE_UNKNOWN; info.uiSize = 0; info.nModifTime = 0; // get file stats if needed if (info.fQueryFlags != 0) { StringA strFilePath; _FileIterator_BuildFilePathIfNeeded(strFilePath, strDir, info.strName); if (STATFUNC(strFilePath, &stats) != 0) { GLB_ASSERT(0); // error while calling stat() from FileIterator ! return; } } // type if ((info.fQueryFlags & FileIterator::QUERY_TYPE) != 0) { if (S_ISDIR(stats.st_mode)) info.eType = FileIterator::TYPE_DIRECTORY; else if (S_ISREG(stats.st_mode)) info.eType = FileIterator::TYPE_FILE; else if (S_ISLNK(stats.st_mode)) info.eType = FileIterator::TYPE_SYMLINK; } // size if ((info.fQueryFlags & FileIterator::QUERY_SIZE) != 0) { GLB_ASSERT(sizeof(info.uiSize) == sizeof(stats.st_size)); info.uiSize = stats.st_size; } // modification time if ((info.fQueryFlags & FileIterator::QUERY_MODIFTIME) != 0) { GLB_ASSERT(sizeof(info.nModifTime) == sizeof(stats.st_mtime)); info.nModifTime = stats.st_mtime; } #undef STATSTRUCT #undef STATFUNC }