CCodec* CreateCodec(CodecType nCodecType) { #ifdef USE_DBGTRACE DbgTrace(("nCodecType %d",nCodecType)); #endif switch(nCodecType) { case CT_DXT1: return new CCodec_DXT1; case CT_DXT3: return new CCodec_DXT3; case CT_DXT5: return new CCodec_DXT5; case CT_DXT5_xGBR: return new CCodec_DXT5_xGBR; case CT_DXT5_RxBG: return new CCodec_DXT5_RxBG; case CT_DXT5_RBxG: return new CCodec_DXT5_RBxG; case CT_DXT5_xRBG: return new CCodec_DXT5_xRBG; case CT_DXT5_RGxB: return new CCodec_DXT5_RGxB; case CT_DXT5_xGxR: return new CCodec_DXT5_xGxR; case CT_ATI1N: return new CCodec_ATI1N; case CT_ATI2N: return new CCodec_ATI2N; case CT_ATI2N_XY: return new CCodec_ATI2N(CT_ATI2N_XY); case CT_ATI2N_DXT5: return new CCodec_ATI2N_DXT5; case CT_ATC_RGB: return new CCodec_ATC_RGB; case CT_ATC_RGBA_Explicit: return new CCodec_ATC_RGBA_Explicit; case CT_ATC_RGBA_Interpolated: return new CCodec_ATC_RGBA_Interpolated; case CT_ETC_RGB: return new CCodec_ETC_RGB; case CT_BC6H: return new CCodec_BC6H; case CT_BC7: return new CCodec_BC7; case CT_ASTC: return new CCodec_ASTC; case CT_GT: return new CCodec_GT; case CT_Unknown: default: assert(0); return NULL; } }
// getStackTrace - Traces the stack as far back as possible, or until 'maxdepth' // frames have been traced. Populates the CallStack with one entry for each // stack frame traced. // // Note: This function uses a documented Windows API to walk the stack. This // API is supposed to be the most reliable way to walk the stack. It claims // to be able to walk stack frames that do not follow the conventional stack // frame layout. However, this robustness comes at a cost: it is *extremely* // slow compared to walking frames by following frame (base) pointers. // // - maxdepth (IN): Maximum number of frames to trace back. // // - framepointer (IN): Frame (base) pointer at which to begin the stack trace. // If NULL, then the stack trace will begin at this function. // // Return Value: // // None. // VOID SafeCallStack::getStackTrace (UINT32 maxdepth, const context_t& context) { UINT_PTR* framePointer = context.fp; DWORD architecture = X86X64ARCHITECTURE; CONTEXT currentContext; memset(¤tContext, 0, sizeof(currentContext)); // Get the required values for initialization of the STACKFRAME64 structure // to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame. #if defined(_M_IX86) UINT_PTR programcounter = *(framePointer + 1); UINT_PTR stackpointer = (*framePointer) - maxdepth * 10 * sizeof(void*); // An approximation. currentContext.SPREG = stackpointer; currentContext.BPREG = (DWORD64)framePointer; currentContext.IPREG = programcounter; #elif defined(_M_X64) currentContext.SPREG = context.Rsp; currentContext.BPREG = (DWORD64)framePointer; currentContext.IPREG = context.Rip; #else // If you want to retarget Visual Leak Detector to another processor // architecture then you'll need to provide architecture-specific code to // obtain the program counter and stack pointer from the given frame pointer. #error "Visual Leak Detector is not supported on this architecture." #endif // _M_IX86 || _M_X64 // Initialize the STACKFRAME64 structure. STACKFRAME64 frame; memset(&frame, 0x0, sizeof(frame)); frame.AddrPC.Offset = currentContext.IPREG; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Offset = currentContext.SPREG; frame.AddrStack.Mode = AddrModeFlat; frame.AddrFrame.Offset = currentContext.BPREG; frame.AddrFrame.Mode = AddrModeFlat; frame.Virtual = TRUE; // Walk the stack. CriticalSectionLocker cs(g_stackWalkLock); UINT32 count = 0; while (count < maxdepth) { count++; DbgTrace(L"dbghelp32.dll %i: StackWalk64\n", GetCurrentThreadId()); if (!StackWalk64(architecture, g_currentProcess, g_currentThread, &frame, ¤tContext, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { // Couldn't trace back through any more frames. break; } if (frame.AddrFrame.Offset == 0) { // End of stack. break; } // Push this frame's program counter onto the CallStack. push_back((UINT_PTR)frame.AddrPC.Offset); } }
// getStackTrace - Traces the stack as far back as possible, or until 'maxdepth' // frames have been traced. Populates the CallStack with one entry for each // stack frame traced. // // Note: This function uses a documented Windows API to walk the stack. This // API is supposed to be the most reliable way to walk the stack. It claims // to be able to walk stack frames that do not follow the conventional stack // frame layout. However, this robustness comes at a cost: it is *extremely* // slow compared to walking frames by following frame (base) pointers. // // - maxdepth (IN): Maximum number of frames to trace back. // // - framepointer (IN): Frame (base) pointer at which to begin the stack trace. // If NULL, then the stack trace will begin at this function. // // Return Value: // // None. // VOID SafeCallStack::getStackTrace (UINT32 maxdepth, const context_t& context) { UINT32 count = 0; UINT_PTR function = context.func; if (function != NULL) { count++; push_back(function); } DWORD architecture = X86X64ARCHITECTURE; // Get the required values for initialization of the STACKFRAME64 structure // to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame. CONTEXT currentContext; memset(¤tContext, 0, sizeof(currentContext)); currentContext.SPREG = context.SPREG; currentContext.BPREG = context.BPREG; currentContext.IPREG = context.IPREG; // Initialize the STACKFRAME64 structure. STACKFRAME64 frame; memset(&frame, 0x0, sizeof(frame)); frame.AddrPC.Offset = currentContext.IPREG; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Offset = currentContext.SPREG; frame.AddrStack.Mode = AddrModeFlat; frame.AddrFrame.Offset = currentContext.BPREG; frame.AddrFrame.Mode = AddrModeFlat; frame.Virtual = TRUE; CriticalSectionLocker<> cs(g_heapMapLock); CriticalSectionLocker<DHStackWalk> locker(g_StackWalk); // Walk the stack. while (count < maxdepth) { count++; DbgTrace(L"dbghelp32.dll %i: StackWalk64\n", GetCurrentThreadId()); if (!g_StackWalk.StackWalk64(architecture, g_currentProcess, g_currentThread, &frame, ¤tContext, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL, locker)) { // Couldn't trace back through any more frames. break; } if (frame.AddrFrame.Offset == 0) { // End of stack. break; } // Push this frame's program counter onto the CallStack. push_back((UINT_PTR)frame.AddrPC.Offset); } }
// isCrtStartupAlloc - Determines whether the memory leak was generated from crt startup code. // This is not an actual memory leaks as it is freed by crt after the VLD object has been destroyed. // // Return Value: // // true if isCrtStartupModule for any callstack frame returns true. // bool CallStack::isCrtStartupAlloc() { if (m_status & CALLSTACK_STATUS_STARTUPCRT) { return true; } else if (m_status & CALLSTACK_STATUS_NOTSTARTUPCRT) { return false; } IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE] = { 0 }; CriticalSectionLocker<DbgHelp> locker(g_DbgHelp); // Iterate through each frame in the call stack. for (UINT32 frame = 0; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; BOOL foundline = FALSE; DWORD displacement = 0; DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); foundline = g_DbgHelp.SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo); if (foundline) { DWORD64 displacement64; LPCWSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer, locker); if (beginWith(functionName, wcslen(functionName), L"`dynamic initializer for '")) { break; } if (isCrtStartupModule(sourceInfo.FileName)) { m_status |= CALLSTACK_STATUS_STARTUPCRT; return true; } } } m_status |= CALLSTACK_STATUS_NOTSTARTUPCRT; return false; }
LPCWSTR CallStack::getFunctionName(SIZE_T programCounter, DWORD64& displacement64, SYMBOL_INFO* functionInfo, CriticalSectionLocker<DbgHelp>& locker) const { // Initialize structures passed to the symbol handler. functionInfo->SizeOfStruct = sizeof(SYMBOL_INFO); functionInfo->MaxNameLen = MAX_SYMBOL_NAME_LENGTH; // Try to get the name of the function containing this program // counter address. displacement64 = 0; LPCWSTR functionName; DbgTrace(L"dbghelp32.dll %i: SymFromAddrW\n", GetCurrentThreadId()); if (g_DbgHelp.SymFromAddrW(g_currentProcess, programCounter, &displacement64, functionInfo, locker)) { functionName = functionInfo->Name; } else { // GetFormattedMessage( GetLastError() ); fmt::WArrayWriter wf(functionInfo->Name, MAX_SYMBOL_NAME_LENGTH); wf.write(L"" ADDRESSCPPFORMAT, programCounter); functionName = wf.c_str(); displacement64 = 0; } return functionName; }
CodecError CCodec_DXT5::Compress(CCodecBuffer& bufferIn, CCodecBuffer& bufferOut, Codec_Feedback_Proc pFeedbackProc, CMP_DWORD_PTR pUser1, CMP_DWORD_PTR pUser2) { #ifndef _WIN64 //todo: add sse2 feature for win64 if(m_nCompressionSpeed == CMP_Speed_SuperFast && m_bUseSSE2) return Compress_SuperFast(bufferIn, bufferOut, pFeedbackProc, pUser1, pUser2); else if((m_nCompressionSpeed == CMP_Speed_Fast || m_nCompressionSpeed == CMP_Speed_SuperFast) && m_bUseSSE) return Compress_Fast(bufferIn, bufferOut, pFeedbackProc, pUser1, pUser2); #endif assert(bufferIn.GetWidth() == bufferOut.GetWidth()); assert(bufferIn.GetHeight() == bufferOut.GetHeight()); if(bufferIn.GetWidth() != bufferOut.GetWidth() || bufferIn.GetHeight() != bufferOut.GetHeight()) return CE_Unknown; #ifdef DXT5_COMPDEBUGGER CompViewerClient g_CompClient; if (g_CompClient.connect()) { DbgTrace(("-------> Remote Server Connected")); } #endif const CMP_DWORD dwBlocksX = ((bufferIn.GetWidth() + 3) >> 2); const CMP_DWORD dwBlocksY = ((bufferIn.GetHeight() + 3) >> 2); #ifdef DXT5_COMPDEBUGGER DbgTrace(("IN : BufferType %d ChannelCount %d ChannelDepth %d",bufferIn.GetBufferType(),bufferIn.GetChannelCount(),bufferIn.GetChannelDepth())); DbgTrace((" : Height %d Width %d Pitch %d isFloat %d",bufferIn.GetHeight(),bufferIn.GetWidth(),bufferIn.GetWidth(),bufferIn.IsFloat())); DbgTrace(("OUT: BufferType %d ChannelCount %d ChannelDepth %d",bufferOut.GetBufferType(),bufferOut.GetChannelCount(),bufferOut.GetChannelDepth())); DbgTrace((" : Height %d Width %d Pitch %d isFloat %d",bufferOut.GetHeight(),bufferOut.GetWidth(),bufferOut.GetWidth(),bufferOut.IsFloat())); #endif; bool bUseFixed = (!bufferIn.IsFloat() && bufferIn.GetChannelDepth() == 8 && !m_bUseFloat); for(CMP_DWORD j = 0; j < dwBlocksY; j++) { for(CMP_DWORD i = 0; i < dwBlocksX; i++) { CMP_DWORD compressedBlock[4]; memset(compressedBlock,0,sizeof(compressedBlock)); if(bUseFixed) { CMP_BYTE srcBlock[BLOCK_SIZE_4X4X4]; memset(srcBlock,0,sizeof(srcBlock)); bufferIn.ReadBlockRGBA(i*4, j*4, 4, 4, srcBlock); #ifdef DXT5_COMPDEBUGGER g_CompClient.SendData(1,sizeof(srcBlock),srcBlock); #endif CompressRGBABlock(srcBlock, compressedBlock, CalculateColourWeightings(srcBlock)); } else { float srcBlock[BLOCK_SIZE_4X4X4]; bufferIn.ReadBlockRGBA(i*4, j*4, 4, 4, srcBlock); CompressRGBABlock(srcBlock, compressedBlock, CalculateColourWeightings(srcBlock)); } bufferOut.WriteBlock(i*4, j*4, compressedBlock, 4); #ifdef DXT5_COMPDEBUGGER //g_CompClient.SendData(2,sizeof(compressedBlock),(byte *)&compressedBlock[0]); #endif #ifdef DXT5_COMPDEBUGGER // Checks decompression it should match or be close to source CMP_BYTE destBlock[BLOCK_SIZE_4X4X4]; DecompressRGBABlock(destBlock, compressedBlock); g_CompClient.SendData(3,sizeof(destBlock),destBlock); #endif } if(pFeedbackProc) { float fProgress = 100.f * (j * dwBlocksX) / (dwBlocksX * dwBlocksY); if(pFeedbackProc(fProgress, pUser1, pUser2)) { #ifdef DXT5_COMPDEBUGGER g_CompClient.disconnect(); #endif return CE_Aborted; } } } #ifdef DXT5_COMPDEBUGGER g_CompClient.disconnect(); #endif return CE_OK; }
// Resolve - Creates a nicely formatted rendition of the CallStack, including // symbolic information (function names and line numbers) if available. and // saves it for later retrieval. This is almost identical to Callstack::dump above. // // Note: The symbol handler must be initialized prior to calling this // function. // // - showInternalFrames (IN): If true, then all frames in the CallStack will be // dumped. Otherwise, frames internal to the heap will not be dumped. // // Return Value: // // None. // void CallStack::resolve(BOOL showInternalFrames) { if (m_resolved) { // already resolved, no need to do it again // resolving twice may report an incorrect module for the stack frames // if the memory was leaked in a dynamic library that was already unloaded. return; } if (m_status & CALLSTACK_STATUS_INCOMPLETE) { // This call stack appears to be incomplete. Using StackWalk64 may be // more reliable. Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n" L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n" L" complete stack trace.\n"); } IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); BYTE symbolBuffer [sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE] = { 0 }; WCHAR callingModuleName [MAX_PATH] = L""; WCHAR lowerCaseName [MAX_PATH]; const size_t max_line_length = MAXREPORTLENGTH + 1; m_resolvedCapacity = m_size * max_line_length; m_resolved = new WCHAR[m_resolvedCapacity]; const size_t allocedBytes = m_resolvedCapacity * sizeof(WCHAR); ZeroMemory(m_resolved, allocedBytes); // Iterate through each frame in the call stack. for (UINT32 frame = 0; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; g_symbolLock.Enter(); BOOL foundline = FALSE; DWORD displacement = 0; // It turns out that calls to SymGetLineFromAddrW64 may free the very memory we are scrutinizing here // in this method. If this is the case, m_Resolved will be null after SymGetLineFromAddrW64 returns. // When that happens there is nothing we can do except crash. DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); foundline = SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo); assert(m_resolved != NULL); if (foundline && !showInternalFrames) { wcscpy_s(lowerCaseName, sourceInfo.FileName); _wcslwr_s(lowerCaseName, wcslen(lowerCaseName) + 1); if (isInternalModule(lowerCaseName)) { // Don't show frames in files internal to the heap. g_symbolLock.Leave(); continue; } } // Initialize structures passed to the symbol handler. SYMBOL_INFO* functionInfo = (SYMBOL_INFO*)&symbolBuffer; functionInfo->SizeOfStruct = sizeof(SYMBOL_INFO); functionInfo->MaxNameLen = MAX_SYMBOL_NAME_LENGTH; // Try to get the name of the function containing this program // counter address. DWORD64 displacement64 = 0; LPWSTR functionName; DbgTrace(L"dbghelp32.dll %i: SymFromAddrW\n", GetCurrentThreadId()); if (SymFromAddrW(g_currentProcess, programCounter, &displacement64, functionInfo)) { functionName = functionInfo->Name; } else { // GetFormattedMessage( GetLastError() ); functionName = L"(Function name unavailable)"; displacement64 = 0; } g_symbolLock.Leave(); HMODULE hCallingModule = GetCallingModule(programCounter); LPWSTR moduleName = L"(Module name unavailable)"; if (hCallingModule && GetModuleFileName(hCallingModule, callingModuleName, _countof(callingModuleName)) > 0) { moduleName = wcsrchr(callingModuleName, L'\\'); if (moduleName == NULL) moduleName = wcsrchr(callingModuleName, L'/'); if (moduleName != NULL) moduleName++; else moduleName = callingModuleName; } // Use static here to increase performance, and avoid heap allocs. Hopefully this won't // prove to be an issue in thread safety. If it does, it will have to be simply non-static. static WCHAR stack_line[max_line_length] = L""; int NumChars = -1; // Display the current stack frame's information. if (foundline) { // Just truncate anything that is too long. if (displacement == 0) NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L" %s (%d): %s!%s\n", sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName); else NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L" %s (%d): %s!%s + 0x%X bytes\n", sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName, displacement); } else { if (displacement64 == 0) NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s\n", programCounter, moduleName, functionName); else NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s + 0x%X bytes\n", programCounter, moduleName, functionName, (DWORD)displacement64); } if (NumChars >= 0) { assert(m_resolved != NULL); m_resolvedLength += NumChars; wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars); } } // end for loop }
// dump - Dumps a nicely formatted rendition of the CallStack, including // symbolic information (function names and line numbers) if available. // // Note: The symbol handler must be initialized prior to calling this // function. // // - showinternalframes (IN): If true, then all frames in the CallStack will be // dumped. Otherwise, frames internal to the heap will not be dumped. // // Return Value: // // None. // void CallStack::dump(BOOL showInternalFrames, UINT start_frame) const { // The stack was dumped already if (m_resolved) { dumpResolved(); return; } if (m_status & CALLSTACK_STATUS_INCOMPLETE) { // This call stack appears to be incomplete. Using StackWalk64 may be // more reliable. Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n" L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n" L" complete stack trace.\n"); } IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); BYTE symbolBuffer [sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE] = { 0 }; WCHAR lowerCaseName [MAX_PATH]; WCHAR callingModuleName [MAX_PATH]; const size_t max_size = MAXREPORTLENGTH + 1; // Iterate through each frame in the call stack. for (UINT32 frame = start_frame; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; g_symbolLock.Enter(); BOOL foundline = FALSE; DWORD displacement = 0; DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); foundline = SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo); if (foundline && !showInternalFrames) { wcscpy_s(lowerCaseName, sourceInfo.FileName); _wcslwr_s(lowerCaseName, wcslen(lowerCaseName) + 1); if (isInternalModule(lowerCaseName)) { // Don't show frames in files internal to the heap. g_symbolLock.Leave(); continue; } } // Initialize structures passed to the symbol handler. SYMBOL_INFO* functionInfo = (SYMBOL_INFO*)&symbolBuffer; functionInfo->SizeOfStruct = sizeof(SYMBOL_INFO); functionInfo->MaxNameLen = MAX_SYMBOL_NAME_LENGTH; // Try to get the name of the function containing this program // counter address. DWORD64 displacement64 = 0; LPWSTR functionName; DbgTrace(L"dbghelp32.dll %i: SymFromAddrW\n", GetCurrentThreadId()); if (SymFromAddrW(g_currentProcess, programCounter, &displacement64, functionInfo)) { functionName = functionInfo->Name; } else { // GetFormattedMessage( GetLastError() ); functionName = L"(Function name unavailable)"; displacement64 = 0; } g_symbolLock.Leave(); HMODULE hCallingModule = GetCallingModule(programCounter); LPWSTR moduleName = L"(Module name unavailable)"; if (hCallingModule && GetModuleFileName(hCallingModule, callingModuleName, _countof(callingModuleName)) > 0) { moduleName = wcsrchr(callingModuleName, L'\\'); if (moduleName == NULL) moduleName = wcsrchr(callingModuleName, L'/'); if (moduleName != NULL) moduleName++; else moduleName = callingModuleName; } // Use static here to increase performance, and avoid heap allocs. Hopefully this won't // prove to be an issue in thread safety. If it does, it will have to be simply non-static. static WCHAR stack_line[MAXREPORTLENGTH + 1] = L""; int NumChars = -1; // Display the current stack frame's information. if (foundline) { if (displacement == 0) NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" %s (%d): %s!%s\n", sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName); else NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" %s (%d): %s!%s + 0x%X bytes\n", sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName, displacement); } else { if (displacement64 == 0) NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s\n", programCounter, moduleName, functionName); else NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s + 0x%X bytes\n", programCounter, moduleName, functionName, (DWORD)displacement64); } Print(stack_line); } }
// Resolve - Creates a nicely formatted rendition of the CallStack, including // symbolic information (function names and line numbers) if available. and // saves it for later retrieval. This is almost identical to Callstack::dump above. // // Note: The symbol handler must be initialized prior to calling this // function. // // - showInternalFrames (IN): If true, then all frames in the CallStack will be // dumped. Otherwise, frames internal to the heap will not be dumped. // // Return Value: // // None. // int CallStack::resolve(BOOL showInternalFrames) { if (m_resolved) { // already resolved, no need to do it again // resolving twice may report an incorrect module for the stack frames // if the memory was leaked in a dynamic library that was already unloaded. return 0; } if (m_status & CALLSTACK_STATUS_STARTUPCRT) { // there is no need to resolve a leak that will not be reported return 0; } if (m_status & CALLSTACK_STATUS_INCOMPLETE) { // This call stack appears to be incomplete. Using StackWalk64 may be // more reliable. Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n" L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n" L" complete stack trace.\n"); } int unresolvedFunctionsCount = 0; IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); bool skipStartupLeaks = !!(g_vld.GetOptions() & VLD_OPT_SKIP_CRTSTARTUP_LEAKS); // Use static here to increase performance, and avoid heap allocs. // It's thread safe because of g_heapMapLock lock. static WCHAR stack_line[MAXREPORTLENGTH + 1] = L""; bool isPrevFrameInternal = false; bool isDynamicInitializer = false; DWORD NumChars = 0; CriticalSectionLocker<DbgHelp> locker(g_DbgHelp); const size_t max_line_length = MAXREPORTLENGTH + 1; m_resolvedCapacity = m_size * max_line_length; const size_t allocedBytes = m_resolvedCapacity * sizeof(WCHAR); m_resolved = new WCHAR[m_resolvedCapacity]; if (m_resolved) { ZeroMemory(m_resolved, allocedBytes); } // Iterate through each frame in the call stack. for (UINT32 frame = 0; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; DWORD displacement = 0; // It turns out that calls to SymGetLineFromAddrW64 may free the very memory we are scrutinizing here // in this method. If this is the case, m_Resolved will be null after SymGetLineFromAddrW64 returns. // When that happens there is nothing we can do except crash. DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); BOOL foundline = g_DbgHelp.SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo, locker); if (skipStartupLeaks && foundline && !isDynamicInitializer && !(m_status & CALLSTACK_STATUS_NOTSTARTUPCRT) && isCrtStartupModule(sourceInfo.FileName)) { m_status |= CALLSTACK_STATUS_STARTUPCRT; delete[] m_resolved; m_resolved = NULL; m_resolvedCapacity = 0; m_resolvedLength = 0; return 0; } bool isFrameInternal = false; if (foundline && !showInternalFrames) { if (isInternalModule(sourceInfo.FileName)) { // Don't show frames in files internal to the heap. isFrameInternal = true; } } // show one allocation function for context if (NumChars > 0 && !isFrameInternal && isPrevFrameInternal) { m_resolvedLength += NumChars; if (m_resolved) { wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars); } } isPrevFrameInternal = isFrameInternal; DWORD64 displacement64; BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE]; LPCWSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer, locker); if (skipStartupLeaks && foundline && beginWith(functionName, wcslen(functionName), L"`dynamic initializer for '")) { isDynamicInitializer = true; } if (!foundline) displacement = (DWORD)displacement64; NumChars = resolveFunction( programCounter, foundline ? &sourceInfo : NULL, displacement, functionName, stack_line, _countof( stack_line )); if (NumChars > 0 && !isFrameInternal) { m_resolvedLength += NumChars; if (m_resolved) { wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars); } } } // end for loop m_status |= CALLSTACK_STATUS_NOTSTARTUPCRT; return unresolvedFunctionsCount; }
// dump - Dumps a nicely formatted rendition of the CallStack, including // symbolic information (function names and line numbers) if available. // // Note: The symbol handler must be initialized prior to calling this // function. // // - showinternalframes (IN): If true, then all frames in the CallStack will be // dumped. Otherwise, frames internal to the heap will not be dumped. // // Return Value: // // None. // void CallStack::dump(BOOL showInternalFrames, UINT start_frame) const { // The stack was dumped already if (m_resolved) { dumpResolved(); return; } if (m_status & CALLSTACK_STATUS_INCOMPLETE) { // This call stack appears to be incomplete. Using StackWalk64 may be // more reliable. Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n" L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n" L" complete stack trace.\n"); } IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); // Use static here to increase performance, and avoid heap allocs. // It's thread safe because of g_heapMapLock lock. static WCHAR stack_line[MAXREPORTLENGTH + 1] = L""; bool isPrevFrameInternal = false; CriticalSectionLocker<DbgHelp> locker(g_DbgHelp); // Iterate through each frame in the call stack. for (UINT32 frame = start_frame; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; BOOL foundline = FALSE; DWORD displacement = 0; DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); foundline = g_DbgHelp.SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo, locker); bool isFrameInternal = false; if (foundline && !showInternalFrames) { if (isInternalModule(sourceInfo.FileName)) { // Don't show frames in files internal to the heap. isFrameInternal = true; } } // show one allocation function for context if (!isFrameInternal && isPrevFrameInternal) Print(stack_line); isPrevFrameInternal = isFrameInternal; DWORD64 displacement64; BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE]; LPCWSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer, locker); if (!foundline) displacement = (DWORD)displacement64; DWORD NumChars = resolveFunction(programCounter, foundline ? &sourceInfo : NULL, displacement, functionName, stack_line, _countof(stack_line)); UNREFERENCED_PARAMETER(NumChars); if (!isFrameInternal) Print(stack_line); } }
CodecError CCodec_GT::Compress(CCodecBuffer& bufferIn, CCodecBuffer& bufferOut, Codec_Feedback_Proc pFeedbackProc, DWORD_PTR pUser1, DWORD_PTR pUser2) { assert(bufferIn.GetWidth() == bufferOut.GetWidth()); assert(bufferIn.GetHeight() == bufferOut.GetHeight()); if(bufferIn.GetWidth() != bufferOut.GetWidth() || bufferIn.GetHeight() != bufferOut.GetHeight()) return CE_Unknown; CodecError err = InitializeGTLibrary(); if (err != CE_OK) return err; #ifdef GT_COMPDEBUGGER CompViewerClient g_CompClient; if (g_CompClient.connect()) { #ifdef USE_DBGTRACE DbgTrace(("-------> Remote Server Connected")); #endif } #endif const CMP_DWORD dwBlocksX = ((bufferIn.GetWidth() + 3) >> 2); const CMP_DWORD dwBlocksY = ((bufferIn.GetHeight() + 3) >> 2); const CMP_DWORD dwBlocksXY = dwBlocksX*dwBlocksY; #ifdef USE_DBGTRACE DbgTrace(("IN : BufferType %d ChannelCount %d ChannelDepth %d",bufferIn.GetBufferType(),bufferIn.GetChannelCount(),bufferIn.GetChannelDepth())); DbgTrace((" : Height %d Width %d Pitch %d isFloat %d",bufferIn.GetHeight(),bufferIn.GetWidth(),bufferIn.GetWidth(),bufferIn.IsFloat())); DbgTrace(("OUT: BufferType %d ChannelCount %d ChannelDepth %d",bufferOut.GetBufferType(),bufferOut.GetChannelCount(),bufferOut.GetChannelDepth())); DbgTrace((" : Height %d Width %d Pitch %d isFloat %d",bufferOut.GetHeight(),bufferOut.GetWidth(),bufferOut.GetWidth(),bufferOut.IsFloat())); #endif; char row,col,srcIndex; CMP_BYTE *pOutBuffer; pOutBuffer = bufferOut.GetData(); CMP_BYTE* pInBuffer; pInBuffer = bufferIn.GetData(); DWORD block = 0; for(CMP_DWORD j = 0; j < dwBlocksY; j++) { for(CMP_DWORD i = 0; i < dwBlocksX; i++) { BYTE blockToEncode[BLOCK_SIZE_4X4][CHANNEL_SIZE_ARGB]; CMP_BYTE srcBlock[BLOCK_SIZE_4X4X4]; memset(srcBlock,0,sizeof(srcBlock)); bufferIn.ReadBlockRGBA(i*4, j*4, 4, 4, srcBlock); #ifdef GT_COMPDEBUGGER g_CompClient.SendData(1,sizeof(srcBlock),srcBlock); #endif // Create the block for encoding srcIndex = 0; for(row=0; row < BLOCK_SIZE_4; row++) { for(col=0; col < BLOCK_SIZE_4; col++) { blockToEncode[row*BLOCK_SIZE_4+col][BC_COMP_RED] = srcBlock[srcIndex]; blockToEncode[row*BLOCK_SIZE_4+col][BC_COMP_GREEN] = srcBlock[srcIndex+1]; blockToEncode[row*BLOCK_SIZE_4+col][BC_COMP_BLUE] = srcBlock[srcIndex+2]; blockToEncode[row*BLOCK_SIZE_4+col][BC_COMP_ALPHA] = srcBlock[srcIndex+3]; srcIndex+=4; } } EncodeGTBlock(blockToEncode,pOutBuffer+block); block += 16; #ifdef GT_COMPDEBUGGER // Checks decompression it should match or be close to source union BBLOCKS { CMP_DWORD compressedBlock[4]; BYTE out[16]; BYTE in[16]; } data; memset(data.in,0,sizeof(data)); union DBLOCKS { double blockToSave[16][4]; double block[64]; } savedata; CMP_BYTE destBlock[BLOCK_SIZE_4X4X4]; memset(savedata.block,0,sizeof(savedata)); m_decoder->DecompressBlock(savedata.blockToSave,data.in); for (row=0; row<64; row++) { destBlock[row] = (BYTE)savedata.block[row]; } g_CompClient.SendData(3,sizeof(destBlock),destBlock); #endif } if(pFeedbackProc) { float fProgress = 100.f * (j * dwBlocksX) / dwBlocksXY; if(pFeedbackProc(fProgress, pUser1, pUser2)) { #ifdef GT_COMPDEBUGGER g_CompClient.disconnect(); #endif FinishGTEncoding(); return CE_Aborted; } } } #ifdef GT_COMPDEBUGGER g_CompClient.disconnect(); #endif return FinishGTEncoding(); }
CodecError CCodec_GT::InitializeGTLibrary() { if (!m_LibraryInitialized) { for(DWORD i=0; i < MAX_GT_THREADS; i++) { m_encoder[i] = NULL; } // Create threaded encoder instances m_LiveThreads = 0; m_LastThread = 0; m_NumEncodingThreads = min(m_NumThreads, MAX_GT_THREADS); if (m_NumEncodingThreads == 0) m_NumEncodingThreads = 1; m_Use_MultiThreading = m_NumEncodingThreads > 1; g_EncodeParameterStorage = new GTEncodeThreadParam[m_NumEncodingThreads]; if(!g_EncodeParameterStorage) { return CE_Unknown; } m_EncodingThreadHandle = new HANDLE[m_NumEncodingThreads]; if(!m_EncodingThreadHandle) { delete[] g_EncodeParameterStorage; g_EncodeParameterStorage = NULL; return CE_Unknown; } DWORD i; for(i=0; i < m_NumEncodingThreads; i++) { // Create single encoder instance m_encoder[i] = new GTBlockEncoder(); // Cleanup if problem! if(!m_encoder[i]) { delete[] g_EncodeParameterStorage; g_EncodeParameterStorage = NULL; delete[] m_EncodingThreadHandle; m_EncodingThreadHandle = NULL; for(DWORD j=0; j<i; j++) { delete m_encoder[j]; m_encoder[j] = NULL; } return CE_Unknown; } #ifdef USE_DBGTRACE DbgTrace(("Encoder[%d]:ModeMask %X, Quality %f\n",i,m_ModeMask,m_Quality)); #endif } // Create the encoding threads in the suspended state for(i=0; i<m_NumEncodingThreads; i++) { m_EncodingThreadHandle[i] = (HANDLE)_beginthreadex(NULL, 0, GTThreadProcEncode, (void*)&g_EncodeParameterStorage[i], CREATE_SUSPENDED, NULL); if(m_EncodingThreadHandle[i]) { g_EncodeParameterStorage[i].encoder = m_encoder[i]; // Inform the thread that at the moment it doesn't have any work to do // but that it should wait for some and not exit g_EncodeParameterStorage[i].run = FALSE; g_EncodeParameterStorage[i].exit = FALSE; // Start the thread and have it wait for work ResumeThread(m_EncodingThreadHandle[i]); m_LiveThreads++; } } // Create single decoder instance m_decoder = new GTBlockDecoder(); if(!m_decoder) { for(DWORD j=0; j<m_NumEncodingThreads; j++) { delete m_encoder[j]; m_encoder[j] = NULL; } return CE_Unknown; } m_LibraryInitialized = true; } return CE_OK; }
CMP_DWORD CalcBufferSize(CodecType nCodecType, CMP_DWORD dwWidth, CMP_DWORD dwHeight) { #ifdef USE_DBGTRACE DbgTrace(("IN: nCodecType %d, dwWidth %d, dwHeight %d",nCodecType,dwWidth,dwHeight)); #endif CMP_DWORD dwChannels; CMP_DWORD dwBitsPerChannel; CMP_DWORD buffsize = 0; switch(nCodecType) { case CT_DXT1: case CT_ATI1N: case CT_ATC_RGB: case CT_ETC_RGB: dwChannels = 1; dwBitsPerChannel = 4; dwWidth = ((dwWidth + 3) / 4) * 4; dwHeight = ((dwHeight + 3) / 4) * 4; buffsize = (dwWidth * dwHeight * dwChannels * dwBitsPerChannel) / 8; break; case CT_DXT3: case CT_DXT5: case CT_DXT5_xGBR: case CT_DXT5_RxBG: case CT_DXT5_RBxG: case CT_DXT5_xRBG: case CT_DXT5_RGxB: case CT_DXT5_xGxR: case CT_ATI2N: case CT_ATI2N_XY: case CT_ATI2N_DXT5: case CT_ATC_RGBA_Explicit: case CT_ATC_RGBA_Interpolated: dwChannels = 2; dwBitsPerChannel = 4; dwWidth = ((dwWidth + 3) / 4) * 4; dwHeight = ((dwHeight + 3) / 4) * 4; buffsize = (dwWidth * dwHeight * dwChannels * dwBitsPerChannel) / 8; break; case CT_BC6H: dwWidth = ((dwWidth + 3) / 4) * 4; dwHeight = ((dwHeight + 3) / 4) * 4; buffsize = dwWidth * dwHeight; if (buffsize < BC6H_BLOCK_BYTES) buffsize = BC6H_BLOCK_BYTES; break; case CT_BC7: // Fix: July 25 2014 was 4x larger than it should be // Aug 1: Added increas in buffer size so that its divisable by 4 dwWidth = ((dwWidth + 3) / 4) * 4; dwHeight = ((dwHeight + 3) / 4) * 4; buffsize = dwWidth * dwHeight; if (buffsize < BC7_BLOCK_BYTES) buffsize = BC7_BLOCK_BYTES; break; case CT_ASTC: //notes: to be implemented! this is veriable size so addtional code is needed. dwWidth = ((dwWidth + 3) / 4) * 4; dwHeight = ((dwHeight + 3) / 4) * 4; buffsize = dwWidth * dwHeight; break; case CT_GT: // Aug 1: Added increas in buffer size so that its divisable by 4 dwWidth = ((dwWidth + 3) / 4) * 4; dwHeight = ((dwHeight + 3) / 4) * 4; buffsize = dwWidth * dwHeight; if (buffsize < (4*4)) buffsize = 4*4; break; default: return 0; } #ifdef USE_DBGTRACE DbgTrace(("OUT: %d",buffsize)); #endif return buffsize; }
CodecError CCodec_BC6H::Compress(CCodecBuffer& bufferIn, CCodecBuffer& bufferOut, Codec_Feedback_Proc pFeedbackProc, DWORD_PTR pUser1, DWORD_PTR pUser2) { assert(bufferIn.GetWidth() == bufferOut.GetWidth()); assert(bufferIn.GetHeight() == bufferOut.GetHeight()); if(bufferIn.GetWidth() != bufferOut.GetWidth() || bufferIn.GetHeight() != bufferOut.GetHeight()) return CE_Unknown; CodecError err = CInitializeBC6HLibrary(); if (err != CE_OK) return err; #ifdef BC6H_COMPDEBUGGER CompViewerClient g_CompClient; if (g_CompClient.connect()) { #ifdef USE_DBGTRACE DbgTrace(("-------> Remote Server Connected")); #endif } #endif #ifdef BC6H_DEBUG_TO_RESULTS_TXT g_fp = fopen("AMD_Results.txt","w"); g_block = 0; #endif const CMP_DWORD dwBlocksX = ((bufferIn.GetWidth() + 3) >> 2); const CMP_DWORD dwBlocksY = ((bufferIn.GetHeight() + 3) >> 2); #ifdef _REMOTE_DEBUG DbgTrace(("IN : BufferType %d ChannelCount %d ChannelDepth %d",bufferIn.GetBufferType(),bufferIn.GetChannelCount(),bufferIn.GetChannelDepth())); DbgTrace((" : Height %d Width %d Pitch %d isFloat %d",bufferIn.GetHeight(),bufferIn.GetWidth(),bufferIn.GetWidth(),bufferIn.IsFloat())); DbgTrace(("OUT: BufferType %d ChannelCount %d ChannelDepth %d",bufferOut.GetBufferType(),bufferOut.GetChannelCount(),bufferOut.GetChannelDepth())); DbgTrace((" : Height %d Width %d Pitch %d isFloat %d",bufferOut.GetHeight(),bufferOut.GetWidth(),bufferOut.GetWidth(),bufferOut.IsFloat())); #endif; char row,col,srcIndex; CMP_BYTE *pOutBuffer; pOutBuffer = bufferOut.GetData(); CMP_BYTE* pInBuffer; pInBuffer = bufferIn.GetData(); DWORD block = 0; #ifdef _SAVE_AS_BC6 FILE *bc6file = fopen("Test.bc6", "wb"); #endif for(CMP_DWORD j = 0; j < dwBlocksY; j++) { for(CMP_DWORD i = 0; i < dwBlocksX; i++) { float blockToEncode[BLOCK_SIZE_4X4][CHANNEL_SIZE_ARGB]; CMP_FLOAT srcBlock[BLOCK_SIZE_4X4X4]; memset(srcBlock,0,sizeof(srcBlock)); bufferIn.ReadBlockRGBA(i*4, j*4, 4, 4, srcBlock); #ifdef _BC6H_COMPDEBUGGER g_CompClient.SendData(1,sizeof(srcBlock),srcBlock); #endif // Create the block for encoding srcIndex = 0; for(row=0; row < BLOCK_SIZE_4; row++) { for(col=0; col < BLOCK_SIZE_4; col++) { blockToEncode[row*BLOCK_SIZE_4+col][BC6H_COMP_RED] = (float)srcBlock[srcIndex]; blockToEncode[row*BLOCK_SIZE_4+col][BC6H_COMP_GREEN] = (float)srcBlock[srcIndex+1]; blockToEncode[row*BLOCK_SIZE_4+col][BC6H_COMP_BLUE] = (float)srcBlock[srcIndex+2]; blockToEncode[row*BLOCK_SIZE_4+col][BC6H_COMP_ALPHA] = (float)srcBlock[srcIndex+3]; srcIndex+=4; } } union BBLOCKS { CMP_DWORD compressedBlock[4]; BYTE out[16]; BYTE in[16]; } data; memset(data.in,0,sizeof(data)); CEncodeBC6HBlock(blockToEncode,pOutBuffer+block); #ifdef _SAVE_AS_BC6 if (fwrite(pOutBuffer+block, sizeof(char), 16, bc6file) != 16) throw "File error on write"; #endif block += 16; #ifdef _BC6H_COMPDEBUGGER // Checks decompression it should match or be close to source union DBLOCKS { float blockToSave[16][4]; float block[64]; } savedata; CMP_BYTE destBlock[BLOCK_SIZE_4X4X4]; memset(savedata.block,0,sizeof(savedata)); m_decoder->DecompressBlock(savedata.blockToSave,data.in); for (row=0; row<64; row++) { destBlock[row] = (BYTE)savedata.block[row]; } g_CompClient.SendData(3,sizeof(destBlock),destBlock); #endif if(pFeedbackProc) { float fProgress = 100.f * (j * dwBlocksX) / (dwBlocksX * dwBlocksY); if(pFeedbackProc(fProgress, pUser1, pUser2)) { #ifdef _BC6H_COMPDEBUGGER g_CompClient.disconnect(); #endif CFinishBC6HEncoding(); return CE_Aborted; } } } } #ifdef _SAVE_AS_BC6 if (fclose(bc6file)) throw "Close failed on .bc6 file"; #endif #ifdef BC6H_COMPDEBUGGER g_CompClient.disconnect(); #endif #ifdef BC6H_DEBUG_TO_RESULTS_TXT if (g_fp) fclose(g_fp); #endif if(pFeedbackProc) { float fProgress = 100.f; pFeedbackProc(fProgress, pUser1, pUser2); } return CFinishBC6HEncoding(); }
CodecError CCodec_BC6H::CInitializeBC6HLibrary() { if (!m_LibraryInitialized) { // This is shared between BC7 also // and checked for initialization based on static flag // See the function for details. Quant_Init(); // One time initialisation for quantizer and shaker // check this is ok to remove for when we are encoding // should have no effect on decoding BC6H_init_ramps(); for(DWORD i=0; i < BC6H_MAX_THREADS; i++) { m_encoder[i] = NULL; } // Create threaded encoder instances m_LiveThreads = 0; m_LastThread = 0; m_NumEncodingThreads = min(m_NumThreads, BC6H_MAX_THREADS); if (m_NumEncodingThreads == 0) m_NumEncodingThreads = 1; m_Use_MultiThreading = m_NumEncodingThreads > 1; g_BC6EncodeParameterStorage = new BC6HEncodeThreadParam[m_NumEncodingThreads]; if(!g_BC6EncodeParameterStorage) { return CE_Unknown; } for (int i=0; i<m_NumEncodingThreads; i++) g_BC6EncodeParameterStorage[i].run = false; m_EncodingThreadHandle = new HANDLE[m_NumEncodingThreads]; if(!m_EncodingThreadHandle) { delete[] g_BC6EncodeParameterStorage; g_BC6EncodeParameterStorage = NULL; return CE_Unknown; } for(int i=0; i < m_NumEncodingThreads; i++) { // Create single encoder instance CMP_BC6H_BLOCK_PARAMETERS user_options; user_options.bIsSigned = m_bIsSigned; user_options.fQuality = m_Quality; user_options.dwMask = m_ModeMask; user_options.fExposure = m_Exposure; user_options.bUsePatternRec = m_UsePatternRec; m_encoder[i] = new BC6HBlockEncoder(user_options); // Cleanup if problem! if(!m_encoder[i]) { delete[] g_BC6EncodeParameterStorage; g_BC6EncodeParameterStorage = NULL; delete[] m_EncodingThreadHandle; m_EncodingThreadHandle = NULL; for(int j=0; j<i; j++) { delete m_encoder[j]; m_encoder[j] = NULL; } return CE_Unknown; } #ifdef USE_DBGTRACE DbgTrace(("Encoder[%d]:ModeMask %X, Quality %f\n",i,m_ModeMask,m_Quality)); #endif } // Create the encoding threads in the suspended state for(int i=0; i<m_NumEncodingThreads; i++) { m_EncodingThreadHandle[i] = (HANDLE)_beginthreadex(NULL, 0, BC6HThreadProcEncode, (void*)&g_BC6EncodeParameterStorage[i], CREATE_SUSPENDED, NULL); if(m_EncodingThreadHandle[i]) { g_BC6EncodeParameterStorage[i].encoder = m_encoder[i]; // Inform the thread that at the moment it doesn't have any work to do // but that it should wait for some and not exit g_BC6EncodeParameterStorage[i].run = FALSE; g_BC6EncodeParameterStorage[i].exit = FALSE; // Start the thread and have it wait for work ResumeThread(m_EncodingThreadHandle[i]); m_LiveThreads++; } } // Create single decoder instance m_decoder = new BC6HBlockDecoder(); if(!m_decoder) { for(DWORD j=0; j<m_NumEncodingThreads; j++) { delete m_encoder[j]; m_encoder[j] = NULL; } return CE_Unknown; } m_LibraryInitialized = true; } return CE_OK; }