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(&currentContext, 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, &currentContext, 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);
    }
}
Exemple #3
0
// 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(&currentContext, 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, &currentContext, 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);
    }
}
Exemple #4
0
// 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;
}
Exemple #5
0
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);
    }
}
Exemple #9
0
// 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;
}
Exemple #10
0
// 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;
}