blob: 290f608fb8131569f5f40c387ceabc5d8efdd0b3 [file] [log] [blame]
/****************************************************************************
*
* The MIT License (MIT)
*
* Copyright (c) 2014 - 2020 Vivante Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************
*
* The GPL License (GPL)
*
* Copyright (C) 2014 - 2020 Vivante Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*****************************************************************************
*
* Note: This software is released under dual MIT and GPL licenses. A
* recipient may use this file under the terms of either the MIT license or
* GPL License. If you wish to use only one license not the other, you can
* indicate your decision by deleting one of the above license notices in your
* version of this file.
*
*****************************************************************************/
#include "gc_hal_kernel_precomp.h"
#include <gc_hal_kernel_debug.h>
/******************************************************************************\
******************************** Debug Variables *******************************
\******************************************************************************/
static gceSTATUS _lastError = gcvSTATUS_OK;
static gctUINT32 _debugLevel = gcvLEVEL_ERROR;
/*
_debugZones config value
Please Reference define in gc_hal_base.h
*/
static gctUINT32 _debugZones = gcdZONE_NONE;
/******************************************************************************\
********************************* Debug Switches *******************************
\******************************************************************************/
/*
gcdTHREAD_BUFFERS
When greater then one, will accumulate messages from the specified number
of threads in separate output buffers.
*/
#define gcdTHREAD_BUFFERS 1
/*
gcdSHOW_LINE_NUMBER
When enabledm each print statement will be preceeded with the current
line number.
*/
#define gcdSHOW_LINE_NUMBER 0
/*
gcdSHOW_PROCESS_ID
When enabledm each print statement will be preceeded with the current
process ID.
*/
#define gcdSHOW_PROCESS_ID 0
/*
gcdSHOW_THREAD_ID
When enabledm each print statement will be preceeded with the current
thread ID.
*/
#define gcdSHOW_THREAD_ID 0
/*
gcdSHOW_TIME
When enabled each print statement will be preceeded with the current
high-resolution time.
*/
#define gcdSHOW_TIME 0
/******************************************************************************\
****************************** Miscellaneous Macros ****************************
\******************************************************************************/
#if gcdSHOW_TIME || gcdSHOW_LINE_NUMBER || gcdSHOW_PROCESS_ID || gcdSHOW_THREAD_ID
# define gcdHAVEPREFIX 1
#else
# define gcdHAVEPREFIX 0
#endif
/******************************************************************************\
****************************** Private Structures ******************************
\******************************************************************************/
typedef struct _gcsBUFFERED_OUTPUT * gcsBUFFERED_OUTPUT_PTR;
typedef struct _gcsBUFFERED_OUTPUT
{
#if gcdTHREAD_BUFFERS > 1
gctUINT32 threadID;
#endif
#if gcdSHOW_LINE_NUMBER
gctUINT lineNumber;
#endif
gctINT indent;
gcsBUFFERED_OUTPUT_PTR prev;
gcsBUFFERED_OUTPUT_PTR next;
}
gcsBUFFERED_OUTPUT;
static gcsBUFFERED_OUTPUT _outputBuffer[gcdTHREAD_BUFFERS];
static gcsBUFFERED_OUTPUT_PTR _outputBufferHead = gcvNULL;
static gcsBUFFERED_OUTPUT_PTR _outputBufferTail = gcvNULL;
/******************************************************************************\
******************************* Printing Functions *****************************
\******************************************************************************/
#if gcdHAVEPREFIX
#if gcdSHOW_TIME
static gcmINLINE gctUINT64
_GetTime(
void
)
{
gctUINT64 time;
gckOS_GetProfileTick(&time);
return time;
}
# define gcdPREFIX_LEADER 1
# define gcdTIMEFORMAT "%18lld"
# define gcdTIMEVALUE ,_GetTime()
# else
# define gcdTIMEFORMAT
# define gcdTIMEVALUE
# endif
#if gcdSHOW_LINE_NUMBER
#ifndef gcdPREFIX_LEADER
# define gcdPREFIX_LEADER 1
# define gcdNUMFORMAT "%8u"
# else
# define gcdNUMFORMAT ", %8u"
# endif
# define gcdNUMVALUE ,OutputBuffer->lineNumber
# else
# define gcdNUMFORMAT
# define gcdNUMVALUE
# endif
#if gcdSHOW_PROCESS_ID
#ifndef gcdPREFIX_LEADER
# define gcdPREFIX_LEADER 1
# define gcdPIDFORMAT "pid=%5u"
# else
# define gcdPIDFORMAT ", pid=%5u"
# endif
# define gcdPIDVALUE ,gcmkGETPROCESSID()
# else
# define gcdPIDFORMAT
# define gcdPIDVALUE
# endif
#if gcdSHOW_THREAD_ID
#ifndef gcdPREFIX_LEADER
# define gcdPREFIX_LEADER 1
# define gcdTIDFORMAT "tid=%5u"
# else
# define gcdTIDFORMAT ", tid=%5u"
# endif
# define gcdTIDVALUE ,gcmkGETTHREADID()
# else
# define gcdTIDFORMAT
# define gcdTIDVALUE
# endif
static gctUINT
_PrintPrefix(
IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
IN char Buffer[],
IN gctUINT Size
)
{
gctINT len;
/* Format the string. */
len = gcmkSPRINTF(Buffer,
Size,
"[" gcdTIMEFORMAT gcdNUMFORMAT gcdPIDFORMAT gcdTIDFORMAT "] "
gcdTIMEVALUE gcdNUMVALUE gcdPIDVALUE gcdTIDVALUE);
if (len > 0)
{
Buffer[len] = '\0';
return (gctUINT)len;
}
return 0;
}
#endif
static int
_AppendIndent(
IN gctINT Indent,
IN char * Buffer,
IN int BufferSize
)
{
gctINT i;
gctINT len = 0;
gctINT indent = Indent % 40;
for (i = 0; i < indent; i += 1)
{
Buffer[len++] = ' ';
}
if (indent != Indent)
{
len += gcmkSPRINTF(
Buffer + len, BufferSize - len, " <%d> ", Indent
);
Buffer[len] = '\0';
}
return len;
}
static gctUINT
_PrintString(
IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
IN gctINT Indent,
IN gctCONST_STRING Message,
IN gctPOINTER Data,
IN char Buffer[],
IN gctUINT Size
)
{
gctINT len;
/* Append the indent string. */
len = _AppendIndent(Indent, Buffer, Size);
/* Format the string. */
len += gcmkVSPRINTF(Buffer + len, Size - len, Message, Data);
Buffer[len] = '\0';
/* Add end-of-line if missing. */
if (Buffer[len - 1] != '\n')
{
Buffer[len++] = '\n';
Buffer[len] = '\0';
}
return (gctUINT)len;
}
/******************************************************************************\
******************************* Private Functions ******************************
\******************************************************************************/
static gcmINLINE void
_InitBuffers(
void
)
{
int i;
if (_outputBufferHead == gcvNULL)
{
for (i = 0; i < gcdTHREAD_BUFFERS; i += 1)
{
if (_outputBufferTail == gcvNULL)
{
_outputBufferHead = &_outputBuffer[i];
}
else
{
_outputBufferTail->next = &_outputBuffer[i];
}
#if gcdTHREAD_BUFFERS > 1
_outputBuffer[i].threadID = ~0U;
#endif
_outputBuffer[i].prev = _outputBufferTail;
_outputBuffer[i].next = gcvNULL;
_outputBufferTail = &_outputBuffer[i];
}
}
}
static gcmINLINE gcsBUFFERED_OUTPUT_PTR
_GetOutputBuffer(
void
)
{
gcsBUFFERED_OUTPUT_PTR outputBuffer;
#if gcdTHREAD_BUFFERS > 1
/* Get the current thread ID. */
gctUINT32 ThreadID = gcmkGETTHREADID();
/* Locate the output buffer for the thread. */
outputBuffer = _outputBufferHead;
while (outputBuffer != gcvNULL)
{
if (outputBuffer->threadID == ThreadID)
{
break;
}
outputBuffer = outputBuffer->next;
}
/* No matching buffer found? */
if (outputBuffer == gcvNULL)
{
/* Get the tail for the buffer. */
outputBuffer = _outputBufferTail;
/* Move it to the head. */
_outputBufferTail = _outputBufferTail->prev;
_outputBufferTail->next = gcvNULL;
outputBuffer->prev = gcvNULL;
outputBuffer->next = _outputBufferHead;
_outputBufferHead->prev = outputBuffer;
_outputBufferHead = outputBuffer;
/* Reset the buffer. */
outputBuffer->threadID = ThreadID;
#if gcdSHOW_LINE_NUMBER
outputBuffer->lineNumber = 0;
# endif
}
#else
outputBuffer = _outputBufferHead;
#endif
return outputBuffer;
}
static void
_Print(
IN gctCONST_STRING Message,
IN gctARGUMENTS * Arguments
)
{
gcsBUFFERED_OUTPUT_PTR outputBuffer;
char buffer[256];
char *ptr = buffer;
gctINT len = 0;
static gcmkDECLARE_MUTEX(printMutex);
gcmkMUTEX_LOCK(printMutex);
/* Initialize output buffer list. */
_InitBuffers();
/* Locate the proper output buffer. */
outputBuffer = _GetOutputBuffer();
/* Print prefix. */
#if gcdHAVEPREFIX
#if gcdSHOW_LINE_NUMBER
/* Update the line number. */
outputBuffer->lineNumber += 1;
# endif
/* Print the prefix. */
len = _PrintPrefix(outputBuffer, buffer, gcmSIZEOF(buffer));
ptr += len;
#endif
/* Form the indent string. */
if (Message[0] == '-' && Message[1] == '-')
{
outputBuffer->indent -= 2;
}
/* Print the message. */
len += _PrintString(
outputBuffer, outputBuffer->indent,
Message, ((gctPOINTER) Arguments),
ptr, gcmSIZEOF(buffer) - outputBuffer->indent - len
);
gcmkOUTPUT_STRING(buffer);
/* Check increasing indent. */
if (Message[0] == '+' && Message[1] == '+')
{
outputBuffer->indent += 2;
}
gcmkMUTEX_UNLOCK(printMutex);
}
/******************************************************************************\
********************************* Debug Macros *********************************
\******************************************************************************/
#ifdef __QNXNTO__
extern volatile unsigned g_nQnxInIsrs;
#define gcmDEBUGPRINT(Message) \
{ \
if (atomic_add_value(&g_nQnxInIsrs, 1) == 0) \
{ \
gctARGUMENTS __arguments__; \
gcmkARGUMENTS_START(__arguments__, Message); \
_Print(Message, &__arguments__); \
gcmkARGUMENTS_END(__arguments__); \
} \
atomic_sub(&g_nQnxInIsrs, 1); \
}
#elif defined(__VXWORKS__)
#define gcmDEBUGPRINT(Message) \
{ \
printf(Message); \
}
#else
#define gcmDEBUGPRINT(Message) \
{ \
gctARGUMENTS __arguments__; \
gcmkARGUMENTS_START(__arguments__, Message); \
_Print(Message, &__arguments__); \
gcmkARGUMENTS_END(__arguments__); \
}
#endif
/******************************************************************************\
********************************** Debug Code **********************************
\******************************************************************************/
/*******************************************************************************
**
** gckOS_Print
**
** Send a message to the debugger.
**
** INPUT:
**
** gctCONST_STRING Message
** Pointer to message.
**
** ...
** Optional arguments.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_Print(
IN gctCONST_STRING Message,
...
)
{
gcmDEBUGPRINT(Message);
}
/*******************************************************************************
**
** gckOS_DebugTrace
**
** Send a leveled message to the debugger.
**
** INPUT:
**
** gctUINT32 Level
** Debug level of message.
**
** gctCONST_STRING Message
** Pointer to message.
**
** ...
** Optional arguments.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_DebugTrace(
IN gctUINT32 Level,
IN gctCONST_STRING Message,
...
)
{
if (Level > _debugLevel)
{
return;
}
gcmDEBUGPRINT(Message);
}
/*******************************************************************************
**
** gckOS_DebugTraceZone
**
** Send a leveled and zoned message to the debugger.
**
** INPUT:
**
** gctUINT32 Level
** Debug level for message.
**
** gctUINT32 Zone
** Debug zone for message.
**
** gctCONST_STRING Message
** Pointer to message.
**
** ...
** Optional arguments.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_DebugTraceZone(
IN gctUINT32 Level,
IN gctUINT32 Zone,
IN gctCONST_STRING Message,
...
)
{
if ((Level > _debugLevel) || !(Zone & _debugZones))
{
return;
}
gcmDEBUGPRINT(Message);
}
/*******************************************************************************
**
** gckOS_DebugBreak
**
** Break into the debugger.
**
** INPUT:
**
** Nothing.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_DebugBreak(
void
)
{
gckOS_DebugTrace(gcvLEVEL_ERROR, "%s(%d)", __FUNCTION__, __LINE__);
}
/*******************************************************************************
**
** gckOS_DebugFatal
**
** Send a message to the debugger and break into the debugger.
**
** INPUT:
**
** gctCONST_STRING Message
** Pointer to message.
**
** ...
** Optional arguments.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_DebugFatal(
IN gctCONST_STRING Message,
...
)
{
gcmkPRINT_VERSION();
gcmDEBUGPRINT(Message);
/* Break into the debugger. */
gckOS_DebugBreak();
}
/*******************************************************************************
**
** gckOS_SetDebugLevel
**
** Set the debug level.
**
** INPUT:
**
** gctUINT32 Level
** New debug level.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_SetDebugLevel(
IN gctUINT32 Level
)
{
_debugLevel = Level;
}
/*******************************************************************************
**
** gckOS_SetDebugZone
**
** Set the debug zone.
**
** INPUT:
**
** gctUINT32 Zone
** New debug zone.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_SetDebugZone(
IN gctUINT32 Zone
)
{
_debugZones = Zone;
}
/*******************************************************************************
**
** gckOS_SetDebugLevelZone
**
** Set the debug level and zone.
**
** INPUT:
**
** gctUINT32 Level
** New debug level.
**
** gctUINT32 Zone
** New debug zone.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_SetDebugLevelZone(
IN gctUINT32 Level,
IN gctUINT32 Zone
)
{
_debugLevel = Level;
_debugZones = Zone;
}
/*******************************************************************************
**
** gckOS_SetDebugZones
**
** Enable or disable debug zones.
**
** INPUT:
**
** gctUINT32 Zones
** Debug zones to enable or disable.
**
** gctBOOL Enable
** Set to gcvTRUE to enable the zones (or the Zones with the current
** zones) or gcvFALSE to disable the specified Zones.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_SetDebugZones(
IN gctUINT32 Zones,
IN gctBOOL Enable
)
{
if (Enable)
{
/* Enable the zones. */
_debugZones |= Zones;
}
else
{
/* Disable the zones. */
_debugZones &= ~Zones;
}
}
/*******************************************************************************
**
** gckOS_Verify
**
** Called to verify the result of a function call.
**
** INPUT:
**
** gceSTATUS Status
** Function call result.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_Verify(
IN gceSTATUS status
)
{
_lastError = status;
}
gctCONST_STRING
gckOS_DebugStatus2Name(
gceSTATUS status
)
{
switch (status)
{
case gcvSTATUS_OK:
return "gcvSTATUS_OK";
case gcvSTATUS_TRUE:
return "gcvSTATUS_TRUE";
case gcvSTATUS_NO_MORE_DATA:
return "gcvSTATUS_NO_MORE_DATA";
case gcvSTATUS_CACHED:
return "gcvSTATUS_CACHED";
case gcvSTATUS_MIPMAP_TOO_LARGE:
return "gcvSTATUS_MIPMAP_TOO_LARGE";
case gcvSTATUS_NAME_NOT_FOUND:
return "gcvSTATUS_NAME_NOT_FOUND";
case gcvSTATUS_NOT_OUR_INTERRUPT:
return "gcvSTATUS_NOT_OUR_INTERRUPT";
case gcvSTATUS_MISMATCH:
return "gcvSTATUS_MISMATCH";
case gcvSTATUS_MIPMAP_TOO_SMALL:
return "gcvSTATUS_MIPMAP_TOO_SMALL";
case gcvSTATUS_LARGER:
return "gcvSTATUS_LARGER";
case gcvSTATUS_SMALLER:
return "gcvSTATUS_SMALLER";
case gcvSTATUS_CHIP_NOT_READY:
return "gcvSTATUS_CHIP_NOT_READY";
case gcvSTATUS_NEED_CONVERSION:
return "gcvSTATUS_NEED_CONVERSION";
case gcvSTATUS_SKIP:
return "gcvSTATUS_SKIP";
case gcvSTATUS_DATA_TOO_LARGE:
return "gcvSTATUS_DATA_TOO_LARGE";
case gcvSTATUS_INVALID_CONFIG:
return "gcvSTATUS_INVALID_CONFIG";
case gcvSTATUS_CHANGED:
return "gcvSTATUS_CHANGED";
case gcvSTATUS_NOT_SUPPORT_DITHER:
return "gcvSTATUS_NOT_SUPPORT_DITHER";
case gcvSTATUS_INVALID_ARGUMENT:
return "gcvSTATUS_INVALID_ARGUMENT";
case gcvSTATUS_INVALID_OBJECT:
return "gcvSTATUS_INVALID_OBJECT";
case gcvSTATUS_OUT_OF_MEMORY:
return "gcvSTATUS_OUT_OF_MEMORY";
case gcvSTATUS_MEMORY_LOCKED:
return "gcvSTATUS_MEMORY_LOCKED";
case gcvSTATUS_MEMORY_UNLOCKED:
return "gcvSTATUS_MEMORY_UNLOCKED";
case gcvSTATUS_HEAP_CORRUPTED:
return "gcvSTATUS_HEAP_CORRUPTED";
case gcvSTATUS_GENERIC_IO:
return "gcvSTATUS_GENERIC_IO";
case gcvSTATUS_INVALID_ADDRESS:
return "gcvSTATUS_INVALID_ADDRESS";
case gcvSTATUS_CONTEXT_LOSSED:
return "gcvSTATUS_CONTEXT_LOSSED";
case gcvSTATUS_TOO_COMPLEX:
return "gcvSTATUS_TOO_COMPLEX";
case gcvSTATUS_BUFFER_TOO_SMALL:
return "gcvSTATUS_BUFFER_TOO_SMALL";
case gcvSTATUS_INTERFACE_ERROR:
return "gcvSTATUS_INTERFACE_ERROR";
case gcvSTATUS_NOT_SUPPORTED:
return "gcvSTATUS_NOT_SUPPORTED";
case gcvSTATUS_MORE_DATA:
return "gcvSTATUS_MORE_DATA";
case gcvSTATUS_TIMEOUT:
return "gcvSTATUS_TIMEOUT";
case gcvSTATUS_OUT_OF_RESOURCES:
return "gcvSTATUS_OUT_OF_RESOURCES";
case gcvSTATUS_INVALID_DATA:
return "gcvSTATUS_INVALID_DATA";
case gcvSTATUS_INVALID_MIPMAP:
return "gcvSTATUS_INVALID_MIPMAP";
case gcvSTATUS_NOT_FOUND:
return "gcvSTATUS_NOT_FOUND";
case gcvSTATUS_NOT_ALIGNED:
return "gcvSTATUS_NOT_ALIGNED";
case gcvSTATUS_INVALID_REQUEST:
return "gcvSTATUS_INVALID_REQUEST";
case gcvSTATUS_GPU_NOT_RESPONDING:
return "gcvSTATUS_GPU_NOT_RESPONDING";
case gcvSTATUS_TIMER_OVERFLOW:
return "gcvSTATUS_TIMER_OVERFLOW";
case gcvSTATUS_VERSION_MISMATCH:
return "gcvSTATUS_VERSION_MISMATCH";
case gcvSTATUS_LOCKED:
return "gcvSTATUS_LOCKED";
case gcvSTATUS_INTERRUPTED:
return "gcvSTATUS_INTERRUPTED";
case gcvSTATUS_DEVICE:
return "gcvSTATUS_DEVICE";
case gcvSTATUS_NOT_MULTI_PIPE_ALIGNED:
return "gcvSTATUS_NOT_MULTI_PIPE_ALIGNED";
/* Linker errors. */
case gcvSTATUS_GLOBAL_TYPE_MISMATCH:
return "gcvSTATUS_GLOBAL_TYPE_MISMATCH";
case gcvSTATUS_TOO_MANY_ATTRIBUTES:
return "gcvSTATUS_TOO_MANY_ATTRIBUTES";
case gcvSTATUS_TOO_MANY_UNIFORMS:
return "gcvSTATUS_TOO_MANY_UNIFORMS";
case gcvSTATUS_TOO_MANY_VARYINGS:
return "gcvSTATUS_TOO_MANY_VARYINGS";
case gcvSTATUS_UNDECLARED_VARYING:
return "gcvSTATUS_UNDECLARED_VARYING";
case gcvSTATUS_VARYING_TYPE_MISMATCH:
return "gcvSTATUS_VARYING_TYPE_MISMATCH";
case gcvSTATUS_MISSING_MAIN:
return "gcvSTATUS_MISSING_MAIN";
case gcvSTATUS_NAME_MISMATCH:
return "gcvSTATUS_NAME_MISMATCH";
case gcvSTATUS_INVALID_INDEX:
return "gcvSTATUS_INVALID_INDEX";
case gcvSTATUS_UNIFORM_MISMATCH:
return "gcvSTATUS_UNIFORM_MISMATCH";
case gcvSTATUS_UNSAT_LIB_SYMBOL:
return "gcvSTATUS_UNSAT_LIB_SYMBOL";
case gcvSTATUS_TOO_MANY_SHADERS:
return "gcvSTATUS_TOO_MANY_SHADERS";
case gcvSTATUS_LINK_INVALID_SHADERS:
return "gcvSTATUS_LINK_INVALID_SHADERS";
case gcvSTATUS_CS_NO_WORKGROUP_SIZE:
return "gcvSTATUS_CS_NO_WORKGROUP_SIZE";
case gcvSTATUS_LINK_LIB_ERROR:
return "gcvSTATUS_LINK_LIB_ERROR";
case gcvSTATUS_SHADER_VERSION_MISMATCH:
return "gcvSTATUS_SHADER_VERSION_MISMATCH";
case gcvSTATUS_TOO_MANY_INSTRUCTION:
return "gcvSTATUS_TOO_MANY_INSTRUCTION";
case gcvSTATUS_SSBO_MISMATCH:
return "gcvSTATUS_SSBO_MISMATCH";
case gcvSTATUS_TOO_MANY_OUTPUT:
return "gcvSTATUS_TOO_MANY_OUTPUT";
case gcvSTATUS_TOO_MANY_INPUT:
return "gcvSTATUS_TOO_MANY_INPUT";
case gcvSTATUS_NOT_SUPPORT_CL:
return "gcvSTATUS_NOT_SUPPORT_CL";
case gcvSTATUS_NOT_SUPPORT_INTEGER:
return "gcvSTATUS_NOT_SUPPORT_INTEGER";
case gcvSTATUS_UNIFORM_TYPE_MISMATCH:
return "gcvSTATUS_UNIFORM_TYPE_MISMATCH";
case gcvSTATUS_MISSING_PRIMITIVE_TYPE:
return "gcvSTATUS_MISSING_PRIMITIVE_TYPE";
case gcvSTATUS_MISSING_OUTPUT_VERTEX_COUNT:
return "gcvSTATUS_MISSING_OUTPUT_VERTEX_COUNT";
case gcvSTATUS_NON_INVOCATION_ID_AS_INDEX:
return "gcvSTATUS_NON_INVOCATION_ID_AS_INDEX";
case gcvSTATUS_INPUT_ARRAY_SIZE_MISMATCH:
return "gcvSTATUS_INPUT_ARRAY_SIZE_MISMATCH";
case gcvSTATUS_OUTPUT_ARRAY_SIZE_MISMATCH:
return "gcvSTATUS_OUTPUT_ARRAY_SIZE_MISMATCH";
/* Compiler errors. */
case gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR:
return "gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR";
case gcvSTATUS_COMPILER_FE_PARSER_ERROR:
return "gcvSTATUS_COMPILER_FE_PARSER_ERROR";
default:
return "nil";
}
}
/*******************************************************************************
***** Kernel Dump **************************************************************
*******************************************************************************/
/*
* TODO: Dump to file is only valid in linux currently.
*/
#ifndef gcmkDUMP_STRING
# define gcmkDUMP_STRING(os, s) gcmkOUTPUT_STRING((s))
#endif
static gcmkDECLARE_MUTEX(_dumpMutex);
static gctCHAR _dumpStorage[512];
/*******************************************************************************
**
** gckOS_Dump
**
** Formated print string to dump pool.
**
** INPUT:
**
** gctCONST_STRING Format
** String format.
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_Dump(
IN gckOS Os,
IN gctCONST_STRING Format,
...
)
{
char buffer[256];
gctINT len;
gctARGUMENTS args;
gcmkARGUMENTS_START(args, Format);
len = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer) - 2, Format, &args);
gcmkARGUMENTS_END(args);
if (len > 0)
{
if (buffer[len - 1] != '\n')
{
buffer[len] = '\n';
buffer[len + 1] = '\0';
}
gcmkMUTEX_LOCK(_dumpMutex);
gcmkDUMP_STRING(Os, buffer);
gcmkMUTEX_UNLOCK(_dumpMutex);
}
}
static void
_DumpUserString(
IN gckOS Os,
IN gctPOINTER UserStr,
IN gctSIZE_T Size
)
{
gceSTATUS status = gcvSTATUS_OK;
gctSIZE_T offset = 0;
gctSIZE_T length = 0;
gctBOOL needCopy = gcvTRUE;
const gctSIZE_T maxLength = gcmSIZEOF(_dumpStorage) - 1;
gcmkVERIFY_OK(gckOS_QueryNeedCopy(Os, 0, &needCopy));
gcmkMUTEX_LOCK(_dumpMutex);
while (offset < Size)
{
length = maxLength < (Size - offset) ? maxLength : (Size - offset);
/* Copy or map from user. */
if (needCopy)
{
gcmkONERROR(gckOS_CopyFromUserData(
Os,
_dumpStorage,
UserStr,
length
));
}
else
{
gctPOINTER ptr = gcvNULL;
gcmkONERROR(gckOS_MapUserPointer(
Os,
UserStr,
length,
(gctPOINTER *)&ptr
));
gckOS_MemCopy(_dumpStorage, ptr, length);
gckOS_UnmapUserPointer(Os, UserStr, length, ptr);
}
_dumpStorage[length] = '\0';
gcmkDUMP_STRING(Os, _dumpStorage);
UserStr = (gctUINT8_PTR)UserStr + length;
offset += length;
}
gcmkDUMP_STRING(Os, "\n");
OnError:
gcmkMUTEX_UNLOCK(_dumpMutex);
}
static void
_DumpDataBuffer(
IN gckOS Os,
IN gceDUMP_BUFFER_TYPE Type,
IN gctPOINTER Data,
IN gctUINT64 Address,
IN gctSIZE_T Size
)
{
gceSTATUS status = gcvSTATUS_OK;
gctSIZE_T offset = 0;
gctSIZE_T length = 0;
gctBOOL needCopy = gcvTRUE;
gctCONST_STRING dumpTag;
char buffer[256];
const gctSIZE_T maxLength = gcmSIZEOF(_dumpStorage);
switch (Type)
{
case gcvDUMP_BUFFER_VERIFY:
dumpTag = "verify";
break;
case gcvDUMP_BUFFER_PHYSICAL_MEMORY:
dumpTag = "physical";
break;
default:
dumpTag = "memory";
break;
}
if (Type <= gcvDUMP_BUFFER_USER_TYPE_LAST)
{
gcmkVERIFY_OK(gckOS_QueryNeedCopy(Os, 0, &needCopy));
}
gcmkMUTEX_LOCK(_dumpMutex);
/* Form and print the opening string. */
if (Type == gcvDUMP_BUFFER_PHYSICAL_MEMORY)
{
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
"@[%s 0x%010llX 0x%08X\n",
dumpTag, (unsigned long long)Address, (gctUINT32)Size);
}
else
{
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
"@[%s 0x%08X 0x%08X\n",
dumpTag, (gctUINT32)Address, (gctUINT32)Size);
}
gcmkDUMP_STRING(Os, buffer);
while (offset < Size)
{
gctPOINTER data = gcvNULL;
gctUINT32_PTR ptr;
gctUINT8_PTR bytePtr;
gctSIZE_T count, tailByteCount;
length = maxLength < (Size - offset) ? maxLength : (Size - offset);
count = length / 4;
tailByteCount = length % 4;
ptr = (gctUINT32_PTR)Data;
if (Type <= gcvDUMP_BUFFER_USER_TYPE_LAST)
{
/* Copy or map from user. */
if (needCopy)
{
gcmkONERROR(gckOS_CopyFromUserData(
Os,
_dumpStorage,
Data,
length
));
ptr = (gctUINT32_PTR)_dumpStorage;
}
else
{
gcmkONERROR(gckOS_MapUserPointer(
Os,
Data,
length,
(gctPOINTER *)&data
));
ptr = (gctUINT32_PTR)data;
}
}
while (count >= 4)
{
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
" 0x%08X 0x%08X 0x%08X 0x%08X\n",
ptr[0], ptr[1], ptr[2], ptr[3]);
ptr += 4;
count -= 4;
gcmkDUMP_STRING(Os, buffer);
}
switch (count)
{
case 3:
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
" 0x%08X 0x%08X 0x%08X",
ptr[0], ptr[1], ptr[2]);
break;
case 2:
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
" 0x%08X 0x%08X",
ptr[0], ptr[1]);
break;
case 1:
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1, " 0x%08X", ptr[0]);
break;
}
if (count > 0)
{
gcmkDUMP_STRING(Os, buffer);
}
bytePtr = (gctUINT8_PTR)(ptr + count);
if (!count && tailByteCount)
{
/* There is an extra space for the new line. */
gcmkDUMP_STRING(Os, " ");
}
switch (tailByteCount)
{
case 3:
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
" 0x00%02X%02X%02X",
bytePtr[2], bytePtr[1], bytePtr[0]);
break;
case 2:
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
" 0x0000%02X%02X",
bytePtr[1], bytePtr[0]);
break;
case 1:
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1,
" 0x000000%02X", bytePtr[0]);
break;
}
if (tailByteCount)
{
gcmkDUMP_STRING(Os, buffer);
}
if (count || tailByteCount)
{
gcmkDUMP_STRING(Os, "\n");
}
if (Type <= gcvDUMP_BUFFER_USER_TYPE_LAST && !needCopy)
{
gckOS_UnmapUserPointer(Os, Data, length, data);
}
/* advance to next batch. */
Data = (gctUINT8_PTR)Data + length;
offset += length;
}
OnError:
gcmkSPRINTF(buffer, gcmSIZEOF(buffer) - 1, "] -- %s\n", dumpTag);
gcmkDUMP_STRING(Os, buffer);
gcmkMUTEX_UNLOCK(_dumpMutex);
}
/*******************************************************************************
**
** gckOS_DumpBuffer
**
** Print the contents of the specified buffer.
**
** INPUT:
**
** gckOS Os
** Pointer to gckOS object.
**
** gceDUMP_BUFFER_TYPE Type
** Buffer type.
**
** gctPOINTER Buffer
** Pointer to the buffer to print.
**
** gctUINT64 Address
** Address.
**
** gctUINT Size
** Size of the buffer.
**
**
** OUTPUT:
**
** Nothing.
*/
void
gckOS_DumpBuffer(
IN gckOS Os,
IN gceDUMP_BUFFER_TYPE Type,
IN gctPOINTER Buffer,
IN gctUINT64 Address,
IN gctSIZE_T Size
)
{
if (!Buffer)
{
return;
}
/* memory dump below. */
if (Type >= gcvDUMP_BUFFER_TYPE_COUNT)
{
gcmkPRINT("#[ERROR: invalid buffer type]\n");
return;
}
if (Type == gcvDUMP_BUFFER_USER_STRING)
{
_DumpUserString(Os, Buffer, Size);
}
else
{
_DumpDataBuffer(Os, Type, Buffer, Address, Size);
}
}
/*******************************************************************************
***** Binary Trace *************************************************************
*******************************************************************************/