From 2ec2a47a53e826b2a9467d526ae97ff7ff43ce61 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Mon, 25 Apr 2022 17:21:00 +0300 Subject: [PATCH 01/34] fix address sanitizer issues --- engine/cl_main.cpp | 2 +- engine/cmodel.cpp | 3 +++ engine/event_system.h | 4 ++-- engine/host_saverestore.cpp | 3 ++- engine/net_ws.cpp | 2 +- engine/shadowmgr.cpp | 16 ++++++++-------- engine/spatialpartition.cpp | 4 ++-- filesystem/filesystem_async.cpp | 2 +- game/client/view_beams.cpp | 3 ++- game/server/TemplateEntities.cpp | 2 +- game/server/ai_component.h | 5 +++++ game/server/func_areaportal.cpp | 5 ++--- mathlib/polyhedron.cpp | 10 ++++------ public/mathlib/polyhedron.h | 6 +++--- public/studio.h | 9 ++++----- studiorender/studiorendercontext.cpp | 2 +- vpklib/packedstore.cpp | 2 +- 17 files changed, 43 insertions(+), 37 deletions(-) diff --git a/engine/cl_main.cpp b/engine/cl_main.cpp index 6d0134ae..9340beea 100644 --- a/engine/cl_main.cpp +++ b/engine/cl_main.cpp @@ -893,7 +893,7 @@ CON_COMMAND_F( connect, "Connect to specified server.", FCVAR_DONTRECORD ) { ConMsg( "Usage: connect \n" ); } - vecArgs.PurgeAndDeleteElements(); + vecArgs.PurgeAndDeleteElementsArray(); } CON_COMMAND_F( redirect, "Redirect client to specified server.", FCVAR_DONTRECORD | FCVAR_SERVER_CAN_EXECUTE ) diff --git a/engine/cmodel.cpp b/engine/cmodel.cpp index e9af063d..ce1c9f2d 100644 --- a/engine/cmodel.cpp +++ b/engine/cmodel.cpp @@ -2677,6 +2677,9 @@ int CM_BoxVisible( const Vector& mins, const Vector& maxs, const byte *visbi int cluster = CM_LeafCluster( leafList[i] ); int offset = cluster>>3; + if( offset == -1 ) + return true; + if ( offset > vissize ) { Sys_Error( "CM_BoxVisible: cluster %i, offset %i out of bounds %i\n", cluster, offset, vissize ); diff --git a/engine/event_system.h b/engine/event_system.h index 0139cb45..7d0ba8a0 100644 --- a/engine/event_system.h +++ b/engine/event_system.h @@ -52,7 +52,7 @@ public: { if ( pData ) { - delete pData; + delete[] pData; } } @@ -65,7 +65,7 @@ public: pSendTable = src.pSendTable; pClientClass = src.pClientClass; filter.AddPlayersFromFilter( &src.filter ); - + if ( src.pData ) { int size = Bits2Bytes( src.bits ); diff --git a/engine/host_saverestore.cpp b/engine/host_saverestore.cpp index 3ae1feaa..6e1afa9f 100644 --- a/engine/host_saverestore.cpp +++ b/engine/host_saverestore.cpp @@ -806,7 +806,8 @@ int CSaveRestore::SaveGameSlot( const char *pSaveName, const char *pSaveComment, m_bWaitingForSafeDangerousSave = bIsAutosaveDangerous; int iHeaderBufferSize = 64 + tokenSize + pSaveData->GetCurPos(); - void *pMem = malloc(iHeaderBufferSize); + void *pMem = new char[iHeaderBufferSize]; + CUtlBuffer saveHeader( pMem, iHeaderBufferSize ); // Write the header -- THIS SHOULD NEVER CHANGE STRUCTURE, USE SAVE_HEADER FOR NEW HEADER INFORMATION diff --git a/engine/net_ws.cpp b/engine/net_ws.cpp index 3c49ab6c..a06cbb1d 100644 --- a/engine/net_ws.cpp +++ b/engine/net_ws.cpp @@ -1389,7 +1389,7 @@ bool NET_GetLoopPacket ( netpacket_t * packet ) if ( loop->data != loop->defbuffer ) { - delete loop->data; + delete[] loop->data; loop->data = loop->defbuffer; } diff --git a/engine/shadowmgr.cpp b/engine/shadowmgr.cpp index d60f953c..00177ebf 100644 --- a/engine/shadowmgr.cpp +++ b/engine/shadowmgr.cpp @@ -2048,34 +2048,34 @@ public: class CClipPlane { public: - static inline bool Inside( ShadowVertex_t const& vert ) + static inline bool Inside( ShadowVertex_t const& vert ) { - return DotProduct( vert.m_Position, *m_pNormal ) < m_Dist; + return DotProduct( vert.m_Position, m_pNormal ) < m_Dist; } - static inline float Clip( const Vector& one, const Vector& two ) + static inline float Clip( const Vector& one, const Vector& two ) { Vector dir; VectorSubtract( two, one, dir ); - return IntersectRayWithPlane( one, dir, *m_pNormal, m_Dist ); + return IntersectRayWithPlane( one, dir, m_pNormal, m_Dist ); } static inline bool IsAbove() {return false;} static inline bool IsPlane() {return true;} - static void SetPlane( const Vector& normal, float dist ) + static void SetPlane( const Vector normal, float dist ) { - m_pNormal = &normal; + m_pNormal = normal; m_Dist = dist; } private: - static const Vector *m_pNormal; + static const Vector m_pNormal; static float m_Dist; }; -const Vector *CClipPlane::m_pNormal; +const Vector CClipPlane::m_pNormal; float CClipPlane::m_Dist; static inline void ClampTexCoord( ShadowVertex_t *pInVertex, ShadowVertex_t *pOutVertex ) diff --git a/engine/spatialpartition.cpp b/engine/spatialpartition.cpp index 489dd9cd..3bcc85f3 100644 --- a/engine/spatialpartition.cpp +++ b/engine/spatialpartition.cpp @@ -2297,9 +2297,9 @@ void CVoxelTree::EnumerateElementsAlongRay( SpatialPartitionListMask_t listMask, vecInvDelta[1] = ( clippedRay.m_Delta[1] != 0.0f ) ? 1.0f / clippedRay.m_Delta[1] : FLT_MAX; vecInvDelta[2] = ( clippedRay.m_Delta[2] != 0.0f ) ? 1.0f / clippedRay.m_Delta[2] : FLT_MAX; - CPartitionVisits *pPrevVisits = BeginVisit(); - m_lock.LockForRead(); + + CPartitionVisits *pPrevVisits = BeginVisit(); if ( ray.m_IsRay ) { EnumerateElementsAlongRay_Ray( listMask, clippedRay, vecInvDelta, vecEnd, pIterator ); diff --git a/filesystem/filesystem_async.cpp b/filesystem/filesystem_async.cpp index 4196e090..ad9bb7dd 100644 --- a/filesystem/filesystem_async.cpp +++ b/filesystem/filesystem_async.cpp @@ -488,7 +488,7 @@ public: { if ( m_pData && m_bFreeMemory ) { - free( (void*) m_pData ); + delete[] (char*)m_pData; } } diff --git a/game/client/view_beams.cpp b/game/client/view_beams.cpp index d8881244..758a5029 100644 --- a/game/client/view_beams.cpp +++ b/game/client/view_beams.cpp @@ -1963,7 +1963,7 @@ void CViewRenderBeams::DrawBeam( Beam_t *pbeam ) // set color float srcColor[3]; - float color[3]; + float color[4]; srcColor[0] = pbeam->r; srcColor[1] = pbeam->g; @@ -1984,6 +1984,7 @@ void CViewRenderBeams::DrawBeam( Beam_t *pbeam ) VectorScale( color, (1/255.0), color ); VectorCopy( color, srcColor ); VectorScale( color, ((float)pbeam->brightness / 255.0), color ); + color[3] = 1.f; switch( pbeam->type ) { diff --git a/game/server/TemplateEntities.cpp b/game/server/TemplateEntities.cpp index a5092904..c47806ea 100644 --- a/game/server/TemplateEntities.cpp +++ b/game/server/TemplateEntities.cpp @@ -385,7 +385,7 @@ void Templates_RemoveAll(void) free(pTemplate->pszMapData); if ( pTemplate->pszFixedMapData ) { - free(pTemplate->pszFixedMapData); + delete[] pTemplate->pszFixedMapData; } free(pTemplate); diff --git a/game/server/ai_component.h b/game/server/ai_component.h index 2385d61b..7722f66a 100644 --- a/game/server/ai_component.h +++ b/game/server/ai_component.h @@ -137,6 +137,11 @@ public: return pResult; } + void operator delete(void *p) + { + MemAlloc_Free( p ); + }; + private: CAI_BaseNPC *m_pOuter; }; diff --git a/game/server/func_areaportal.cpp b/game/server/func_areaportal.cpp index ca391317..321da0f8 100644 --- a/game/server/func_areaportal.cpp +++ b/game/server/func_areaportal.cpp @@ -45,9 +45,8 @@ public: DECLARE_DATADESC(); private: - bool UpdateState( void ); - - int m_state; + bool UpdateState( void ); + int m_state; }; LINK_ENTITY_TO_CLASS( func_areaportal, CAreaPortal ); diff --git a/mathlib/polyhedron.cpp b/mathlib/polyhedron.cpp index 54e243ff..f02bba6f 100644 --- a/mathlib/polyhedron.cpp +++ b/mathlib/polyhedron.cpp @@ -71,20 +71,18 @@ void CreateDumpDirectory( const char *szDirectoryName ) void CPolyhedron_AllocByNew::Release( void ) { - delete this; + free(this); } CPolyhedron_AllocByNew *CPolyhedron_AllocByNew::Allocate( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ) //creates the polyhedron along with enough memory to hold all it's data in a single allocation { - void *pMemory = new unsigned char [ sizeof( CPolyhedron_AllocByNew ) + + void *pMemory = malloc(sizeof( CPolyhedron_AllocByNew ) + (iVertices * sizeof(Vector)) + (iLines * sizeof(Polyhedron_IndexedLine_t)) + (iIndices * sizeof( Polyhedron_IndexedLineReference_t )) + - (iPolygons * sizeof( Polyhedron_IndexedPolygon_t ))]; + (iPolygons * sizeof( Polyhedron_IndexedPolygon_t ))); -#include "tier0/memdbgoff.h" //the following placement new doesn't compile with memory debugging CPolyhedron_AllocByNew *pAllocated = new ( pMemory ) CPolyhedron_AllocByNew; -#include "tier0/memdbgon.h" pAllocated->iVertexCount = iVertices; pAllocated->iLineCount = iLines; @@ -106,7 +104,7 @@ public: int iReferenceCount; #endif - virtual void Release( void ) + void Release( void ) override { #ifdef DBGFLAG_ASSERT --iReferenceCount; diff --git a/public/mathlib/polyhedron.h b/public/mathlib/polyhedron.h index 38b465c7..8f4a4955 100644 --- a/public/mathlib/polyhedron.h +++ b/public/mathlib/polyhedron.h @@ -42,7 +42,7 @@ public: Polyhedron_IndexedLine_t *pLines; Polyhedron_IndexedLineReference_t *pIndices; Polyhedron_IndexedPolygon_t *pPolygons; - + unsigned short iVertexCount; unsigned short iLineCount; unsigned short iIndexCount; @@ -53,10 +53,10 @@ public: Vector Center( void ); }; -class CPolyhedron_AllocByNew : public CPolyhedron +class CPolyhedron_AllocByNew final : public CPolyhedron { public: - virtual void Release( void ); + void Release( void ) override; static CPolyhedron_AllocByNew *Allocate( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ); //creates the polyhedron along with enough memory to hold all it's data in a single allocation private: diff --git a/public/studio.h b/public/studio.h index f67a78cc..17bb0659 100644 --- a/public/studio.h +++ b/public/studio.h @@ -2062,6 +2062,8 @@ struct studiohdr2_t struct studiohdr_t { DECLARE_BYTESWAP_DATADESC(); + studiohdr_t() = default; + int id; int version; @@ -2077,10 +2079,10 @@ struct studiohdr_t Vector illumposition; // illumination center Vector hull_min; // ideal movement hull size - Vector hull_max; + Vector hull_max; Vector view_bbmin; // clipping bounding box - Vector view_bbmax; + Vector view_bbmax; int flags; @@ -2329,9 +2331,6 @@ struct studiohdr_t // [and move all fields in studiohdr2_t into studiohdr_t and kill studiohdr2_t], // or add your stuff to studiohdr2_t. See NumSrcBoneTransforms/SrcBoneTransform for the pattern to use. int unused2[1]; - - studiohdr_t() {} - private: // No copy constructors allowed studiohdr_t(const studiohdr_t& vOther); diff --git a/studiorender/studiorendercontext.cpp b/studiorender/studiorendercontext.cpp index 2d857da3..c29a27b6 100644 --- a/studiorender/studiorendercontext.cpp +++ b/studiorender/studiorendercontext.cpp @@ -1317,7 +1317,7 @@ void CStudioRenderContext::R_StudioDestroyStaticMeshes( int numStudioMeshes, stu if ( *ppStudioMeshes ) { - delete *ppStudioMeshes; + delete[] *ppStudioMeshes; *ppStudioMeshes = 0; } } diff --git a/vpklib/packedstore.cpp b/vpklib/packedstore.cpp index 8b7d7ba7..33f28b56 100644 --- a/vpklib/packedstore.cpp +++ b/vpklib/packedstore.cpp @@ -502,7 +502,7 @@ void SplitFileComponents( char const *pFileName, char *pDirOut, char *pBaseOut, if ( !pDirOut[0] ) strcpy( pDirOut, " " ); // blank dir name - V_strcpy( pBaseOut, V_UnqualifiedFileName( pFileName ) ); + V_strncpy( pBaseOut, V_UnqualifiedFileName( pFileName ), MAX_PATH ); char *pDot = strrchr( pBaseOut, '.' ); if ( pDot ) { From ce68fffa3b33819dbd5a4ea65c35576d7712c3c4 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 1 May 2022 15:53:52 +0300 Subject: [PATCH 02/34] togles: use original glCompressedTexture2D when gpu have DXT support --- togles/linuxwin/cglmbuffer.cpp | 2 +- togles/linuxwin/cglmtex.cpp | 24 +++++++++--------------- togles/linuxwin/glentrypoints.cpp | 4 ++-- togles/linuxwin/glmgr.cpp | 5 ++--- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/togles/linuxwin/cglmbuffer.cpp b/togles/linuxwin/cglmbuffer.cpp index 8f866da2..1fb77b62 100644 --- a/togles/linuxwin/cglmbuffer.cpp +++ b/togles/linuxwin/cglmbuffer.cpp @@ -472,7 +472,7 @@ CGLMBuffer::CGLMBuffer( GLMContext *pCtx, EGLMBufferType type, uint size, uint o m_bPseudo = true; #endif - const char *szRenderer = gGL->glGetString(GL_VENDOR); + const char *szRenderer = (const char*)gGL->glGetString(GL_VENDOR); // Msg("GL_VENDOR: %s\n", szRenderer); if( strcmp(szRenderer, "ARM") == 0 ) diff --git a/togles/linuxwin/cglmtex.cpp b/togles/linuxwin/cglmtex.cpp index 2cc034e9..5230ad11 100644 --- a/togles/linuxwin/cglmtex.cpp +++ b/togles/linuxwin/cglmtex.cpp @@ -3435,15 +3435,15 @@ GLvoid *uncompressDXTc(GLsizei width, GLsizei height, GLenum format, GLsizei ima case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - DecompressBlockDXT1(x, y, width, (uint8_t*)src, transparent0, simpleAlpha, complexAlpha, pixels); + DecompressBlockDXT1(x, y, width, (uint8_t*)src, transparent0, simpleAlpha, complexAlpha, (uint32_t*)pixels); break; case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: - DecompressBlockDXT3(x, y, width, (uint8_t*)src, transparent0, simpleAlpha, complexAlpha, pixels); + DecompressBlockDXT3(x, y, width, (uint8_t*)src, transparent0, simpleAlpha, complexAlpha, (uint32_t*)pixels); break; case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - DecompressBlockDXT5(x, y, width, (uint8_t*)src, transparent0, simpleAlpha, complexAlpha, pixels); + DecompressBlockDXT5(x, y, width, (uint8_t*)src, transparent0, simpleAlpha, complexAlpha, (uint32_t*)pixels); break; } src+=blocksize; @@ -3641,24 +3641,18 @@ void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDa // adjust target to steer to the proper face, then fall through to the 2D texture path. target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + desc->m_req.m_face; - case GL_TEXTURE_2D: - { + { // check compressed or not if (format->m_chunkSize != 1) { Assert( writeWholeSlice ); //subimage not implemented in this path yet - // compressed path // http://www.opengl.org/sdk/docs/man/xhtml/glCompressedTexImage2D.xml - CompressedTexImage2D( target, // target - desc->m_req.m_mip, // level - intformat, // internalformat - don't use format->m_glIntFormat because we have the SRGB select going on above - slice->m_xSize, // width - slice->m_ySize, // height - 0, // border - slice->m_storageSize, // imageSize - sliceAddress ); // data + if( gGL->m_bHave_GL_EXT_texture_compression_dxt1 ) + gGL->glCompressedTexImage2D( target, desc->m_req.m_mip, intformat, slice->m_xSize, slice->m_ySize, 0, slice->m_storageSize, sliceAddress ); + else + CompressedTexImage2D( target, desc->m_req.m_mip, intformat, slice->m_xSize, slice->m_ySize, 0, slice->m_storageSize, sliceAddress ); } else { @@ -3669,7 +3663,7 @@ void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDa gGL->glPixelStorei( GL_UNPACK_ROW_LENGTH, slice->m_xSize ); // in pixels gGL->glPixelStorei( GL_UNPACK_SKIP_PIXELS, writeBox.xmin ); // in pixels gGL->glPixelStorei( GL_UNPACK_SKIP_ROWS, writeBox.ymin ); // in pixels - + convert_texture(intformat, writeBox.xmax - writeBox.xmin, writeBox.ymax - writeBox.ymin, glDataFormat, glDataType, sliceAddress); gGL->glTexSubImage2D( target, diff --git a/togles/linuxwin/glentrypoints.cpp b/togles/linuxwin/glentrypoints.cpp index 394f4f99..e4f78713 100644 --- a/togles/linuxwin/glentrypoints.cpp +++ b/togles/linuxwin/glentrypoints.cpp @@ -485,12 +485,12 @@ COpenGLEntryPoints::COpenGLEntryPoints() } #endif -#ifndef OSX +/*#ifndef OSX if ( !m_bHave_GL_EXT_texture_sRGB_decode ) { Error( "Required OpenGL extension \"GL_EXT_texture_sRGB_decode\" is not supported. Please update your OpenGL driver.\n" ); } -#endif +#endif*/ } COpenGLEntryPoints::~COpenGLEntryPoints() diff --git a/togles/linuxwin/glmgr.cpp b/togles/linuxwin/glmgr.cpp index cab42e47..7fb01e38 100644 --- a/togles/linuxwin/glmgr.cpp +++ b/togles/linuxwin/glmgr.cpp @@ -1729,14 +1729,13 @@ void GLMContext::PreloadTex( CGLMTex *tex, bool force ) 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; - static int indices[] = { 0, 1, 2 }; - + static unsigned short indices[] = { 0, 1, 2 }; gGL->glEnableVertexAttribArray( 0 ); gGL->glVertexAttribPointer( 0, 3, GL_FLOAT, 0, 0, posns ); - gGL->glDrawRangeElements( GL_TRIANGLES, 0, 2, 3, GL_UNSIGNED_INT, indices); + gGL->glDrawRangeElements( GL_TRIANGLES, 0, 2, 3, GL_UNSIGNED_SHORT, indices); gGL->glDisableVertexAttribArray( 0 ); From 61cd8d0afcaec3010e90ca6cd94d05787afbad0e Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 1 May 2022 20:08:32 +0300 Subject: [PATCH 03/34] fix address sanitizer issues #2 --- engine/audio/private/voice_record_sdl.cpp | 2 +- engine/cl_main.cpp | 2 +- engine/client.cpp | 6 +- engine/console.cpp | 1 + engine/saverestore_filesystem.cpp | 2 +- engine/shadowmgr.cpp | 4 +- materialsystem/cmaterial_queuefriendly.h | 2 + materialsystem/shaderapidx9/shaderapidx8.cpp | 60 +++++++++---------- .../shaderapidx9/shaderdevicedx8.cpp | 2 +- materialsystem/stdshaders/depthwrite.cpp | 2 +- .../stdshaders/particlesphere_dx9.cpp | 7 ++- public/collisionutils.cpp | 10 +++- public/datamap.h | 2 +- public/dispcoll_common.cpp | 2 +- public/icvar.h | 4 +- public/mathlib/ssemath.h | 2 +- public/studio.h | 2 +- public/tier0/threadtools.h | 23 +++++-- public/tier0/tslist.h | 2 +- public/tier1/tier1.h | 3 +- tier0/cpu.cpp | 44 +++++++++----- tier0/vprof.cpp | 2 +- tier1/processor_detect_linux.cpp | 8 ++- togl/linuxwin/glmgr.cpp | 4 +- vphysics/physics_object.cpp | 2 - vphysics/vcollide_parse.cpp | 6 +- vpklib/packedstore.cpp | 4 +- 27 files changed, 119 insertions(+), 91 deletions(-) diff --git a/engine/audio/private/voice_record_sdl.cpp b/engine/audio/private/voice_record_sdl.cpp index 0bfef7fd..142a8f49 100644 --- a/engine/audio/private/voice_record_sdl.cpp +++ b/engine/audio/private/voice_record_sdl.cpp @@ -109,7 +109,7 @@ private: void audioRecordingCallback( void *userdata, uint8 *stream, int len ) { VoiceRecord_SDL *voice = (VoiceRecord_SDL*)userdata; - voice->RenderBuffer( stream, len ); + voice->RenderBuffer( (char*)stream, len ); } VoiceRecord_SDL::VoiceRecord_SDL() : diff --git a/engine/cl_main.cpp b/engine/cl_main.cpp index 9340beea..16ddddf4 100644 --- a/engine/cl_main.cpp +++ b/engine/cl_main.cpp @@ -2751,7 +2751,7 @@ void CL_InitLanguageCvar() else if( szLang ) { ELanguage lang = PchLanguageICUCodeToELanguage(szLang, k_Lang_English); - char *szShortLang = GetLanguageShortName(lang); + const char *szShortLang = GetLanguageShortName(lang); cl_language.SetValue( szShortLang ); } else diff --git a/engine/client.cpp b/engine/client.cpp index c2098376..712131a2 100644 --- a/engine/client.cpp +++ b/engine/client.cpp @@ -1816,14 +1816,14 @@ void CClientState::FinishSignonState_New() // // This is pretty janky, but doesn't really have any cost (and even makes our one-frozen-frame load screen slightly // less likely to trigger OS "not responding" warnings) - extern void V_RenderVGuiOnly(); - V_RenderVGuiOnly(); +// extern void V_RenderVGuiOnly(); +// V_RenderVGuiOnly(); // Before we do anything with the whitelist, make sure we have the proper map pack mounted // this will load the .bsp by setting the world model the string list at the hardcoded index 1. cl.SetModel( 1 ); - V_RenderVGuiOnly(); + //V_RenderVGuiOnly(); // Check for a new whitelist. It's good to do it early in the connection process here because if we wait until later, // the client may have loaded some files w/o the proper whitelist restrictions and we'd have to reload them. diff --git a/engine/console.cpp b/engine/console.cpp index f2a2ba76..b68d68b2 100644 --- a/engine/console.cpp +++ b/engine/console.cpp @@ -865,6 +865,7 @@ CConPanel::CConPanel( vgui::Panel *parent ) : CBasePanel( parent, "CConPanel" ) //----------------------------------------------------------------------------- CConPanel::~CConPanel( void ) { + g_pConPanel = NULL; } void CConPanel::Con_NPrintf( int idx, const char *msg ) diff --git a/engine/saverestore_filesystem.cpp b/engine/saverestore_filesystem.cpp index 3aef07ad..f0d40ec2 100644 --- a/engine/saverestore_filesystem.cpp +++ b/engine/saverestore_filesystem.cpp @@ -1289,7 +1289,7 @@ public: SaveMsg( "DirectoryCopy: AsyncAppend %s, %s\n", szName, pDestFileName ); g_pFileSystem->AsyncAppend( pDestFileName, memcpy( new char[MAX_PATH], list[i].szFileName, MAX_PATH), MAX_PATH, true ); // Filename can only be as long as a map name + extension - g_pFileSystem->AsyncAppend( pDestFileName, new int(fileSize), sizeof(int), true ); + g_pFileSystem->AsyncAppend( pDestFileName, memcpy( new char[sizeof(int)], &fileSize, sizeof(int)), sizeof(int), true ); g_pFileSystem->AsyncAppendFile( pDestFileName, szName ); } } diff --git a/engine/shadowmgr.cpp b/engine/shadowmgr.cpp index 00177ebf..49abd6e8 100644 --- a/engine/shadowmgr.cpp +++ b/engine/shadowmgr.cpp @@ -2071,11 +2071,11 @@ public: private: - static const Vector m_pNormal; + static Vector m_pNormal; static float m_Dist; }; -const Vector CClipPlane::m_pNormal; +Vector CClipPlane::m_pNormal; float CClipPlane::m_Dist; static inline void ClampTexCoord( ShadowVertex_t *pInVertex, ShadowVertex_t *pOutVertex ) diff --git a/materialsystem/cmaterial_queuefriendly.h b/materialsystem/cmaterial_queuefriendly.h index d91792c9..4cdeabe7 100644 --- a/materialsystem/cmaterial_queuefriendly.h +++ b/materialsystem/cmaterial_queuefriendly.h @@ -18,6 +18,8 @@ class CMaterial_QueueFriendly : public IMaterialInternal //wraps a CMaterial with queue friendly functions for game/engine code. materialsystem/shaderapi code should use CMaterial directly. { public: + CMaterial_QueueFriendly() : m_pRealTimeVersion(NULL) {} + virtual const char * GetName() const; virtual const char * GetTextureGroupName() const; virtual PreviewImageRetVal_t GetPreviewImageProperties( int *width, int *height, ImageFormat *imageFormat, bool* isTranslucent ) const; diff --git a/materialsystem/shaderapidx9/shaderapidx8.cpp b/materialsystem/shaderapidx9/shaderapidx8.cpp index 21fd9586..69a510c7 100644 --- a/materialsystem/shaderapidx9/shaderapidx8.cpp +++ b/materialsystem/shaderapidx9/shaderapidx8.cpp @@ -6301,27 +6301,16 @@ int CShaderAPIDx8::GetCurrentDynamicVBSize( void ) FORCEINLINE void CShaderAPIDx8::SetVertexShaderConstantInternal( int var, float const* pVec, int numVecs, bool bForce ) { + Assert( numVecs > 0 ); Assert( pVec ); - // DX8 asm shaders use a constant mapping which has transforms and vertex shader - // specific constants shifted down by 10 constants (two 5-constant light structures) - if ( IsPC() ) + if ( IsPC() || IsPS3() ) { - if ( (g_pHardwareConfig->Caps().m_nDXSupportLevel < 90) && (var >= VERTEX_SHADER_MODULATION_COLOR) ) - { - var -= 10; - } Assert( var + numVecs <= g_pHardwareConfig->NumVertexShaderConstants() ); - if ( !bForce ) - { - int skip = 0; - numVecs = AdjustUpdateRange( pVec, &m_DesiredState.m_pVectorVertexShaderConstant[var], numVecs, &skip ); - if ( !numVecs ) - return; - var += skip; - pVec += skip * 4; - } + if ( !bForce && memcmp( pVec, &m_DynamicState.m_pVectorVertexShaderConstant[var], numVecs * 4 * sizeof( float ) ) == 0 ) + return; + Dx9Device()->SetVertexShaderConstantF( var, pVec, numVecs ); memcpy( &m_DynamicState.m_pVectorVertexShaderConstant[var], pVec, numVecs * 4 * sizeof(float) ); } @@ -6330,12 +6319,10 @@ FORCEINLINE void CShaderAPIDx8::SetVertexShaderConstantInternal( int var, float Assert( var + numVecs <= g_pHardwareConfig->NumVertexShaderConstants() ); } - memcpy( &m_DesiredState.m_pVectorVertexShaderConstant[var], pVec, numVecs * 4 * sizeof(float) ); + if ( IsX360() && var + numVecs > m_MaxVectorVertexShaderConstant ) + m_MaxVectorVertexShaderConstant = var + numVecs; - if ( IsX360() ) - { - m_MaxVectorVertexShaderConstant = max( m_MaxVectorVertexShaderConstant, var + numVecs ); - } + memcpy( &m_DesiredState.m_pVectorVertexShaderConstant[var], pVec, numVecs * 4 * sizeof(float) ); } @@ -6417,29 +6404,40 @@ FORCEINLINE void CShaderAPIDx8::SetPixelShaderConstantInternal( int nStartConst, { Assert( nStartConst + nNumConsts <= g_pHardwareConfig->NumPixelShaderConstants() ); - if ( IsPC() ) + if ( IsPC() || IsPS3() ) { - if ( ! bForce ) + if ( !bForce ) { - int skip = 0; - nNumConsts = AdjustUpdateRange( pValues, &m_DesiredState.m_pVectorPixelShaderConstant[nStartConst], nNumConsts, &skip ); + DWORD* pSrc = (DWORD*)pValues; + DWORD* pDst = (DWORD*)&m_DesiredState.m_pVectorPixelShaderConstant[nStartConst]; + while( nNumConsts && ( pSrc[0] == pDst[0] ) && ( pSrc[1] == pDst[1] ) && ( pSrc[2] == pDst[2] ) && ( pSrc[3] == pDst[3] ) ) + { + pSrc += 4; + pDst += 4; + nNumConsts--; + nStartConst++; + } if ( !nNumConsts ) return; - nStartConst += skip; - pValues += skip * 4; + pValues = reinterpret_cast< float const * >( pSrc ); } Dx9Device()->SetPixelShaderConstantF( nStartConst, pValues, nNumConsts ); memcpy( &m_DynamicState.m_pVectorPixelShaderConstant[nStartConst], pValues, nNumConsts * 4 * sizeof(float) ); } - memcpy( &m_DesiredState.m_pVectorPixelShaderConstant[nStartConst], pValues, nNumConsts * 4 * sizeof(float) ); - - if ( IsX360() ) + if ( IsX360() && nStartConst + nNumConsts > m_MaxVectorPixelShaderConstant ) { - m_MaxVectorPixelShaderConstant = max( m_MaxVectorPixelShaderConstant, nStartConst + nNumConsts ); + m_MaxVectorPixelShaderConstant = nStartConst + nNumConsts; Assert( m_MaxVectorPixelShaderConstant <= 32 ); + if ( m_MaxVectorPixelShaderConstant > 32 ) + { + // NOTE! There really are 224 pixel shader constants on the 360, but we do an optimization that only blasts the first 32 always. + Error( "Don't use more then the first 32 pixel shader constants on the 360!" ); + } } + + memcpy( &m_DesiredState.m_pVectorPixelShaderConstant[nStartConst], pValues, nNumConsts * 4 * sizeof(float) ); } void CShaderAPIDx8::SetPixelShaderConstant( int var, float const* pVec, int numVecs, bool bForce ) diff --git a/materialsystem/shaderapidx9/shaderdevicedx8.cpp b/materialsystem/shaderapidx9/shaderdevicedx8.cpp index 328a1ea3..d4406091 100644 --- a/materialsystem/shaderapidx9/shaderdevicedx8.cpp +++ b/materialsystem/shaderapidx9/shaderdevicedx8.cpp @@ -562,7 +562,7 @@ void CShaderDeviceMgrDx8::CheckVendorDependentAlphaToCoverage( HardwareCaps_t *p ConVar mat_hdr_level( "mat_hdr_level", "2", FCVAR_ARCHIVE ); ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT ); #ifdef DX_TO_GL_ABSTRACTION -ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "20", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY ); +ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "40", FCVAR_CHEAT ); #else ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT ); #endif diff --git a/materialsystem/stdshaders/depthwrite.cpp b/materialsystem/stdshaders/depthwrite.cpp index 06d7690f..8b0fb20d 100644 --- a/materialsystem/stdshaders/depthwrite.cpp +++ b/materialsystem/stdshaders/depthwrite.cpp @@ -198,7 +198,7 @@ BEGIN_VS_SHADER_FLAGS( DepthWrite, "Help for Depth Write", SHADER_NOT_EDITABLE ) vParms.y = 4000.0f; // arbitrary far vParms.z = 0.0f; vParms.w = 0.0f; - pShaderAPI->SetPixelShaderConstant( 1, vParms.Base(), 2 ); + pShaderAPI->SetPixelShaderConstant( 1, vParms.Base(), 1 ); } // DYNAMIC_STATE diff --git a/materialsystem/stdshaders/particlesphere_dx9.cpp b/materialsystem/stdshaders/particlesphere_dx9.cpp index 07b28eb0..ed8881c8 100644 --- a/materialsystem/stdshaders/particlesphere_dx9.cpp +++ b/materialsystem/stdshaders/particlesphere_dx9.cpp @@ -132,15 +132,16 @@ BEGIN_VS_SHADER_FLAGS( ParticleSphere_DX9, "Help for BumpmappedEnvMap", SHADER_N // (It does this by seeing if the intensity*1/distSqr is > 1. If so, then it scales it so // it is equal to 1). const float *f = params[LIGHT_COLOR]->GetVecValue(); - Vector vLightColor( f[0], f[1], f[2] ); + Vector4D vLightColor( f[0], f[1], f[2], 0.f ); float flScale = max( vLightColor.x, max( vLightColor.y, vLightColor.z ) ); if ( flScale < 0.01f ) flScale = 0.01f; - float vScaleVec[3] = { flScale, flScale, flScale }; + + Vector4D vScaleVec = { flScale, flScale, flScale, 0.f }; vLightColor /= flScale; pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_1, vLightColor.Base() ); - pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_2, vScaleVec ); + pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_2, vScaleVec.Base() ); pShaderAPI->SetPixelShaderFogParams( PSREG_FOG_PARAMS ); diff --git a/public/collisionutils.cpp b/public/collisionutils.cpp index 2549a569..e451c385 100644 --- a/public/collisionutils.cpp +++ b/public/collisionutils.cpp @@ -635,14 +635,18 @@ bool IsOBBIntersectingOBB( const Vector &vecOrigin1, const QAngle &vecAngles1, c } // NOTE: This is only very slightly faster on high end PCs and x360 + +#ifdef __SANITIZE_ADDRESS__ +#define USE_SIMD_RAY_CHECKS 0 +#else #define USE_SIMD_RAY_CHECKS 1 +#endif //----------------------------------------------------------------------------- // returns true if there's an intersection between box and ray //----------------------------------------------------------------------------- bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, const Vector& origin, const Vector& vecDelta, float flTolerance ) { - #if USE_SIMD_RAY_CHECKS // Load the unaligned ray/box parameters into SIMD registers fltx4 start = LoadUnaligned3SIMD(origin.Base()); @@ -695,7 +699,7 @@ bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, return IsAllZeros(separation); #else // On the x360, we force use of the SIMD functions. -#if defined(_X360) +#if defined(_X360) if (IsX360()) { fltx4 delta = LoadUnaligned3SIMD(vecDelta.Base()); @@ -766,7 +770,7 @@ bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax, const Vector& origin, const Vector& vecDelta, const Vector& vecInvDelta, float flTolerance ) -{ +{ #if USE_SIMD_RAY_CHECKS // Load the unaligned ray/box parameters into SIMD registers fltx4 start = LoadUnaligned3SIMD(origin.Base()); diff --git a/public/datamap.h b/public/datamap.h index d49a9871..11f06d0c 100644 --- a/public/datamap.h +++ b/public/datamap.h @@ -431,7 +431,7 @@ public: { for ( int i = 0; i < m_Names.Count(); i++ ) { - delete m_Names[i]; + delete[] m_Names[i]; } } diff --git a/public/dispcoll_common.cpp b/public/dispcoll_common.cpp index b5378621..673cbb1c 100644 --- a/public/dispcoll_common.cpp +++ b/public/dispcoll_common.cpp @@ -429,7 +429,7 @@ void CDispCollTree::AABBTree_CreateLeafs( void ) } } -void CDispCollTree::AABBTree_GenerateBoxes_r( int nodeIndex, Vector *pMins, Vector *pMaxs ) +void __attribute__((no_sanitize("address"))) CDispCollTree::AABBTree_GenerateBoxes_r( int nodeIndex, Vector *pMins, Vector *pMaxs ) { // leaf ClearBounds( *pMins, *pMaxs ); diff --git a/public/icvar.h b/public/icvar.h index 50176805..95423dcc 100644 --- a/public/icvar.h +++ b/public/icvar.h @@ -195,9 +195,7 @@ inline ConCommandBase * ICvar::Iterator::Get( void ) // don't have to include tier1.h //----------------------------------------------------------------------------- -// These are marked DLL_EXPORT for Linux. -DLL_EXPORT ICvar *cvar; +extern ICvar *cvar; extern ICvar *g_pCVar; - #endif // ICVAR_H diff --git a/public/mathlib/ssemath.h b/public/mathlib/ssemath.h index d5617c4b..6a73b3f6 100644 --- a/public/mathlib/ssemath.h +++ b/public/mathlib/ssemath.h @@ -23,7 +23,7 @@ #define USE_STDC_FOR_SIMD 0 #endif -#if (!defined (__arm__) && !defined(_X360) && (USE_STDC_FOR_SIMD == 0)) +#if !(defined(_X360) && (USE_STDC_FOR_SIMD == 0)) #define _SSE1 1 #endif diff --git a/public/studio.h b/public/studio.h index 17bb0659..ae20a045 100644 --- a/public/studio.h +++ b/public/studio.h @@ -83,7 +83,7 @@ Studio models are position independent, so the cache manager can move them. #define MAXSTUDIOFLEXDESC 1024 // maximum number of low level flexes (actual morph targets) #define MAXSTUDIOFLEXCTRL 96 // maximum number of flexcontrollers (input sliders) #define MAXSTUDIOPOSEPARAM 24 -#define MAXSTUDIOBONECTRLS 4 +#define MAXSTUDIOBONECTRLS 5 #define MAXSTUDIOANIMBLOCKS 256 #define MAXSTUDIOBONEBITS 7 // NOTE: MUST MATCH MAXSTUDIOBONES diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h index f5328699..d7655b14 100644 --- a/public/tier0/threadtools.h +++ b/public/tier0/threadtools.h @@ -1182,7 +1182,11 @@ private: class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock { public: - CThreadSpinRWLock() { COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); Assert( (intp)this % 8 == 0 ); memset( this, 0, sizeof( *this ) ); } + CThreadSpinRWLock() + { + COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); + Assert( (intp)this % 8 == 0 ); + } bool TryLockForWrite(); bool TryLockForRead(); @@ -1200,11 +1204,18 @@ public: void UnlockWrite() const { const_cast(this)->UnlockWrite(); } private: + struct LockInfo_t + { + LockInfo_t(uint32 thread_id = 0, int readers = 0) { - uint32 m_writerId; - int m_nReaders; - }; + m_writerId = thread_id; + m_nReaders = readers; + } + + uint32 m_writerId; + int m_nReaders; + }; bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ); bool TryLockForWrite( const uint32 threadId ); @@ -1751,8 +1762,8 @@ inline bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId ) return false; } - static const LockInfo_t oldValue = { 0, 0 }; - LockInfo_t newValue = { threadId, 0 }; + static const LockInfo_t oldValue( 0, 0 ); + LockInfo_t newValue( threadId, 0 ); const bool bSuccess = AssignIf( newValue, oldValue ); #if defined(_X360) if ( bSuccess ) diff --git a/public/tier0/tslist.h b/public/tier0/tslist.h index d6610e0c..ab530c59 100644 --- a/public/tier0/tslist.h +++ b/public/tier0/tslist.h @@ -231,7 +231,7 @@ public: #endif } - TSLNodeBase_t *Pop() + __attribute__((no_sanitize("address"))) TSLNodeBase_t *Pop() { #ifdef USE_NATIVE_SLIST #ifdef _X360 diff --git a/public/tier1/tier1.h b/public/tier1/tier1.h index ac790673..ee63d4a5 100644 --- a/public/tier1/tier1.h +++ b/public/tier1/tier1.h @@ -30,8 +30,7 @@ class IProcessUtils; // allowing link libraries to access tier1 library interfaces //----------------------------------------------------------------------------- -// These are marked DLL_EXPORT for Linux. -DLL_EXPORT ICvar *cvar; +extern ICvar *cvar; extern ICvar *g_pCVar; extern IProcessUtils *g_pProcessUtils; diff --git a/tier0/cpu.cpp b/tier0/cpu.cpp index cf6fd787..d5bf6c9b 100644 --- a/tier0/cpu.cpp +++ b/tier0/cpu.cpp @@ -142,9 +142,9 @@ static bool IsWin98OrOlder() static bool CheckSSETechnology(void) { -#if defined( __ARM__ ) +#if defined(__SANITIZE_ADDRESS__) return false; -#elif defined( _X360 ) || defined( _PS3 ) +#elif defined( _X360 ) || defined( _PS3 ) || defined (__arm__) return true; #else if ( IsWin98OrOlder() ) { @@ -162,8 +162,10 @@ static bool CheckSSETechnology(void) static bool CheckSSE2Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) return false; +#elif defined (__arm__) + return true; #else unsigned long eax,ebx,edx,unused; if ( !cpuid(1,eax,ebx,unused,edx) ) @@ -175,8 +177,10 @@ static bool CheckSSE2Technology(void) bool CheckSSE3Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) return false; +#elif defined (__arm__) + return true; #else unsigned long eax,ebx,edx,ecx; if( !cpuid(1,eax,ebx,ecx,edx) ) @@ -188,8 +192,10 @@ bool CheckSSE3Technology(void) bool CheckSSSE3Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) return false; +#elif defined (__arm__) + return true; #else // SSSE 3 is implemented by both Intel and AMD // detection is done the same way for both vendors @@ -203,8 +209,10 @@ bool CheckSSSE3Technology(void) bool CheckSSE41Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) return false; +#elif defined (__arm__) + return true; #else // SSE 4.1 is implemented by both Intel and AMD // detection is done the same way for both vendors @@ -219,8 +227,10 @@ bool CheckSSE41Technology(void) bool CheckSSE42Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) return false; +#elif defined (__arm__) + return true; #else // SSE4.2 is an Intel-only feature @@ -239,8 +249,10 @@ bool CheckSSE42Technology(void) bool CheckSSE4aTechnology( void ) { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) return false; +#elif defined (__arm__) + return true; #else // SSE 4a is an AMD-only feature @@ -259,7 +271,7 @@ bool CheckSSE4aTechnology( void ) static bool Check3DNowTechnology(void) { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined (__arm__) || defined(__SANITIZE_ADDRESS__) return false; #else unsigned long eax, unused; @@ -279,7 +291,7 @@ static bool Check3DNowTechnology(void) static bool CheckCMOVTechnology() { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined (__arm__) || defined(__SANITIZE_ADDRESS__) return false; #else unsigned long eax,ebx,edx,unused; @@ -292,7 +304,7 @@ static bool CheckCMOVTechnology() static bool CheckFCMOVTechnology(void) { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined (__arm__) || defined(__SANITIZE_ADDRESS__) return false; #else unsigned long eax,ebx,edx,unused; @@ -305,7 +317,7 @@ static bool CheckFCMOVTechnology(void) static bool CheckRDTSCTechnology(void) { -#if defined( _X360 ) || defined( _PS3 ) +#if defined( _X360 ) || defined( _PS3 ) || defined (__arm__) || defined(__SANITIZE_ADDRESS__) return false; #else unsigned long eax,ebx,edx,unused; @@ -321,11 +333,13 @@ const tchar* GetProcessorVendorId() { #if defined( _X360 ) || defined( _PS3 ) return "PPC"; +#elif defined ( __arm__ ) + return "ARM"; #else unsigned long unused, VendorIDRegisters[3]; static tchar VendorID[13]; - + memset( VendorID, 0, sizeof(VendorID) ); if ( !cpuid(0,unused, VendorIDRegisters[0], VendorIDRegisters[2], VendorIDRegisters[1] ) ) { @@ -375,7 +389,7 @@ static bool HTSupported(void) // Check to see if this is a Pentium 4 or later processor if (((reg_eax & FAMILY_ID) == PENTIUM4_ID) || (reg_eax & EXT_FAMILY_ID)) - if (vendor_id[0] == 'uneG' && vendor_id[1] == 'Ieni' && vendor_id[2] == 'letn') + if (vendor_id[0] == 0x756E6547 && vendor_id[1] == 0x49656E69 && vendor_id[2] == 0x6C65746E) return (reg_edx & HT_BIT) != 0; // Genuine Intel Processor with Hyper-Threading Technology return false; // This is not a genuine Intel processor. @@ -391,7 +405,7 @@ static uint8 LogicalProcessorsPerPackage(void) // EBX[23:16] indicate number of logical processors per package const unsigned NUM_LOGICAL_BITS = 0x00FF0000; - unsigned long unused, reg_ebx = 0; + unsigned long unused, reg_ebx = 0; if ( !HTSupported() ) return 1; diff --git a/tier0/vprof.cpp b/tier0/vprof.cpp index bff5868f..4b3d78b8 100644 --- a/tier0/vprof.cpp +++ b/tier0/vprof.cpp @@ -1516,7 +1516,7 @@ void CVProfile::Term() { delete [] m_pBudgetGroups[i].m_pName; } - delete m_pBudgetGroups; + delete[] m_pBudgetGroups; m_nBudgetGroupNames = m_nBudgetGroupNamesAllocated = 0; m_pBudgetGroups = NULL; diff --git a/tier1/processor_detect_linux.cpp b/tier1/processor_detect_linux.cpp index 189fef8a..11248ab2 100644 --- a/tier1/processor_detect_linux.cpp +++ b/tier1/processor_detect_linux.cpp @@ -6,12 +6,16 @@ // $NoKeywords: $ //=============================================================================// - -#if defined (__arm__) +#if defined __SANITIZE_ADDRESS__ bool CheckMMXTechnology(void) { return false; } bool CheckSSETechnology(void) { return false; } bool CheckSSE2Technology(void) { return false; } bool Check3DNowTechnology(void) { return false; } +#elif defined (__arm__) +bool CheckMMXTechnology(void) { return true; } +bool CheckSSETechnology(void) { return true; } +bool CheckSSE2Technology(void) { return true; } +bool Check3DNowTechnology(void) { return false; } #else #define cpuid(in,a,b,c,d) \ diff --git a/togl/linuxwin/glmgr.cpp b/togl/linuxwin/glmgr.cpp index 1c18720f..61fc979d 100644 --- a/togl/linuxwin/glmgr.cpp +++ b/togl/linuxwin/glmgr.cpp @@ -1788,14 +1788,14 @@ void GLMContext::PreloadTex( CGLMTex *tex, bool force ) 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; - static int indices[] = { 0, 1, 2 }; + static short indices[] = { 0, 1, 2 }; gGL->glEnableVertexAttribArray( 0 ); gGL->glVertexAttribPointer( 0, 3, GL_FLOAT, 0, 0, posns ); - gGL->glDrawRangeElements( GL_TRIANGLES, 0, 3, 3, GL_UNSIGNED_INT, indices); + gGL->glDrawRangeElements( GL_TRIANGLES, 0, 2, 3, GL_UNSIGNED_SHORT, indices); gGL->glDisableVertexAttribArray( 0 ); diff --git a/vphysics/physics_object.cpp b/vphysics/physics_object.cpp index 7693be3b..69f78f6a 100644 --- a/vphysics/physics_object.cpp +++ b/vphysics/physics_object.cpp @@ -647,8 +647,6 @@ void CPhysicsObject::SetInertia( const Vector &inertia ) ri.k[1] = IVP_Inline_Math::fabsd(ri.k[1]); ri.k[2] = IVP_Inline_Math::fabsd(ri.k[2]); - if( ri.k[0] > 1e14f ) ri.k[0] = 1e14f; if( ri.k[1] > 1e14f ) ri.k[1] = 1e14f; if( ri.k[2] > 1e14f ) ri.k[2] = 1e14f; - m_pObject->get_core()->set_rotation_inertia( &ri ); } diff --git a/vphysics/vcollide_parse.cpp b/vphysics/vcollide_parse.cpp index f480b76c..071a9ac5 100644 --- a/vphysics/vcollide_parse.cpp +++ b/vphysics/vcollide_parse.cpp @@ -174,8 +174,7 @@ void CVPhysicsParse::ParseSolid( solid_t *pSolid, IVPhysicsKeyHandler *unknownKe } else if ( !Q_stricmp( key, "inertia" ) ) { - float inertia = atof(value); - pSolid->params.inertia = (inertia > 1e14f) ? 1e14f : inertia; + pSolid->params.inertia = atof(value); } else if ( !Q_stricmp( key, "damping" ) ) { @@ -469,8 +468,7 @@ void CVPhysicsParse::ParseVehicleWheel( vehicle_wheelparams_t &wheel ) } else if ( !Q_stricmp( key, "inertia" ) ) { - float inertia = atof(value); - wheel.inertia = (inertia > 1e14f) ? 1e14f : inertia; + wheel.inertia = atof(value); } else if ( !Q_stricmp( key, "damping" ) ) { diff --git a/vpklib/packedstore.cpp b/vpklib/packedstore.cpp index 33f28b56..a6671ed2 100644 --- a/vpklib/packedstore.cpp +++ b/vpklib/packedstore.cpp @@ -473,11 +473,11 @@ CPackedStore::~CPackedStore( void ) } // Free the FindFirst cache data - m_directoryList.PurgeAndDeleteElements(); + m_directoryList.PurgeAndDeleteElementsArray(); FOR_EACH_MAP( m_dirContents, i ) { - m_dirContents[i]->PurgeAndDeleteElements(); + m_dirContents[i]->PurgeAndDeleteElementsArray(); delete m_dirContents[i]; } } From 600695b15f04118c7a859c8ce3f956eb3b415dce Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 1 May 2022 20:09:55 +0300 Subject: [PATCH 04/34] game: init uninitialized variables --- game/client/c_baseanimating.cpp | 4 +++ game/client/c_baseentity.cpp | 11 +++--- game/client/c_baseflex.h | 2 +- game/client/c_func_occluder.cpp | 2 +- game/client/c_te_legacytempents.cpp | 2 +- game/client/hud_basechat.cpp | 3 +- game/client/view.cpp | 2 +- game/client/viewrender.cpp | 45 +++++-------------------- game/server/ai_basenpc.cpp | 1 + game/server/ai_behavior_lead.cpp | 2 +- game/server/ai_squad.cpp | 6 ++-- game/server/func_dust.cpp | 2 +- game/server/hl1/hl1_ents.cpp | 2 +- game/server/hl2/npc_scanner.cpp | 2 +- game/server/nav_mesh.h | 2 +- game/shared/Sprite.cpp | 2 +- game/shared/basecombatweapon_shared.cpp | 3 +- 17 files changed, 37 insertions(+), 56 deletions(-) diff --git a/game/client/c_baseanimating.cpp b/game/client/c_baseanimating.cpp index c41ff46b..5727d7b0 100644 --- a/game/client/c_baseanimating.cpp +++ b/game/client/c_baseanimating.cpp @@ -677,6 +677,8 @@ C_BaseAnimating::C_BaseAnimating() : m_pRagdoll = NULL; m_builtRagdoll = false; m_hitboxBoneCacheHandle = 0; + m_nHitboxSet = 0; + int i; for ( i = 0; i < ARRAYSIZE( m_flEncodedController ); i++ ) { @@ -694,6 +696,8 @@ C_BaseAnimating::C_BaseAnimating() : m_bStoreRagdollInfo = false; m_pRagdollInfo = NULL; + m_pJiggleBones = NULL; + m_pBoneMergeCache = NULL; m_flPlaybackRate = 1.0f; diff --git a/game/client/c_baseentity.cpp b/game/client/c_baseentity.cpp index 8f40d7ef..ca8c8348 100644 --- a/game/client/c_baseentity.cpp +++ b/game/client/c_baseentity.cpp @@ -903,6 +903,7 @@ C_BaseEntity::C_BaseEntity() : m_DataChangeEventRef = -1; m_EntClientFlags = 0; + m_bEnableRenderingClipPlane = false; m_iParentAttachment = 0; m_nRenderFXBlend = 255; @@ -940,10 +941,12 @@ C_BaseEntity::C_BaseEntity() : #if !defined( NO_ENTITY_PREDICTION ) m_pPredictionContext = NULL; #endif - //NOTE: not virtual! we are in the constructor! C_BaseEntity::Clear(); - + + SetModelName( NULL_STRING ); + m_iClassname = NULL_STRING; + m_InterpolationListEntry = 0xFFFF; m_TeleportListEntry = 0xFFFF; @@ -984,7 +987,6 @@ C_BaseEntity::~C_BaseEntity() void C_BaseEntity::Clear( void ) { m_bDormant = true; - m_nCreationTick = -1; m_RefEHandle.Term(); m_ModelInstance = MODEL_INSTANCE_INVALID; @@ -998,6 +1000,7 @@ void C_BaseEntity::Clear( void ) SetLocalOrigin( vec3_origin ); SetLocalAngles( vec3_angle ); model = NULL; + m_pOriginalData = NULL; m_vecAbsOrigin.Init(); m_angAbsRotation.Init(); m_vecVelocity.Init(); @@ -3741,7 +3744,7 @@ void C_BaseEntity::AddColoredDecal( const Vector& rayStart, const Vector& rayEnd case mod_brush: { - color32 cColor32 = { cColor.r(), cColor.g(), cColor.b(), cColor.a() }; + color32 cColor32 = { (uint8)cColor.r(), (uint8)cColor.g(), (uint8)cColor.b(), (uint8)cColor.a() }; effects->DecalColorShoot( decalIndex, index, model, GetAbsOrigin(), GetAbsAngles(), decalCenter, 0, 0, cColor32 ); } break; diff --git a/game/client/c_baseflex.h b/game/client/c_baseflex.h index 71cee3d8..56c86cb3 100644 --- a/game/client/c_baseflex.h +++ b/game/client/c_baseflex.h @@ -91,7 +91,7 @@ struct FS_LocalToGlobal_t const flexsettinghdr_t *m_Key; int m_nCount; - int *m_Mapping; + int *m_Mapping = NULL; }; bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs ); diff --git a/game/client/c_func_occluder.cpp b/game/client/c_func_occluder.cpp index b9c2f56f..32d01687 100644 --- a/game/client/c_func_occluder.cpp +++ b/game/client/c_func_occluder.cpp @@ -24,7 +24,7 @@ public: private: int m_nOccluderIndex; - bool m_bActive; + bool m_bActive = false; }; IMPLEMENT_CLIENTCLASS_DT( C_FuncOccluder, DT_FuncOccluder, CFuncOccluder ) diff --git a/game/client/c_te_legacytempents.cpp b/game/client/c_te_legacytempents.cpp index 3c8adf68..831715a8 100644 --- a/game/client/c_te_legacytempents.cpp +++ b/game/client/c_te_legacytempents.cpp @@ -1539,7 +1539,7 @@ void CTempEnts::BloodSprite( const Vector &org, int r, int g, int b, int a, int { C_LocalTempEntity *pTemp; int frameCount = modelinfo->GetModelFrameCount( model ); - color32 impactcolor = { r, g, b, a }; + color32 impactcolor = { (uint8)r, (uint8)g, (uint8)b, (uint8)a }; //Large, single blood sprite is a high-priority tent if ( ( pTemp = TempEntAllocHigh( org, model ) ) != NULL ) diff --git a/game/client/hud_basechat.cpp b/game/client/hud_basechat.cpp index 69d67862..db9dc2fa 100644 --- a/game/client/hud_basechat.cpp +++ b/game/client/hud_basechat.cpp @@ -633,6 +633,7 @@ CBaseHudChat::CBaseHudChat( const char *pElementName ) } m_pChatHistory = new CHudChatHistory( this, "HudChatHistory" ); + m_pFilterPanel = NULL; CreateChatLines(); CreateChatInputLine(); @@ -1829,4 +1830,4 @@ void CBaseHudChat::FireGameEvent( IGameEvent *event ) ChatPrintf( player->entindex(), CHAT_FILTER_NONE, "(SourceTV) %s", event->GetString( "text" ) ); } #endif -} \ No newline at end of file +} diff --git a/game/client/view.cpp b/game/client/view.cpp index 333a2756..3c28d89a 100644 --- a/game/client/view.cpp +++ b/game/client/view.cpp @@ -931,7 +931,7 @@ void CViewRender::WriteSaveGameScreenshotOfSize( const char *pFilename, int widt { // Write TGA format to buffer int iMaxTGASize = 1024 + ( nSrcWidth * nSrcHeight * 4 ); - void *pTGA = malloc( iMaxTGASize ); + void *pTGA = new char[ iMaxTGASize ]; buffer.SetExternalBuffer( pTGA, iMaxTGASize, 0 ); bWriteResult = TGAWriter::WriteToBuffer( pSrcImage, buffer, nSrcWidth, nSrcHeight, IMAGE_FORMAT_RGB888, IMAGE_FORMAT_RGB888 ); diff --git a/game/client/viewrender.cpp b/game/client/viewrender.cpp index a629071b..0240c238 100644 --- a/game/client/viewrender.cpp +++ b/game/client/viewrender.cpp @@ -1435,8 +1435,8 @@ static void GetFogColorTransition( fogparams_t *pFogParams, float *pColorPrimary { float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration ); - float flPrimaryColorLerp[3] = { pFogParams->colorPrimaryLerpTo.GetR(), pFogParams->colorPrimaryLerpTo.GetG(), pFogParams->colorPrimaryLerpTo.GetB() }; - float flSecondaryColorLerp[3] = { pFogParams->colorSecondaryLerpTo.GetR(), pFogParams->colorSecondaryLerpTo.GetG(), pFogParams->colorSecondaryLerpTo.GetB() }; + float flPrimaryColorLerp[3] = { (float)pFogParams->colorPrimaryLerpTo.GetR(), (float)pFogParams->colorPrimaryLerpTo.GetG(), (float)pFogParams->colorPrimaryLerpTo.GetB() }; + float flSecondaryColorLerp[3] = { (float)pFogParams->colorSecondaryLerpTo.GetR(), (float)pFogParams->colorSecondaryLerpTo.GetG(), (float)pFogParams->colorSecondaryLerpTo.GetB() }; CheckAndTransitionColor( flPercent, pColorPrimary, flPrimaryColorLerp ); CheckAndTransitionColor( flPercent, pColorSecondary, flSecondaryColorLerp ); @@ -1459,8 +1459,8 @@ static void GetFogColor( fogparams_t *pFogParams, float *pColor ) } else { - float flPrimaryColor[3] = { pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetG(), pFogParams->colorPrimary.GetB() }; - float flSecondaryColor[3] = { pFogParams->colorSecondary.GetR(), pFogParams->colorSecondary.GetG(), pFogParams->colorSecondary.GetB() }; + float flPrimaryColor[3] = { (float)pFogParams->colorPrimary.GetR(), (float)pFogParams->colorPrimary.GetG(), (float)pFogParams->colorPrimary.GetB() }; + float flSecondaryColor[3] = { (float)pFogParams->colorSecondary.GetR(), (float)pFogParams->colorSecondary.GetG(), (float)pFogParams->colorSecondary.GetB() }; GetFogColorTransition( pFogParams, flPrimaryColor, flSecondaryColor ); @@ -2689,6 +2689,7 @@ bool DoesViewPlaneIntersectWater( float waterZ, int leafWaterDataID ) // &view - the camera view to render from // nClearFlags - how to clear the buffer //----------------------------------------------------------------------------- + void CViewRender::ViewDrawScene_PortalStencil( const CViewSetup &viewIn, ViewCustomVisibility_t *pCustomVisibility ) { VPROF( "CViewRender::ViewDrawScene_PortalStencil" ); @@ -2700,28 +2701,6 @@ void CViewRender::ViewDrawScene_PortalStencil( const CViewSetup &viewIn, ViewCus QAngle vecOldAngles = CurrentViewAngles(); int iCurrentViewID = g_CurrentViewID; - int iRecursionLevel = g_pPortalRender->GetViewRecursionLevel(); - Assert( iRecursionLevel > 0 ); - - //get references to reflection textures - CTextureReference pPrimaryWaterReflectionTexture; - pPrimaryWaterReflectionTexture.Init( GetWaterReflectionTexture() ); - CTextureReference pReplacementWaterReflectionTexture; - pReplacementWaterReflectionTexture.Init( portalrendertargets->GetWaterReflectionTextureForStencilDepth( iRecursionLevel ) ); - - //get references to refraction textures - CTextureReference pPrimaryWaterRefractionTexture; - pPrimaryWaterRefractionTexture.Init( GetWaterRefractionTexture() ); - CTextureReference pReplacementWaterRefractionTexture; - pReplacementWaterRefractionTexture.Init( portalrendertargets->GetWaterRefractionTextureForStencilDepth( iRecursionLevel ) ); - - - //swap texture contents for the primary render targets with those we set aside for this recursion level - if( pReplacementWaterReflectionTexture != NULL ) - pPrimaryWaterReflectionTexture->SwapContents( pReplacementWaterReflectionTexture ); - - if( pReplacementWaterRefractionTexture != NULL ) - pPrimaryWaterRefractionTexture->SwapContents( pReplacementWaterRefractionTexture ); bool bDrew3dSkybox = false; SkyboxVisibility_t nSkyboxVisible = SKYBOX_NOT_VISIBLE; @@ -2738,7 +2717,7 @@ void CViewRender::ViewDrawScene_PortalStencil( const CViewSetup &viewIn, ViewCus //generate unique view ID's for each stencil view view_id_t iNewViewID = (view_id_t)g_pPortalRender->GetCurrentViewId(); SetupCurrentView( view.origin, view.angles, (view_id_t)iNewViewID ); - + // update vis data unsigned int visFlags; SetupVis( view, visFlags, pCustomVisibility ); @@ -2757,10 +2736,10 @@ void CViewRender::ViewDrawScene_PortalStencil( const CViewSetup &viewIn, ViewCus DetermineWaterRenderInfo( fogInfo, waterInfo ); if ( waterInfo.m_bCheapWater ) - { + { cplane_t glassReflectionPlane; if ( IsReflectiveGlassInView( viewIn, glassReflectionPlane ) ) - { + { CRefPtr pGlassReflectionView = new CReflectiveGlassView( this ); pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, glassReflectionPlane ); AddViewToScene( pGlassReflectionView ); @@ -2813,14 +2792,6 @@ void CViewRender::ViewDrawScene_PortalStencil( const CViewSetup &viewIn, ViewCus // Return to the previous view SetupCurrentView( vecOldOrigin, vecOldAngles, (view_id_t)iCurrentViewID ); g_CurrentViewID = iCurrentViewID; //just in case the cast to view_id_t screwed up the id # - - - //swap back the water render targets - if( pReplacementWaterReflectionTexture != NULL ) - pPrimaryWaterReflectionTexture->SwapContents( pReplacementWaterReflectionTexture ); - - if( pReplacementWaterRefractionTexture != NULL ) - pPrimaryWaterRefractionTexture->SwapContents( pReplacementWaterRefractionTexture ); } void CViewRender::Draw3dSkyboxworld_Portal( const CViewSetup &view, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget ) diff --git a/game/server/ai_basenpc.cpp b/game/server/ai_basenpc.cpp index 1db9eab1..0acc458f 100644 --- a/game/server/ai_basenpc.cpp +++ b/game/server/ai_basenpc.cpp @@ -11331,6 +11331,7 @@ CAI_BaseNPC::CAI_BaseNPC(void) m_flHeadYaw = 0; m_flHeadPitch = 0; m_spawnEquipment = NULL_STRING; + m_SquadName = NULL_STRING; m_pEnemies = new CAI_Enemies; m_bIgnoreUnseenEnemies = false; m_flEyeIntegRate = 0.95; diff --git a/game/server/ai_behavior_lead.cpp b/game/server/ai_behavior_lead.cpp index 6a316c1e..a844f546 100644 --- a/game/server/ai_behavior_lead.cpp +++ b/game/server/ai_behavior_lead.cpp @@ -1543,7 +1543,7 @@ void CAI_LeadGoal::InputActivate( inputdata_t &inputdata ) AI_LeadArgs_t leadArgs = { GetGoalEntityName(), STRING(m_iszWaitPointName), - m_spawnflags, + (unsigned)m_spawnflags, m_flWaitDistance, m_flLeadDistance, m_flRetrieveDistance, diff --git a/game/server/ai_squad.cpp b/game/server/ai_squad.cpp index 17e0c18f..9ad4b6bb 100644 --- a/game/server/ai_squad.cpp +++ b/game/server/ai_squad.cpp @@ -153,7 +153,7 @@ END_DATADESC() //------------------------------------- -CAI_Squad::CAI_Squad(string_t newName) +CAI_Squad::CAI_Squad(string_t newName) #ifndef PER_ENEMY_SQUADSLOTS : m_squadSlotsUsed(MAX_SQUADSLOTS) #endif @@ -163,7 +163,7 @@ CAI_Squad::CAI_Squad(string_t newName) //------------------------------------- -CAI_Squad::CAI_Squad() +CAI_Squad::CAI_Squad() #ifndef PER_ENEMY_SQUADSLOTS : m_squadSlotsUsed(MAX_SQUADSLOTS) #endif @@ -175,7 +175,7 @@ CAI_Squad::CAI_Squad() void CAI_Squad::Init(string_t newName) { - m_Name = AllocPooledString( STRING(newName) ); + m_Name = newName; m_pNextSquad = NULL; m_flSquadSoundWaitTime = 0; m_SquadMembers.RemoveAll(); diff --git a/game/server/func_dust.cpp b/game/server/func_dust.cpp index 3e3fcb21..5bf15160 100644 --- a/game/server/func_dust.cpp +++ b/game/server/func_dust.cpp @@ -162,7 +162,7 @@ void CFunc_Dust::Spawn() //Since keyvalues can arrive in any order, and UTIL_StringToColor32 stomps alpha, //install the alpha value here. - color32 clr = { m_Color.m_Value.r, m_Color.m_Value.g, m_Color.m_Value.b, m_iAlpha }; + color32 clr = { m_Color.m_Value.r, m_Color.m_Value.g, m_Color.m_Value.b, (uint8)m_iAlpha }; m_Color.Set( clr ); BaseClass::Spawn(); diff --git a/game/server/hl1/hl1_ents.cpp b/game/server/hl1/hl1_ents.cpp index c5ab56ef..5aba5f29 100644 --- a/game/server/hl1/hl1_ents.cpp +++ b/game/server/hl1/hl1_ents.cpp @@ -289,7 +289,7 @@ bool CMultiManager::KeyValue( const char *szKeyName, const char *szValue ) { char tmp[128]; - UTIL_StripToken( szKeyName, tmp, Q_ARRAYSIZE( tmp ) ); + UTIL_StripToken( szKeyName, tmp ); m_iTargetName [ m_cTargets ] = AllocPooledString( tmp ); m_flTargetDelay [ m_cTargets ] = atof (szValue); m_cTargets++; diff --git a/game/server/hl2/npc_scanner.cpp b/game/server/hl2/npc_scanner.cpp index 031ce6d9..e0ed558a 100644 --- a/game/server/hl2/npc_scanner.cpp +++ b/game/server/hl2/npc_scanner.cpp @@ -1988,7 +1988,7 @@ void CNPC_CScanner::BlindFlashTarget( CBaseEntity *pTarget ) if ( tr.startsolid == false && tr.fraction == 1.0) { - color32 white = { 255, 255, 255, SCANNER_FLASH_MAX_VALUE * dotPr }; + color32 white = { 255, 255, 255, (uint8)(SCANNER_FLASH_MAX_VALUE * dotPr) }; if ( ( g_pMaterialSystemHardwareConfig != NULL ) && ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE ) ) { diff --git a/game/server/nav_mesh.h b/game/server/nav_mesh.h index 24faed41..fe5c98d9 100644 --- a/game/server/nav_mesh.h +++ b/game/server/nav_mesh.h @@ -199,7 +199,7 @@ public: unsigned int operator()( const NavVisPair_t &item ) const { COMPILE_TIME_ASSERT( sizeof(CNavArea *) == 4 ); - int key[2] = { (int)item.pAreas[0] + item.pAreas[1]->GetID(), (int)item.pAreas[1] + item.pAreas[0]->GetID() }; + int key[2] = { (int)(item.pAreas[0] + item.pAreas[1]->GetID()), (int)(item.pAreas[1] + item.pAreas[0]->GetID()) }; return Hash8( key ); } }; diff --git a/game/shared/Sprite.cpp b/game/shared/Sprite.cpp index 2393f148..8eed62e4 100644 --- a/game/shared/Sprite.cpp +++ b/game/shared/Sprite.cpp @@ -174,7 +174,7 @@ BEGIN_NETWORK_TABLE( CSprite, DT_Sprite ) END_NETWORK_TABLE() -CSprite::CSprite() +CSprite::CSprite() : BaseClass() { m_flGlowProxySize = 2.0f; m_flHDRColorScale = 1.0f; diff --git a/game/shared/basecombatweapon_shared.cpp b/game/shared/basecombatweapon_shared.cpp index 754919d3..0b35d147 100644 --- a/game/shared/basecombatweapon_shared.cpp +++ b/game/shared/basecombatweapon_shared.cpp @@ -60,7 +60,7 @@ ConVar tf_weapon_criticals_bucket_bottom( "tf_weapon_criticals_bucket_bottom", " ConVar tf_weapon_criticals_bucket_default( "tf_weapon_criticals_bucket_default", "300.0", FCVAR_REPLICATED | FCVAR_CHEAT ); #endif // TF -CBaseCombatWeapon::CBaseCombatWeapon() +CBaseCombatWeapon::CBaseCombatWeapon() : BASECOMBATWEAPON_DERIVED_FROM() { // Constructor must call this // CONSTRUCT_PREDICTABLE( CBaseCombatWeapon ); @@ -77,6 +77,7 @@ CBaseCombatWeapon::CBaseCombatWeapon() m_nViewModelIndex = 0; m_bFlipViewModel = false; + m_iSubType = 0; #if defined( CLIENT_DLL ) m_iState = m_iOldState = WEAPON_NOT_CARRIED; From 1218fa659c2e832f550ab5f0467175a1a8dd820d Mon Sep 17 00:00:00 2001 From: nillerusr Date: Fri, 13 May 2022 12:16:34 +0300 Subject: [PATCH 05/34] engine: remove useless vprof for rcon --- engine/cl_rcon.cpp | 186 ------------------------------------- engine/cl_rcon.h | 46 --------- engine/sv_remoteaccess.cpp | 57 ------------ public/tier0/vprof.h | 6 +- 4 files changed, 3 insertions(+), 292 deletions(-) diff --git a/engine/cl_rcon.cpp b/engine/cl_rcon.cpp index ff732ec6..b26c3085 100644 --- a/engine/cl_rcon.cpp +++ b/engine/cl_rcon.cpp @@ -56,12 +56,10 @@ public: // Immediately try to start vprofiling // Also, enable cheats on this client only Cmd_SetRptActive( true ); - StartVProfData(); } virtual void OnSocketClosed( SocketHandle_t hSocket, const netadr_t & netAdr, void* pData ) { - StopVProfData(); Cmd_SetRptActive( false ); BaseClass::OnSocketClosed( hSocket, netAdr, pData ); } @@ -98,135 +96,6 @@ static void RconAddressChanged_f( IConVar *pConVar, const char *pOldString, floa static ConVar rcon_address( "rcon_address", "", FCVAR_SERVER_CANNOT_QUERY|FCVAR_DONTRECORD, "Address of remote server if sending unconnected rcon commands (format x.x.x.x:p) ", RconAddressChanged_f ); - - -//----------------------------------------------------------------------------- -// Implementation of remote vprof -//----------------------------------------------------------------------------- -CRConVProfExport::CRConVProfExport() -{ -} - -void CRConVProfExport::AddListener() -{ -} - -void CRConVProfExport::RemoveListener() -{ -} - -void CRConVProfExport::SetBudgetFlagsFilter( int filter ) -{ -} - -int CRConVProfExport::GetNumBudgetGroups() -{ - return m_Info.Count(); -} - -void CRConVProfExport::GetBudgetGroupInfos( CExportedBudgetGroupInfo *pInfos ) -{ - memcpy( pInfos, m_Info.Base(), GetNumBudgetGroups() * sizeof(CExportedBudgetGroupInfo) ); -} - -void CRConVProfExport::GetBudgetGroupTimes( float times[IVProfExport::MAX_BUDGETGROUP_TIMES] ) -{ - int nGroups = min( m_Times.Count(), (int)IVProfExport::MAX_BUDGETGROUP_TIMES ); - memset( times, 0, nGroups * sizeof(float) ); - nGroups = min( GetNumBudgetGroups(), nGroups ); - memcpy( times, m_Times.Base(), nGroups * sizeof(float) ); -} - -void CRConVProfExport::PauseProfile() -{ - // NOTE: This only has effect when testing on a listen server - // it shouldn't do anything in the wild. When drawing the budget panel - // this will cause the time spent doing so to not be counted - VProfExport_Pause(); -} - -void CRConVProfExport::ResumeProfile() -{ - // NOTE: This only has effect when testing on a listen server - // it shouldn't do anything in the wild - VProfExport_Resume(); -} - -void CRConVProfExport::CleanupGroupData() -{ - int nCount = m_Info.Count(); - for ( int i = 0; i < nCount; ++i ) - { - delete m_Info[i].m_pName; - } - - m_Info.RemoveAll(); -} - -void CRConVProfExport::OnRemoteGroupData( const void *data, int len ) -{ - CUtlBuffer buf( data, len, CUtlBuffer::READ_ONLY ); - int nFirstGroup = buf.GetInt(); - - if ( nFirstGroup == 0 ) - { - CleanupGroupData(); - } - else - { - Assert( nFirstGroup == m_Info.Count() ); - } - - // NOTE: See WriteRemoteVProfGroupData in vprof_engine.cpp - // to see the encoding of this data - int nGroupCount = buf.GetInt(); - int nBase = m_Info.AddMultipleToTail( nGroupCount ); - char temp[1024]; - for ( int i = 0; i < nGroupCount; ++i ) - { - CExportedBudgetGroupInfo *pInfo = &m_Info[nBase + i]; - - unsigned char red, green, blue, alpha; - red = buf.GetUnsignedChar( ); - green = buf.GetUnsignedChar( ); - blue = buf.GetUnsignedChar( ); - alpha = buf.GetUnsignedChar( ); - buf.GetString( temp ); - int nLen = Q_strlen( temp ); - - pInfo->m_Color.SetColor( red, green, blue, alpha ); - char *pBuf = new char[ nLen + 1 ]; - pInfo->m_pName = pBuf; - memcpy( pBuf, temp, nLen+1 ); - pInfo->m_BudgetFlags = 0; - } -} - -void CRConVProfExport::OnRemoteData( const void *data, int len ) -{ - // NOTE: See WriteRemoteVProfData in vprof_engine.cpp - // to see the encoding of this data - int nCount = len / sizeof(float); - Assert( nCount == m_Info.Count() ); - - CUtlBuffer buf( data, len, CUtlBuffer::READ_ONLY ); - m_Times.SetCount( nCount ); - memcpy( m_Times.Base(), data, nCount * sizeof(float) ); -} - - -CON_COMMAND( vprof_remote_start, "Request a VProf data stream from the remote server (requires authentication)" ) -{ - // TODO: Make this work (it might already!) -// RCONClient().StartVProfData(); -} - -CON_COMMAND( vprof_remote_stop, "Stop an existing remote VProf data request" ) -{ - // TODO: Make this work (it might already!) -// RCONClient().StopVProfData(); -} - #ifdef ENABLE_RPT CON_COMMAND_F( rpt_screenshot, "", FCVAR_HIDDEN | FCVAR_DONTRECORD ) { @@ -454,22 +323,6 @@ void CRConClient::ParseReceivedData() } break; - case SERVERDATA_VPROF_DATA: - { - int nDataSize = m_RecvBuffer.GetInt(); - m_VProfExport.OnRemoteData( m_RecvBuffer.PeekGet(), nDataSize ); - m_RecvBuffer.SeekGet( CUtlBuffer::SEEK_CURRENT, nDataSize ); - } - break; - - case SERVERDATA_VPROF_GROUPS: - { - int nDataSize = m_RecvBuffer.GetInt(); - m_VProfExport.OnRemoteGroupData( m_RecvBuffer.PeekGet(), nDataSize ); - m_RecvBuffer.SeekGet( CUtlBuffer::SEEK_CURRENT, nDataSize ); - } - break; - case SERVERDATA_RESPONSE_STRING: { char pBuf[2048]; @@ -706,45 +559,6 @@ void CRConClient::SendCmd( const char *msg ) SendResponse( response ); } - -//----------------------------------------------------------------------------- -// Purpose: Start vprofiling -//----------------------------------------------------------------------------- -void CRConClient::StartVProfData() -{ - if ( !IsConnected() ) - { - if ( !ConnectSocket() ) - return; - } - - // Override the vprof export to point to our local profiling data - OverrideVProfExport( &m_VProfExport ); - - CUtlBuffer response; - BuildResponse( response, SERVERDATA_VPROF, "", "" ); - SendResponse( response ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Stop vprofiling -//----------------------------------------------------------------------------- -void CRConClient::StopVProfData() -{ - // Reset the vprof export to point to the normal profiling data - ResetVProfExport( &m_VProfExport ); - - // Don't bother restarting a connection to turn this off - if ( !IsConnected() ) - return; - - CUtlBuffer response; - BuildResponse( response, SERVERDATA_REMOVE_VPROF, "", "" ); - SendResponse( response ); -} - - //----------------------------------------------------------------------------- // Purpose: get data from the server //----------------------------------------------------------------------------- diff --git a/engine/cl_rcon.h b/engine/cl_rcon.h index f94d938a..01305a99 100644 --- a/engine/cl_rcon.h +++ b/engine/cl_rcon.h @@ -27,47 +27,6 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -abstract_class IVProfData -{ -public: - virtual void OnRemoteGroupData( const void *data, int len ) = 0; - virtual void OnRemoteData( const void *data, int len ) = 0; -}; - - -//----------------------------------------------------------------------------- -// Used to display client perf data in showbudget -//----------------------------------------------------------------------------- -class CRConVProfExport : public IVProfExport, public IVProfData -{ - // Inherited from IVProfExport -public: - virtual void AddListener(); - virtual void RemoveListener(); - virtual void PauseProfile(); - virtual void ResumeProfile(); - virtual void SetBudgetFlagsFilter( int filter ); - virtual int GetNumBudgetGroups(); - virtual void GetBudgetGroupInfos( CExportedBudgetGroupInfo *pInfos ); - virtual void GetBudgetGroupTimes( float times[MAX_BUDGETGROUP_TIMES] ); - - // Inherited from IVProfData -public: - virtual void OnRemoteGroupData( const void *data, int len ); - virtual void OnRemoteData( const void *data, int len ); - - // Other public methods -public: - CRConVProfExport(); - -private: - void CleanupGroupData(); - - CUtlVector< CExportedBudgetGroupInfo > m_Info; - CUtlVector m_Times; // Times from the most recent snapshot. -}; - - class CRConClient : public ISocketCreatorListener { public: @@ -89,10 +48,6 @@ public: bool IsConnected() const; bool IsAuthenticated() const { return m_bAuthenticated; } - void RegisterVProfDataCallback( IVProfData *callback ); - void StopVProfData(); - void StartVProfData(); - void TakeScreenshot(); void GrabConsoleLog(); @@ -116,7 +71,6 @@ private: void SaveRemoteScreenshot( const void* pBuffer, int nBufLen ); void SaveRemoteConsoleLog( const void* pBuffer, int nBufLen ); - CRConVProfExport m_VProfExport; CSocketCreator m_Socket; netadr_t m_Address; int m_iAuthRequestID; diff --git a/engine/sv_remoteaccess.cpp b/engine/sv_remoteaccess.cpp index 7d4f7a99..50839a55 100644 --- a/engine/sv_remoteaccess.cpp +++ b/engine/sv_remoteaccess.cpp @@ -284,53 +284,6 @@ void CServerRemoteAccess::WriteDataRequest( CRConServer *pNetworkListener, ra_li #endif } break; - -#ifdef VPROF_ENABLED - case SERVERDATA_VPROF: - { - char password[25]; - if ( !GetStringHelper( cmd, password, sizeof(password) ) ) - { - invalidRequest = true; - break; - } - if ( !GetStringHelper( cmd, password, sizeof(password) ) ) - { - invalidRequest = true; - break; - } - if ( IsAuthenticated(listener) ) - { - RegisterVProfDataListener( listener ); - LogCommand( listener, "Remote VProf started!\n" ); - RespondString( listener, requestID, "Remote VProf started!\n" ); - } - } - break; - - case SERVERDATA_REMOVE_VPROF: - { - char password[25]; - if ( !GetStringHelper( cmd, password, sizeof(password) ) ) - { - invalidRequest = true; - break; - } - if ( !GetStringHelper( cmd, password, sizeof(password) ) ) - { - invalidRequest = true; - break; - } - if ( IsAuthenticated(listener) ) - { - RemoveVProfDataListener( listener ); - LogCommand( listener, "Remote VProf finished!\n" ); - RespondString( listener, requestID, "Remote VProf finished!\n" ); - } - } - break; -#endif - default: Assert(!("Unknown requestType in CServerRemoteAccess::WriteDataRequest()")); cmd.Purge(); @@ -911,16 +864,6 @@ void CServerRemoteAccess::SendResponseToClient( ra_listener_id listenerID, Serve response.Put( pData, nDataLen ); } - -//----------------------------------------------------------------------------- -// Purpose: sends an opaque blob of data from VProf to a remote rcon listener -//----------------------------------------------------------------------------- -void CServerRemoteAccess::SendVProfData( ra_listener_id listenerID, bool bGroupData, void *data, int len ) -{ - Assert( listenerID != m_AdminUIID ); // only RCON clients support this right now - SendResponseToClient( listenerID, bGroupData ? SERVERDATA_VPROF_GROUPS : SERVERDATA_VPROF_DATA, data, len ); -} - //----------------------------------------------------------------------------- // Purpose: C function for rest of engine to access CServerRemoteAccess class //----------------------------------------------------------------------------- diff --git a/public/tier0/vprof.h b/public/tier0/vprof.h index c298911e..7a183eac 100644 --- a/public/tier0/vprof.h +++ b/public/tier0/vprof.h @@ -15,9 +15,9 @@ #include "tier0/vprof_telemetry.h" // VProf is enabled by default in all configurations -except- X360 Retail. -#if !( defined( _X360 ) && defined( _CERT ) ) -#define VPROF_ENABLED -#endif +//#if !( defined( _X360 ) && defined( _CERT ) ) +//#define VPROF_ENABLED +//#endif #if defined(_X360) && defined(VPROF_ENABLED) #include "tier0/pmc360.h" From 3a73624b7e7ab165952f492bbbcaebc7af7778a0 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 15 May 2022 21:09:59 +0300 Subject: [PATCH 06/34] misaligment fixes --- bitmap/colorconversion.cpp | 5 +- common/sse2neon.h | 13043 +++++++++++--------- engine/OcclusionSystem.cpp | 6 +- engine/gl_rsurf.cpp | 4 +- game/client/c_rumble.cpp | 4 +- game/client/c_vote_controller.cpp | 4 +- game/client/client_hl1mp.vpc | 109 + game/client/hud_vote.h | 3 + game/client/viewrender.cpp | 2 +- game/client/wscript | 2 +- game/server/AI_Criteria.h | 4 +- game/server/AI_ResponseSystem.cpp | 2 - game/server/server_hl1mp.vpc | 179 + game/server/wscript | 2 +- game/shared/saverestore.cpp | 3 +- gameui/BaseSaveGameDialog.cpp | 17 +- public/bone_setup.cpp | 14 +- public/dt_send.cpp | 2 +- public/mathlib/compressed_vector.h | 4 +- public/mathlib/lightdesc.h | 3 +- public/mathlib/vector4d.h | 16 +- public/mathlib/vmatrix.h | 6 + public/studio.h | 4 +- public/togles/linuxwin/dxabstract_types.h | 4 +- public/togles/linuxwin/glentrypoints.h | 96 +- serverbrowser/ServerBrowserDialog.cpp | 7 +- studiorender/studiorendercontext.cpp | 4 +- tier0/cpu.cpp | 28 +- tier1/checksum_crc.cpp | 12 +- tier1/processor_detect_linux.cpp | 6 +- tier1/snappy-stubs-internal.h | 3 +- togles/linuxwin/cglmbuffer.cpp | 5 +- togles/linuxwin/cglmprogram.cpp | 5 +- togles/linuxwin/cglmtex.cpp | 4 +- togles/linuxwin/decompress.o | Bin 35548 -> 0 bytes togles/linuxwin/dx9asmtogl2.cpp | 21 +- togles/linuxwin/glentrypoints.cpp | 6 +- togles/linuxwin/glmgr.cpp | 2 +- vphysics/physics_collide.cpp | 7 +- 39 files changed, 7592 insertions(+), 6056 deletions(-) create mode 100644 game/client/client_hl1mp.vpc create mode 100644 game/server/server_hl1mp.vpc delete mode 100644 togles/linuxwin/decompress.o diff --git a/bitmap/colorconversion.cpp b/bitmap/colorconversion.cpp index ac033fd2..9b9432fe 100644 --- a/bitmap/colorconversion.cpp +++ b/bitmap/colorconversion.cpp @@ -435,7 +435,8 @@ static inline void DecodeAlpha3BitLinear( CDestPixel *pImPos, DXTAlphaBlock3BitL // pRows = (Alpha3BitRows*) & ( pAlphaBlock->stuff[0] ); const DWORD mask = 0x00000007; // bits = 00 00 01 11 - DWORD bits = *( (DWORD*) & ( pAlphaBlock->stuff[0] )); + DWORD bits; + memcpy( &bits, &(pAlphaBlock->stuff[0]), sizeof(DWORD) ); gBits[0][0] = (BYTE)( bits & mask ); bits >>= 3; @@ -454,7 +455,7 @@ static inline void DecodeAlpha3BitLinear( CDestPixel *pImPos, DXTAlphaBlock3BitL gBits[1][3] = (BYTE)( bits & mask ); // now for last two rows: - bits = *( (DWORD*) & ( pAlphaBlock->stuff[3] )); // last 3 bytes + memcpy( &bits, &(pAlphaBlock->stuff[3]), sizeof(DWORD) ); gBits[2][0] = (BYTE)( bits & mask ); bits >>= 3; diff --git a/common/sse2neon.h b/common/sse2neon.h index 9e512acf..490c0a45 100644 --- a/common/sse2neon.h +++ b/common/sse2neon.h @@ -52,9 +52,9 @@ /* Enable precise implementation of math operations * This would slow down the computation a bit, but gives consistent result with - * x86 SSE2. (e.g. would solve a hole or NaN pixel in the rendering result) + * x86 SSE. (e.g. would solve a hole or NaN pixel in the rendering result) */ -/* _mm_min_ps and _mm_max_ps */ +/* _mm_min|max_ps|ss|pd|sd */ #ifndef SSE2NEON_PRECISE_MINMAX #define SSE2NEON_PRECISE_MINMAX (0) #endif @@ -66,33 +66,36 @@ #ifndef SSE2NEON_PRECISE_SQRT #define SSE2NEON_PRECISE_SQRT (0) #endif +/* _mm_dp_pd */ +#ifndef SSE2NEON_PRECISE_DP +#define SSE2NEON_PRECISE_DP (0) +#endif +/* compiler specific definitions */ #if defined(__GNUC__) || defined(__clang__) #pragma push_macro("FORCE_INLINE") #pragma push_macro("ALIGN_STRUCT") #define FORCE_INLINE static inline __attribute__((always_inline)) #define ALIGN_STRUCT(x) __attribute__((aligned(x))) -#ifndef likely -#define likely(x) __builtin_expect(!!(x), 1) -#endif -#ifndef unlikely -#define unlikely(x) __builtin_expect(!!(x), 0) -#endif -#else -#error "Macro name collisions may happen with unsupported compiler." -#ifdef FORCE_INLINE -#undef FORCE_INLINE -#endif +#define _sse2neon_likely(x) __builtin_expect(!!(x), 1) +#define _sse2neon_unlikely(x) __builtin_expect(!!(x), 0) +#else /* non-GNU / non-clang compilers */ +#warning "Macro name collisions may happen with unsupported compiler." +#ifndef FORCE_INLINE #define FORCE_INLINE static inline +#endif #ifndef ALIGN_STRUCT #define ALIGN_STRUCT(x) __declspec(align(x)) #endif +#define _sse2neon_likely(x) (x) +#define _sse2neon_unlikely(x) (x) #endif -#ifndef likely -#define likely(x) (x) -#endif -#ifndef unlikely -#define unlikely(x) (x) + +/* C language does not allow initializing a variable with a function call. */ +#ifdef __cplusplus +#define _sse2neon_const static const +#else +#define _sse2neon_const const #endif #include @@ -118,12 +121,25 @@ #pragma GCC push_options #pragma GCC target("+simd") #endif +#elif __ARM_ARCH == 8 +#if !defined(__ARM_NEON) || !defined(__ARM_NEON__) +#error \ + "You must enable NEON instructions (e.g. -mfpu=neon-fp-armv8) to use SSE2NEON." +#endif +#if !defined(__clang__) +#pragma GCC push_options +#endif #else #error "Unsupported target. Must be either ARMv7-A+NEON or ARMv8-A." #endif #endif #include +#if !defined(__aarch64__) && (__ARM_ARCH == 8) +#if defined __has_include && __has_include() +#include +#endif +#endif /* Rounding functions require either Aarch64 instructions or libm failback */ #if !defined(__aarch64__) @@ -135,7 +151,7 @@ */ #ifndef __has_builtin /* GCC prior to 10 or non-clang compilers */ /* Compatibility with gcc <= 9 */ -#if __GNUC__ <= 9 +#if defined(__GNUC__) && (__GNUC__ <= 9) #define __has_builtin(x) HAS##x #define HAS__builtin_popcount 1 #define HAS__builtin_popcountll 1 @@ -162,10 +178,25 @@ #define _MM_FROUND_TO_ZERO 0x03 #define _MM_FROUND_CUR_DIRECTION 0x04 #define _MM_FROUND_NO_EXC 0x08 +#define _MM_FROUND_RAISE_EXC 0x00 +#define _MM_FROUND_NINT (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_FLOOR (_MM_FROUND_TO_NEG_INF | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_CEIL (_MM_FROUND_TO_POS_INF | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_TRUNC (_MM_FROUND_TO_ZERO | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_RINT (_MM_FROUND_CUR_DIRECTION | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_NEARBYINT (_MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC) #define _MM_ROUND_NEAREST 0x0000 #define _MM_ROUND_DOWN 0x2000 #define _MM_ROUND_UP 0x4000 #define _MM_ROUND_TOWARD_ZERO 0x6000 +/* Flush zero mode macros. */ +#define _MM_FLUSH_ZERO_MASK 0x8000 +#define _MM_FLUSH_ZERO_ON 0x8000 +#define _MM_FLUSH_ZERO_OFF 0x0000 +/* Denormals are zeros mode macros. */ +#define _MM_DENORMALS_ZERO_MASK 0x0040 +#define _MM_DENORMALS_ZERO_ON 0x0040 +#define _MM_DENORMALS_ZERO_OFF 0x0000 /* indicate immediate constant argument in a given range */ #define __constrange(a, b) const @@ -188,6 +219,16 @@ typedef float32x4_t __m128d; #endif typedef int64x2_t __m128i; /* 128-bit vector containing integers */ +// __int64 is defined in the Intrinsics Guide which maps to different datatype +// in different data model +#if !(defined(_WIN32) || defined(_WIN64) || defined(__int64)) +#if (defined(__x86_64__) || defined(__i386__)) +#define __int64 long long +#else +#define __int64 int64_t +#endif +#endif + /* type-safe casting between types */ #define vreinterpretq_m128_f16(x) vreinterpretq_f32_f16(x) @@ -301,10 +342,10 @@ typedef int64x2_t __m128i; /* 128-bit vector containing integers */ #endif // A struct is defined in this header file called 'SIMDVec' which can be used -// by applications which attempt to access the contents of an _m128 struct +// by applications which attempt to access the contents of an __m128 struct // directly. It is important to note that accessing the __m128 struct directly // is bad coding practice by Microsoft: @see: -// https://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx +// https://docs.microsoft.com/en-us/cpp/cpp/m128 // // However, some legacy source code may try to access the contents of an __m128 // struct directly so the developer can use the SIMDVec as an alias for it. Any @@ -340,13 +381,48 @@ typedef union ALIGN_STRUCT(16) SIMDVec { #define vreinterpretq_nth_u32_m128i(x, n) (((SIMDVec *) &x)->m128_u32[n]) #define vreinterpretq_nth_u8_m128i(x, n) (((SIMDVec *) &x)->m128_u8[n]) +/* SSE macros */ +#define _MM_GET_FLUSH_ZERO_MODE _sse2neon_mm_get_flush_zero_mode +#define _MM_SET_FLUSH_ZERO_MODE _sse2neon_mm_set_flush_zero_mode +#define _MM_GET_DENORMALS_ZERO_MODE _sse2neon_mm_get_denormals_zero_mode +#define _MM_SET_DENORMALS_ZERO_MODE _sse2neon_mm_set_denormals_zero_mode + +// Function declaration +// SSE +FORCE_INLINE unsigned int _MM_GET_ROUNDING_MODE(); +FORCE_INLINE __m128 _mm_move_ss(__m128, __m128); +FORCE_INLINE __m128 _mm_or_ps(__m128, __m128); +FORCE_INLINE __m128 _mm_set_ps1(float); +FORCE_INLINE __m128 _mm_setzero_ps(void); +// SSE2 +FORCE_INLINE __m128i _mm_and_si128(__m128i, __m128i); +FORCE_INLINE __m128i _mm_castps_si128(__m128); +FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i, __m128i); +FORCE_INLINE __m128i _mm_cvtps_epi32(__m128); +FORCE_INLINE __m128d _mm_move_sd(__m128d, __m128d); +FORCE_INLINE __m128i _mm_or_si128(__m128i, __m128i); +FORCE_INLINE __m128i _mm_set_epi32(int, int, int, int); +FORCE_INLINE __m128i _mm_set_epi64x(int64_t, int64_t); +FORCE_INLINE __m128d _mm_set_pd(double, double); +FORCE_INLINE __m128i _mm_set1_epi32(int); +FORCE_INLINE __m128i _mm_setzero_si128(); +// SSE4.1 +FORCE_INLINE __m128d _mm_ceil_pd(__m128d); +FORCE_INLINE __m128 _mm_ceil_ps(__m128); +FORCE_INLINE __m128d _mm_floor_pd(__m128d); +FORCE_INLINE __m128 _mm_floor_ps(__m128); +FORCE_INLINE __m128d _mm_round_pd(__m128d, int); +FORCE_INLINE __m128 _mm_round_ps(__m128, int); +// SSE4.2 +FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t, uint8_t); + /* Backwards compatibility for compilers with lack of specific type support */ // Older gcc does not define vld1q_u8_x4 type -#if defined(__GNUC__) && !defined(__clang__) && \ - ((__GNUC__ == 10 && (__GNUC_MINOR__ <= 1)) || \ - (__GNUC__ == 9 && (__GNUC_MINOR__ <= 3)) || \ - (__GNUC__ == 8 && (__GNUC_MINOR__ <= 4)) || __GNUC__ <= 7) +#if defined(__GNUC__) && !defined(__clang__) && \ + ((__GNUC__ <= 10 && defined(__arm__)) || \ + (__GNUC__ == 10 && __GNUC_MINOR__ < 3 && defined(__aarch64__)) || \ + (__GNUC__ <= 9 && defined(__aarch64__))) FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p) { uint8x16x4_t ret; @@ -441,8 +517,6 @@ FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p) +------+------+------+------+------+------+-------------+ */ -/* Set/get methods */ - /* Constants for use with _mm_prefetch. */ enum _mm_hint { _MM_HINT_NTA = 0, /* load data to L1 and L2 cache, mark it as NTA */ @@ -455,1323 +529,18 @@ enum _mm_hint { _MM_HINT_ET2 = 7 /* exclusive version of _MM_HINT_T2 */ }; -// Loads one cache line of data from address p to a location closer to the -// processor. https://msdn.microsoft.com/en-us/library/84szxsww(v=vs.100).aspx -FORCE_INLINE void _mm_prefetch(const void *p, int i) -{ - (void) i; - __builtin_prefetch(p); -} - -// Pause the processor. This is typically used in spin-wait loops and depending -// on the x86 processor typical values are in the 40-100 cycle range. The -// 'yield' instruction isn't a good fit beacuse it's effectively a nop on most -// Arm cores. Experience with several databases has shown has shown an 'isb' is -// a reasonable approximation. -FORCE_INLINE void _mm_pause() -{ - __asm__ __volatile__("isb\n"); -} - -// Copy the lower single-precision (32-bit) floating-point element of a to dst. -// -// dst[31:0] := a[31:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_f32 -FORCE_INLINE float _mm_cvtss_f32(__m128 a) -{ - return vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); -} - -// Convert the lower single-precision (32-bit) floating-point element in b to a -// double-precision (64-bit) floating-point element, store the result in the -// lower element of dst, and copy the upper element from a to the upper element -// of dst. -// -// dst[63:0] := Convert_FP32_To_FP64(b[31:0]) -// dst[127:64] := a[127:64] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_sd -FORCE_INLINE __m128d _mm_cvtss_sd(__m128d a, __m128 b) -{ - double d = (double) vgetq_lane_f32(vreinterpretq_f32_m128(b), 0); +// The bit field mapping to the FPCR(floating-point control register) +typedef struct { + uint16_t res0; + uint8_t res1 : 6; + uint8_t bit22 : 1; + uint8_t bit23 : 1; + uint8_t bit24 : 1; + uint8_t res2 : 7; #if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vsetq_lane_f64(d, vreinterpretq_f64_m128d(a), 0)); -#else - return vreinterpretq_m128d_s64( - vsetq_lane_s64(*(int64_t *) &d, vreinterpretq_s64_m128d(a), 0)); + uint32_t res3; #endif -} - -// Convert the lower single-precision (32-bit) floating-point element in a to a -// 32-bit integer, and store the result in dst. -// -// dst[31:0] := Convert_FP32_To_Int32(a[31:0]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si32 -#define _mm_cvtss_si32(a) _mm_cvt_ss2si(a) - -// Convert the lower single-precision (32-bit) floating-point element in a to a -// 64-bit integer, and store the result in dst. -// -// dst[63:0] := Convert_FP32_To_Int64(a[31:0]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si64 -FORCE_INLINE int _mm_cvtss_si64(__m128 a) -{ -#if defined(__aarch64__) - return vgetq_lane_s64( - vreinterpretq_s64_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a))), 0); -#else - float32_t data = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); - float32_t diff = data - floor(data); - if (diff > 0.5) - return (int64_t) ceil(data); - if (unlikely(diff == 0.5)) { - int64_t f = (int64_t) floor(data); - int64_t c = (int64_t) ceil(data); - return c & 1 ? f : c; - } - return (int64_t) floor(data); -#endif -} - -// Convert packed single-precision (32-bit) floating-point elements in a to -// packed 32-bit integers with truncation, and store the results in dst. -// -// FOR j := 0 to 1 -// i := 32*j -// dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ps2pi -FORCE_INLINE __m64 _mm_cvtt_ps2pi(__m128 a) -{ - return vreinterpret_m64_s32( - vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)))); -} - -// Convert the lower single-precision (32-bit) floating-point element in a to a -// 32-bit integer with truncation, and store the result in dst. -// -// dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ss2si -FORCE_INLINE int _mm_cvtt_ss2si(__m128 a) -{ - return vgetq_lane_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)), 0); -} - -// Convert packed single-precision (32-bit) floating-point elements in a to -// packed 32-bit integers with truncation, and store the results in dst. -// -// FOR j := 0 to 1 -// i := 32*j -// dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttps_pi32 -#define _mm_cvttps_pi32(a) _mm_cvtt_ps2pi(a) - -// Convert the lower single-precision (32-bit) floating-point element in a to a -// 32-bit integer with truncation, and store the result in dst. -// -// dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si32 -#define _mm_cvttss_si32(a) _mm_cvtt_ss2si(a) - -// Convert the lower single-precision (32-bit) floating-point element in a to a -// 64-bit integer with truncation, and store the result in dst. -// -// dst[63:0] := Convert_FP32_To_Int64_Truncate(a[31:0]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si64 -FORCE_INLINE int64_t _mm_cvttss_si64(__m128 a) -{ - return vgetq_lane_s64( - vmovl_s32(vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)))), 0); -} - -// Sets the 128-bit value to zero -// https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx -FORCE_INLINE __m128i _mm_setzero_si128(void) -{ - return vreinterpretq_m128i_s32(vdupq_n_s32(0)); -} - -// Clears the four single-precision, floating-point values. -// https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx -FORCE_INLINE __m128 _mm_setzero_ps(void) -{ - return vreinterpretq_m128_f32(vdupq_n_f32(0)); -} - -// Return vector of type __m128d with all elements set to zero. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setzero_pd -FORCE_INLINE __m128d _mm_setzero_pd(void) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64(vdupq_n_f64(0)); -#else - return vreinterpretq_m128d_f32(vdupq_n_f32(0)); -#endif -} - -// Sets the four single-precision, floating-point values to w. -// -// r0 := r1 := r2 := r3 := w -// -// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx -FORCE_INLINE __m128 _mm_set1_ps(float _w) -{ - return vreinterpretq_m128_f32(vdupq_n_f32(_w)); -} - -// Sets the four single-precision, floating-point values to w. -// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx -FORCE_INLINE __m128 _mm_set_ps1(float _w) -{ - return vreinterpretq_m128_f32(vdupq_n_f32(_w)); -} - -// Sets the four single-precision, floating-point values to the four inputs. -// https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx -FORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x) -{ - float ALIGN_STRUCT(16) data[4] = {x, y, z, w}; - return vreinterpretq_m128_f32(vld1q_f32(data)); -} - -// Copy single-precision (32-bit) floating-point element a to the lower element -// of dst, and zero the upper 3 elements. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_ss -FORCE_INLINE __m128 _mm_set_ss(float a) -{ - float ALIGN_STRUCT(16) data[4] = {a, 0, 0, 0}; - return vreinterpretq_m128_f32(vld1q_f32(data)); -} - -// Sets the four single-precision, floating-point values to the four inputs in -// reverse order. -// https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx -FORCE_INLINE __m128 _mm_setr_ps(float w, float z, float y, float x) -{ - float ALIGN_STRUCT(16) data[4] = {w, z, y, x}; - return vreinterpretq_m128_f32(vld1q_f32(data)); -} - -// Sets the 8 signed 16-bit integer values in reverse order. -// -// Return Value -// r0 := w0 -// r1 := w1 -// ... -// r7 := w7 -FORCE_INLINE __m128i _mm_setr_epi16(short w0, - short w1, - short w2, - short w3, - short w4, - short w5, - short w6, - short w7) -{ - int16_t ALIGN_STRUCT(16) data[8] = {w0, w1, w2, w3, w4, w5, w6, w7}; - return vreinterpretq_m128i_s16(vld1q_s16((int16_t *) data)); -} - -// Sets the 4 signed 32-bit integer values in reverse order -// https://technet.microsoft.com/en-us/library/security/27yb3ee5(v=vs.90).aspx -FORCE_INLINE __m128i _mm_setr_epi32(int i3, int i2, int i1, int i0) -{ - int32_t ALIGN_STRUCT(16) data[4] = {i3, i2, i1, i0}; - return vreinterpretq_m128i_s32(vld1q_s32(data)); -} - -// Set packed 64-bit integers in dst with the supplied values in reverse order. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_epi64 -FORCE_INLINE __m128i _mm_setr_epi64(__m64 e1, __m64 e0) -{ - return vreinterpretq_m128i_s64(vcombine_s64(e1, e0)); -} - -// Sets the 16 signed 8-bit integer values to b. -// -// r0 := b -// r1 := b -// ... -// r15 := b -// -// https://msdn.microsoft.com/en-us/library/6e14xhyf(v=vs.100).aspx -FORCE_INLINE __m128i _mm_set1_epi8(signed char w) -{ - return vreinterpretq_m128i_s8(vdupq_n_s8(w)); -} - -// Broadcast double-precision (64-bit) floating-point value a to all elements of -// dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_pd -FORCE_INLINE __m128d _mm_set1_pd(double d) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64(vdupq_n_f64(d)); -#else - return vreinterpretq_m128d_s64(vdupq_n_s64(*(int64_t *) &d)); -#endif -} - -// Sets the 8 signed 16-bit integer values to w. -// -// r0 := w -// r1 := w -// ... -// r7 := w -// -// https://msdn.microsoft.com/en-us/library/k0ya3x0e(v=vs.90).aspx -FORCE_INLINE __m128i _mm_set1_epi16(short w) -{ - return vreinterpretq_m128i_s16(vdupq_n_s16(w)); -} - -// Sets the 16 signed 8-bit integer values. -// https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx -FORCE_INLINE __m128i _mm_set_epi8(signed char b15, - signed char b14, - signed char b13, - signed char b12, - signed char b11, - signed char b10, - signed char b9, - signed char b8, - signed char b7, - signed char b6, - signed char b5, - signed char b4, - signed char b3, - signed char b2, - signed char b1, - signed char b0) -{ - int8_t ALIGN_STRUCT(16) - data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3, - (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7, - (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11, - (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15}; - return (__m128i) vld1q_s8(data); -} - -// Sets the 8 signed 16-bit integer values. -// https://msdn.microsoft.com/en-au/library/3e0fek84(v=vs.90).aspx -FORCE_INLINE __m128i _mm_set_epi16(short i7, - short i6, - short i5, - short i4, - short i3, - short i2, - short i1, - short i0) -{ - int16_t ALIGN_STRUCT(16) data[8] = {i0, i1, i2, i3, i4, i5, i6, i7}; - return vreinterpretq_m128i_s16(vld1q_s16(data)); -} - -// Sets the 16 signed 8-bit integer values in reverse order. -// https://msdn.microsoft.com/en-us/library/2khb9c7k(v=vs.90).aspx -FORCE_INLINE __m128i _mm_setr_epi8(signed char b0, - signed char b1, - signed char b2, - signed char b3, - signed char b4, - signed char b5, - signed char b6, - signed char b7, - signed char b8, - signed char b9, - signed char b10, - signed char b11, - signed char b12, - signed char b13, - signed char b14, - signed char b15) -{ - int8_t ALIGN_STRUCT(16) - data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3, - (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7, - (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11, - (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15}; - return (__m128i) vld1q_s8(data); -} - -// Sets the 4 signed 32-bit integer values to i. -// -// r0 := i -// r1 := i -// r2 := i -// r3 := I -// -// https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx -FORCE_INLINE __m128i _mm_set1_epi32(int _i) -{ - return vreinterpretq_m128i_s32(vdupq_n_s32(_i)); -} - -// Sets the 2 signed 64-bit integer values to i. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/whtfzhzk(v=vs.100) -FORCE_INLINE __m128i _mm_set1_epi64(__m64 _i) -{ - return vreinterpretq_m128i_s64(vdupq_n_s64((int64_t) _i)); -} - -// Sets the 2 signed 64-bit integer values to i. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_epi64x -FORCE_INLINE __m128i _mm_set1_epi64x(int64_t _i) -{ - return vreinterpretq_m128i_s64(vdupq_n_s64(_i)); -} - -// Sets the 4 signed 32-bit integer values. -// https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx -FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0) -{ - int32_t ALIGN_STRUCT(16) data[4] = {i0, i1, i2, i3}; - return vreinterpretq_m128i_s32(vld1q_s32(data)); -} - -// Returns the __m128i structure with its two 64-bit integer values -// initialized to the values of the two 64-bit integers passed in. -// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx -FORCE_INLINE __m128i _mm_set_epi64x(int64_t i1, int64_t i2) -{ - return vreinterpretq_m128i_s64( - vcombine_s64(vcreate_s64(i2), vcreate_s64(i1))); -} - -// Returns the __m128i structure with its two 64-bit integer values -// initialized to the values of the two 64-bit integers passed in. -// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx -FORCE_INLINE __m128i _mm_set_epi64(__m64 i1, __m64 i2) -{ - return _mm_set_epi64x((int64_t) i1, (int64_t) i2); -} - -// Set packed double-precision (64-bit) floating-point elements in dst with the -// supplied values. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd -FORCE_INLINE __m128d _mm_set_pd(double e1, double e0) -{ - double ALIGN_STRUCT(16) data[2] = {e0, e1}; -#if defined(__aarch64__) - return vreinterpretq_m128d_f64(vld1q_f64((float64_t *) data)); -#else - return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) data)); -#endif -} - -// Set packed double-precision (64-bit) floating-point elements in dst with the -// supplied values in reverse order. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_pd -FORCE_INLINE __m128d _mm_setr_pd(double e1, double e0) -{ - return _mm_set_pd(e0, e1); -} - -// Copy double-precision (64-bit) floating-point element a to the lower element -// of dst, and zero the upper element. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_sd -FORCE_INLINE __m128d _mm_set_sd(double a) -{ - return _mm_set_pd(0, a); -} - -// Broadcast double-precision (64-bit) floating-point value a to all elements of -// dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd1 -#define _mm_set_pd1 _mm_set1_pd - -// Stores four single-precision, floating-point values. -// https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx -FORCE_INLINE void _mm_store_ps(float *p, __m128 a) -{ - vst1q_f32(p, vreinterpretq_f32_m128(a)); -} - -// Store the lower single-precision (32-bit) floating-point element from a into -// 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte -// boundary or a general-protection exception may be generated. -// -// MEM[mem_addr+31:mem_addr] := a[31:0] -// MEM[mem_addr+63:mem_addr+32] := a[31:0] -// MEM[mem_addr+95:mem_addr+64] := a[31:0] -// MEM[mem_addr+127:mem_addr+96] := a[31:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_ps1 -FORCE_INLINE void _mm_store_ps1(float *p, __m128 a) -{ - float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); - vst1q_f32(p, vdupq_n_f32(a0)); -} - -// Store the lower single-precision (32-bit) floating-point element from a into -// 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte -// boundary or a general-protection exception may be generated. -// -// MEM[mem_addr+31:mem_addr] := a[31:0] -// MEM[mem_addr+63:mem_addr+32] := a[31:0] -// MEM[mem_addr+95:mem_addr+64] := a[31:0] -// MEM[mem_addr+127:mem_addr+96] := a[31:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store1_ps -#define _mm_store1_ps _mm_store_ps1 - -// Store 4 single-precision (32-bit) floating-point elements from a into memory -// in reverse order. mem_addr must be aligned on a 16-byte boundary or a -// general-protection exception may be generated. -// -// MEM[mem_addr+31:mem_addr] := a[127:96] -// MEM[mem_addr+63:mem_addr+32] := a[95:64] -// MEM[mem_addr+95:mem_addr+64] := a[63:32] -// MEM[mem_addr+127:mem_addr+96] := a[31:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_ps -FORCE_INLINE void _mm_storer_ps(float *p, __m128 a) -{ - float32x4_t tmp = vrev64q_f32(vreinterpretq_f32_m128(a)); - float32x4_t rev = vextq_f32(tmp, tmp, 2); - vst1q_f32(p, rev); -} - -// Stores four single-precision, floating-point values. -// https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx -FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a) -{ - vst1q_f32(p, vreinterpretq_f32_m128(a)); -} - -// Stores four 32-bit integer values as (as a __m128i value) at the address p. -// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx -FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a) -{ - vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a)); -} - -// Stores 128-bits of integer data a at the address p. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si128 -FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a) -{ - vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a)); -} - -// Stores 64-bits of integer data a at the address p. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si64 -FORCE_INLINE void _mm_storeu_si64(void *p, __m128i a) -{ - vst1q_lane_s64((int64_t *) p, vreinterpretq_s64_m128i(a), 0); -} - -// Stores 32-bits of integer data a at the address p. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si32 -FORCE_INLINE void _mm_storeu_si32(void *p, __m128i a) -{ - vst1q_lane_s32((int32_t *) p, vreinterpretq_s32_m128i(a), 0); -} - -// Stores 16-bits of integer data a at the address p. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si16 -FORCE_INLINE void _mm_storeu_si16(void *p, __m128i a) -{ - vst1q_lane_s16((int16_t *) p, vreinterpretq_s16_m128i(a), 0); -} - -// Stores the lower single - precision, floating - point value. -// https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx -FORCE_INLINE void _mm_store_ss(float *p, __m128 a) -{ - vst1q_lane_f32(p, vreinterpretq_f32_m128(a), 0); -} - -// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point -// elements) from a into memory. mem_addr must be aligned on a 16-byte boundary -// or a general-protection exception may be generated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd -FORCE_INLINE void _mm_store_pd(double *mem_addr, __m128d a) -{ -#if defined(__aarch64__) - vst1q_f64((float64_t *) mem_addr, vreinterpretq_f64_m128d(a)); -#else - vst1q_f32((float32_t *) mem_addr, vreinterpretq_f32_m128d(a)); -#endif -} - -// Store the upper double-precision (64-bit) floating-point element from a into -// memory. -// -// MEM[mem_addr+63:mem_addr] := a[127:64] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeh_pd -FORCE_INLINE void _mm_storeh_pd(double *mem_addr, __m128d a) -{ -#if defined(__aarch64__) - vst1_f64((float64_t *) mem_addr, vget_high_f64(vreinterpretq_f64_m128d(a))); -#else - vst1_f32((float32_t *) mem_addr, vget_high_f32(vreinterpretq_f32_m128d(a))); -#endif -} - -// Store the lower double-precision (64-bit) floating-point element from a into -// memory. -// -// MEM[mem_addr+63:mem_addr] := a[63:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storel_pd -FORCE_INLINE void _mm_storel_pd(double *mem_addr, __m128d a) -{ -#if defined(__aarch64__) - vst1_f64((float64_t *) mem_addr, vget_low_f64(vreinterpretq_f64_m128d(a))); -#else - vst1_f32((float32_t *) mem_addr, vget_low_f32(vreinterpretq_f32_m128d(a))); -#endif -} - -// Store 2 double-precision (64-bit) floating-point elements from a into memory -// in reverse order. mem_addr must be aligned on a 16-byte boundary or a -// general-protection exception may be generated. -// -// MEM[mem_addr+63:mem_addr] := a[127:64] -// MEM[mem_addr+127:mem_addr+64] := a[63:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_pd -FORCE_INLINE void _mm_storer_pd(double *mem_addr, __m128d a) -{ - float32x4_t f = vreinterpretq_f32_m128d(a); - _mm_store_pd(mem_addr, vreinterpretq_m128d_f32(vextq_f32(f, f, 2))); -} - -// Store the lower double-precision (64-bit) floating-point element from a into -// 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte -// boundary or a general-protection exception may be generated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd1 -FORCE_INLINE void _mm_store_pd1(double *mem_addr, __m128d a) -{ -#if defined(__aarch64__) - float64x1_t a_low = vget_low_f64(vreinterpretq_f64_m128d(a)); - vst1q_f64((float64_t *) mem_addr, - vreinterpretq_f64_m128d(vcombine_f64(a_low, a_low))); -#else - float32x2_t a_low = vget_low_f32(vreinterpretq_f32_m128d(a)); - vst1q_f32((float32_t *) mem_addr, - vreinterpretq_f32_m128d(vcombine_f32(a_low, a_low))); -#endif -} - -// Store the lower double-precision (64-bit) floating-point element from a into -// memory. mem_addr does not need to be aligned on any particular boundary. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_store_sd -FORCE_INLINE void _mm_store_sd(double *mem_addr, __m128d a) -{ -#if defined(__aarch64__) - vst1_f64((float64_t *) mem_addr, vget_low_f64(vreinterpretq_f64_m128d(a))); -#else - vst1_u64((uint64_t *) mem_addr, vget_low_u64(vreinterpretq_u64_m128d(a))); -#endif -} - -// Store the lower double-precision (64-bit) floating-point element from a into -// 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte -// boundary or a general-protection exception may be generated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=9,526,5601&text=_mm_store1_pd -#define _mm_store1_pd _mm_store_pd1 - -// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point -// elements) from a into memory. mem_addr does not need to be aligned on any -// particular boundary. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_pd -FORCE_INLINE void _mm_storeu_pd(double *mem_addr, __m128d a) -{ - _mm_store_pd(mem_addr, a); -} - -// Reads the lower 64 bits of b and stores them into the lower 64 bits of a. -// https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx -FORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b) -{ - uint64x1_t hi = vget_high_u64(vreinterpretq_u64_m128i(*a)); - uint64x1_t lo = vget_low_u64(vreinterpretq_u64_m128i(b)); - *a = vreinterpretq_m128i_u64(vcombine_u64(lo, hi)); -} - -// Stores the lower two single-precision floating point values of a to the -// address p. -// -// *p0 := a0 -// *p1 := a1 -// -// https://msdn.microsoft.com/en-us/library/h54t98ks(v=vs.90).aspx -FORCE_INLINE void _mm_storel_pi(__m64 *p, __m128 a) -{ - *p = vreinterpret_m64_f32(vget_low_f32(a)); -} - -// Stores the upper two single-precision, floating-point values of a to the -// address p. -// -// *p0 := a2 -// *p1 := a3 -// -// https://msdn.microsoft.com/en-us/library/a7525fs8(v%3dvs.90).aspx -FORCE_INLINE void _mm_storeh_pi(__m64 *p, __m128 a) -{ - *p = vreinterpret_m64_f32(vget_high_f32(a)); -} - -// Loads a single single-precision, floating-point value, copying it into all -// four words -// https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx -FORCE_INLINE __m128 _mm_load1_ps(const float *p) -{ - return vreinterpretq_m128_f32(vld1q_dup_f32(p)); -} - -// Load a single-precision (32-bit) floating-point element from memory into all -// elements of dst. -// -// dst[31:0] := MEM[mem_addr+31:mem_addr] -// dst[63:32] := MEM[mem_addr+31:mem_addr] -// dst[95:64] := MEM[mem_addr+31:mem_addr] -// dst[127:96] := MEM[mem_addr+31:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_ps1 -#define _mm_load_ps1 _mm_load1_ps - -// Sets the lower two single-precision, floating-point values with 64 -// bits of data loaded from the address p; the upper two values are passed -// through from a. -// -// Return Value -// r0 := *p0 -// r1 := *p1 -// r2 := a2 -// r3 := a3 -// -// https://msdn.microsoft.com/en-us/library/s57cyak2(v=vs.100).aspx -FORCE_INLINE __m128 _mm_loadl_pi(__m128 a, __m64 const *p) -{ - return vreinterpretq_m128_f32( - vcombine_f32(vld1_f32((const float32_t *) p), vget_high_f32(a))); -} - -// Load 4 single-precision (32-bit) floating-point elements from memory into dst -// in reverse order. mem_addr must be aligned on a 16-byte boundary or a -// general-protection exception may be generated. -// -// dst[31:0] := MEM[mem_addr+127:mem_addr+96] -// dst[63:32] := MEM[mem_addr+95:mem_addr+64] -// dst[95:64] := MEM[mem_addr+63:mem_addr+32] -// dst[127:96] := MEM[mem_addr+31:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_ps -FORCE_INLINE __m128 _mm_loadr_ps(const float *p) -{ - float32x4_t v = vrev64q_f32(vld1q_f32(p)); - return vreinterpretq_m128_f32(vextq_f32(v, v, 2)); -} - -// Sets the upper two single-precision, floating-point values with 64 -// bits of data loaded from the address p; the lower two values are passed -// through from a. -// -// r0 := a0 -// r1 := a1 -// r2 := *p0 -// r3 := *p1 -// -// https://msdn.microsoft.com/en-us/library/w92wta0x(v%3dvs.100).aspx -FORCE_INLINE __m128 _mm_loadh_pi(__m128 a, __m64 const *p) -{ - return vreinterpretq_m128_f32( - vcombine_f32(vget_low_f32(a), vld1_f32((const float32_t *) p))); -} - -// Loads four single-precision, floating-point values. -// https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx -FORCE_INLINE __m128 _mm_load_ps(const float *p) -{ - return vreinterpretq_m128_f32(vld1q_f32(p)); -} - -// Loads four single-precision, floating-point values. -// https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx -FORCE_INLINE __m128 _mm_loadu_ps(const float *p) -{ - // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are - // equivalent for neon - return vreinterpretq_m128_f32(vld1q_f32(p)); -} - -// Load unaligned 16-bit integer from memory into the first element of dst. -// -// dst[15:0] := MEM[mem_addr+15:mem_addr] -// dst[MAX:16] := 0 -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si16 -FORCE_INLINE __m128i _mm_loadu_si16(const void *p) -{ - return vreinterpretq_m128i_s16( - vsetq_lane_s16(*(const int16_t *) p, vdupq_n_s16(0), 0)); -} - -// Load unaligned 64-bit integer from memory into the first element of dst. -// -// dst[63:0] := MEM[mem_addr+63:mem_addr] -// dst[MAX:64] := 0 -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si64 -FORCE_INLINE __m128i _mm_loadu_si64(const void *p) -{ - return vreinterpretq_m128i_s64( - vcombine_s64(vld1_s64((const int64_t *) p), vdup_n_s64(0))); -} - -// Load a double-precision (64-bit) floating-point element from memory into the -// lower of dst, and zero the upper element. mem_addr does not need to be -// aligned on any particular boundary. -// -// dst[63:0] := MEM[mem_addr+63:mem_addr] -// dst[127:64] := 0 -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_sd -FORCE_INLINE __m128d _mm_load_sd(const double *p) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64(vsetq_lane_f64(*p, vdupq_n_f64(0), 0)); -#else - const float *fp = (const float *) p; - float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], 0, 0}; - return vreinterpretq_m128d_f32(vld1q_f32(data)); -#endif -} - -// Loads two double-precision from 16-byte aligned memory, floating-point -// values. -// -// dst[127:0] := MEM[mem_addr+127:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd -FORCE_INLINE __m128d _mm_load_pd(const double *p) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64(vld1q_f64(p)); -#else - const float *fp = (const float *) p; - float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], fp[2], fp[3]}; - return vreinterpretq_m128d_f32(vld1q_f32(data)); -#endif -} - -// Loads two double-precision from unaligned memory, floating-point values. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_pd -FORCE_INLINE __m128d _mm_loadu_pd(const double *p) -{ - return _mm_load_pd(p); -} - -// Loads an single - precision, floating - point value into the low word and -// clears the upper three words. -// https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx -FORCE_INLINE __m128 _mm_load_ss(const float *p) -{ - return vreinterpretq_m128_f32(vsetq_lane_f32(*p, vdupq_n_f32(0), 0)); -} - -// Load 64-bit integer from memory into the first element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_epi64 -FORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p) -{ - /* Load the lower 64 bits of the value pointed to by p into the - * lower 64 bits of the result, zeroing the upper 64 bits of the result. - */ - return vreinterpretq_m128i_s32( - vcombine_s32(vld1_s32((int32_t const *) p), vcreate_s32(0))); -} - -// Load a double-precision (64-bit) floating-point element from memory into the -// lower element of dst, and copy the upper element from a to dst. mem_addr does -// not need to be aligned on any particular boundary. -// -// dst[63:0] := MEM[mem_addr+63:mem_addr] -// dst[127:64] := a[127:64] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_pd -FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double *p) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vcombine_f64(vld1_f64(p), vget_high_f64(vreinterpretq_f64_m128d(a)))); -#else - return vreinterpretq_m128d_f32( - vcombine_f32(vld1_f32((const float *) p), - vget_high_f32(vreinterpretq_f32_m128d(a)))); -#endif -} - -// Load 2 double-precision (64-bit) floating-point elements from memory into dst -// in reverse order. mem_addr must be aligned on a 16-byte boundary or a -// general-protection exception may be generated. -// -// dst[63:0] := MEM[mem_addr+127:mem_addr+64] -// dst[127:64] := MEM[mem_addr+63:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_pd -FORCE_INLINE __m128d _mm_loadr_pd(const double *p) -{ -#if defined(__aarch64__) - float64x2_t v = vld1q_f64(p); - return vreinterpretq_m128d_f64(vextq_f64(v, v, 1)); -#else - int64x2_t v = vld1q_s64((const int64_t *) p); - return vreinterpretq_m128d_s64(vextq_s64(v, v, 1)); -#endif -} - -// Sets the low word to the single-precision, floating-point value of b -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/35hdzazd(v=vs.100) -FORCE_INLINE __m128 _mm_move_ss(__m128 a, __m128 b) -{ - return vreinterpretq_m128_f32( - vsetq_lane_f32(vgetq_lane_f32(vreinterpretq_f32_m128(b), 0), - vreinterpretq_f32_m128(a), 0)); -} - -// Move the lower double-precision (64-bit) floating-point element from b to the -// lower element of dst, and copy the upper element from a to the upper element -// of dst. -// -// dst[63:0] := b[63:0] -// dst[127:64] := a[127:64] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_sd -FORCE_INLINE __m128d _mm_move_sd(__m128d a, __m128d b) -{ - return vreinterpretq_m128d_f32( - vcombine_f32(vget_low_f32(vreinterpretq_f32_m128d(b)), - vget_high_f32(vreinterpretq_f32_m128d(a)))); -} - -// Copy the lower 64-bit integer in a to the lower element of dst, and zero the -// upper element. -// -// dst[63:0] := a[63:0] -// dst[127:64] := 0 -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_epi64 -FORCE_INLINE __m128i _mm_move_epi64(__m128i a) -{ - return vreinterpretq_m128i_s64( - vsetq_lane_s64(0, vreinterpretq_s64_m128i(a), 1)); -} - -// Return vector of type __m128 with undefined elements. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_ps -FORCE_INLINE __m128 _mm_undefined_ps(void) -{ -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuninitialized" -#endif - __m128 a; - return a; -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif -} - -/* Logic/Binary operations */ - -// Computes the bitwise AND-NOT of the four single-precision, floating-point -// values of a and b. -// -// r0 := ~a0 & b0 -// r1 := ~a1 & b1 -// r2 := ~a2 & b2 -// r3 := ~a3 & b3 -// -// https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx -FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_s32( - vbicq_s32(vreinterpretq_s32_m128(b), - vreinterpretq_s32_m128(a))); // *NOTE* argument swap -} - -// Compute the bitwise NOT of packed double-precision (64-bit) floating-point -// elements in a and then AND with b, and store the results in dst. -// -// FOR j := 0 to 1 -// i := j*64 -// dst[i+63:i] := ((NOT a[i+63:i]) AND b[i+63:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_andnot_pd -FORCE_INLINE __m128d _mm_andnot_pd(__m128d a, __m128d b) -{ - // *NOTE* argument swap - return vreinterpretq_m128d_s64( - vbicq_s64(vreinterpretq_s64_m128d(b), vreinterpretq_s64_m128d(a))); -} - -// Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the -// 128-bit value in a. -// -// r := (~a) & b -// -// https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx -FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s32( - vbicq_s32(vreinterpretq_s32_m128i(b), - vreinterpretq_s32_m128i(a))); // *NOTE* argument swap -} - -// Computes the bitwise AND of the 128-bit value in a and the 128-bit value in -// b. -// -// r := a & b -// -// https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx -FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s32( - vandq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -} - -// Computes the bitwise AND of the four single-precision, floating-point values -// of a and b. -// -// r0 := a0 & b0 -// r1 := a1 & b1 -// r2 := a2 & b2 -// r3 := a3 & b3 -// -// https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx -FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_s32( - vandq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); -} - -// Compute the bitwise AND of packed double-precision (64-bit) floating-point -// elements in a and b, and store the results in dst. -// -// FOR j := 0 to 1 -// i := j*64 -// dst[i+63:i] := a[i+63:i] AND b[i+63:i] -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_and_pd -FORCE_INLINE __m128d _mm_and_pd(__m128d a, __m128d b) -{ - return vreinterpretq_m128d_s64( - vandq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); -} - -// Computes the bitwise OR of the four single-precision, floating-point values -// of a and b. -// https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx -FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_s32( - vorrq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); -} - -// Computes bitwise EXOR (exclusive-or) of the four single-precision, -// floating-point values of a and b. -// https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx -FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_s32( - veorq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); -} - -// Compute the bitwise XOR of packed double-precision (64-bit) floating-point -// elements in a and b, and store the results in dst. -// -// FOR j := 0 to 1 -// i := j*64 -// dst[i+63:i] := a[i+63:i] XOR b[i+63:i] -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_xor_pd -FORCE_INLINE __m128d _mm_xor_pd(__m128d a, __m128d b) -{ - return vreinterpretq_m128d_s64( - veorq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); -} - -// Compute the bitwise OR of packed double-precision (64-bit) floating-point -// elements in a and b, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_or_pd -FORCE_INLINE __m128d _mm_or_pd(__m128d a, __m128d b) -{ - return vreinterpretq_m128d_s64( - vorrq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); -} - -// Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b. -// -// r := a | b -// -// https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx -FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s32( - vorrq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -} - -// Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in -// b. https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx -FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s32( - veorq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -} - -// Duplicate the low double-precision (64-bit) floating-point element from a, -// and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movedup_pd -FORCE_INLINE __m128d _mm_movedup_pd(__m128d a) -{ -#if (__aarch64__) - return vreinterpretq_m128d_f64( - vdupq_laneq_f64(vreinterpretq_f64_m128d(a), 0)); -#else - return vreinterpretq_m128d_u64( - vdupq_n_u64(vgetq_lane_u64(vreinterpretq_u64_m128d(a), 0))); -#endif -} - -// Duplicate odd-indexed single-precision (32-bit) floating-point elements -// from a, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movehdup_ps -FORCE_INLINE __m128 _mm_movehdup_ps(__m128 a) -{ -#if __has_builtin(__builtin_shufflevector) - return vreinterpretq_m128_f32(__builtin_shufflevector( - vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 1, 1, 3, 3)); -#else - float32_t a1 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 1); - float32_t a3 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 3); - float ALIGN_STRUCT(16) data[4] = {a1, a1, a3, a3}; - return vreinterpretq_m128_f32(vld1q_f32(data)); -#endif -} - -// Duplicate even-indexed single-precision (32-bit) floating-point elements -// from a, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_moveldup_ps -FORCE_INLINE __m128 _mm_moveldup_ps(__m128 a) -{ -#if __has_builtin(__builtin_shufflevector) - return vreinterpretq_m128_f32(__builtin_shufflevector( - vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 0, 0, 2, 2)); -#else - float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); - float32_t a2 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 2); - float ALIGN_STRUCT(16) data[4] = {a0, a0, a2, a2}; - return vreinterpretq_m128_f32(vld1q_f32(data)); -#endif -} - -// Moves the upper two values of B into the lower two values of A. -// -// r3 := a3 -// r2 := a2 -// r1 := b3 -// r0 := b2 -FORCE_INLINE __m128 _mm_movehl_ps(__m128 __A, __m128 __B) -{ - float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(__A)); - float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(__B)); - return vreinterpretq_m128_f32(vcombine_f32(b32, a32)); -} - -// Moves the lower two values of B into the upper two values of A. -// -// r3 := b1 -// r2 := b0 -// r1 := a1 -// r0 := a0 -FORCE_INLINE __m128 _mm_movelh_ps(__m128 __A, __m128 __B) -{ - float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(__A)); - float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(__B)); - return vreinterpretq_m128_f32(vcombine_f32(a10, b10)); -} - -// Create mask from the most significant bit of each 8-bit element in a, and -// store the result in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movemask_pi8 -FORCE_INLINE int _mm_movemask_pi8(__m64 a) -{ - uint8x8_t input = vreinterpret_u8_m64(a); -#if defined(__aarch64__) - static const int8x8_t shift = {0, 1, 2, 3, 4, 5, 6, 7}; - uint8x8_t tmp = vshr_n_u8(input, 7); - return vaddv_u8(vshl_u8(tmp, shift)); -#else - // Refer the implementation of `_mm_movemask_epi8` - uint16x4_t high_bits = vreinterpret_u16_u8(vshr_n_u8(input, 7)); - uint32x2_t paired16 = - vreinterpret_u32_u16(vsra_n_u16(high_bits, high_bits, 7)); - uint8x8_t paired32 = - vreinterpret_u8_u32(vsra_n_u32(paired16, paired16, 14)); - return vget_lane_u8(paired32, 0) | ((int) vget_lane_u8(paired32, 4) << 4); -#endif -} - -// Compute the absolute value of packed signed 32-bit integers in a, and store -// the unsigned results in dst. -// -// FOR j := 0 to 3 -// i := j*32 -// dst[i+31:i] := ABS(a[i+31:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi32 -FORCE_INLINE __m128i _mm_abs_epi32(__m128i a) -{ - return vreinterpretq_m128i_s32(vabsq_s32(vreinterpretq_s32_m128i(a))); -} - -// Compute the absolute value of packed signed 16-bit integers in a, and store -// the unsigned results in dst. -// -// FOR j := 0 to 7 -// i := j*16 -// dst[i+15:i] := ABS(a[i+15:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi16 -FORCE_INLINE __m128i _mm_abs_epi16(__m128i a) -{ - return vreinterpretq_m128i_s16(vabsq_s16(vreinterpretq_s16_m128i(a))); -} - -// Compute the absolute value of packed signed 8-bit integers in a, and store -// the unsigned results in dst. -// -// FOR j := 0 to 15 -// i := j*8 -// dst[i+7:i] := ABS(a[i+7:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi8 -FORCE_INLINE __m128i _mm_abs_epi8(__m128i a) -{ - return vreinterpretq_m128i_s8(vabsq_s8(vreinterpretq_s8_m128i(a))); -} - -// Compute the absolute value of packed signed 32-bit integers in a, and store -// the unsigned results in dst. -// -// FOR j := 0 to 1 -// i := j*32 -// dst[i+31:i] := ABS(a[i+31:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi32 -FORCE_INLINE __m64 _mm_abs_pi32(__m64 a) -{ - return vreinterpret_m64_s32(vabs_s32(vreinterpret_s32_m64(a))); -} - -// Compute the absolute value of packed signed 16-bit integers in a, and store -// the unsigned results in dst. -// -// FOR j := 0 to 3 -// i := j*16 -// dst[i+15:i] := ABS(a[i+15:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi16 -FORCE_INLINE __m64 _mm_abs_pi16(__m64 a) -{ - return vreinterpret_m64_s16(vabs_s16(vreinterpret_s16_m64(a))); -} - -// Compute the absolute value of packed signed 8-bit integers in a, and store -// the unsigned results in dst. -// -// FOR j := 0 to 7 -// i := j*8 -// dst[i+7:i] := ABS(a[i+7:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi8 -FORCE_INLINE __m64 _mm_abs_pi8(__m64 a) -{ - return vreinterpret_m64_s8(vabs_s8(vreinterpret_s8_m64(a))); -} - -// Concatenate 16-byte blocks in a and b into a 32-byte temporary result, shift -// the result right by imm8 bytes, and store the low 16 bytes in dst. -// -// tmp[255:0] := ((a[127:0] << 128)[255:0] OR b[127:0]) >> (imm8*8) -// dst[127:0] := tmp[127:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_epi8 -#define _mm_alignr_epi8(a, b, imm) \ - __extension__({ \ - __m128i ret; \ - if (unlikely((imm) >= 32)) { \ - ret = _mm_setzero_si128(); \ - } else { \ - uint8x16_t tmp_low, tmp_high; \ - if (imm >= 16) { \ - const int idx = imm - 16; \ - tmp_low = vreinterpretq_u8_m128i(a); \ - tmp_high = vdupq_n_u8(0); \ - ret = \ - vreinterpretq_m128i_u8(vextq_u8(tmp_low, tmp_high, idx)); \ - } else { \ - const int idx = imm; \ - tmp_low = vreinterpretq_u8_m128i(b); \ - tmp_high = vreinterpretq_u8_m128i(a); \ - ret = \ - vreinterpretq_m128i_u8(vextq_u8(tmp_low, tmp_high, idx)); \ - } \ - } \ - ret; \ - }) - -// Concatenate 8-byte blocks in a and b into a 16-byte temporary result, shift -// the result right by imm8 bytes, and store the low 8 bytes in dst. -// -// tmp[127:0] := ((a[63:0] << 64)[127:0] OR b[63:0]) >> (imm8*8) -// dst[63:0] := tmp[63:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_pi8 -#define _mm_alignr_pi8(a, b, imm) \ - __extension__({ \ - __m64 ret; \ - if (unlikely((imm) >= 16)) { \ - ret = vreinterpret_m64_s8(vdup_n_s8(0)); \ - } else { \ - uint8x8_t tmp_low, tmp_high; \ - if (imm >= 8) { \ - const int idx = imm - 8; \ - tmp_low = vreinterpret_u8_m64(a); \ - tmp_high = vdup_n_u8(0); \ - ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \ - } else { \ - const int idx = imm; \ - tmp_low = vreinterpret_u8_m64(b); \ - tmp_high = vreinterpret_u8_m64(a); \ - ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \ - } \ - } \ - ret; \ - }) +} fpcr_bitfield; // Takes the upper 64 bits of a and places it in the low end of the result // Takes the lower 64 bits of b and places it into the high end of the result. @@ -1908,6 +677,255 @@ FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b) return vreinterpretq_m128_f32(vcombine_f32(a32, b20)); } +// Kahan summation for accurate summation of floating-point numbers. +// http://blog.zachbjornson.com/2019/08/11/fast-float-summation.html +FORCE_INLINE void _sse2neon_kadd_f32(float *sum, float *c, float y) +{ + y -= *c; + float t = *sum + y; + *c = (t - *sum) - y; + *sum = t; +} + +#if defined(__ARM_FEATURE_CRYPTO) && \ + (defined(__aarch64__) || __has_builtin(__builtin_arm_crypto_vmullp64)) +// Wraps vmull_p64 +FORCE_INLINE uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b) +{ + poly64_t a = vget_lane_p64(vreinterpret_p64_u64(_a), 0); + poly64_t b = vget_lane_p64(vreinterpret_p64_u64(_b), 0); + return vreinterpretq_u64_p128(vmull_p64(a, b)); +} +#else // ARMv7 polyfill +// ARMv7/some A64 lacks vmull_p64, but it has vmull_p8. +// +// vmull_p8 calculates 8 8-bit->16-bit polynomial multiplies, but we need a +// 64-bit->128-bit polynomial multiply. +// +// It needs some work and is somewhat slow, but it is still faster than all +// known scalar methods. +// +// Algorithm adapted to C from +// https://www.workofard.com/2017/07/ghash-for-low-end-cores/, which is adapted +// from "Fast Software Polynomial Multiplication on ARM Processors Using the +// NEON Engine" by Danilo Camara, Conrado Gouvea, Julio Lopez and Ricardo Dahab +// (https://hal.inria.fr/hal-01506572) +static uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b) +{ + poly8x8_t a = vreinterpret_p8_u64(_a); + poly8x8_t b = vreinterpret_p8_u64(_b); + + // Masks + uint8x16_t k48_32 = vcombine_u8(vcreate_u8(0x0000ffffffffffff), + vcreate_u8(0x00000000ffffffff)); + uint8x16_t k16_00 = vcombine_u8(vcreate_u8(0x000000000000ffff), + vcreate_u8(0x0000000000000000)); + + // Do the multiplies, rotating with vext to get all combinations + uint8x16_t d = vreinterpretq_u8_p16(vmull_p8(a, b)); // D = A0 * B0 + uint8x16_t e = + vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 1))); // E = A0 * B1 + uint8x16_t f = + vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 1), b)); // F = A1 * B0 + uint8x16_t g = + vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 2))); // G = A0 * B2 + uint8x16_t h = + vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 2), b)); // H = A2 * B0 + uint8x16_t i = + vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 3))); // I = A0 * B3 + uint8x16_t j = + vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 3), b)); // J = A3 * B0 + uint8x16_t k = + vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 4))); // L = A0 * B4 + + // Add cross products + uint8x16_t l = veorq_u8(e, f); // L = E + F + uint8x16_t m = veorq_u8(g, h); // M = G + H + uint8x16_t n = veorq_u8(i, j); // N = I + J + + // Interleave. Using vzip1 and vzip2 prevents Clang from emitting TBL + // instructions. +#if defined(__aarch64__) + uint8x16_t lm_p0 = vreinterpretq_u8_u64( + vzip1q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m))); + uint8x16_t lm_p1 = vreinterpretq_u8_u64( + vzip2q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m))); + uint8x16_t nk_p0 = vreinterpretq_u8_u64( + vzip1q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k))); + uint8x16_t nk_p1 = vreinterpretq_u8_u64( + vzip2q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k))); +#else + uint8x16_t lm_p0 = vcombine_u8(vget_low_u8(l), vget_low_u8(m)); + uint8x16_t lm_p1 = vcombine_u8(vget_high_u8(l), vget_high_u8(m)); + uint8x16_t nk_p0 = vcombine_u8(vget_low_u8(n), vget_low_u8(k)); + uint8x16_t nk_p1 = vcombine_u8(vget_high_u8(n), vget_high_u8(k)); +#endif + // t0 = (L) (P0 + P1) << 8 + // t1 = (M) (P2 + P3) << 16 + uint8x16_t t0t1_tmp = veorq_u8(lm_p0, lm_p1); + uint8x16_t t0t1_h = vandq_u8(lm_p1, k48_32); + uint8x16_t t0t1_l = veorq_u8(t0t1_tmp, t0t1_h); + + // t2 = (N) (P4 + P5) << 24 + // t3 = (K) (P6 + P7) << 32 + uint8x16_t t2t3_tmp = veorq_u8(nk_p0, nk_p1); + uint8x16_t t2t3_h = vandq_u8(nk_p1, k16_00); + uint8x16_t t2t3_l = veorq_u8(t2t3_tmp, t2t3_h); + + // De-interleave +#if defined(__aarch64__) + uint8x16_t t0 = vreinterpretq_u8_u64( + vuzp1q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h))); + uint8x16_t t1 = vreinterpretq_u8_u64( + vuzp2q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h))); + uint8x16_t t2 = vreinterpretq_u8_u64( + vuzp1q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h))); + uint8x16_t t3 = vreinterpretq_u8_u64( + vuzp2q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h))); +#else + uint8x16_t t1 = vcombine_u8(vget_high_u8(t0t1_l), vget_high_u8(t0t1_h)); + uint8x16_t t0 = vcombine_u8(vget_low_u8(t0t1_l), vget_low_u8(t0t1_h)); + uint8x16_t t3 = vcombine_u8(vget_high_u8(t2t3_l), vget_high_u8(t2t3_h)); + uint8x16_t t2 = vcombine_u8(vget_low_u8(t2t3_l), vget_low_u8(t2t3_h)); +#endif + // Shift the cross products + uint8x16_t t0_shift = vextq_u8(t0, t0, 15); // t0 << 8 + uint8x16_t t1_shift = vextq_u8(t1, t1, 14); // t1 << 16 + uint8x16_t t2_shift = vextq_u8(t2, t2, 13); // t2 << 24 + uint8x16_t t3_shift = vextq_u8(t3, t3, 12); // t3 << 32 + + // Accumulate the products + uint8x16_t cross1 = veorq_u8(t0_shift, t1_shift); + uint8x16_t cross2 = veorq_u8(t2_shift, t3_shift); + uint8x16_t mix = veorq_u8(d, cross1); + uint8x16_t r = veorq_u8(mix, cross2); + return vreinterpretq_u64_u8(r); +} +#endif // ARMv7 polyfill + +// C equivalent: +// __m128i _mm_shuffle_epi32_default(__m128i a, +// __constrange(0, 255) int imm) { +// __m128i ret; +// ret[0] = a[imm & 0x3]; ret[1] = a[(imm >> 2) & 0x3]; +// ret[2] = a[(imm >> 4) & 0x03]; ret[3] = a[(imm >> 6) & 0x03]; +// return ret; +// } +#define _mm_shuffle_epi32_default(a, imm) \ + __extension__({ \ + int32x4_t ret; \ + ret = vmovq_n_s32( \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm) & (0x3))); \ + ret = vsetq_lane_s32( \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 2) & 0x3), \ + ret, 1); \ + ret = vsetq_lane_s32( \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 4) & 0x3), \ + ret, 2); \ + ret = vsetq_lane_s32( \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 6) & 0x3), \ + ret, 3); \ + vreinterpretq_m128i_s32(ret); \ + }) + +// Takes the upper 64 bits of a and places it in the low end of the result +// Takes the lower 64 bits of a and places it into the high end of the result. +FORCE_INLINE __m128i _mm_shuffle_epi_1032(__m128i a) +{ + int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a)); + int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); + return vreinterpretq_m128i_s32(vcombine_s32(a32, a10)); +} + +// takes the lower two 32-bit values from a and swaps them and places in low end +// of result takes the higher two 32 bit values from a and swaps them and places +// in high end of result. +FORCE_INLINE __m128i _mm_shuffle_epi_2301(__m128i a) +{ + int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); + int32x2_t a23 = vrev64_s32(vget_high_s32(vreinterpretq_s32_m128i(a))); + return vreinterpretq_m128i_s32(vcombine_s32(a01, a23)); +} + +// rotates the least significant 32 bits into the most significant 32 bits, and +// shifts the rest down +FORCE_INLINE __m128i _mm_shuffle_epi_0321(__m128i a) +{ + return vreinterpretq_m128i_s32( + vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 1)); +} + +// rotates the most significant 32 bits into the least significant 32 bits, and +// shifts the rest up +FORCE_INLINE __m128i _mm_shuffle_epi_2103(__m128i a) +{ + return vreinterpretq_m128i_s32( + vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 3)); +} + +// gets the lower 64 bits of a, and places it in the upper 64 bits +// gets the lower 64 bits of a and places it in the lower 64 bits +FORCE_INLINE __m128i _mm_shuffle_epi_1010(__m128i a) +{ + int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); + return vreinterpretq_m128i_s32(vcombine_s32(a10, a10)); +} + +// gets the lower 64 bits of a, swaps the 0 and 1 elements, and places it in the +// lower 64 bits gets the lower 64 bits of a, and places it in the upper 64 bits +FORCE_INLINE __m128i _mm_shuffle_epi_1001(__m128i a) +{ + int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); + int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); + return vreinterpretq_m128i_s32(vcombine_s32(a01, a10)); +} + +// gets the lower 64 bits of a, swaps the 0 and 1 elements and places it in the +// upper 64 bits gets the lower 64 bits of a, swaps the 0 and 1 elements, and +// places it in the lower 64 bits +FORCE_INLINE __m128i _mm_shuffle_epi_0101(__m128i a) +{ + int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); + return vreinterpretq_m128i_s32(vcombine_s32(a01, a01)); +} + +FORCE_INLINE __m128i _mm_shuffle_epi_2211(__m128i a) +{ + int32x2_t a11 = vdup_lane_s32(vget_low_s32(vreinterpretq_s32_m128i(a)), 1); + int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0); + return vreinterpretq_m128i_s32(vcombine_s32(a11, a22)); +} + +FORCE_INLINE __m128i _mm_shuffle_epi_0122(__m128i a) +{ + int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0); + int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); + return vreinterpretq_m128i_s32(vcombine_s32(a22, a01)); +} + +FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a) +{ + int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a)); + int32x2_t a33 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 1); + return vreinterpretq_m128i_s32(vcombine_s32(a32, a33)); +} + +// FORCE_INLINE __m128i _mm_shuffle_epi32_splat(__m128i a, __constrange(0,255) +// int imm) +#if defined(__aarch64__) +#define _mm_shuffle_epi32_splat(a, imm) \ + __extension__({ \ + vreinterpretq_m128i_s32( \ + vdupq_laneq_s32(vreinterpretq_s32_m128i(a), (imm))); \ + }) +#else +#define _mm_shuffle_epi32_splat(a, imm) \ + __extension__({ \ + vreinterpretq_m128i_s32( \ + vdupq_n_s32(vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)))); \ + }) +#endif + // NEON does not support a general purpose permute intrinsic // Selects four specific single-precision, floating-point values from a and b, // based on the mask i. @@ -1939,6 +957,1595 @@ FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b) vreinterpretq_m128_f32(ret); \ }) +// Shuffles the lower 4 signed or unsigned 16-bit integers in a as specified +// by imm. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/y41dkk37(v=vs.100) +// FORCE_INLINE __m128i _mm_shufflelo_epi16_function(__m128i a, +// __constrange(0,255) int +// imm) +#define _mm_shufflelo_epi16_function(a, imm) \ + __extension__({ \ + int16x8_t ret = vreinterpretq_s16_m128i(a); \ + int16x4_t lowBits = vget_low_s16(ret); \ + ret = vsetq_lane_s16(vget_lane_s16(lowBits, (imm) & (0x3)), ret, 0); \ + ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 2) & 0x3), ret, \ + 1); \ + ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 4) & 0x3), ret, \ + 2); \ + ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 6) & 0x3), ret, \ + 3); \ + vreinterpretq_m128i_s16(ret); \ + }) + +// Shuffles the upper 4 signed or unsigned 16-bit integers in a as specified +// by imm. +// https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx +// FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a, +// __constrange(0,255) int +// imm) +#define _mm_shufflehi_epi16_function(a, imm) \ + __extension__({ \ + int16x8_t ret = vreinterpretq_s16_m128i(a); \ + int16x4_t highBits = vget_high_s16(ret); \ + ret = vsetq_lane_s16(vget_lane_s16(highBits, (imm) & (0x3)), ret, 4); \ + ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 2) & 0x3), ret, \ + 5); \ + ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 4) & 0x3), ret, \ + 6); \ + ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 6) & 0x3), ret, \ + 7); \ + vreinterpretq_m128i_s16(ret); \ + }) + +/* MMX */ + +//_mm_empty is a no-op on arm +FORCE_INLINE void _mm_empty(void) {} + +/* SSE */ + +// Adds the four single-precision, floating-point values of a and b. +// +// r0 := a0 + b0 +// r1 := a1 + b1 +// r2 := a2 + b2 +// r3 := a3 + b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx +FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_f32( + vaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// adds the scalar single-precision floating point values of a and b. +// https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx +FORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b) +{ + float32_t b0 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 0); + float32x4_t value = vsetq_lane_f32(b0, vdupq_n_f32(0), 0); + // the upper values in the result must be the remnants of . + return vreinterpretq_m128_f32(vaddq_f32(a, value)); +} + +// Computes the bitwise AND of the four single-precision, floating-point values +// of a and b. +// +// r0 := a0 & b0 +// r1 := a1 & b1 +// r2 := a2 & b2 +// r3 := a3 & b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx +FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_s32( + vandq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); +} + +// Computes the bitwise AND-NOT of the four single-precision, floating-point +// values of a and b. +// +// r0 := ~a0 & b0 +// r1 := ~a1 & b1 +// r2 := ~a2 & b2 +// r3 := ~a3 & b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx +FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_s32( + vbicq_s32(vreinterpretq_s32_m128(b), + vreinterpretq_s32_m128(a))); // *NOTE* argument swap +} + +// Average packed unsigned 16-bit integers in a and b, and store the results in +// dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu16 +FORCE_INLINE __m64 _mm_avg_pu16(__m64 a, __m64 b) +{ + return vreinterpret_m64_u16( + vrhadd_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b))); +} + +// Average packed unsigned 8-bit integers in a and b, and store the results in +// dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu8 +FORCE_INLINE __m64 _mm_avg_pu8(__m64 a, __m64 b) +{ + return vreinterpret_m64_u8( + vrhadd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); +} + +// Compares for equality. +// https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for equality. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/k423z28e(v=vs.100) +FORCE_INLINE __m128 _mm_cmpeq_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpeq_ps(a, b)); +} + +// Compares for greater than or equal. +// https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for greater than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/kesh3ddc(v=vs.100) +FORCE_INLINE __m128 _mm_cmpge_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpge_ps(a, b)); +} + +// Compares for greater than. +// +// r0 := (a0 > b0) ? 0xffffffff : 0x0 +// r1 := (a1 > b1) ? 0xffffffff : 0x0 +// r2 := (a2 > b2) ? 0xffffffff : 0x0 +// r3 := (a3 > b3) ? 0xffffffff : 0x0 +// +// https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for greater than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/1xyyyy9e(v=vs.100) +FORCE_INLINE __m128 _mm_cmpgt_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpgt_ps(a, b)); +} + +// Compares for less than or equal. +// +// r0 := (a0 <= b0) ? 0xffffffff : 0x0 +// r1 := (a1 <= b1) ? 0xffffffff : 0x0 +// r2 := (a2 <= b2) ? 0xffffffff : 0x0 +// r3 := (a3 <= b3) ? 0xffffffff : 0x0 +// +// https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for less than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/a7x0hbhw(v=vs.100) +FORCE_INLINE __m128 _mm_cmple_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmple_ps(a, b)); +} + +// Compares for less than +// https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for less than +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fy94wye7(v=vs.100) +FORCE_INLINE __m128 _mm_cmplt_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmplt_ps(a, b)); +} + +// Compares for inequality. +// https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32(vmvnq_u32( + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)))); +} + +// Compares for inequality. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ekya8fh4(v=vs.100) +FORCE_INLINE __m128 _mm_cmpneq_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpneq_ps(a, b)); +} + +// Compares for not greater than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/wsexys62(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnge_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32(vmvnq_u32( + vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)))); +} + +// Compares for not greater than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fk2y80s8(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnge_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpnge_ps(a, b)); +} + +// Compares for not greater than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/d0xh7w0s(v=vs.100) +FORCE_INLINE __m128 _mm_cmpngt_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32(vmvnq_u32( + vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)))); +} + +// Compares for not greater than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100) +FORCE_INLINE __m128 _mm_cmpngt_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpngt_ps(a, b)); +} + +// Compares for not less than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/6a330kxw(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnle_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32(vmvnq_u32( + vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)))); +} + +// Compares for not less than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnle_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpnle_ps(a, b)); +} + +// Compares for not less than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/4686bbdw(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnlt_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32(vmvnq_u32( + vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)))); +} + +// Compares for not less than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/56b9z2wf(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnlt_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpnlt_ps(a, b)); +} + +// Compares the four 32-bit floats in a and b to check if any values are NaN. +// Ordered compare between each value returns true for "orderable" and false for +// "not orderable" (NaN). +// https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx see +// also: +// http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean +// http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics +FORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b) +{ + // Note: NEON does not have ordered compare builtin + // Need to compare a eq a and b eq b to check for NaN + // Do AND of results to get final + uint32x4_t ceqaa = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t ceqbb = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_u32(vandq_u32(ceqaa, ceqbb)); +} + +// Compares for ordered. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/343t62da(v=vs.100) +FORCE_INLINE __m128 _mm_cmpord_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpord_ps(a, b)); +} + +// Compares for unordered. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/khy6fk1t(v=vs.100) +FORCE_INLINE __m128 _mm_cmpunord_ps(__m128 a, __m128 b) +{ + uint32x4_t f32a = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t f32b = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_u32(vmvnq_u32(vandq_u32(f32a, f32b))); +} + +// Compares for unordered. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/2as2387b(v=vs.100) +FORCE_INLINE __m128 _mm_cmpunord_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpunord_ps(a, b)); +} + +// Compares the lower single-precision floating point scalar values of a and b +// using an equality operation. : +// https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx +FORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b) +{ + uint32x4_t a_eq_b = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return vgetq_lane_u32(a_eq_b, 0) & 0x1; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using a greater than or equal operation. : +// https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx +FORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b) +{ + uint32x4_t a_ge_b = + vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return vgetq_lane_u32(a_ge_b, 0) & 0x1; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using a greater than operation. : +// https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx +FORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b) +{ + uint32x4_t a_gt_b = + vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return vgetq_lane_u32(a_gt_b, 0) & 0x1; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using a less than or equal operation. : +// https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx +FORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b) +{ + uint32x4_t a_le_b = + vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return vgetq_lane_u32(a_le_b, 0) & 0x1; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using a less than operation. : +// https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx Important +// note!! The documentation on MSDN is incorrect! If either of the values is a +// NAN the docs say you will get a one, but in fact, it will return a zero!! +FORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b) +{ + uint32x4_t a_lt_b = + vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return vgetq_lane_u32(a_lt_b, 0) & 0x1; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using an inequality operation. : +// https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx +FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b) +{ + return !_mm_comieq_ss(a, b); +} + +// Convert packed signed 32-bit integers in b to packed single-precision +// (32-bit) floating-point elements, store the results in the lower 2 elements +// of dst, and copy the upper 2 packed elements from a to the upper elements of +// dst. +// +// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) +// dst[63:32] := Convert_Int32_To_FP32(b[63:32]) +// dst[95:64] := a[95:64] +// dst[127:96] := a[127:96] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_pi2ps +FORCE_INLINE __m128 _mm_cvt_pi2ps(__m128 a, __m64 b) +{ + return vreinterpretq_m128_f32( + vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)), + vget_high_f32(vreinterpretq_f32_m128(a)))); +} + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed 32-bit integers, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ps2pi +FORCE_INLINE __m64 _mm_cvt_ps2pi(__m128 a) +{ +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) + return vreinterpret_m64_s32( + vget_low_s32(vcvtnq_s32_f32(vrndiq_f32(vreinterpretq_f32_m128(a))))); +#else + return vreinterpret_m64_s32(vcvt_s32_f32(vget_low_f32( + vreinterpretq_f32_m128(_mm_round_ps(a, _MM_FROUND_CUR_DIRECTION))))); +#endif +} + +// Convert the signed 32-bit integer b to a single-precision (32-bit) +// floating-point element, store the result in the lower element of dst, and +// copy the upper 3 packed elements from a to the upper elements of dst. +// +// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_si2ss +FORCE_INLINE __m128 _mm_cvt_si2ss(__m128 a, int b) +{ + return vreinterpretq_m128_f32( + vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0)); +} + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 32-bit integer, and store the result in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ss2si +FORCE_INLINE int _mm_cvt_ss2si(__m128 a) +{ +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) + return vgetq_lane_s32(vcvtnq_s32_f32(vrndiq_f32(vreinterpretq_f32_m128(a))), + 0); +#else + float32_t data = vgetq_lane_f32( + vreinterpretq_f32_m128(_mm_round_ps(a, _MM_FROUND_CUR_DIRECTION)), 0); + return (int32_t) data; +#endif +} + +// Convert packed 16-bit integers in a to packed single-precision (32-bit) +// floating-point elements, and store the results in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// m := j*32 +// dst[m+31:m] := Convert_Int16_To_FP32(a[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi16_ps +FORCE_INLINE __m128 _mm_cvtpi16_ps(__m64 a) +{ + return vreinterpretq_m128_f32( + vcvtq_f32_s32(vmovl_s16(vreinterpret_s16_m64(a)))); +} + +// Convert packed 32-bit integers in b to packed single-precision (32-bit) +// floating-point elements, store the results in the lower 2 elements of dst, +// and copy the upper 2 packed elements from a to the upper elements of dst. +// +// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) +// dst[63:32] := Convert_Int32_To_FP32(b[63:32]) +// dst[95:64] := a[95:64] +// dst[127:96] := a[127:96] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_ps +FORCE_INLINE __m128 _mm_cvtpi32_ps(__m128 a, __m64 b) +{ + return vreinterpretq_m128_f32( + vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)), + vget_high_f32(vreinterpretq_f32_m128(a)))); +} + +// Convert packed signed 32-bit integers in a to packed single-precision +// (32-bit) floating-point elements, store the results in the lower 2 elements +// of dst, then convert the packed signed 32-bit integers in b to +// single-precision (32-bit) floating-point element, and store the results in +// the upper 2 elements of dst. +// +// dst[31:0] := Convert_Int32_To_FP32(a[31:0]) +// dst[63:32] := Convert_Int32_To_FP32(a[63:32]) +// dst[95:64] := Convert_Int32_To_FP32(b[31:0]) +// dst[127:96] := Convert_Int32_To_FP32(b[63:32]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32x2_ps +FORCE_INLINE __m128 _mm_cvtpi32x2_ps(__m64 a, __m64 b) +{ + return vreinterpretq_m128_f32(vcvtq_f32_s32( + vcombine_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b)))); +} + +// Convert the lower packed 8-bit integers in a to packed single-precision +// (32-bit) floating-point elements, and store the results in dst. +// +// FOR j := 0 to 3 +// i := j*8 +// m := j*32 +// dst[m+31:m] := Convert_Int8_To_FP32(a[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi8_ps +FORCE_INLINE __m128 _mm_cvtpi8_ps(__m64 a) +{ + return vreinterpretq_m128_f32(vcvtq_f32_s32( + vmovl_s16(vget_low_s16(vmovl_s8(vreinterpret_s8_m64(a)))))); +} + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed 16-bit integers, and store the results in dst. Note: this intrinsic +// will generate 0x7FFF, rather than 0x8000, for input values between 0x7FFF and +// 0x7FFFFFFF. +// +// FOR j := 0 to 3 +// i := 16*j +// k := 32*j +// IF a[k+31:k] >= FP32(0x7FFF) && a[k+31:k] <= FP32(0x7FFFFFFF) +// dst[i+15:i] := 0x7FFF +// ELSE +// dst[i+15:i] := Convert_FP32_To_Int16(a[k+31:k]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi16 +FORCE_INLINE __m64 _mm_cvtps_pi16(__m128 a) +{ + const __m128 i16Min = _mm_set_ps1((float) INT16_MIN); + const __m128 i16Max = _mm_set_ps1((float) INT16_MAX); + const __m128 i32Max = _mm_set_ps1((float) INT32_MAX); + const __m128i maxMask = _mm_castps_si128( + _mm_and_ps(_mm_cmpge_ps(a, i16Max), _mm_cmple_ps(a, i32Max))); + const __m128i betweenMask = _mm_castps_si128( + _mm_and_ps(_mm_cmpgt_ps(a, i16Min), _mm_cmplt_ps(a, i16Max))); + const __m128i minMask = _mm_cmpeq_epi32(_mm_or_si128(maxMask, betweenMask), + _mm_setzero_si128()); + __m128i max = _mm_and_si128(maxMask, _mm_set1_epi32(INT16_MAX)); + __m128i min = _mm_and_si128(minMask, _mm_set1_epi32(INT16_MIN)); + __m128i cvt = _mm_and_si128(betweenMask, _mm_cvtps_epi32(a)); + __m128i res32 = _mm_or_si128(_mm_or_si128(max, min), cvt); + return vreinterpret_m64_s16(vmovn_s32(vreinterpretq_s32_m128i(res32))); +} + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed 32-bit integers, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi32 +#define _mm_cvtps_pi32(a) _mm_cvt_ps2pi(a) + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed 8-bit integers, and store the results in lower 4 elements of dst. +// Note: this intrinsic will generate 0x7F, rather than 0x80, for input values +// between 0x7F and 0x7FFFFFFF. +// +// FOR j := 0 to 3 +// i := 8*j +// k := 32*j +// IF a[k+31:k] >= FP32(0x7F) && a[k+31:k] <= FP32(0x7FFFFFFF) +// dst[i+7:i] := 0x7F +// ELSE +// dst[i+7:i] := Convert_FP32_To_Int8(a[k+31:k]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi8 +FORCE_INLINE __m64 _mm_cvtps_pi8(__m128 a) +{ + const __m128 i8Min = _mm_set_ps1((float) INT8_MIN); + const __m128 i8Max = _mm_set_ps1((float) INT8_MAX); + const __m128 i32Max = _mm_set_ps1((float) INT32_MAX); + const __m128i maxMask = _mm_castps_si128( + _mm_and_ps(_mm_cmpge_ps(a, i8Max), _mm_cmple_ps(a, i32Max))); + const __m128i betweenMask = _mm_castps_si128( + _mm_and_ps(_mm_cmpgt_ps(a, i8Min), _mm_cmplt_ps(a, i8Max))); + const __m128i minMask = _mm_cmpeq_epi32(_mm_or_si128(maxMask, betweenMask), + _mm_setzero_si128()); + __m128i max = _mm_and_si128(maxMask, _mm_set1_epi32(INT8_MAX)); + __m128i min = _mm_and_si128(minMask, _mm_set1_epi32(INT8_MIN)); + __m128i cvt = _mm_and_si128(betweenMask, _mm_cvtps_epi32(a)); + __m128i res32 = _mm_or_si128(_mm_or_si128(max, min), cvt); + int16x4_t res16 = vmovn_s32(vreinterpretq_s32_m128i(res32)); + int8x8_t res8 = vmovn_s16(vcombine_s16(res16, res16)); + static const uint32_t bitMask[2] = {0xFFFFFFFF, 0}; + int8x8_t mask = vreinterpret_s8_u32(vld1_u32(bitMask)); + + return vreinterpret_m64_s8(vorr_s8(vand_s8(mask, res8), vdup_n_s8(0))); +} + +// Convert packed unsigned 16-bit integers in a to packed single-precision +// (32-bit) floating-point elements, and store the results in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// m := j*32 +// dst[m+31:m] := Convert_UInt16_To_FP32(a[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu16_ps +FORCE_INLINE __m128 _mm_cvtpu16_ps(__m64 a) +{ + return vreinterpretq_m128_f32( + vcvtq_f32_u32(vmovl_u16(vreinterpret_u16_m64(a)))); +} + +// Convert the lower packed unsigned 8-bit integers in a to packed +// single-precision (32-bit) floating-point elements, and store the results in +// dst. +// +// FOR j := 0 to 3 +// i := j*8 +// m := j*32 +// dst[m+31:m] := Convert_UInt8_To_FP32(a[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu8_ps +FORCE_INLINE __m128 _mm_cvtpu8_ps(__m64 a) +{ + return vreinterpretq_m128_f32(vcvtq_f32_u32( + vmovl_u16(vget_low_u16(vmovl_u8(vreinterpret_u8_m64(a)))))); +} + +// Convert the signed 32-bit integer b to a single-precision (32-bit) +// floating-point element, store the result in the lower element of dst, and +// copy the upper 3 packed elements from a to the upper elements of dst. +// +// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_ss +#define _mm_cvtsi32_ss(a, b) _mm_cvt_si2ss(a, b) + +// Convert the signed 64-bit integer b to a single-precision (32-bit) +// floating-point element, store the result in the lower element of dst, and +// copy the upper 3 packed elements from a to the upper elements of dst. +// +// dst[31:0] := Convert_Int64_To_FP32(b[63:0]) +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_ss +FORCE_INLINE __m128 _mm_cvtsi64_ss(__m128 a, int64_t b) +{ + return vreinterpretq_m128_f32( + vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0)); +} + +// Copy the lower single-precision (32-bit) floating-point element of a to dst. +// +// dst[31:0] := a[31:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_f32 +FORCE_INLINE float _mm_cvtss_f32(__m128 a) +{ + return vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); +} + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 32-bit integer, and store the result in dst. +// +// dst[31:0] := Convert_FP32_To_Int32(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si32 +#define _mm_cvtss_si32(a) _mm_cvt_ss2si(a) + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 64-bit integer, and store the result in dst. +// +// dst[63:0] := Convert_FP32_To_Int64(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si64 +FORCE_INLINE int64_t _mm_cvtss_si64(__m128 a) +{ +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) + return (int64_t) vgetq_lane_f32(vrndiq_f32(vreinterpretq_f32_m128(a)), 0); +#else + float32_t data = vgetq_lane_f32( + vreinterpretq_f32_m128(_mm_round_ps(a, _MM_FROUND_CUR_DIRECTION)), 0); + return (int64_t) data; +#endif +} + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed 32-bit integers with truncation, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ps2pi +FORCE_INLINE __m64 _mm_cvtt_ps2pi(__m128 a) +{ + return vreinterpret_m64_s32( + vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)))); +} + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 32-bit integer with truncation, and store the result in dst. +// +// dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ss2si +FORCE_INLINE int _mm_cvtt_ss2si(__m128 a) +{ + return vgetq_lane_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)), 0); +} + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed 32-bit integers with truncation, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttps_pi32 +#define _mm_cvttps_pi32(a) _mm_cvtt_ps2pi(a) + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 32-bit integer with truncation, and store the result in dst. +// +// dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si32 +#define _mm_cvttss_si32(a) _mm_cvtt_ss2si(a) + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 64-bit integer with truncation, and store the result in dst. +// +// dst[63:0] := Convert_FP32_To_Int64_Truncate(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si64 +FORCE_INLINE int64_t _mm_cvttss_si64(__m128 a) +{ + return (int64_t) vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); +} + +// Divides the four single-precision, floating-point values of a and b. +// +// r0 := a0 / b0 +// r1 := a1 / b1 +// r2 := a2 / b2 +// r3 := a3 / b3 +// +// https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx +FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b) +{ +#if defined(__aarch64__) && !SSE2NEON_PRECISE_DIV + return vreinterpretq_m128_f32( + vdivq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#else + float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(b)); + recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b))); +#if SSE2NEON_PRECISE_DIV + // Additional Netwon-Raphson iteration for accuracy + recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b))); +#endif + return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(a), recip)); +#endif +} + +// Divides the scalar single-precision floating point value of a by b. +// https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx +FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b) +{ + float32_t value = + vgetq_lane_f32(vreinterpretq_f32_m128(_mm_div_ps(a, b)), 0); + return vreinterpretq_m128_f32( + vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); +} + +// Extract a 16-bit integer from a, selected with imm8, and store the result in +// the lower element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_extract_pi16 +#define _mm_extract_pi16(a, imm) \ + (int32_t) vget_lane_u16(vreinterpret_u16_m64(a), (imm)) + +// Free aligned memory that was allocated with _mm_malloc. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_free +FORCE_INLINE void _mm_free(void *addr) +{ + free(addr); +} + +// Macro: Get the flush zero bits from the MXCSR control and status register. +// The flush zero may contain any of the following flags: _MM_FLUSH_ZERO_ON or +// _MM_FLUSH_ZERO_OFF +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_GET_FLUSH_ZERO_MODE +FORCE_INLINE unsigned int _sse2neon_mm_get_flush_zero_mode() +{ + union { + fpcr_bitfield field; +#if defined(__aarch64__) + uint64_t value; +#else + uint32_t value; +#endif + } r; + +#if defined(__aarch64__) + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ +#else + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ +#endif + + return r.field.bit24 ? _MM_FLUSH_ZERO_ON : _MM_FLUSH_ZERO_OFF; +} + +// Macro: Get the rounding mode bits from the MXCSR control and status register. +// The rounding mode may contain any of the following flags: _MM_ROUND_NEAREST, +// _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_GET_ROUNDING_MODE +FORCE_INLINE unsigned int _MM_GET_ROUNDING_MODE() +{ + union { + fpcr_bitfield field; +#if defined(__aarch64__) + uint64_t value; +#else + uint32_t value; +#endif + } r; + +#if defined(__aarch64__) + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ +#else + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ +#endif + + if (r.field.bit22) { + return r.field.bit23 ? _MM_ROUND_TOWARD_ZERO : _MM_ROUND_UP; + } else { + return r.field.bit23 ? _MM_ROUND_DOWN : _MM_ROUND_NEAREST; + } +} + +// Copy a to dst, and insert the 16-bit integer i into dst at the location +// specified by imm8. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_insert_pi16 +#define _mm_insert_pi16(a, b, imm) \ + __extension__({ \ + vreinterpret_m64_s16( \ + vset_lane_s16((b), vreinterpret_s16_m64(a), (imm))); \ + }) + +// Loads four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx +FORCE_INLINE __m128 _mm_load_ps(const float *p) +{ + return vreinterpretq_m128_f32(vld1q_f32(p)); +} + +// Load a single-precision (32-bit) floating-point element from memory into all +// elements of dst. +// +// dst[31:0] := MEM[mem_addr+31:mem_addr] +// dst[63:32] := MEM[mem_addr+31:mem_addr] +// dst[95:64] := MEM[mem_addr+31:mem_addr] +// dst[127:96] := MEM[mem_addr+31:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_ps1 +#define _mm_load_ps1 _mm_load1_ps + +// Loads an single - precision, floating - point value into the low word and +// clears the upper three words. +// https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx +FORCE_INLINE __m128 _mm_load_ss(const float *p) +{ + return vreinterpretq_m128_f32(vsetq_lane_f32(*p, vdupq_n_f32(0), 0)); +} + +// Loads a single single-precision, floating-point value, copying it into all +// four words +// https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx +FORCE_INLINE __m128 _mm_load1_ps(const float *p) +{ + return vreinterpretq_m128_f32(vld1q_dup_f32(p)); +} + +// Sets the upper two single-precision, floating-point values with 64 +// bits of data loaded from the address p; the lower two values are passed +// through from a. +// +// r0 := a0 +// r1 := a1 +// r2 := *p0 +// r3 := *p1 +// +// https://msdn.microsoft.com/en-us/library/w92wta0x(v%3dvs.100).aspx +FORCE_INLINE __m128 _mm_loadh_pi(__m128 a, __m64 const *p) +{ + return vreinterpretq_m128_f32( + vcombine_f32(vget_low_f32(a), vld1_f32((const float32_t *) p))); +} + +// Sets the lower two single-precision, floating-point values with 64 +// bits of data loaded from the address p; the upper two values are passed +// through from a. +// +// Return Value +// r0 := *p0 +// r1 := *p1 +// r2 := a2 +// r3 := a3 +// +// https://msdn.microsoft.com/en-us/library/s57cyak2(v=vs.100).aspx +FORCE_INLINE __m128 _mm_loadl_pi(__m128 a, __m64 const *p) +{ + return vreinterpretq_m128_f32( + vcombine_f32(vld1_f32((const float32_t *) p), vget_high_f32(a))); +} + +// Load 4 single-precision (32-bit) floating-point elements from memory into dst +// in reverse order. mem_addr must be aligned on a 16-byte boundary or a +// general-protection exception may be generated. +// +// dst[31:0] := MEM[mem_addr+127:mem_addr+96] +// dst[63:32] := MEM[mem_addr+95:mem_addr+64] +// dst[95:64] := MEM[mem_addr+63:mem_addr+32] +// dst[127:96] := MEM[mem_addr+31:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_ps +FORCE_INLINE __m128 _mm_loadr_ps(const float *p) +{ + float32x4_t v = vrev64q_f32(vld1q_f32(p)); + return vreinterpretq_m128_f32(vextq_f32(v, v, 2)); +} + +// Loads four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx +FORCE_INLINE __m128 _mm_loadu_ps(const float *p) +{ + // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are + // equivalent for neon + return vreinterpretq_m128_f32(vld1q_f32(p)); +} + +// Load unaligned 16-bit integer from memory into the first element of dst. +// +// dst[15:0] := MEM[mem_addr+15:mem_addr] +// dst[MAX:16] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si16 +FORCE_INLINE __m128i _mm_loadu_si16(const void *p) +{ + return vreinterpretq_m128i_s16( + vsetq_lane_s16(*(const int16_t *) p, vdupq_n_s16(0), 0)); +} + +// Load unaligned 64-bit integer from memory into the first element of dst. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[MAX:64] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si64 +FORCE_INLINE __m128i _mm_loadu_si64(const void *p) +{ + return vreinterpretq_m128i_s64( + vcombine_s64(vld1_s64((const int64_t *) p), vdup_n_s64(0))); +} + +// Allocate aligned blocks of memory. +// https://software.intel.com/en-us/ +// cpp-compiler-developer-guide-and-reference-allocating-and-freeing-aligned-memory-blocks +FORCE_INLINE void *_mm_malloc(size_t size, size_t align) +{ + void *ptr; + if (align == 1) + return malloc(size); + if (align == 2 || (sizeof(void *) == 8 && align == 4)) + align = sizeof(void *); + if (!posix_memalign(&ptr, align, size)) + return ptr; + return NULL; +} + +// Conditionally store 8-bit integer elements from a into memory using mask +// (elements are not stored when the highest bit is not set in the corresponding +// element) and a non-temporal memory hint. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskmove_si64 +FORCE_INLINE void _mm_maskmove_si64(__m64 a, __m64 mask, char *mem_addr) +{ + int8x8_t shr_mask = vshr_n_s8(vreinterpret_s8_m64(mask), 7); + __m128 b = _mm_load_ps((const float *) mem_addr); + int8x8_t masked = + vbsl_s8(vreinterpret_u8_s8(shr_mask), vreinterpret_s8_m64(a), + vreinterpret_s8_u64(vget_low_u64(vreinterpretq_u64_m128(b)))); + vst1_s8((int8_t *) mem_addr, masked); +} + +// Conditionally store 8-bit integer elements from a into memory using mask +// (elements are not stored when the highest bit is not set in the corresponding +// element) and a non-temporal memory hint. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_maskmovq +#define _m_maskmovq(a, mask, mem_addr) _mm_maskmove_si64(a, mask, mem_addr) + +// Compare packed signed 16-bit integers in a and b, and store packed maximum +// values in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := MAX(a[i+15:i], b[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16 +FORCE_INLINE __m64 _mm_max_pi16(__m64 a, __m64 b) +{ + return vreinterpret_m64_s16( + vmax_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); +} + +// Computes the maximums of the four single-precision, floating-point values of +// a and b. +// https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx +FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b) +{ +#if SSE2NEON_PRECISE_MINMAX + float32x4_t _a = vreinterpretq_f32_m128(a); + float32x4_t _b = vreinterpretq_f32_m128(b); + return vreinterpretq_m128_f32(vbslq_f32(vcgtq_f32(_a, _b), _a, _b)); +#else + return vreinterpretq_m128_f32( + vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#endif +} + +// Compare packed unsigned 8-bit integers in a and b, and store packed maximum +// values in dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := MAX(a[i+7:i], b[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8 +FORCE_INLINE __m64 _mm_max_pu8(__m64 a, __m64 b) +{ + return vreinterpret_m64_u8( + vmax_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); +} + +// Computes the maximum of the two lower scalar single-precision floating point +// values of a and b. +// https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx +FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b) +{ + float32_t value = vgetq_lane_f32(_mm_max_ps(a, b), 0); + return vreinterpretq_m128_f32( + vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); +} + +// Compare packed signed 16-bit integers in a and b, and store packed minimum +// values in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := MIN(a[i+15:i], b[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16 +FORCE_INLINE __m64 _mm_min_pi16(__m64 a, __m64 b) +{ + return vreinterpret_m64_s16( + vmin_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); +} + +// Computes the minima of the four single-precision, floating-point values of a +// and b. +// https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx +FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b) +{ +#if SSE2NEON_PRECISE_MINMAX + float32x4_t _a = vreinterpretq_f32_m128(a); + float32x4_t _b = vreinterpretq_f32_m128(b); + return vreinterpretq_m128_f32(vbslq_f32(vcltq_f32(_a, _b), _a, _b)); +#else + return vreinterpretq_m128_f32( + vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#endif +} + +// Compare packed unsigned 8-bit integers in a and b, and store packed minimum +// values in dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := MIN(a[i+7:i], b[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8 +FORCE_INLINE __m64 _mm_min_pu8(__m64 a, __m64 b) +{ + return vreinterpret_m64_u8( + vmin_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); +} + +// Computes the minimum of the two lower scalar single-precision floating point +// values of a and b. +// https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx +FORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b) +{ + float32_t value = vgetq_lane_f32(_mm_min_ps(a, b), 0); + return vreinterpretq_m128_f32( + vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); +} + +// Sets the low word to the single-precision, floating-point value of b +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/35hdzazd(v=vs.100) +FORCE_INLINE __m128 _mm_move_ss(__m128 a, __m128 b) +{ + return vreinterpretq_m128_f32( + vsetq_lane_f32(vgetq_lane_f32(vreinterpretq_f32_m128(b), 0), + vreinterpretq_f32_m128(a), 0)); +} + +// Moves the upper two values of B into the lower two values of A. +// +// r3 := a3 +// r2 := a2 +// r1 := b3 +// r0 := b2 +FORCE_INLINE __m128 _mm_movehl_ps(__m128 __A, __m128 __B) +{ + float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(__A)); + float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(__B)); + return vreinterpretq_m128_f32(vcombine_f32(b32, a32)); +} + +// Moves the lower two values of B into the upper two values of A. +// +// r3 := b1 +// r2 := b0 +// r1 := a1 +// r0 := a0 +FORCE_INLINE __m128 _mm_movelh_ps(__m128 __A, __m128 __B) +{ + float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(__A)); + float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(__B)); + return vreinterpretq_m128_f32(vcombine_f32(a10, b10)); +} + +// Create mask from the most significant bit of each 8-bit element in a, and +// store the result in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movemask_pi8 +FORCE_INLINE int _mm_movemask_pi8(__m64 a) +{ + uint8x8_t input = vreinterpret_u8_m64(a); +#if defined(__aarch64__) + static const int8x8_t shift = {0, 1, 2, 3, 4, 5, 6, 7}; + uint8x8_t tmp = vshr_n_u8(input, 7); + return vaddv_u8(vshl_u8(tmp, shift)); +#else + // Refer the implementation of `_mm_movemask_epi8` + uint16x4_t high_bits = vreinterpret_u16_u8(vshr_n_u8(input, 7)); + uint32x2_t paired16 = + vreinterpret_u32_u16(vsra_n_u16(high_bits, high_bits, 7)); + uint8x8_t paired32 = + vreinterpret_u8_u32(vsra_n_u32(paired16, paired16, 14)); + return vget_lane_u8(paired32, 0) | ((int) vget_lane_u8(paired32, 4) << 4); +#endif +} + +// NEON does not provide this method +// Creates a 4-bit mask from the most significant bits of the four +// single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx +FORCE_INLINE int _mm_movemask_ps(__m128 a) +{ + uint32x4_t input = vreinterpretq_u32_m128(a); +#if defined(__aarch64__) + static const int32x4_t shift = {0, 1, 2, 3}; + uint32x4_t tmp = vshrq_n_u32(input, 31); + return vaddvq_u32(vshlq_u32(tmp, shift)); +#else + // Uses the exact same method as _mm_movemask_epi8, see that for details. + // Shift out everything but the sign bits with a 32-bit unsigned shift + // right. + uint64x2_t high_bits = vreinterpretq_u64_u32(vshrq_n_u32(input, 31)); + // Merge the two pairs together with a 64-bit unsigned shift right + add. + uint8x16_t paired = + vreinterpretq_u8_u64(vsraq_n_u64(high_bits, high_bits, 31)); + // Extract the result. + return vgetq_lane_u8(paired, 0) | (vgetq_lane_u8(paired, 8) << 2); +#endif +} + +// Multiplies the four single-precision, floating-point values of a and b. +// +// r0 := a0 * b0 +// r1 := a1 * b1 +// r2 := a2 * b2 +// r3 := a3 * b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx +FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_f32( + vmulq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Multiply the lower single-precision (32-bit) floating-point element in a and +// b, store the result in the lower element of dst, and copy the upper 3 packed +// elements from a to the upper elements of dst. +// +// dst[31:0] := a[31:0] * b[31:0] +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_ss +FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_mul_ps(a, b)); +} + +// Multiply the packed unsigned 16-bit integers in a and b, producing +// intermediate 32-bit integers, and store the high 16 bits of the intermediate +// integers in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_pu16 +FORCE_INLINE __m64 _mm_mulhi_pu16(__m64 a, __m64 b) +{ + return vreinterpret_m64_u16(vshrn_n_u32( + vmull_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b)), 16)); +} + +// Computes the bitwise OR of the four single-precision, floating-point values +// of a and b. +// https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx +FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_s32( + vorrq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); +} + +// Average packed unsigned 8-bit integers in a and b, and store the results in +// dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgb +#define _m_pavgb(a, b) _mm_avg_pu8(a, b) + +// Average packed unsigned 16-bit integers in a and b, and store the results in +// dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgw +#define _m_pavgw(a, b) _mm_avg_pu16(a, b) + +// Extract a 16-bit integer from a, selected with imm8, and store the result in +// the lower element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pextrw +#define _m_pextrw(a, imm) _mm_extract_pi16(a, imm) + +// Copy a to dst, and insert the 16-bit integer i into dst at the location +// specified by imm8. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_pinsrw +#define _m_pinsrw(a, i, imm) _mm_insert_pi16(a, i, imm) + +// Compare packed signed 16-bit integers in a and b, and store packed maximum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxsw +#define _m_pmaxsw(a, b) _mm_max_pi16(a, b) + +// Compare packed unsigned 8-bit integers in a and b, and store packed maximum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxub +#define _m_pmaxub(a, b) _mm_max_pu8(a, b) + +// Compare packed signed 16-bit integers in a and b, and store packed minimum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminsw +#define _m_pminsw(a, b) _mm_min_pi16(a, b) + +// Compare packed unsigned 8-bit integers in a and b, and store packed minimum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminub +#define _m_pminub(a, b) _mm_min_pu8(a, b) + +// Create mask from the most significant bit of each 8-bit element in a, and +// store the result in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmovmskb +#define _m_pmovmskb(a) _mm_movemask_pi8(a) + +// Multiply the packed unsigned 16-bit integers in a and b, producing +// intermediate 32-bit integers, and store the high 16 bits of the intermediate +// integers in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmulhuw +#define _m_pmulhuw(a, b) _mm_mulhi_pu16(a, b) + +// Loads one cache line of data from address p to a location closer to the +// processor. https://msdn.microsoft.com/en-us/library/84szxsww(v=vs.100).aspx +FORCE_INLINE void _mm_prefetch(const void *p, int i) +{ + (void) i; + __builtin_prefetch(p); +} + +// Compute the absolute differences of packed unsigned 8-bit integers in a and +// b, then horizontally sum each consecutive 8 differences to produce four +// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low +// 16 bits of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_psadbw +#define _m_psadbw(a, b) _mm_sad_pu8(a, b) + +// Shuffle 16-bit integers in a using the control in imm8, and store the results +// in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pshufw +#define _m_pshufw(a, imm) _mm_shuffle_pi16(a, imm) + +// Compute the approximate reciprocal of packed single-precision (32-bit) +// floating-point elements in a, and store the results in dst. The maximum +// relative error for this approximation is less than 1.5*2^-12. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ps +FORCE_INLINE __m128 _mm_rcp_ps(__m128 in) +{ + float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in)); + recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in))); +#if SSE2NEON_PRECISE_DIV + // Additional Netwon-Raphson iteration for accuracy + recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in))); +#endif + return vreinterpretq_m128_f32(recip); +} + +// Compute the approximate reciprocal of the lower single-precision (32-bit) +// floating-point element in a, store the result in the lower element of dst, +// and copy the upper 3 packed elements from a to the upper elements of dst. The +// maximum relative error for this approximation is less than 1.5*2^-12. +// +// dst[31:0] := (1.0 / a[31:0]) +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ss +FORCE_INLINE __m128 _mm_rcp_ss(__m128 a) +{ + return _mm_move_ss(a, _mm_rcp_ps(a)); +} + +// Computes the approximations of the reciprocal square roots of the four +// single-precision floating point values of in. +// The current precision is 1% error. +// https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx +FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in) +{ + float32x4_t out = vrsqrteq_f32(vreinterpretq_f32_m128(in)); +#if SSE2NEON_PRECISE_SQRT + // Additional Netwon-Raphson iteration for accuracy + out = vmulq_f32( + out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out)); + out = vmulq_f32( + out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out)); +#endif + return vreinterpretq_m128_f32(out); +} + +// Compute the approximate reciprocal square root of the lower single-precision +// (32-bit) floating-point element in a, store the result in the lower element +// of dst, and copy the upper 3 packed elements from a to the upper elements of +// dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt_ss +FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in) +{ + return vsetq_lane_f32(vgetq_lane_f32(_mm_rsqrt_ps(in), 0), in, 0); +} + +// Compute the absolute differences of packed unsigned 8-bit integers in a and +// b, then horizontally sum each consecutive 8 differences to produce four +// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low +// 16 bits of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_pu8 +FORCE_INLINE __m64 _mm_sad_pu8(__m64 a, __m64 b) +{ + uint64x1_t t = vpaddl_u32(vpaddl_u16( + vpaddl_u8(vabd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))))); + return vreinterpret_m64_u16( + vset_lane_u16(vget_lane_u64(t, 0), vdup_n_u16(0), 0)); +} + +// Macro: Set the flush zero bits of the MXCSR control and status register to +// the value in unsigned 32-bit integer a. The flush zero may contain any of the +// following flags: _MM_FLUSH_ZERO_ON or _MM_FLUSH_ZERO_OFF +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_SET_FLUSH_ZERO_MODE +FORCE_INLINE void _sse2neon_mm_set_flush_zero_mode(unsigned int flag) +{ + // AArch32 Advanced SIMD arithmetic always uses the Flush-to-zero setting, + // regardless of the value of the FZ bit. + union { + fpcr_bitfield field; +#if defined(__aarch64__) + uint64_t value; +#else + uint32_t value; +#endif + } r; + +#if defined(__aarch64__) + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ +#else + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ +#endif + + r.field.bit24 = (flag & _MM_FLUSH_ZERO_MASK) == _MM_FLUSH_ZERO_ON; + +#if defined(__aarch64__) + __asm__ __volatile__("msr FPCR, %0" ::"r"(r)); /* write */ +#else + __asm__ __volatile__("vmsr FPSCR, %0" ::"r"(r)); /* write */ +#endif +} + +// Sets the four single-precision, floating-point values to the four inputs. +// https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx +FORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x) +{ + float ALIGN_STRUCT(16) data[4] = {x, y, z, w}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +} + +// Sets the four single-precision, floating-point values to w. +// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx +FORCE_INLINE __m128 _mm_set_ps1(float _w) +{ + return vreinterpretq_m128_f32(vdupq_n_f32(_w)); +} + +// Macro: Set the rounding mode bits of the MXCSR control and status register to +// the value in unsigned 32-bit integer a. The rounding mode may contain any of +// the following flags: _MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, +// _MM_ROUND_TOWARD_ZERO +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_SET_ROUNDING_MODE +FORCE_INLINE void _MM_SET_ROUNDING_MODE(int rounding) +{ + union { + fpcr_bitfield field; +#if defined(__aarch64__) + uint64_t value; +#else + uint32_t value; +#endif + } r; + +#if defined(__aarch64__) + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ +#else + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ +#endif + + switch (rounding) { + case _MM_ROUND_TOWARD_ZERO: + r.field.bit22 = 1; + r.field.bit23 = 1; + break; + case _MM_ROUND_DOWN: + r.field.bit22 = 0; + r.field.bit23 = 1; + break; + case _MM_ROUND_UP: + r.field.bit22 = 1; + r.field.bit23 = 0; + break; + default: //_MM_ROUND_NEAREST + r.field.bit22 = 0; + r.field.bit23 = 0; + } + +#if defined(__aarch64__) + __asm__ __volatile__("msr FPCR, %0" ::"r"(r)); /* write */ +#else + __asm__ __volatile__("vmsr FPSCR, %0" ::"r"(r)); /* write */ +#endif +} + +// Copy single-precision (32-bit) floating-point element a to the lower element +// of dst, and zero the upper 3 elements. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_ss +FORCE_INLINE __m128 _mm_set_ss(float a) +{ + float ALIGN_STRUCT(16) data[4] = {a, 0, 0, 0}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +} + +// Sets the four single-precision, floating-point values to w. +// +// r0 := r1 := r2 := r3 := w +// +// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx +FORCE_INLINE __m128 _mm_set1_ps(float _w) +{ + return vreinterpretq_m128_f32(vdupq_n_f32(_w)); +} + +// FIXME: _mm_setcsr() implementation supports changing the rounding mode only. +FORCE_INLINE void _mm_setcsr(unsigned int a) +{ + _MM_SET_ROUNDING_MODE(a); +} + +// FIXME: _mm_getcsr() implementation supports reading the rounding mode only. +FORCE_INLINE unsigned int _mm_getcsr() +{ + return _MM_GET_ROUNDING_MODE(); +} + +// Sets the four single-precision, floating-point values to the four inputs in +// reverse order. +// https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx +FORCE_INLINE __m128 _mm_setr_ps(float w, float z, float y, float x) +{ + float ALIGN_STRUCT(16) data[4] = {w, z, y, x}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +} + +// Clears the four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx +FORCE_INLINE __m128 _mm_setzero_ps(void) +{ + return vreinterpretq_m128_f32(vdupq_n_f32(0)); +} + +// Shuffle 16-bit integers in a using the control in imm8, and store the results +// in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pi16 +#if __has_builtin(__builtin_shufflevector) +#define _mm_shuffle_pi16(a, imm) \ + __extension__({ \ + vreinterpret_m64_s16(__builtin_shufflevector( \ + vreinterpret_s16_m64(a), vreinterpret_s16_m64(a), (imm & 0x3), \ + ((imm >> 2) & 0x3), ((imm >> 4) & 0x3), ((imm >> 6) & 0x3))); \ + }) +#else +#define _mm_shuffle_pi16(a, imm) \ + __extension__({ \ + int16x4_t ret; \ + ret = \ + vmov_n_s16(vget_lane_s16(vreinterpret_s16_m64(a), (imm) & (0x3))); \ + ret = vset_lane_s16( \ + vget_lane_s16(vreinterpret_s16_m64(a), ((imm) >> 2) & 0x3), ret, \ + 1); \ + ret = vset_lane_s16( \ + vget_lane_s16(vreinterpret_s16_m64(a), ((imm) >> 4) & 0x3), ret, \ + 2); \ + ret = vset_lane_s16( \ + vget_lane_s16(vreinterpret_s16_m64(a), ((imm) >> 6) & 0x3), ret, \ + 3); \ + vreinterpret_m64_s16(ret); \ + }) +#endif + +// Guarantees that every preceding store is globally visible before any +// subsequent store. +// https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx +FORCE_INLINE void _mm_sfence(void) +{ + __sync_synchronize(); +} + // FORCE_INLINE __m128 _mm_shuffle_ps(__m128 a, __m128 b, __constrange(0,255) // int imm) #if __has_builtin(__builtin_shufflevector) @@ -2015,737 +2622,2127 @@ FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b) }) #endif -// Takes the upper 64 bits of a and places it in the low end of the result -// Takes the lower 64 bits of a and places it into the high end of the result. -FORCE_INLINE __m128i _mm_shuffle_epi_1032(__m128i a) +// Computes the approximations of square roots of the four single-precision, +// floating-point values of a. First computes reciprocal square roots and then +// reciprocals of the four values. +// +// r0 := sqrt(a0) +// r1 := sqrt(a1) +// r2 := sqrt(a2) +// r3 := sqrt(a3) +// +// https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx +FORCE_INLINE __m128 _mm_sqrt_ps(__m128 in) { - int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a)); - int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); - return vreinterpretq_m128i_s32(vcombine_s32(a32, a10)); -} +#if SSE2NEON_PRECISE_SQRT + float32x4_t recip = vrsqrteq_f32(vreinterpretq_f32_m128(in)); -// takes the lower two 32-bit values from a and swaps them and places in low end -// of result takes the higher two 32 bit values from a and swaps them and places -// in high end of result. -FORCE_INLINE __m128i _mm_shuffle_epi_2301(__m128i a) -{ - int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); - int32x2_t a23 = vrev64_s32(vget_high_s32(vreinterpretq_s32_m128i(a))); - return vreinterpretq_m128i_s32(vcombine_s32(a01, a23)); -} + // Test for vrsqrteq_f32(0) -> positive infinity case. + // Change to zero, so that s * 1/sqrt(s) result is zero too. + const uint32x4_t pos_inf = vdupq_n_u32(0x7F800000); + const uint32x4_t div_by_zero = + vceqq_u32(pos_inf, vreinterpretq_u32_f32(recip)); + recip = vreinterpretq_f32_u32( + vandq_u32(vmvnq_u32(div_by_zero), vreinterpretq_u32_f32(recip))); -// rotates the least significant 32 bits into the most signficant 32 bits, and -// shifts the rest down -FORCE_INLINE __m128i _mm_shuffle_epi_0321(__m128i a) -{ - return vreinterpretq_m128i_s32( - vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 1)); -} + // Additional Netwon-Raphson iteration for accuracy + recip = vmulq_f32( + vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)), + recip); + recip = vmulq_f32( + vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)), + recip); -// rotates the most significant 32 bits into the least signficant 32 bits, and -// shifts the rest up -FORCE_INLINE __m128i _mm_shuffle_epi_2103(__m128i a) -{ - return vreinterpretq_m128i_s32( - vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 3)); -} - -// gets the lower 64 bits of a, and places it in the upper 64 bits -// gets the lower 64 bits of a and places it in the lower 64 bits -FORCE_INLINE __m128i _mm_shuffle_epi_1010(__m128i a) -{ - int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); - return vreinterpretq_m128i_s32(vcombine_s32(a10, a10)); -} - -// gets the lower 64 bits of a, swaps the 0 and 1 elements, and places it in the -// lower 64 bits gets the lower 64 bits of a, and places it in the upper 64 bits -FORCE_INLINE __m128i _mm_shuffle_epi_1001(__m128i a) -{ - int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); - int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); - return vreinterpretq_m128i_s32(vcombine_s32(a01, a10)); -} - -// gets the lower 64 bits of a, swaps the 0 and 1 elements and places it in the -// upper 64 bits gets the lower 64 bits of a, swaps the 0 and 1 elements, and -// places it in the lower 64 bits -FORCE_INLINE __m128i _mm_shuffle_epi_0101(__m128i a) -{ - int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); - return vreinterpretq_m128i_s32(vcombine_s32(a01, a01)); -} - -FORCE_INLINE __m128i _mm_shuffle_epi_2211(__m128i a) -{ - int32x2_t a11 = vdup_lane_s32(vget_low_s32(vreinterpretq_s32_m128i(a)), 1); - int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0); - return vreinterpretq_m128i_s32(vcombine_s32(a11, a22)); -} - -FORCE_INLINE __m128i _mm_shuffle_epi_0122(__m128i a) -{ - int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0); - int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); - return vreinterpretq_m128i_s32(vcombine_s32(a22, a01)); -} - -FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a) -{ - int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a)); - int32x2_t a33 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 1); - return vreinterpretq_m128i_s32(vcombine_s32(a32, a33)); -} - -// Shuffle packed 8-bit integers in a according to shuffle control mask in the -// corresponding 8-bit element of b, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8 -FORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b) -{ - int8x16_t tbl = vreinterpretq_s8_m128i(a); // input a - uint8x16_t idx = vreinterpretq_u8_m128i(b); // input b - uint8x16_t idx_masked = - vandq_u8(idx, vdupq_n_u8(0x8F)); // avoid using meaningless bits -#if defined(__aarch64__) - return vreinterpretq_m128i_s8(vqtbl1q_s8(tbl, idx_masked)); -#elif defined(__GNUC__) - int8x16_t ret; - // %e and %f represent the even and odd D registers - // respectively. - __asm__ __volatile__( - "vtbl.8 %e[ret], {%e[tbl], %f[tbl]}, %e[idx]\n" - "vtbl.8 %f[ret], {%e[tbl], %f[tbl]}, %f[idx]\n" - : [ret] "=&w"(ret) - : [tbl] "w"(tbl), [idx] "w"(idx_masked)); - return vreinterpretq_m128i_s8(ret); + // sqrt(s) = s * 1/sqrt(s) + return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(in), recip)); +#elif defined(__aarch64__) + return vreinterpretq_m128_f32(vsqrtq_f32(vreinterpretq_f32_m128(in))); #else - // use this line if testing on aarch64 - int8x8x2_t a_split = {vget_low_s8(tbl), vget_high_s8(tbl)}; + float32x4_t recipsq = vrsqrteq_f32(vreinterpretq_f32_m128(in)); + float32x4_t sq = vrecpeq_f32(recipsq); + return vreinterpretq_m128_f32(sq); +#endif +} + +// Computes the approximation of the square root of the scalar single-precision +// floating point value of in. +// https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx +FORCE_INLINE __m128 _mm_sqrt_ss(__m128 in) +{ + float32_t value = + vgetq_lane_f32(vreinterpretq_f32_m128(_mm_sqrt_ps(in)), 0); + return vreinterpretq_m128_f32( + vsetq_lane_f32(value, vreinterpretq_f32_m128(in), 0)); +} + +// Stores four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx +FORCE_INLINE void _mm_store_ps(float *p, __m128 a) +{ + vst1q_f32(p, vreinterpretq_f32_m128(a)); +} + +// Store the lower single-precision (32-bit) floating-point element from a into +// 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte +// boundary or a general-protection exception may be generated. +// +// MEM[mem_addr+31:mem_addr] := a[31:0] +// MEM[mem_addr+63:mem_addr+32] := a[31:0] +// MEM[mem_addr+95:mem_addr+64] := a[31:0] +// MEM[mem_addr+127:mem_addr+96] := a[31:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_ps1 +FORCE_INLINE void _mm_store_ps1(float *p, __m128 a) +{ + float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); + vst1q_f32(p, vdupq_n_f32(a0)); +} + +// Stores the lower single - precision, floating - point value. +// https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx +FORCE_INLINE void _mm_store_ss(float *p, __m128 a) +{ + vst1q_lane_f32(p, vreinterpretq_f32_m128(a), 0); +} + +// Store the lower single-precision (32-bit) floating-point element from a into +// 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte +// boundary or a general-protection exception may be generated. +// +// MEM[mem_addr+31:mem_addr] := a[31:0] +// MEM[mem_addr+63:mem_addr+32] := a[31:0] +// MEM[mem_addr+95:mem_addr+64] := a[31:0] +// MEM[mem_addr+127:mem_addr+96] := a[31:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store1_ps +#define _mm_store1_ps _mm_store_ps1 + +// Stores the upper two single-precision, floating-point values of a to the +// address p. +// +// *p0 := a2 +// *p1 := a3 +// +// https://msdn.microsoft.com/en-us/library/a7525fs8(v%3dvs.90).aspx +FORCE_INLINE void _mm_storeh_pi(__m64 *p, __m128 a) +{ + *p = vreinterpret_m64_f32(vget_high_f32(a)); +} + +// Stores the lower two single-precision floating point values of a to the +// address p. +// +// *p0 := a0 +// *p1 := a1 +// +// https://msdn.microsoft.com/en-us/library/h54t98ks(v=vs.90).aspx +FORCE_INLINE void _mm_storel_pi(__m64 *p, __m128 a) +{ + *p = vreinterpret_m64_f32(vget_low_f32(a)); +} + +// Store 4 single-precision (32-bit) floating-point elements from a into memory +// in reverse order. mem_addr must be aligned on a 16-byte boundary or a +// general-protection exception may be generated. +// +// MEM[mem_addr+31:mem_addr] := a[127:96] +// MEM[mem_addr+63:mem_addr+32] := a[95:64] +// MEM[mem_addr+95:mem_addr+64] := a[63:32] +// MEM[mem_addr+127:mem_addr+96] := a[31:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_ps +FORCE_INLINE void _mm_storer_ps(float *p, __m128 a) +{ + float32x4_t tmp = vrev64q_f32(vreinterpretq_f32_m128(a)); + float32x4_t rev = vextq_f32(tmp, tmp, 2); + vst1q_f32(p, rev); +} + +// Stores four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx +FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a) +{ + vst1q_f32(p, vreinterpretq_f32_m128(a)); +} + +// Stores 16-bits of integer data a at the address p. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si16 +FORCE_INLINE void _mm_storeu_si16(void *p, __m128i a) +{ + vst1q_lane_s16((int16_t *) p, vreinterpretq_s16_m128i(a), 0); +} + +// Stores 64-bits of integer data a at the address p. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si64 +FORCE_INLINE void _mm_storeu_si64(void *p, __m128i a) +{ + vst1q_lane_s64((int64_t *) p, vreinterpretq_s64_m128i(a), 0); +} + +// Store 64-bits of integer data from a into memory using a non-temporal memory +// hint. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_pi +FORCE_INLINE void _mm_stream_pi(__m64 *p, __m64 a) +{ + vst1_s64((int64_t *) p, vreinterpret_s64_m64(a)); +} + +// Store 128-bits (composed of 4 packed single-precision (32-bit) floating- +// point elements) from a into memory using a non-temporal memory hint. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_ps +FORCE_INLINE void _mm_stream_ps(float *p, __m128 a) +{ +#if __has_builtin(__builtin_nontemporal_store) + __builtin_nontemporal_store(a, (float32x4_t *) p); +#else + vst1q_f32(p, vreinterpretq_f32_m128(a)); +#endif +} + +// Subtracts the four single-precision, floating-point values of a and b. +// +// r0 := a0 - b0 +// r1 := a1 - b1 +// r2 := a2 - b2 +// r3 := a3 - b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx +FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_f32( + vsubq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Subtract the lower single-precision (32-bit) floating-point element in b from +// the lower single-precision (32-bit) floating-point element in a, store the +// result in the lower element of dst, and copy the upper 3 packed elements from +// a to the upper elements of dst. +// +// dst[31:0] := a[31:0] - b[31:0] +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_ss +FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_sub_ps(a, b)); +} + +// Macro: Transpose the 4x4 matrix formed by the 4 rows of single-precision +// (32-bit) floating-point elements in row0, row1, row2, and row3, and store the +// transposed matrix in these vectors (row0 now contains column 0, etc.). +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=MM_TRANSPOSE4_PS +#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \ + do { \ + float32x4x2_t ROW01 = vtrnq_f32(row0, row1); \ + float32x4x2_t ROW23 = vtrnq_f32(row2, row3); \ + row0 = vcombine_f32(vget_low_f32(ROW01.val[0]), \ + vget_low_f32(ROW23.val[0])); \ + row1 = vcombine_f32(vget_low_f32(ROW01.val[1]), \ + vget_low_f32(ROW23.val[1])); \ + row2 = vcombine_f32(vget_high_f32(ROW01.val[0]), \ + vget_high_f32(ROW23.val[0])); \ + row3 = vcombine_f32(vget_high_f32(ROW01.val[1]), \ + vget_high_f32(ROW23.val[1])); \ + } while (0) + +// according to the documentation, these intrinsics behave the same as the +// non-'u' versions. We'll just alias them here. +#define _mm_ucomieq_ss _mm_comieq_ss +#define _mm_ucomige_ss _mm_comige_ss +#define _mm_ucomigt_ss _mm_comigt_ss +#define _mm_ucomile_ss _mm_comile_ss +#define _mm_ucomilt_ss _mm_comilt_ss +#define _mm_ucomineq_ss _mm_comineq_ss + +// Return vector of type __m128i with undefined elements. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_undefined_si128 +FORCE_INLINE __m128i _mm_undefined_si128(void) +{ +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif + __m128i a; + return a; +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif +} + +// Return vector of type __m128 with undefined elements. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_ps +FORCE_INLINE __m128 _mm_undefined_ps(void) +{ +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif + __m128 a; + return a; +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif +} + +// Selects and interleaves the upper two single-precision, floating-point values +// from a and b. +// +// r0 := a2 +// r1 := b2 +// r2 := a3 +// r3 := b3 +// +// https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx +FORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vzip2q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#else + float32x2_t a1 = vget_high_f32(vreinterpretq_f32_m128(a)); + float32x2_t b1 = vget_high_f32(vreinterpretq_f32_m128(b)); + float32x2x2_t result = vzip_f32(a1, b1); + return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1])); +#endif +} + +// Selects and interleaves the lower two single-precision, floating-point values +// from a and b. +// +// r0 := a0 +// r1 := b0 +// r2 := a1 +// r3 := b1 +// +// https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx +FORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vzip1q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#else + float32x2_t a1 = vget_low_f32(vreinterpretq_f32_m128(a)); + float32x2_t b1 = vget_low_f32(vreinterpretq_f32_m128(b)); + float32x2x2_t result = vzip_f32(a1, b1); + return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1])); +#endif +} + +// Computes bitwise EXOR (exclusive-or) of the four single-precision, +// floating-point values of a and b. +// https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx +FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_s32( + veorq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); +} + +/* SSE2 */ + +// Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or +// unsigned 16-bit integers in b. +// https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx +FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or +// unsigned 32-bit integers in b. +// +// r0 := a0 + b0 +// r1 := a1 + b1 +// r2 := a2 + b2 +// r3 := a3 + b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx +FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vaddq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Adds the 4 signed or unsigned 64-bit integers in a to the 4 signed or +// unsigned 32-bit integers in b. +// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx +FORCE_INLINE __m128i _mm_add_epi64(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s64( + vaddq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); +} + +// Adds the 16 signed or unsigned 8-bit integers in a to the 16 signed or +// unsigned 8-bit integers in b. +// https://technet.microsoft.com/en-us/subscriptions/yc7tcyzs(v=vs.90) +FORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b) +{ return vreinterpretq_m128i_s8( - vcombine_s8(vtbl2_s8(a_split, vget_low_u8(idx_masked)), - vtbl2_s8(a_split, vget_high_u8(idx_masked)))); + vaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Add packed double-precision (64-bit) floating-point elements in a and b, and +// store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_pd +FORCE_INLINE __m128d _mm_add_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + double *da = (double *) &a; + double *db = (double *) &b; + double c[2]; + c[0] = da[0] + db[0]; + c[1] = da[1] + db[1]; + return vld1q_f32((float32_t *) c); #endif } -// C equivalent: -// __m128i _mm_shuffle_epi32_default(__m128i a, -// __constrange(0, 255) int imm) { -// __m128i ret; -// ret[0] = a[imm & 0x3]; ret[1] = a[(imm >> 2) & 0x3]; -// ret[2] = a[(imm >> 4) & 0x03]; ret[3] = a[(imm >> 6) & 0x03]; -// return ret; -// } -#define _mm_shuffle_epi32_default(a, imm) \ - __extension__({ \ - int32x4_t ret; \ - ret = vmovq_n_s32( \ - vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm) & (0x3))); \ - ret = vsetq_lane_s32( \ - vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 2) & 0x3), \ - ret, 1); \ - ret = vsetq_lane_s32( \ - vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 4) & 0x3), \ - ret, 2); \ - ret = vsetq_lane_s32( \ - vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 6) & 0x3), \ - ret, 3); \ - vreinterpretq_m128i_s32(ret); \ - }) - -// FORCE_INLINE __m128i _mm_shuffle_epi32_splat(__m128i a, __constrange(0,255) -// int imm) +// Add the lower double-precision (64-bit) floating-point element in a and b, +// store the result in the lower element of dst, and copy the upper element from +// a to the upper element of dst. +// +// dst[63:0] := a[63:0] + b[63:0] +// dst[127:64] := a[127:64] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_sd +FORCE_INLINE __m128d _mm_add_sd(__m128d a, __m128d b) +{ #if defined(__aarch64__) -#define _mm_shuffle_epi32_splat(a, imm) \ - __extension__({ \ - vreinterpretq_m128i_s32( \ - vdupq_laneq_s32(vreinterpretq_s32_m128i(a), (imm))); \ - }) + return _mm_move_sd(a, _mm_add_pd(a, b)); #else -#define _mm_shuffle_epi32_splat(a, imm) \ - __extension__({ \ - vreinterpretq_m128i_s32( \ - vdupq_n_s32(vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)))); \ - }) + double *da = (double *) &a; + double *db = (double *) &b; + double c[2]; + c[0] = da[0] + db[0]; + c[1] = da[1]; + return vld1q_f32((float32_t *) c); #endif +} -// Shuffles the 4 signed or unsigned 32-bit integers in a as specified by imm. -// https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx -// FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i a, -// __constrange(0,255) int imm) -#if __has_builtin(__builtin_shufflevector) -#define _mm_shuffle_epi32(a, imm) \ - __extension__({ \ - int32x4_t _input = vreinterpretq_s32_m128i(a); \ - int32x4_t _shuf = __builtin_shufflevector( \ - _input, _input, (imm) & (0x3), ((imm) >> 2) & 0x3, \ - ((imm) >> 4) & 0x3, ((imm) >> 6) & 0x3); \ - vreinterpretq_m128i_s32(_shuf); \ - }) -#else // generic -#define _mm_shuffle_epi32(a, imm) \ - __extension__({ \ - __m128i ret; \ - switch (imm) { \ - case _MM_SHUFFLE(1, 0, 3, 2): \ - ret = _mm_shuffle_epi_1032((a)); \ - break; \ - case _MM_SHUFFLE(2, 3, 0, 1): \ - ret = _mm_shuffle_epi_2301((a)); \ - break; \ - case _MM_SHUFFLE(0, 3, 2, 1): \ - ret = _mm_shuffle_epi_0321((a)); \ - break; \ - case _MM_SHUFFLE(2, 1, 0, 3): \ - ret = _mm_shuffle_epi_2103((a)); \ - break; \ - case _MM_SHUFFLE(1, 0, 1, 0): \ - ret = _mm_shuffle_epi_1010((a)); \ - break; \ - case _MM_SHUFFLE(1, 0, 0, 1): \ - ret = _mm_shuffle_epi_1001((a)); \ - break; \ - case _MM_SHUFFLE(0, 1, 0, 1): \ - ret = _mm_shuffle_epi_0101((a)); \ - break; \ - case _MM_SHUFFLE(2, 2, 1, 1): \ - ret = _mm_shuffle_epi_2211((a)); \ - break; \ - case _MM_SHUFFLE(0, 1, 2, 2): \ - ret = _mm_shuffle_epi_0122((a)); \ - break; \ - case _MM_SHUFFLE(3, 3, 3, 2): \ - ret = _mm_shuffle_epi_3332((a)); \ - break; \ - case _MM_SHUFFLE(0, 0, 0, 0): \ - ret = _mm_shuffle_epi32_splat((a), 0); \ - break; \ - case _MM_SHUFFLE(1, 1, 1, 1): \ - ret = _mm_shuffle_epi32_splat((a), 1); \ - break; \ - case _MM_SHUFFLE(2, 2, 2, 2): \ - ret = _mm_shuffle_epi32_splat((a), 2); \ - break; \ - case _MM_SHUFFLE(3, 3, 3, 3): \ - ret = _mm_shuffle_epi32_splat((a), 3); \ - break; \ - default: \ - ret = _mm_shuffle_epi32_default((a), (imm)); \ - break; \ - } \ - ret; \ - }) -#endif - -// Shuffles the lower 4 signed or unsigned 16-bit integers in a as specified -// by imm. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/y41dkk37(v=vs.100) -// FORCE_INLINE __m128i _mm_shufflelo_epi16_function(__m128i a, -// __constrange(0,255) int -// imm) -#define _mm_shufflelo_epi16_function(a, imm) \ - __extension__({ \ - int16x8_t ret = vreinterpretq_s16_m128i(a); \ - int16x4_t lowBits = vget_low_s16(ret); \ - ret = vsetq_lane_s16(vget_lane_s16(lowBits, (imm) & (0x3)), ret, 0); \ - ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 2) & 0x3), ret, \ - 1); \ - ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 4) & 0x3), ret, \ - 2); \ - ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 6) & 0x3), ret, \ - 3); \ - vreinterpretq_m128i_s16(ret); \ - }) - -// FORCE_INLINE __m128i _mm_shufflelo_epi16(__m128i a, -// __constrange(0,255) int imm) -#if __has_builtin(__builtin_shufflevector) -#define _mm_shufflelo_epi16(a, imm) \ - __extension__({ \ - int16x8_t _input = vreinterpretq_s16_m128i(a); \ - int16x8_t _shuf = __builtin_shufflevector( \ - _input, _input, ((imm) & (0x3)), (((imm) >> 2) & 0x3), \ - (((imm) >> 4) & 0x3), (((imm) >> 6) & 0x3), 4, 5, 6, 7); \ - vreinterpretq_m128i_s16(_shuf); \ - }) -#else // generic -#define _mm_shufflelo_epi16(a, imm) _mm_shufflelo_epi16_function((a), (imm)) -#endif - -// Shuffles the upper 4 signed or unsigned 16-bit integers in a as specified -// by imm. -// https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx -// FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a, -// __constrange(0,255) int -// imm) -#define _mm_shufflehi_epi16_function(a, imm) \ - __extension__({ \ - int16x8_t ret = vreinterpretq_s16_m128i(a); \ - int16x4_t highBits = vget_high_s16(ret); \ - ret = vsetq_lane_s16(vget_lane_s16(highBits, (imm) & (0x3)), ret, 4); \ - ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 2) & 0x3), ret, \ - 5); \ - ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 4) & 0x3), ret, \ - 6); \ - ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 6) & 0x3), ret, \ - 7); \ - vreinterpretq_m128i_s16(ret); \ - }) - -// FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a, -// __constrange(0,255) int imm) -#if __has_builtin(__builtin_shufflevector) -#define _mm_shufflehi_epi16(a, imm) \ - __extension__({ \ - int16x8_t _input = vreinterpretq_s16_m128i(a); \ - int16x8_t _shuf = __builtin_shufflevector( \ - _input, _input, 0, 1, 2, 3, ((imm) & (0x3)) + 4, \ - (((imm) >> 2) & 0x3) + 4, (((imm) >> 4) & 0x3) + 4, \ - (((imm) >> 6) & 0x3) + 4); \ - vreinterpretq_m128i_s16(_shuf); \ - }) -#else // generic -#define _mm_shufflehi_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm)) -#endif - -// Shuffle double-precision (64-bit) floating-point elements using the control -// in imm8, and store the results in dst. +// Add 64-bit integers a and b, and store the result in dst. // -// dst[63:0] := (imm8[0] == 0) ? a[63:0] : a[127:64] -// dst[127:64] := (imm8[1] == 0) ? b[63:0] : b[127:64] +// dst[63:0] := a[63:0] + b[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pd -#if __has_builtin(__builtin_shufflevector) -#define _mm_shuffle_pd(a, b, imm8) \ - vreinterpretq_m128d_s64(__builtin_shufflevector( \ - vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b), imm8 & 0x1, \ - ((imm8 & 0x2) >> 1) + 2)) -#else -#define _mm_shuffle_pd(a, b, imm8) \ - _mm_castsi128_pd(_mm_set_epi64x( \ - vgetq_lane_s64(vreinterpretq_s64_m128d(b), (imm8 & 0x2) >> 1), \ - vgetq_lane_s64(vreinterpretq_s64_m128d(a), imm8 & 0x1))) -#endif +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_si64 +FORCE_INLINE __m64 _mm_add_si64(__m64 a, __m64 b) +{ + return vreinterpret_m64_s64( + vadd_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b))); +} -// Blend packed 16-bit integers from a and b using control mask imm8, and store -// the results in dst. +// Adds the 8 signed 16-bit integers in a to the 8 signed 16-bit integers in b +// and saturates. // -// FOR j := 0 to 7 -// i := j*16 -// IF imm8[j] -// dst[i+15:i] := b[i+15:i] -// ELSE -// dst[i+15:i] := a[i+15:i] -// FI -// ENDFOR -// FORCE_INLINE __m128i _mm_blend_epi16(__m128i a, __m128i b, -// __constrange(0,255) int imm) -#define _mm_blend_epi16(a, b, imm) \ - __extension__({ \ - const uint16_t _mask[8] = {((imm) & (1 << 0)) ? (uint16_t) -1 : 0x0, \ - ((imm) & (1 << 1)) ? (uint16_t) -1 : 0x0, \ - ((imm) & (1 << 2)) ? (uint16_t) -1 : 0x0, \ - ((imm) & (1 << 3)) ? (uint16_t) -1 : 0x0, \ - ((imm) & (1 << 4)) ? (uint16_t) -1 : 0x0, \ - ((imm) & (1 << 5)) ? (uint16_t) -1 : 0x0, \ - ((imm) & (1 << 6)) ? (uint16_t) -1 : 0x0, \ - ((imm) & (1 << 7)) ? (uint16_t) -1 : 0x0}; \ - uint16x8_t _mask_vec = vld1q_u16(_mask); \ - uint16x8_t _a = vreinterpretq_u16_m128i(a); \ - uint16x8_t _b = vreinterpretq_u16_m128i(b); \ - vreinterpretq_m128i_u16(vbslq_u16(_mask_vec, _b, _a)); \ - }) +// r0 := SignedSaturate(a0 + b0) +// r1 := SignedSaturate(a1 + b1) +// ... +// r7 := SignedSaturate(a7 + b7) +// +// https://msdn.microsoft.com/en-us/library/1a306ef8(v=vs.100).aspx +FORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vqaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} -// Blend packed double-precision (64-bit) floating-point elements from a and b -// using control mask imm8, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_pd -#define _mm_blend_pd(a, b, imm) \ - __extension__({ \ - const uint64_t _mask[2] = { \ - ((imm) & (1 << 0)) ? ~UINT64_C(0) : UINT64_C(0), \ - ((imm) & (1 << 1)) ? ~UINT64_C(0) : UINT64_C(0)}; \ - uint64x2_t _mask_vec = vld1q_u64(_mask); \ - uint64x2_t _a = vreinterpretq_u64_m128d(a); \ - uint64x2_t _b = vreinterpretq_u64_m128d(b); \ - vreinterpretq_m128d_u64(vbslq_u64(_mask_vec, _b, _a)); \ - }) - -// Blend packed 8-bit integers from a and b using mask, and store the results in -// dst. +// Add packed signed 8-bit integers in a and b using saturation, and store the +// results in dst. // // FOR j := 0 to 15 -// i := j*8 -// IF mask[i+7] -// dst[i+7:i] := b[i+7:i] -// ELSE -// dst[i+7:i] := a[i+7:i] -// FI -// ENDFOR -FORCE_INLINE __m128i _mm_blendv_epi8(__m128i _a, __m128i _b, __m128i _mask) -{ - // Use a signed shift right to create a mask with the sign bit - uint8x16_t mask = - vreinterpretq_u8_s8(vshrq_n_s8(vreinterpretq_s8_m128i(_mask), 7)); - uint8x16_t a = vreinterpretq_u8_m128i(_a); - uint8x16_t b = vreinterpretq_u8_m128i(_b); - return vreinterpretq_m128i_u8(vbslq_u8(mask, b, a)); -} - -/* Shifts */ - - -// Shift packed 16-bit integers in a right by imm while shifting in sign -// bits, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi16 -FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int imm) -{ - const int count = (imm & ~15) ? 15 : imm; - return (__m128i) vshlq_s16((int16x8_t) a, vdupq_n_s16(-count)); -} - -// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while -// shifting in zeros. -// -// r0 := a0 << count -// r1 := a1 << count -// ... -// r7 := a7 << count -// -// https://msdn.microsoft.com/en-us/library/es73bcsy(v=vs.90).aspx -#define _mm_slli_epi16(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (unlikely((imm)) <= 0) { \ - ret = a; \ - } \ - if (unlikely((imm) > 15)) { \ - ret = _mm_setzero_si128(); \ - } else { \ - ret = vreinterpretq_m128i_s16( \ - vshlq_n_s16(vreinterpretq_s16_m128i(a), (imm))); \ - } \ - ret; \ - }) - -// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while -// shifting in zeros. : -// https://msdn.microsoft.com/en-us/library/z2k3bbtb%28v=vs.90%29.aspx -// FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, __constrange(0,255) int imm) -FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, int imm) -{ - if (unlikely(imm <= 0)) /* TODO: add constant range macro: [0, 255] */ - return a; - if (unlikely(imm > 31)) - return _mm_setzero_si128(); - return vreinterpretq_m128i_s32( - vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(imm))); -} - -// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and -// store the results in dst. -FORCE_INLINE __m128i _mm_slli_epi64(__m128i a, int imm) -{ - if (unlikely(imm <= 0)) /* TODO: add constant range macro: [0, 255] */ - return a; - if (unlikely(imm > 63)) - return _mm_setzero_si128(); - return vreinterpretq_m128i_s64( - vshlq_s64(vreinterpretq_s64_m128i(a), vdupq_n_s64(imm))); -} - -// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and -// store the results in dst. -// -// FOR j := 0 to 7 -// i := j*16 -// IF imm8[7:0] > 15 -// dst[i+15:i] := 0 -// ELSE -// dst[i+15:i] := ZeroExtend16(a[i+15:i] >> imm8[7:0]) -// FI +// i := j*8 +// dst[i+7:i] := Saturate8( a[i+7:i] + b[i+7:i] ) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi16 -#define _mm_srli_epi16(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (unlikely(imm) == 0) { \ - ret = a; \ - } \ - if (likely(0 < (imm) && (imm) < 16)) { \ - ret = vreinterpretq_m128i_u16( \ - vshlq_u16(vreinterpretq_u16_m128i(a), vdupq_n_s16(-imm))); \ - } else { \ - ret = _mm_setzero_si128(); \ - } \ - ret; \ - }) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epi8 +FORCE_INLINE __m128i _mm_adds_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vqaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} -// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and -// store the results in dst. -// -// FOR j := 0 to 3 -// i := j*32 -// IF imm8[7:0] > 31 -// dst[i+31:i] := 0 -// ELSE -// dst[i+31:i] := ZeroExtend32(a[i+31:i] >> imm8[7:0]) -// FI -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi32 -// FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, __constrange(0,255) int imm) -#define _mm_srli_epi32(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (unlikely((imm) == 0)) { \ - ret = a; \ - } \ - if (likely(0 < (imm) && (imm) < 32)) { \ - ret = vreinterpretq_m128i_u32( \ - vshlq_u32(vreinterpretq_u32_m128i(a), vdupq_n_s32(-imm))); \ - } else { \ - ret = _mm_setzero_si128(); \ - } \ - ret; \ - }) +// Add packed unsigned 16-bit integers in a and b using saturation, and store +// the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epu16 +FORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vqaddq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); +} -// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and -// store the results in dst. +// Adds the 16 unsigned 8-bit integers in a to the 16 unsigned 8-bit integers in +// b and saturates.. +// https://msdn.microsoft.com/en-us/library/9hahyddy(v=vs.100).aspx +FORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vqaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +// Compute the bitwise AND of packed double-precision (64-bit) floating-point +// elements in a and b, and store the results in dst. // // FOR j := 0 to 1 // i := j*64 -// IF imm8[7:0] > 63 -// dst[i+63:i] := 0 -// ELSE -// dst[i+63:i] := ZeroExtend64(a[i+63:i] >> imm8[7:0]) -// FI +// dst[i+63:i] := a[i+63:i] AND b[i+63:i] // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi64 -#define _mm_srli_epi64(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (unlikely((imm) == 0)) { \ - ret = a; \ - } \ - if (likely(0 < (imm) && (imm) < 64)) { \ - ret = vreinterpretq_m128i_u64( \ - vshlq_u64(vreinterpretq_u64_m128i(a), vdupq_n_s64(-imm))); \ - } else { \ - ret = _mm_setzero_si128(); \ - } \ - ret; \ - }) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_and_pd +FORCE_INLINE __m128d _mm_and_pd(__m128d a, __m128d b) +{ + return vreinterpretq_m128d_s64( + vandq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); +} -// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, -// and store the results in dst. +// Computes the bitwise AND of the 128-bit value in a and the 128-bit value in +// b. // -// FOR j := 0 to 3 -// i := j*32 -// IF imm8[7:0] > 31 -// dst[i+31:i] := (a[i+31] ? 0xFFFFFFFF : 0x0) -// ELSE -// dst[i+31:i] := SignExtend32(a[i+31:i] >> imm8[7:0]) -// FI +// r := a & b +// +// https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx +FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vandq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Compute the bitwise NOT of packed double-precision (64-bit) floating-point +// elements in a and then AND with b, and store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// dst[i+63:i] := ((NOT a[i+63:i]) AND b[i+63:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi32 -// FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, __constrange(0,255) int imm) -#define _mm_srai_epi32(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (unlikely((imm) == 0)) { \ - ret = a; \ - } \ - if (likely(0 < (imm) && (imm) < 32)) { \ - ret = vreinterpretq_m128i_s32( \ - vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(-imm))); \ - } else { \ - ret = vreinterpretq_m128i_s32( \ - vshrq_n_s32(vreinterpretq_s32_m128i(a), 31)); \ - } \ - ret; \ - }) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_andnot_pd +FORCE_INLINE __m128d _mm_andnot_pd(__m128d a, __m128d b) +{ + // *NOTE* argument swap + return vreinterpretq_m128d_s64( + vbicq_s64(vreinterpretq_s64_m128d(b), vreinterpretq_s64_m128d(a))); +} -// Shifts the 128 - bit value in a right by imm bytes while shifting in -// zeros.imm must be an immediate. +// Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the +// 128-bit value in a. // -// r := srl(a, imm*8) +// r := (~a) & b // -// https://msdn.microsoft.com/en-us/library/305w28yz(v=vs.100).aspx -// FORCE_INLINE _mm_srli_si128(__m128i a, __constrange(0,255) int imm) -#define _mm_srli_si128(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (unlikely((imm) <= 0)) { \ - ret = a; \ - } \ - if (unlikely((imm) > 15)) { \ - ret = _mm_setzero_si128(); \ - } else { \ - ret = vreinterpretq_m128i_s8( \ - vextq_s8(vreinterpretq_s8_m128i(a), vdupq_n_s8(0), (imm))); \ - } \ - ret; \ - }) +// https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx +FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vbicq_s32(vreinterpretq_s32_m128i(b), + vreinterpretq_s32_m128i(a))); // *NOTE* argument swap +} -// Shifts the 128-bit value in a left by imm bytes while shifting in zeros. imm -// must be an immediate. +// Computes the average of the 8 unsigned 16-bit integers in a and the 8 +// unsigned 16-bit integers in b and rounds. // -// r := a << (imm * 8) +// r0 := (a0 + b0) / 2 +// r1 := (a1 + b1) / 2 +// ... +// r7 := (a7 + b7) / 2 // -// https://msdn.microsoft.com/en-us/library/34d3k2kt(v=vs.100).aspx -// FORCE_INLINE __m128i _mm_slli_si128(__m128i a, __constrange(0,255) int imm) -#define _mm_slli_si128(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (unlikely((imm) <= 0)) { \ - ret = a; \ - } \ - if (unlikely((imm) > 15)) { \ - ret = _mm_setzero_si128(); \ - } else { \ - ret = vreinterpretq_m128i_s8(vextq_s8( \ - vdupq_n_s8(0), vreinterpretq_s8_m128i(a), 16 - (imm))); \ - } \ - ret; \ - }) +// https://msdn.microsoft.com/en-us/library/vstudio/y13ca3c8(v=vs.90).aspx +FORCE_INLINE __m128i _mm_avg_epu16(__m128i a, __m128i b) +{ + return (__m128i) vrhaddq_u16(vreinterpretq_u16_m128i(a), + vreinterpretq_u16_m128i(b)); +} -// Compute the square root of packed double-precision (64-bit) floating-point -// elements in a, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_pd -FORCE_INLINE __m128d _mm_sqrt_pd(__m128d a) +// Computes the average of the 16 unsigned 8-bit integers in a and the 16 +// unsigned 8-bit integers in b and rounds. +// +// r0 := (a0 + b0) / 2 +// r1 := (a1 + b1) / 2 +// ... +// r15 := (a15 + b15) / 2 +// +// https://msdn.microsoft.com/en-us/library/vstudio/8zwh554a(v%3dvs.90).aspx +FORCE_INLINE __m128i _mm_avg_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vrhaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +// Shift a left by imm8 bytes while shifting in zeros, and store the results in +// dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_bslli_si128 +#define _mm_bslli_si128(a, imm) _mm_slli_si128(a, imm) + +// Shift a right by imm8 bytes while shifting in zeros, and store the results in +// dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_bsrli_si128 +#define _mm_bsrli_si128(a, imm) _mm_srli_si128(a, imm) + +// Cast vector of type __m128d to type __m128. This intrinsic is only used for +// compilation and does not generate any instructions, thus it has zero latency. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_ps +FORCE_INLINE __m128 _mm_castpd_ps(__m128d a) +{ + return vreinterpretq_m128_s64(vreinterpretq_s64_m128d(a)); +} + +// Cast vector of type __m128d to type __m128i. This intrinsic is only used for +// compilation and does not generate any instructions, thus it has zero latency. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_si128 +FORCE_INLINE __m128i _mm_castpd_si128(__m128d a) +{ + return vreinterpretq_m128i_s64(vreinterpretq_s64_m128d(a)); +} + +// Cast vector of type __m128 to type __m128d. This intrinsic is only used for +// compilation and does not generate any instructions, thus it has zero latency. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castps_pd +FORCE_INLINE __m128d _mm_castps_pd(__m128 a) +{ + return vreinterpretq_m128d_s32(vreinterpretq_s32_m128(a)); +} + +// Applies a type cast to reinterpret four 32-bit floating point values passed +// in as a 128-bit parameter as packed 32-bit integers. +// https://msdn.microsoft.com/en-us/library/bb514099.aspx +FORCE_INLINE __m128i _mm_castps_si128(__m128 a) +{ + return vreinterpretq_m128i_s32(vreinterpretq_s32_m128(a)); +} + +// Cast vector of type __m128i to type __m128d. This intrinsic is only used for +// compilation and does not generate any instructions, thus it has zero latency. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castsi128_pd +FORCE_INLINE __m128d _mm_castsi128_pd(__m128i a) { #if defined(__aarch64__) - return vreinterpretq_m128d_f64(vsqrtq_f64(vreinterpretq_f64_m128d(a))); + return vreinterpretq_m128d_f64(vreinterpretq_f64_m128i(a)); #else - double a0 = sqrt(((double *) &a)[0]); - double a1 = sqrt(((double *) &a)[1]); + return vreinterpretq_m128d_f32(vreinterpretq_f32_m128i(a)); +#endif +} + +// Applies a type cast to reinterpret four 32-bit integers passed in as a +// 128-bit parameter as packed 32-bit floating point values. +// https://msdn.microsoft.com/en-us/library/bb514029.aspx +FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a) +{ + return vreinterpretq_m128_s32(vreinterpretq_s32_m128i(a)); +} + +// Cache line containing p is flushed and invalidated from all caches in the +// coherency domain. : +// https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx +FORCE_INLINE void _mm_clflush(void const *p) +{ + (void) p; + // no corollary for Neon? +} + +// Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or +// unsigned 16-bit integers in b for equality. +// https://msdn.microsoft.com/en-us/library/2ay060te(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmpeq_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vceqq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Compare packed 32-bit integers in a and b for equality, and store the results +// in dst +FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u32( + vceqq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Compares the 16 signed or unsigned 8-bit integers in a and the 16 signed or +// unsigned 8-bit integers in b for equality. +// https://msdn.microsoft.com/en-us/library/windows/desktop/bz5xk21a(v=vs.90).aspx +FORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vceqq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for equality, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_pd +FORCE_INLINE __m128d _mm_cmpeq_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_u64( + vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) + uint32x4_t cmp = + vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); + uint32x4_t swapped = vrev64q_u32(cmp); + return vreinterpretq_m128d_u32(vandq_u32(cmp, swapped)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for equality, store the result in the lower element of dst, and copy the +// upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_sd +FORCE_INLINE __m128d _mm_cmpeq_sd(__m128d a, __m128d b) +{ + return _mm_move_sd(a, _mm_cmpeq_pd(a, b)); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for greater-than-or-equal, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpge_pd +FORCE_INLINE __m128d _mm_cmpge_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_u64( + vcgeq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) >= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = (*(double *) &a1) >= (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for greater-than-or-equal, store the result in the lower element of dst, +// and copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpge_sd +FORCE_INLINE __m128d _mm_cmpge_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return _mm_move_sd(a, _mm_cmpge_pd(a, b)); +#else + // expand "_mm_cmpge_pd()" to reduce unnecessary operations + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) >= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = a1; + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers +// in b for greater than. +// +// r0 := (a0 > b0) ? 0xffff : 0x0 +// r1 := (a1 > b1) ? 0xffff : 0x0 +// ... +// r7 := (a7 > b7) ? 0xffff : 0x0 +// +// https://technet.microsoft.com/en-us/library/xd43yfsa(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmpgt_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vcgtq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers +// in b for greater than. +// https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u32( + vcgtq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers +// in b for greater than. +// +// r0 := (a0 > b0) ? 0xff : 0x0 +// r1 := (a1 > b1) ? 0xff : 0x0 +// ... +// r15 := (a15 > b15) ? 0xff : 0x0 +// +// https://msdn.microsoft.com/zh-tw/library/wf45zt2b(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vcgtq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for greater-than, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpgt_pd +FORCE_INLINE __m128d _mm_cmpgt_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_u64( + vcgtq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) > (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = (*(double *) &a1) > (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for greater-than, store the result in the lower element of dst, and copy +// the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpgt_sd +FORCE_INLINE __m128d _mm_cmpgt_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return _mm_move_sd(a, _mm_cmpgt_pd(a, b)); +#else + // expand "_mm_cmpge_pd()" to reduce unnecessary operations + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) > (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = a1; + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for less-than-or-equal, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmple_pd +FORCE_INLINE __m128d _mm_cmple_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_u64( + vcleq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) <= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = (*(double *) &a1) <= (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for less-than-or-equal, store the result in the lower element of dst, and +// copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmple_sd +FORCE_INLINE __m128d _mm_cmple_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return _mm_move_sd(a, _mm_cmple_pd(a, b)); +#else + // expand "_mm_cmpge_pd()" to reduce unnecessary operations + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) <= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = a1; + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers +// in b for less than. +// +// r0 := (a0 < b0) ? 0xffff : 0x0 +// r1 := (a1 < b1) ? 0xffff : 0x0 +// ... +// r7 := (a7 < b7) ? 0xffff : 0x0 +// +// https://technet.microsoft.com/en-us/library/t863edb2(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmplt_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vcltq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + + +// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers +// in b for less than. +// https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u32( + vcltq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers +// in b for lesser than. +// https://msdn.microsoft.com/en-us/library/windows/desktop/9s46csht(v=vs.90).aspx +FORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vcltq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for less-than, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmplt_pd +FORCE_INLINE __m128d _mm_cmplt_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_u64( + vcltq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) < (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = (*(double *) &a1) < (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for less-than, store the result in the lower element of dst, and copy the +// upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmplt_sd +FORCE_INLINE __m128d _mm_cmplt_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return _mm_move_sd(a, _mm_cmplt_pd(a, b)); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) < (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = a1; + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for not-equal, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpneq_pd +FORCE_INLINE __m128d _mm_cmpneq_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_s32(vmvnq_s32(vreinterpretq_s32_u64( + vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))))); +#else + // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) + uint32x4_t cmp = + vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); + uint32x4_t swapped = vrev64q_u32(cmp); + return vreinterpretq_m128d_u32(vmvnq_u32(vandq_u32(cmp, swapped))); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for not-equal, store the result in the lower element of dst, and copy the +// upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpneq_sd +FORCE_INLINE __m128d _mm_cmpneq_sd(__m128d a, __m128d b) +{ + return _mm_move_sd(a, _mm_cmpneq_pd(a, b)); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for not-greater-than-or-equal, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnge_pd +FORCE_INLINE __m128d _mm_cmpnge_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_u64(veorq_u64( + vcgeq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)), + vdupq_n_u64(UINT64_MAX))); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = + !((*(double *) &a0) >= (*(double *) &b0)) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = + !((*(double *) &a1) >= (*(double *) &b1)) ? ~UINT64_C(0) : UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for not-greater-than-or-equal, store the result in the lower element of +// dst, and copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnge_sd +FORCE_INLINE __m128d _mm_cmpnge_sd(__m128d a, __m128d b) +{ + return _mm_move_sd(a, _mm_cmpnge_pd(a, b)); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for not-greater-than, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_cmpngt_pd +FORCE_INLINE __m128d _mm_cmpngt_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_u64(veorq_u64( + vcgtq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)), + vdupq_n_u64(UINT64_MAX))); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = + !((*(double *) &a0) > (*(double *) &b0)) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = + !((*(double *) &a1) > (*(double *) &b1)) ? ~UINT64_C(0) : UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for not-greater-than, store the result in the lower element of dst, and +// copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpngt_sd +FORCE_INLINE __m128d _mm_cmpngt_sd(__m128d a, __m128d b) +{ + return _mm_move_sd(a, _mm_cmpngt_pd(a, b)); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for not-less-than-or-equal, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnle_pd +FORCE_INLINE __m128d _mm_cmpnle_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_u64(veorq_u64( + vcleq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)), + vdupq_n_u64(UINT64_MAX))); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = + !((*(double *) &a0) <= (*(double *) &b0)) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = + !((*(double *) &a1) <= (*(double *) &b1)) ? ~UINT64_C(0) : UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for not-less-than-or-equal, store the result in the lower element of dst, +// and copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnle_sd +FORCE_INLINE __m128d _mm_cmpnle_sd(__m128d a, __m128d b) +{ + return _mm_move_sd(a, _mm_cmpnle_pd(a, b)); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// for not-less-than, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnlt_pd +FORCE_INLINE __m128d _mm_cmpnlt_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_u64(veorq_u64( + vcltq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)), + vdupq_n_u64(UINT64_MAX))); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = + !((*(double *) &a0) < (*(double *) &b0)) ? ~UINT64_C(0) : UINT64_C(0); + d[1] = + !((*(double *) &a1) < (*(double *) &b1)) ? ~UINT64_C(0) : UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b for not-less-than, store the result in the lower element of dst, and copy +// the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnlt_sd +FORCE_INLINE __m128d _mm_cmpnlt_sd(__m128d a, __m128d b) +{ + return _mm_move_sd(a, _mm_cmpnlt_pd(a, b)); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// to see if neither is NaN, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpord_pd +FORCE_INLINE __m128d _mm_cmpord_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + // Excluding NaNs, any two floating point numbers can be compared. + uint64x2_t not_nan_a = + vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(a)); + uint64x2_t not_nan_b = + vceqq_f64(vreinterpretq_f64_m128d(b), vreinterpretq_f64_m128d(b)); + return vreinterpretq_m128d_u64(vandq_u64(not_nan_a, not_nan_b)); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = ((*(double *) &a0) == (*(double *) &a0) && + (*(double *) &b0) == (*(double *) &b0)) + ? ~UINT64_C(0) + : UINT64_C(0); + d[1] = ((*(double *) &a1) == (*(double *) &a1) && + (*(double *) &b1) == (*(double *) &b1)) + ? ~UINT64_C(0) + : UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b to see if neither is NaN, store the result in the lower element of dst, and +// copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpord_sd +FORCE_INLINE __m128d _mm_cmpord_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return _mm_move_sd(a, _mm_cmpord_pd(a, b)); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t d[2]; + d[0] = ((*(double *) &a0) == (*(double *) &a0) && + (*(double *) &b0) == (*(double *) &b0)) + ? ~UINT64_C(0) + : UINT64_C(0); + d[1] = a1; + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b +// to see if either is NaN, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpunord_pd +FORCE_INLINE __m128d _mm_cmpunord_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + // Two NaNs are not equal in comparison operation. + uint64x2_t not_nan_a = + vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(a)); + uint64x2_t not_nan_b = + vceqq_f64(vreinterpretq_f64_m128d(b), vreinterpretq_f64_m128d(b)); + return vreinterpretq_m128d_s32( + vmvnq_s32(vreinterpretq_s32_u64(vandq_u64(not_nan_a, not_nan_b)))); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = ((*(double *) &a0) == (*(double *) &a0) && + (*(double *) &b0) == (*(double *) &b0)) + ? UINT64_C(0) + : ~UINT64_C(0); + d[1] = ((*(double *) &a1) == (*(double *) &a1) && + (*(double *) &b1) == (*(double *) &b1)) + ? UINT64_C(0) + : ~UINT64_C(0); + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b to see if either is NaN, store the result in the lower element of dst, and +// copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpunord_sd +FORCE_INLINE __m128d _mm_cmpunord_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return _mm_move_sd(a, _mm_cmpunord_pd(a, b)); +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t d[2]; + d[0] = ((*(double *) &a0) == (*(double *) &a0) && + (*(double *) &b0) == (*(double *) &b0)) + ? UINT64_C(0) + : ~UINT64_C(0); + d[1] = a1; + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point element in a and b +// for greater-than-or-equal, and return the boolean result (0 or 1). +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comige_sd +FORCE_INLINE int _mm_comige_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vgetq_lane_u64(vcgeq_f64(a, b), 0) & 0x1; +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + + return (*(double *) &a0 >= *(double *) &b0); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point element in a and b +// for greater-than, and return the boolean result (0 or 1). +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comigt_sd +FORCE_INLINE int _mm_comigt_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vgetq_lane_u64(vcgtq_f64(a, b), 0) & 0x1; +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + + return (*(double *) &a0 > *(double *) &b0); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point element in a and b +// for less-than-or-equal, and return the boolean result (0 or 1). +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comile_sd +FORCE_INLINE int _mm_comile_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vgetq_lane_u64(vcleq_f64(a, b), 0) & 0x1; +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + + return (*(double *) &a0 <= *(double *) &b0); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point element in a and b +// for less-than, and return the boolean result (0 or 1). +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comilt_sd +FORCE_INLINE int _mm_comilt_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vgetq_lane_u64(vcltq_f64(a, b), 0) & 0x1; +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + + return (*(double *) &a0 < *(double *) &b0); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point element in a and b +// for equality, and return the boolean result (0 or 1). +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comieq_sd +FORCE_INLINE int _mm_comieq_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vgetq_lane_u64(vceqq_f64(a, b), 0) & 0x1; +#else + uint32x4_t a_not_nan = + vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(a)); + uint32x4_t b_not_nan = + vceqq_u32(vreinterpretq_u32_m128d(b), vreinterpretq_u32_m128d(b)); + uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); + uint32x4_t a_eq_b = + vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); + uint64x2_t and_results = vandq_u64(vreinterpretq_u64_u32(a_and_b_not_nan), + vreinterpretq_u64_u32(a_eq_b)); + return vgetq_lane_u64(and_results, 0) & 0x1; +#endif +} + +// Compare the lower double-precision (64-bit) floating-point element in a and b +// for not-equal, and return the boolean result (0 or 1). +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comineq_sd +FORCE_INLINE int _mm_comineq_sd(__m128d a, __m128d b) +{ + return !_mm_comieq_sd(a, b); +} + +// Convert packed signed 32-bit integers in a to packed double-precision +// (64-bit) floating-point elements, and store the results in dst. +// +// FOR j := 0 to 1 +// i := j*32 +// m := j*64 +// dst[m+63:m] := Convert_Int32_To_FP64(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtepi32_pd +FORCE_INLINE __m128d _mm_cvtepi32_pd(__m128i a) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vcvtq_f64_s64(vmovl_s32(vget_low_s32(vreinterpretq_s32_m128i(a))))); +#else + double a0 = (double) vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0); + double a1 = (double) vgetq_lane_s32(vreinterpretq_s32_m128i(a), 1); return _mm_set_pd(a1, a0); #endif } -// Compute the square root of the lower double-precision (64-bit) floating-point -// element in b, store the result in the lower element of dst, and copy the -// upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_sd -FORCE_INLINE __m128d _mm_sqrt_sd(__m128d a, __m128d b) +// Converts the four signed 32-bit integer values of a to single-precision, +// floating-point values +// https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a) +{ + return vreinterpretq_m128_f32(vcvtq_f32_s32(vreinterpretq_s32_m128i(a))); +} + +// Convert packed double-precision (64-bit) floating-point elements in a to +// packed 32-bit integers, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// k := 64*j +// dst[i+31:i] := Convert_FP64_To_Int32(a[k+63:k]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_epi32 +FORCE_INLINE __m128i _mm_cvtpd_epi32(__m128d a) +{ + __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); + double d0 = ((double *) &rnd)[0]; + double d1 = ((double *) &rnd)[1]; + return _mm_set_epi32(0, 0, (int32_t) d1, (int32_t) d0); +} + +// Convert packed double-precision (64-bit) floating-point elements in a to +// packed 32-bit integers, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// k := 64*j +// dst[i+31:i] := Convert_FP64_To_Int32(a[k+63:k]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_pi32 +FORCE_INLINE __m64 _mm_cvtpd_pi32(__m128d a) +{ + __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); + double d0 = ((double *) &rnd)[0]; + double d1 = ((double *) &rnd)[1]; + int32_t ALIGN_STRUCT(16) data[2] = {(int32_t) d0, (int32_t) d1}; + return vreinterpret_m64_s32(vld1_s32(data)); +} + +// Convert packed double-precision (64-bit) floating-point elements in a to +// packed single-precision (32-bit) floating-point elements, and store the +// results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// k := 64*j +// dst[i+31:i] := Convert_FP64_To_FP32(a[k+64:k]) +// ENDFOR +// dst[127:64] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_ps +FORCE_INLINE __m128 _mm_cvtpd_ps(__m128d a) { #if defined(__aarch64__) - return _mm_move_sd(a, _mm_sqrt_pd(b)); + float32x2_t tmp = vcvt_f32_f64(vreinterpretq_f64_m128d(a)); + return vreinterpretq_m128_f32(vcombine_f32(tmp, vdup_n_f32(0))); #else - return _mm_set_pd(((double *) &a)[1], sqrt(((double *) &b)[0])); + float a0 = (float) ((double *) &a)[0]; + float a1 = (float) ((double *) &a)[1]; + return _mm_set_ps(0, 0, a1, a0); #endif } -// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while -// shifting in zeros. +// Convert packed signed 32-bit integers in a to packed double-precision +// (64-bit) floating-point elements, and store the results in dst. // -// r0 := a0 << count -// r1 := a1 << count -// ... -// r7 := a7 << count +// FOR j := 0 to 1 +// i := j*32 +// m := j*64 +// dst[m+63:m] := Convert_Int32_To_FP64(a[i+31:i]) +// ENDFOR // -// https://msdn.microsoft.com/en-us/library/c79w388h(v%3dvs.90).aspx -FORCE_INLINE __m128i _mm_sll_epi16(__m128i a, __m128i count) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_pd +FORCE_INLINE __m128d _mm_cvtpi32_pd(__m64 a) { - uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); - if (unlikely(c > 15)) - return _mm_setzero_si128(); - - int16x8_t vc = vdupq_n_s16((int16_t) c); - return vreinterpretq_m128i_s16(vshlq_s16(vreinterpretq_s16_m128i(a), vc)); +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vcvtq_f64_s64(vmovl_s32(vreinterpret_s32_m64(a)))); +#else + double a0 = (double) vget_lane_s32(vreinterpret_s32_m64(a), 0); + double a1 = (double) vget_lane_s32(vreinterpret_s32_m64(a), 1); + return _mm_set_pd(a1, a0); +#endif } -// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while -// shifting in zeros. +// Converts the four single-precision, floating-point values of a to signed +// 32-bit integer values. // -// r0 := a0 << count -// r1 := a1 << count -// r2 := a2 << count -// r3 := a3 << count +// r0 := (int) a0 +// r1 := (int) a1 +// r2 := (int) a2 +// r3 := (int) a3 // -// https://msdn.microsoft.com/en-us/library/6fe5a6s9(v%3dvs.90).aspx -FORCE_INLINE __m128i _mm_sll_epi32(__m128i a, __m128i count) +// https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx +// *NOTE*. The default rounding mode on SSE is 'round to even', which ARMv7-A +// does not support! It is supported on ARMv8-A however. +FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a) { - uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); - if (unlikely(c > 31)) - return _mm_setzero_si128(); - - int32x4_t vc = vdupq_n_s32((int32_t) c); - return vreinterpretq_m128i_s32(vshlq_s32(vreinterpretq_s32_m128i(a), vc)); +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) + switch (_MM_GET_ROUNDING_MODE()) { + case _MM_ROUND_NEAREST: + return vreinterpretq_m128i_s32(vcvtnq_s32_f32(a)); + case _MM_ROUND_DOWN: + return vreinterpretq_m128i_s32(vcvtmq_s32_f32(a)); + case _MM_ROUND_UP: + return vreinterpretq_m128i_s32(vcvtpq_s32_f32(a)); + default: // _MM_ROUND_TOWARD_ZERO + return vreinterpretq_m128i_s32(vcvtq_s32_f32(a)); + } +#else + float *f = (float *) &a; + switch (_MM_GET_ROUNDING_MODE()) { + case _MM_ROUND_NEAREST: { + uint32x4_t signmask = vdupq_n_u32(0x80000000); + float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a), + vdupq_n_f32(0.5f)); /* +/- 0.5 */ + int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32( + vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/ + int32x4_t r_trunc = vcvtq_s32_f32( + vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */ + int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32( + vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */ + int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone), + vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */ + float32x4_t delta = vsubq_f32( + vreinterpretq_f32_m128(a), + vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */ + uint32x4_t is_delta_half = + vceqq_f32(delta, half); /* delta == +/- 0.5 */ + return vreinterpretq_m128i_s32( + vbslq_s32(is_delta_half, r_even, r_normal)); + } + case _MM_ROUND_DOWN: + return _mm_set_epi32(floorf(f[3]), floorf(f[2]), floorf(f[1]), + floorf(f[0])); + case _MM_ROUND_UP: + return _mm_set_epi32(ceilf(f[3]), ceilf(f[2]), ceilf(f[1]), + ceilf(f[0])); + default: // _MM_ROUND_TOWARD_ZERO + return _mm_set_epi32((int32_t) f[3], (int32_t) f[2], (int32_t) f[1], + (int32_t) f[0]); + } +#endif } -// Shifts the 2 signed or unsigned 64-bit integers in a left by count bits while -// shifting in zeros. +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed double-precision (64-bit) floating-point elements, and store the +// results in dst. // -// r0 := a0 << count -// r1 := a1 << count +// FOR j := 0 to 1 +// i := 64*j +// k := 32*j +// dst[i+63:i] := Convert_FP32_To_FP64(a[k+31:k]) +// ENDFOR // -// https://msdn.microsoft.com/en-us/library/6ta9dffd(v%3dvs.90).aspx -FORCE_INLINE __m128i _mm_sll_epi64(__m128i a, __m128i count) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pd +FORCE_INLINE __m128d _mm_cvtps_pd(__m128 a) { - uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); - if (unlikely(c > 63)) - return _mm_setzero_si128(); - - int64x2_t vc = vdupq_n_s64((int64_t) c); - return vreinterpretq_m128i_s64(vshlq_s64(vreinterpretq_s64_m128i(a), vc)); +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vcvt_f64_f32(vget_low_f32(vreinterpretq_f32_m128(a)))); +#else + double a0 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); + double a1 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 1); + return _mm_set_pd(a1, a0); +#endif } -// Shifts the 8 signed or unsigned 16-bit integers in a right by count bits -// while shifting in zeros. +// Copy the lower double-precision (64-bit) floating-point element of a to dst. // -// r0 := srl(a0, count) -// r1 := srl(a1, count) -// ... -// r7 := srl(a7, count) +// dst[63:0] := a[63:0] // -// https://msdn.microsoft.com/en-us/library/wd5ax830(v%3dvs.90).aspx -FORCE_INLINE __m128i _mm_srl_epi16(__m128i a, __m128i count) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_f64 +FORCE_INLINE double _mm_cvtsd_f64(__m128d a) { - uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); - if (unlikely(c > 15)) - return _mm_setzero_si128(); - - int16x8_t vc = vdupq_n_s16(-(int16_t) c); - return vreinterpretq_m128i_u16(vshlq_u16(vreinterpretq_u16_m128i(a), vc)); +#if defined(__aarch64__) + return (double) vgetq_lane_f64(vreinterpretq_f64_m128d(a), 0); +#else + return ((double *) &a)[0]; +#endif } -// Shifts the 4 signed or unsigned 32-bit integers in a right by count bits -// while shifting in zeros. +// Convert the lower double-precision (64-bit) floating-point element in a to a +// 32-bit integer, and store the result in dst. // -// r0 := srl(a0, count) -// r1 := srl(a1, count) -// r2 := srl(a2, count) -// r3 := srl(a3, count) +// dst[31:0] := Convert_FP64_To_Int32(a[63:0]) // -// https://msdn.microsoft.com/en-us/library/a9cbttf4(v%3dvs.90).aspx -FORCE_INLINE __m128i _mm_srl_epi32(__m128i a, __m128i count) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_si32 +FORCE_INLINE int32_t _mm_cvtsd_si32(__m128d a) { - uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); - if (unlikely(c > 31)) - return _mm_setzero_si128(); - - int32x4_t vc = vdupq_n_s32(-(int32_t) c); - return vreinterpretq_m128i_u32(vshlq_u32(vreinterpretq_u32_m128i(a), vc)); +#if defined(__aarch64__) + return (int32_t) vgetq_lane_f64(vrndiq_f64(vreinterpretq_f64_m128d(a)), 0); +#else + __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); + double ret = ((double *) &rnd)[0]; + return (int32_t) ret; +#endif } -// Shifts the 2 signed or unsigned 64-bit integers in a right by count bits -// while shifting in zeros. +// Convert the lower double-precision (64-bit) floating-point element in a to a +// 64-bit integer, and store the result in dst. // -// r0 := srl(a0, count) -// r1 := srl(a1, count) +// dst[63:0] := Convert_FP64_To_Int64(a[63:0]) // -// https://msdn.microsoft.com/en-us/library/yf6cf9k8(v%3dvs.90).aspx -FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_si64 +FORCE_INLINE int64_t _mm_cvtsd_si64(__m128d a) { - uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); - if (unlikely(c > 63)) - return _mm_setzero_si128(); +#if defined(__aarch64__) + return (int64_t) vgetq_lane_f64(vrndiq_f64(vreinterpretq_f64_m128d(a)), 0); +#else + __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); + double ret = ((double *) &rnd)[0]; + return (int64_t) ret; +#endif +} - int64x2_t vc = vdupq_n_s64(-(int64_t) c); - return vreinterpretq_m128i_u64(vshlq_u64(vreinterpretq_u64_m128i(a), vc)); +// Convert the lower double-precision (64-bit) floating-point element in a to a +// 64-bit integer, and store the result in dst. +// +// dst[63:0] := Convert_FP64_To_Int64(a[63:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_si64x +#define _mm_cvtsd_si64x _mm_cvtsd_si64 + +// Convert the lower double-precision (64-bit) floating-point element in b to a +// single-precision (32-bit) floating-point element, store the result in the +// lower element of dst, and copy the upper 3 packed elements from a to the +// upper elements of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_ss +FORCE_INLINE __m128 _mm_cvtsd_ss(__m128 a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32(vsetq_lane_f32( + vget_lane_f32(vcvt_f32_f64(vreinterpretq_f64_m128d(b)), 0), + vreinterpretq_f32_m128(a), 0)); +#else + return vreinterpretq_m128_f32(vsetq_lane_f32((float) ((double *) &b)[0], + vreinterpretq_f32_m128(a), 0)); +#endif +} + +// Copy the lower 32-bit integer in a to dst. +// +// dst[31:0] := a[31:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si32 +FORCE_INLINE int _mm_cvtsi128_si32(__m128i a) +{ + return vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0); +} + +// Copy the lower 64-bit integer in a to dst. +// +// dst[63:0] := a[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64 +FORCE_INLINE int64_t _mm_cvtsi128_si64(__m128i a) +{ + return vgetq_lane_s64(vreinterpretq_s64_m128i(a), 0); +} + +// Copy the lower 64-bit integer in a to dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x +#define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a) + +// Convert the signed 32-bit integer b to a double-precision (64-bit) +// floating-point element, store the result in the lower element of dst, and +// copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_sd +FORCE_INLINE __m128d _mm_cvtsi32_sd(__m128d a, int32_t b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vsetq_lane_f64((double) b, vreinterpretq_f64_m128d(a), 0)); +#else + double bf = (double) b; + return vreinterpretq_m128d_s64( + vsetq_lane_s64(*(int64_t *) &bf, vreinterpretq_s64_m128d(a), 0)); +#endif +} + +// Copy the lower 64-bit integer in a to dst. +// +// dst[63:0] := a[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x +#define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a) + +// Moves 32-bit integer a to the least significant 32 bits of an __m128 object, +// zero extending the upper bits. +// +// r0 := a +// r1 := 0x0 +// r2 := 0x0 +// r3 := 0x0 +// +// https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_cvtsi32_si128(int a) +{ + return vreinterpretq_m128i_s32(vsetq_lane_s32(a, vdupq_n_s32(0), 0)); +} + +// Convert the signed 64-bit integer b to a double-precision (64-bit) +// floating-point element, store the result in the lower element of dst, and +// copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_sd +FORCE_INLINE __m128d _mm_cvtsi64_sd(__m128d a, int64_t b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vsetq_lane_f64((double) b, vreinterpretq_f64_m128d(a), 0)); +#else + double bf = (double) b; + return vreinterpretq_m128d_s64( + vsetq_lane_s64(*(int64_t *) &bf, vreinterpretq_s64_m128d(a), 0)); +#endif +} + +// Moves 64-bit integer a to the least significant 64 bits of an __m128 object, +// zero extending the upper bits. +// +// r0 := a +// r1 := 0x0 +FORCE_INLINE __m128i _mm_cvtsi64_si128(int64_t a) +{ + return vreinterpretq_m128i_s64(vsetq_lane_s64(a, vdupq_n_s64(0), 0)); +} + +// Copy 64-bit integer a to the lower element of dst, and zero the upper +// element. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64x_si128 +#define _mm_cvtsi64x_si128(a) _mm_cvtsi64_si128(a) + +// Convert the signed 64-bit integer b to a double-precision (64-bit) +// floating-point element, store the result in the lower element of dst, and +// copy the upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64x_sd +#define _mm_cvtsi64x_sd(a, b) _mm_cvtsi64_sd(a, b) + +// Convert the lower single-precision (32-bit) floating-point element in b to a +// double-precision (64-bit) floating-point element, store the result in the +// lower element of dst, and copy the upper element from a to the upper element +// of dst. +// +// dst[63:0] := Convert_FP32_To_FP64(b[31:0]) +// dst[127:64] := a[127:64] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_sd +FORCE_INLINE __m128d _mm_cvtss_sd(__m128d a, __m128 b) +{ + double d = (double) vgetq_lane_f32(vreinterpretq_f32_m128(b), 0); +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vsetq_lane_f64(d, vreinterpretq_f64_m128d(a), 0)); +#else + return vreinterpretq_m128d_s64( + vsetq_lane_s64(*(int64_t *) &d, vreinterpretq_s64_m128d(a), 0)); +#endif +} + +// Convert packed double-precision (64-bit) floating-point elements in a to +// packed 32-bit integers with truncation, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttpd_epi32 +FORCE_INLINE __m128i _mm_cvttpd_epi32(__m128d a) +{ + double a0 = ((double *) &a)[0]; + double a1 = ((double *) &a)[1]; + return _mm_set_epi32(0, 0, (int32_t) a1, (int32_t) a0); +} + +// Convert packed double-precision (64-bit) floating-point elements in a to +// packed 32-bit integers with truncation, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttpd_pi32 +FORCE_INLINE __m64 _mm_cvttpd_pi32(__m128d a) +{ + double a0 = ((double *) &a)[0]; + double a1 = ((double *) &a)[1]; + int32_t ALIGN_STRUCT(16) data[2] = {(int32_t) a0, (int32_t) a1}; + return vreinterpret_m64_s32(vld1_s32(data)); +} + +// Converts the four single-precision, floating-point values of a to signed +// 32-bit integer values using truncate. +// https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a) +{ + return vreinterpretq_m128i_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a))); +} + +// Convert the lower double-precision (64-bit) floating-point element in a to a +// 32-bit integer with truncation, and store the result in dst. +// +// dst[63:0] := Convert_FP64_To_Int32_Truncate(a[63:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si32 +FORCE_INLINE int32_t _mm_cvttsd_si32(__m128d a) +{ + double ret = *((double *) &a); + return (int32_t) ret; +} + +// Convert the lower double-precision (64-bit) floating-point element in a to a +// 64-bit integer with truncation, and store the result in dst. +// +// dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64 +FORCE_INLINE int64_t _mm_cvttsd_si64(__m128d a) +{ +#if defined(__aarch64__) + return vgetq_lane_s64(vcvtq_s64_f64(vreinterpretq_f64_m128d(a)), 0); +#else + double ret = *((double *) &a); + return (int64_t) ret; +#endif +} + +// Convert the lower double-precision (64-bit) floating-point element in a to a +// 64-bit integer with truncation, and store the result in dst. +// +// dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64x +#define _mm_cvttsd_si64x(a) _mm_cvttsd_si64(a) + +// Divide packed double-precision (64-bit) floating-point elements in a by +// packed elements in b, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 64*j +// dst[i+63:i] := a[i+63:i] / b[i+63:i] +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_pd +FORCE_INLINE __m128d _mm_div_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + double *da = (double *) &a; + double *db = (double *) &b; + double c[2]; + c[0] = da[0] / db[0]; + c[1] = da[1] / db[1]; + return vld1q_f32((float32_t *) c); +#endif +} + +// Divide the lower double-precision (64-bit) floating-point element in a by the +// lower double-precision (64-bit) floating-point element in b, store the result +// in the lower element of dst, and copy the upper element from a to the upper +// element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_sd +FORCE_INLINE __m128d _mm_div_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + float64x2_t tmp = + vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)); + return vreinterpretq_m128d_f64( + vsetq_lane_f64(vgetq_lane_f64(vreinterpretq_f64_m128d(a), 1), tmp, 1)); +#else + return _mm_move_sd(a, _mm_div_pd(a, b)); +#endif +} + +// Extracts the selected signed or unsigned 16-bit integer from a and zero +// extends. +// https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx +// FORCE_INLINE int _mm_extract_epi16(__m128i a, __constrange(0,8) int imm) +#define _mm_extract_epi16(a, imm) \ + vgetq_lane_u16(vreinterpretq_u16_m128i(a), (imm)) + +// Inserts the least significant 16 bits of b into the selected 16-bit integer +// of a. +// https://msdn.microsoft.com/en-us/library/kaze8hz1%28v=vs.100%29.aspx +// FORCE_INLINE __m128i _mm_insert_epi16(__m128i a, int b, +// __constrange(0,8) int imm) +#define _mm_insert_epi16(a, b, imm) \ + __extension__({ \ + vreinterpretq_m128i_s16( \ + vsetq_lane_s16((b), vreinterpretq_s16_m128i(a), (imm))); \ + }) + +// Loads two double-precision from 16-byte aligned memory, floating-point +// values. +// +// dst[127:0] := MEM[mem_addr+127:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd +FORCE_INLINE __m128d _mm_load_pd(const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vld1q_f64(p)); +#else + const float *fp = (const float *) p; + float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], fp[2], fp[3]}; + return vreinterpretq_m128d_f32(vld1q_f32(data)); +#endif +} + +// Load a double-precision (64-bit) floating-point element from memory into both +// elements of dst. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1 +#define _mm_load_pd1 _mm_load1_pd + +// Load a double-precision (64-bit) floating-point element from memory into the +// lower of dst, and zero the upper element. mem_addr does not need to be +// aligned on any particular boundary. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_sd +FORCE_INLINE __m128d _mm_load_sd(const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vsetq_lane_f64(*p, vdupq_n_f64(0), 0)); +#else + const float *fp = (const float *) p; + float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], 0, 0}; + return vreinterpretq_m128d_f32(vld1q_f32(data)); +#endif +} + +// Loads 128-bit value. : +// https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx +FORCE_INLINE __m128i _mm_load_si128(const __m128i *p) +{ + return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p)); +} + +// Load a double-precision (64-bit) floating-point element from memory into both +// elements of dst. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load1_pd +FORCE_INLINE __m128d _mm_load1_pd(const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vld1q_dup_f64(p)); +#else + return vreinterpretq_m128d_s64(vdupq_n_s64(*(const int64_t *) p)); +#endif +} + +// Load a double-precision (64-bit) floating-point element from memory into the +// upper element of dst, and copy the lower element from a to dst. mem_addr does +// not need to be aligned on any particular boundary. +// +// dst[63:0] := a[63:0] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadh_pd +FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vcombine_f64(vget_low_f64(vreinterpretq_f64_m128d(a)), vld1_f64(p))); +#else + return vreinterpretq_m128d_f32(vcombine_f32( + vget_low_f32(vreinterpretq_f32_m128d(a)), vld1_f32((const float *) p))); +#endif +} + +// Load 64-bit integer from memory into the first element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_epi64 +FORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p) +{ + /* Load the lower 64 bits of the value pointed to by p into the + * lower 64 bits of the result, zeroing the upper 64 bits of the result. + */ + return vreinterpretq_m128i_s32( + vcombine_s32(vld1_s32((int32_t const *) p), vcreate_s32(0))); +} + +// Load a double-precision (64-bit) floating-point element from memory into the +// lower element of dst, and copy the upper element from a to dst. mem_addr does +// not need to be aligned on any particular boundary. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := a[127:64] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_pd +FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vcombine_f64(vld1_f64(p), vget_high_f64(vreinterpretq_f64_m128d(a)))); +#else + return vreinterpretq_m128d_f32( + vcombine_f32(vld1_f32((const float *) p), + vget_high_f32(vreinterpretq_f32_m128d(a)))); +#endif +} + +// Load 2 double-precision (64-bit) floating-point elements from memory into dst +// in reverse order. mem_addr must be aligned on a 16-byte boundary or a +// general-protection exception may be generated. +// +// dst[63:0] := MEM[mem_addr+127:mem_addr+64] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_pd +FORCE_INLINE __m128d _mm_loadr_pd(const double *p) +{ +#if defined(__aarch64__) + float64x2_t v = vld1q_f64(p); + return vreinterpretq_m128d_f64(vextq_f64(v, v, 1)); +#else + int64x2_t v = vld1q_s64((const int64_t *) p); + return vreinterpretq_m128d_s64(vextq_s64(v, v, 1)); +#endif +} + +// Loads two double-precision from unaligned memory, floating-point values. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_pd +FORCE_INLINE __m128d _mm_loadu_pd(const double *p) +{ + return _mm_load_pd(p); +} + +// Loads 128-bit value. : +// https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx +FORCE_INLINE __m128i _mm_loadu_si128(const __m128i *p) +{ + return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p)); +} + +// Load unaligned 32-bit integer from memory into the first element of dst. +// +// dst[31:0] := MEM[mem_addr+31:mem_addr] +// dst[MAX:32] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si32 +FORCE_INLINE __m128i _mm_loadu_si32(const void *p) +{ + return vreinterpretq_m128i_s32( + vsetq_lane_s32(*(const int32_t *) p, vdupq_n_s32(0), 0)); +} + +// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit +// integers from b. +// +// r0 := (a0 * b0) + (a1 * b1) +// r1 := (a2 * b2) + (a3 * b3) +// r2 := (a4 * b4) + (a5 * b5) +// r3 := (a6 * b6) + (a7 * b7) +// https://msdn.microsoft.com/en-us/library/yht36sa6(v=vs.90).aspx +FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b) +{ + int32x4_t low = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)), + vget_low_s16(vreinterpretq_s16_m128i(b))); + int32x4_t high = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)), + vget_high_s16(vreinterpretq_s16_m128i(b))); + + int32x2_t low_sum = vpadd_s32(vget_low_s32(low), vget_high_s32(low)); + int32x2_t high_sum = vpadd_s32(vget_low_s32(high), vget_high_s32(high)); + + return vreinterpretq_m128i_s32(vcombine_s32(low_sum, high_sum)); +} + +// Conditionally store 8-bit integer elements from a into memory using mask +// (elements are not stored when the highest bit is not set in the corresponding +// element) and a non-temporal memory hint. mem_addr does not need to be aligned +// on any particular boundary. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskmoveu_si128 +FORCE_INLINE void _mm_maskmoveu_si128(__m128i a, __m128i mask, char *mem_addr) +{ + int8x16_t shr_mask = vshrq_n_s8(vreinterpretq_s8_m128i(mask), 7); + __m128 b = _mm_load_ps((const float *) mem_addr); + int8x16_t masked = + vbslq_s8(vreinterpretq_u8_s8(shr_mask), vreinterpretq_s8_m128i(a), + vreinterpretq_s8_m128(b)); + vst1q_s8((int8_t *) mem_addr, masked); +} + +// Computes the pairwise maxima of the 8 signed 16-bit integers from a and the 8 +// signed 16-bit integers from b. +// https://msdn.microsoft.com/en-us/LIBRary/3x060h7c(v=vs.100).aspx +FORCE_INLINE __m128i _mm_max_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vmaxq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Computes the pairwise maxima of the 16 unsigned 8-bit integers from a and the +// 16 unsigned 8-bit integers from b. +// https://msdn.microsoft.com/en-us/library/st6634za(v=vs.100).aspx +FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vmaxq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b, +// and store packed maximum values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pd +FORCE_INLINE __m128d _mm_max_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) +#if SSE2NEON_PRECISE_MINMAX + float64x2_t _a = vreinterpretq_f64_m128d(a); + float64x2_t _b = vreinterpretq_f64_m128d(b); + return vreinterpretq_m128d_f64(vbslq_f64(vcgtq_f64(_a, _b), _a, _b)); +#else + return vreinterpretq_m128d_f64( + vmaxq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#endif +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) > (*(double *) &b0) ? a0 : b0; + d[1] = (*(double *) &a1) > (*(double *) &b1) ? a1 : b1; + + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b, store the maximum value in the lower element of dst, and copy the upper +// element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_sd +FORCE_INLINE __m128d _mm_max_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return _mm_move_sd(a, _mm_max_pd(a, b)); +#else + double *da = (double *) &a; + double *db = (double *) &b; + double c[2] = {da[0] > db[0] ? da[0] : db[0], da[1]}; + return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) c)); +#endif +} + +// Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8 +// signed 16-bit integers from b. +// https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx +FORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vminq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Computes the pairwise minima of the 16 unsigned 8-bit integers from a and the +// 16 unsigned 8-bit integers from b. +// https://msdn.microsoft.com/ko-kr/library/17k8cf58(v=vs.100).aspxx +FORCE_INLINE __m128i _mm_min_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vminq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +// Compare packed double-precision (64-bit) floating-point elements in a and b, +// and store packed minimum values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pd +FORCE_INLINE __m128d _mm_min_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) +#if SSE2NEON_PRECISE_MINMAX + float64x2_t _a = vreinterpretq_f64_m128d(a); + float64x2_t _b = vreinterpretq_f64_m128d(b); + return vreinterpretq_m128d_f64(vbslq_f64(vcltq_f64(_a, _b), _a, _b)); +#else + return vreinterpretq_m128d_f64( + vminq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#endif +#else + uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); + uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); + uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); + uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); + uint64_t d[2]; + d[0] = (*(double *) &a0) < (*(double *) &b0) ? a0 : b0; + d[1] = (*(double *) &a1) < (*(double *) &b1) ? a1 : b1; + return vreinterpretq_m128d_u64(vld1q_u64(d)); +#endif +} + +// Compare the lower double-precision (64-bit) floating-point elements in a and +// b, store the minimum value in the lower element of dst, and copy the upper +// element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_sd +FORCE_INLINE __m128d _mm_min_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return _mm_move_sd(a, _mm_min_pd(a, b)); +#else + double *da = (double *) &a; + double *db = (double *) &b; + double c[2] = {da[0] < db[0] ? da[0] : db[0], da[1]}; + return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) c)); +#endif +} + +// Copy the lower 64-bit integer in a to the lower element of dst, and zero the +// upper element. +// +// dst[63:0] := a[63:0] +// dst[127:64] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_epi64 +FORCE_INLINE __m128i _mm_move_epi64(__m128i a) +{ + return vreinterpretq_m128i_s64( + vsetq_lane_s64(0, vreinterpretq_s64_m128i(a), 1)); +} + +// Move the lower double-precision (64-bit) floating-point element from b to the +// lower element of dst, and copy the upper element from a to the upper element +// of dst. +// +// dst[63:0] := b[63:0] +// dst[127:64] := a[127:64] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_sd +FORCE_INLINE __m128d _mm_move_sd(__m128d a, __m128d b) +{ + return vreinterpretq_m128d_f32( + vcombine_f32(vget_low_f32(vreinterpretq_f32_m128d(b)), + vget_high_f32(vreinterpretq_f32_m128d(a)))); } // NEON does not provide a version of this function. @@ -2865,88 +4862,1193 @@ FORCE_INLINE __m128i _mm_movpi64_epi64(__m64 a) vcombine_s64(vreinterpret_s64_m64(a), vdup_n_s64(0))); } -// NEON does not provide this method -// Creates a 4-bit mask from the most significant bits of the four -// single-precision, floating-point values. -// https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx -FORCE_INLINE int _mm_movemask_ps(__m128 a) +// Multiply the low unsigned 32-bit integers from each packed 64-bit element in +// a and b, and store the unsigned 64-bit results in dst. +// +// r0 := (a0 & 0xFFFFFFFF) * (b0 & 0xFFFFFFFF) +// r1 := (a2 & 0xFFFFFFFF) * (b2 & 0xFFFFFFFF) +FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b) +{ + // vmull_u32 upcasts instead of masking, so we downcast. + uint32x2_t a_lo = vmovn_u64(vreinterpretq_u64_m128i(a)); + uint32x2_t b_lo = vmovn_u64(vreinterpretq_u64_m128i(b)); + return vreinterpretq_m128i_u64(vmull_u32(a_lo, b_lo)); +} + +// Multiply packed double-precision (64-bit) floating-point elements in a and b, +// and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_pd +FORCE_INLINE __m128d _mm_mul_pd(__m128d a, __m128d b) { - uint32x4_t input = vreinterpretq_u32_m128(a); #if defined(__aarch64__) - static const int32x4_t shift = {0, 1, 2, 3}; - uint32x4_t tmp = vshrq_n_u32(input, 31); - return vaddvq_u32(vshlq_u32(tmp, shift)); + return vreinterpretq_m128d_f64( + vmulq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else - // Uses the exact same method as _mm_movemask_epi8, see that for details. - // Shift out everything but the sign bits with a 32-bit unsigned shift - // right. - uint64x2_t high_bits = vreinterpretq_u64_u32(vshrq_n_u32(input, 31)); - // Merge the two pairs together with a 64-bit unsigned shift right + add. - uint8x16_t paired = - vreinterpretq_u8_u64(vsraq_n_u64(high_bits, high_bits, 31)); - // Extract the result. - return vgetq_lane_u8(paired, 0) | (vgetq_lane_u8(paired, 8) << 2); + double *da = (double *) &a; + double *db = (double *) &b; + double c[2]; + c[0] = da[0] * db[0]; + c[1] = da[1] * db[1]; + return vld1q_f32((float32_t *) c); #endif } -// Compute the bitwise NOT of a and then AND with a 128-bit vector containing -// all 1's, and return 1 if the result is zero, otherwise return 0. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_ones -FORCE_INLINE int _mm_test_all_ones(__m128i a) +// Multiply the lower double-precision (64-bit) floating-point element in a and +// b, store the result in the lower element of dst, and copy the upper element +// from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mul_sd +FORCE_INLINE __m128d _mm_mul_sd(__m128d a, __m128d b) { - return (uint64_t)(vgetq_lane_s64(a, 0) & vgetq_lane_s64(a, 1)) == - ~(uint64_t) 0; + return _mm_move_sd(a, _mm_mul_pd(a, b)); } -// Compute the bitwise AND of 128 bits (representing integer data) in a and -// mask, and return 1 if the result is zero, otherwise return 0. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_zeros -FORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask) +// Multiply the low unsigned 32-bit integers from a and b, and store the +// unsigned 64-bit result in dst. +// +// dst[63:0] := a[31:0] * b[31:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_su32 +FORCE_INLINE __m64 _mm_mul_su32(__m64 a, __m64 b) { - int64x2_t a_and_mask = - vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(mask)); - return (vgetq_lane_s64(a_and_mask, 0) | vgetq_lane_s64(a_and_mask, 1)) ? 0 - : 1; + return vreinterpret_m64_u64(vget_low_u64( + vmull_u32(vreinterpret_u32_m64(a), vreinterpret_u32_m64(b)))); } -/* Math operations */ - -// Subtracts the four single-precision, floating-point values of a and b. +// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit +// integers from b. // -// r0 := a0 - b0 -// r1 := a1 - b1 -// r2 := a2 - b2 -// r3 := a3 - b3 +// r0 := (a0 * b0)[31:16] +// r1 := (a1 * b1)[31:16] +// ... +// r7 := (a7 * b7)[31:16] // -// https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx -FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b) +// https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx +FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b) { - return vreinterpretq_m128_f32( - vsubq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); + /* FIXME: issue with large values because of result saturation */ + // int16x8_t ret = vqdmulhq_s16(vreinterpretq_s16_m128i(a), + // vreinterpretq_s16_m128i(b)); /* =2*a*b */ return + // vreinterpretq_m128i_s16(vshrq_n_s16(ret, 1)); + int16x4_t a3210 = vget_low_s16(vreinterpretq_s16_m128i(a)); + int16x4_t b3210 = vget_low_s16(vreinterpretq_s16_m128i(b)); + int32x4_t ab3210 = vmull_s16(a3210, b3210); /* 3333222211110000 */ + int16x4_t a7654 = vget_high_s16(vreinterpretq_s16_m128i(a)); + int16x4_t b7654 = vget_high_s16(vreinterpretq_s16_m128i(b)); + int32x4_t ab7654 = vmull_s16(a7654, b7654); /* 7777666655554444 */ + uint16x8x2_t r = + vuzpq_u16(vreinterpretq_u16_s32(ab3210), vreinterpretq_u16_s32(ab7654)); + return vreinterpretq_m128i_u16(r.val[1]); } -// Subtract the lower single-precision (32-bit) floating-point element in b from -// the lower single-precision (32-bit) floating-point element in a, store the -// result in the lower element of dst, and copy the upper 3 packed elements from -// a to the upper elements of dst. -// -// dst[31:0] := a[31:0] - b[31:0] -// dst[127:32] := a[127:32] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_ss -FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b) +// Multiply the packed unsigned 16-bit integers in a and b, producing +// intermediate 32-bit integers, and store the high 16 bits of the intermediate +// integers in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_epu16 +FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b) { - return _mm_move_ss(a, _mm_sub_ps(a, b)); + uint16x4_t a3210 = vget_low_u16(vreinterpretq_u16_m128i(a)); + uint16x4_t b3210 = vget_low_u16(vreinterpretq_u16_m128i(b)); + uint32x4_t ab3210 = vmull_u16(a3210, b3210); +#if defined(__aarch64__) + uint32x4_t ab7654 = + vmull_high_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)); + uint16x8_t r = vuzp2q_u16(vreinterpretq_u16_u32(ab3210), + vreinterpretq_u16_u32(ab7654)); + return vreinterpretq_m128i_u16(r); +#else + uint16x4_t a7654 = vget_high_u16(vreinterpretq_u16_m128i(a)); + uint16x4_t b7654 = vget_high_u16(vreinterpretq_u16_m128i(b)); + uint32x4_t ab7654 = vmull_u16(a7654, b7654); + uint16x8x2_t r = + vuzpq_u16(vreinterpretq_u16_u32(ab3210), vreinterpretq_u16_u32(ab7654)); + return vreinterpretq_m128i_u16(r.val[1]); +#endif } -// Subtract 2 packed 64-bit integers in b from 2 packed 64-bit integers in a, -// and store the results in dst. -// r0 := a0 - b0 -// r1 := a1 - b1 -FORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b) +// Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or +// unsigned 16-bit integers from b. +// +// r0 := (a0 * b0)[15:0] +// r1 := (a1 * b1)[15:0] +// ... +// r7 := (a7 * b7)[15:0] +// +// https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx +FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vmulq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Compute the bitwise OR of packed double-precision (64-bit) floating-point +// elements in a and b, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_or_pd +FORCE_INLINE __m128d _mm_or_pd(__m128d a, __m128d b) +{ + return vreinterpretq_m128d_s64( + vorrq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); +} + +// Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b. +// +// r := a | b +// +// https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx +FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vorrq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Packs the 16 signed 16-bit integers from a and b into 8-bit integers and +// saturates. +// https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vcombine_s8(vqmovn_s16(vreinterpretq_s16_m128i(a)), + vqmovn_s16(vreinterpretq_s16_m128i(b)))); +} + +// Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers +// and saturates. +// +// r0 := SignedSaturate(a0) +// r1 := SignedSaturate(a1) +// r2 := SignedSaturate(a2) +// r3 := SignedSaturate(a3) +// r4 := SignedSaturate(b0) +// r5 := SignedSaturate(b1) +// r6 := SignedSaturate(b2) +// r7 := SignedSaturate(b3) +// +// https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vcombine_s16(vqmovn_s32(vreinterpretq_s32_m128i(a)), + vqmovn_s32(vreinterpretq_s32_m128i(b)))); +} + +// Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned +// integers and saturates. +// +// r0 := UnsignedSaturate(a0) +// r1 := UnsignedSaturate(a1) +// ... +// r7 := UnsignedSaturate(a7) +// r8 := UnsignedSaturate(b0) +// r9 := UnsignedSaturate(b1) +// ... +// r15 := UnsignedSaturate(b7) +// +// https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx +FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b) +{ + return vreinterpretq_m128i_u8( + vcombine_u8(vqmovun_s16(vreinterpretq_s16_m128i(a)), + vqmovun_s16(vreinterpretq_s16_m128i(b)))); +} + +// Pause the processor. This is typically used in spin-wait loops and depending +// on the x86 processor typical values are in the 40-100 cycle range. The +// 'yield' instruction isn't a good fit because it's effectively a nop on most +// Arm cores. Experience with several databases has shown has shown an 'isb' is +// a reasonable approximation. +FORCE_INLINE void _mm_pause() +{ + __asm__ __volatile__("isb\n"); +} + +// Compute the absolute differences of packed unsigned 8-bit integers in a and +// b, then horizontally sum each consecutive 8 differences to produce two +// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low +// 16 bits of 64-bit elements in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_epu8 +FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b) +{ + uint16x8_t t = vpaddlq_u8(vabdq_u8((uint8x16_t) a, (uint8x16_t) b)); + return vreinterpretq_m128i_u64(vpaddlq_u32(vpaddlq_u16(t))); +} + +// Sets the 8 signed 16-bit integer values. +// https://msdn.microsoft.com/en-au/library/3e0fek84(v=vs.90).aspx +FORCE_INLINE __m128i _mm_set_epi16(short i7, + short i6, + short i5, + short i4, + short i3, + short i2, + short i1, + short i0) +{ + int16_t ALIGN_STRUCT(16) data[8] = {i0, i1, i2, i3, i4, i5, i6, i7}; + return vreinterpretq_m128i_s16(vld1q_s16(data)); +} + +// Sets the 4 signed 32-bit integer values. +// https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx +FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0) +{ + int32_t ALIGN_STRUCT(16) data[4] = {i0, i1, i2, i3}; + return vreinterpretq_m128i_s32(vld1q_s32(data)); +} + +// Returns the __m128i structure with its two 64-bit integer values +// initialized to the values of the two 64-bit integers passed in. +// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx +FORCE_INLINE __m128i _mm_set_epi64(__m64 i1, __m64 i2) +{ + return _mm_set_epi64x((int64_t) i1, (int64_t) i2); +} + +// Returns the __m128i structure with its two 64-bit integer values +// initialized to the values of the two 64-bit integers passed in. +// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx +FORCE_INLINE __m128i _mm_set_epi64x(int64_t i1, int64_t i2) { return vreinterpretq_m128i_s64( - vsubq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); + vcombine_s64(vcreate_s64(i2), vcreate_s64(i1))); +} + +// Sets the 16 signed 8-bit integer values. +// https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx +FORCE_INLINE __m128i _mm_set_epi8(signed char b15, + signed char b14, + signed char b13, + signed char b12, + signed char b11, + signed char b10, + signed char b9, + signed char b8, + signed char b7, + signed char b6, + signed char b5, + signed char b4, + signed char b3, + signed char b2, + signed char b1, + signed char b0) +{ + int8_t ALIGN_STRUCT(16) + data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3, + (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7, + (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11, + (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15}; + return (__m128i) vld1q_s8(data); +} + +// Set packed double-precision (64-bit) floating-point elements in dst with the +// supplied values. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd +FORCE_INLINE __m128d _mm_set_pd(double e1, double e0) +{ + double ALIGN_STRUCT(16) data[2] = {e0, e1}; +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vld1q_f64((float64_t *) data)); +#else + return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) data)); +#endif +} + +// Broadcast double-precision (64-bit) floating-point value a to all elements of +// dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd1 +#define _mm_set_pd1 _mm_set1_pd + +// Copy double-precision (64-bit) floating-point element a to the lower element +// of dst, and zero the upper element. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_sd +FORCE_INLINE __m128d _mm_set_sd(double a) +{ + return _mm_set_pd(0, a); +} + +// Sets the 8 signed 16-bit integer values to w. +// +// r0 := w +// r1 := w +// ... +// r7 := w +// +// https://msdn.microsoft.com/en-us/library/k0ya3x0e(v=vs.90).aspx +FORCE_INLINE __m128i _mm_set1_epi16(short w) +{ + return vreinterpretq_m128i_s16(vdupq_n_s16(w)); +} + +// Sets the 4 signed 32-bit integer values to i. +// +// r0 := i +// r1 := i +// r2 := i +// r3 := I +// +// https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx +FORCE_INLINE __m128i _mm_set1_epi32(int _i) +{ + return vreinterpretq_m128i_s32(vdupq_n_s32(_i)); +} + +// Sets the 2 signed 64-bit integer values to i. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/whtfzhzk(v=vs.100) +FORCE_INLINE __m128i _mm_set1_epi64(__m64 _i) +{ + return vreinterpretq_m128i_s64(vdupq_n_s64((int64_t) _i)); +} + +// Sets the 2 signed 64-bit integer values to i. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_epi64x +FORCE_INLINE __m128i _mm_set1_epi64x(int64_t _i) +{ + return vreinterpretq_m128i_s64(vdupq_n_s64(_i)); +} + +// Sets the 16 signed 8-bit integer values to b. +// +// r0 := b +// r1 := b +// ... +// r15 := b +// +// https://msdn.microsoft.com/en-us/library/6e14xhyf(v=vs.100).aspx +FORCE_INLINE __m128i _mm_set1_epi8(signed char w) +{ + return vreinterpretq_m128i_s8(vdupq_n_s8(w)); +} + +// Broadcast double-precision (64-bit) floating-point value a to all elements of +// dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_pd +FORCE_INLINE __m128d _mm_set1_pd(double d) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vdupq_n_f64(d)); +#else + return vreinterpretq_m128d_s64(vdupq_n_s64(*(int64_t *) &d)); +#endif +} + +// Sets the 8 signed 16-bit integer values in reverse order. +// +// Return Value +// r0 := w0 +// r1 := w1 +// ... +// r7 := w7 +FORCE_INLINE __m128i _mm_setr_epi16(short w0, + short w1, + short w2, + short w3, + short w4, + short w5, + short w6, + short w7) +{ + int16_t ALIGN_STRUCT(16) data[8] = {w0, w1, w2, w3, w4, w5, w6, w7}; + return vreinterpretq_m128i_s16(vld1q_s16((int16_t *) data)); +} + +// Sets the 4 signed 32-bit integer values in reverse order +// https://technet.microsoft.com/en-us/library/security/27yb3ee5(v=vs.90).aspx +FORCE_INLINE __m128i _mm_setr_epi32(int i3, int i2, int i1, int i0) +{ + int32_t ALIGN_STRUCT(16) data[4] = {i3, i2, i1, i0}; + return vreinterpretq_m128i_s32(vld1q_s32(data)); +} + +// Set packed 64-bit integers in dst with the supplied values in reverse order. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_epi64 +FORCE_INLINE __m128i _mm_setr_epi64(__m64 e1, __m64 e0) +{ + return vreinterpretq_m128i_s64(vcombine_s64(e1, e0)); +} + +// Sets the 16 signed 8-bit integer values in reverse order. +// https://msdn.microsoft.com/en-us/library/2khb9c7k(v=vs.90).aspx +FORCE_INLINE __m128i _mm_setr_epi8(signed char b0, + signed char b1, + signed char b2, + signed char b3, + signed char b4, + signed char b5, + signed char b6, + signed char b7, + signed char b8, + signed char b9, + signed char b10, + signed char b11, + signed char b12, + signed char b13, + signed char b14, + signed char b15) +{ + int8_t ALIGN_STRUCT(16) + data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3, + (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7, + (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11, + (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15}; + return (__m128i) vld1q_s8(data); +} + +// Set packed double-precision (64-bit) floating-point elements in dst with the +// supplied values in reverse order. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_pd +FORCE_INLINE __m128d _mm_setr_pd(double e1, double e0) +{ + return _mm_set_pd(e0, e1); +} + +// Return vector of type __m128d with all elements set to zero. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setzero_pd +FORCE_INLINE __m128d _mm_setzero_pd(void) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vdupq_n_f64(0)); +#else + return vreinterpretq_m128d_f32(vdupq_n_f32(0)); +#endif +} + +// Sets the 128-bit value to zero +// https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx +FORCE_INLINE __m128i _mm_setzero_si128(void) +{ + return vreinterpretq_m128i_s32(vdupq_n_s32(0)); +} + +// Shuffles the 4 signed or unsigned 32-bit integers in a as specified by imm. +// https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx +// FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i a, +// __constrange(0,255) int imm) +#if __has_builtin(__builtin_shufflevector) +#define _mm_shuffle_epi32(a, imm) \ + __extension__({ \ + int32x4_t _input = vreinterpretq_s32_m128i(a); \ + int32x4_t _shuf = __builtin_shufflevector( \ + _input, _input, (imm) & (0x3), ((imm) >> 2) & 0x3, \ + ((imm) >> 4) & 0x3, ((imm) >> 6) & 0x3); \ + vreinterpretq_m128i_s32(_shuf); \ + }) +#else // generic +#define _mm_shuffle_epi32(a, imm) \ + __extension__({ \ + __m128i ret; \ + switch (imm) { \ + case _MM_SHUFFLE(1, 0, 3, 2): \ + ret = _mm_shuffle_epi_1032((a)); \ + break; \ + case _MM_SHUFFLE(2, 3, 0, 1): \ + ret = _mm_shuffle_epi_2301((a)); \ + break; \ + case _MM_SHUFFLE(0, 3, 2, 1): \ + ret = _mm_shuffle_epi_0321((a)); \ + break; \ + case _MM_SHUFFLE(2, 1, 0, 3): \ + ret = _mm_shuffle_epi_2103((a)); \ + break; \ + case _MM_SHUFFLE(1, 0, 1, 0): \ + ret = _mm_shuffle_epi_1010((a)); \ + break; \ + case _MM_SHUFFLE(1, 0, 0, 1): \ + ret = _mm_shuffle_epi_1001((a)); \ + break; \ + case _MM_SHUFFLE(0, 1, 0, 1): \ + ret = _mm_shuffle_epi_0101((a)); \ + break; \ + case _MM_SHUFFLE(2, 2, 1, 1): \ + ret = _mm_shuffle_epi_2211((a)); \ + break; \ + case _MM_SHUFFLE(0, 1, 2, 2): \ + ret = _mm_shuffle_epi_0122((a)); \ + break; \ + case _MM_SHUFFLE(3, 3, 3, 2): \ + ret = _mm_shuffle_epi_3332((a)); \ + break; \ + case _MM_SHUFFLE(0, 0, 0, 0): \ + ret = _mm_shuffle_epi32_splat((a), 0); \ + break; \ + case _MM_SHUFFLE(1, 1, 1, 1): \ + ret = _mm_shuffle_epi32_splat((a), 1); \ + break; \ + case _MM_SHUFFLE(2, 2, 2, 2): \ + ret = _mm_shuffle_epi32_splat((a), 2); \ + break; \ + case _MM_SHUFFLE(3, 3, 3, 3): \ + ret = _mm_shuffle_epi32_splat((a), 3); \ + break; \ + default: \ + ret = _mm_shuffle_epi32_default((a), (imm)); \ + break; \ + } \ + ret; \ + }) +#endif + +// Shuffle double-precision (64-bit) floating-point elements using the control +// in imm8, and store the results in dst. +// +// dst[63:0] := (imm8[0] == 0) ? a[63:0] : a[127:64] +// dst[127:64] := (imm8[1] == 0) ? b[63:0] : b[127:64] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pd +#if __has_builtin(__builtin_shufflevector) +#define _mm_shuffle_pd(a, b, imm8) \ + vreinterpretq_m128d_s64(__builtin_shufflevector( \ + vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b), imm8 & 0x1, \ + ((imm8 & 0x2) >> 1) + 2)) +#else +#define _mm_shuffle_pd(a, b, imm8) \ + _mm_castsi128_pd(_mm_set_epi64x( \ + vgetq_lane_s64(vreinterpretq_s64_m128d(b), (imm8 & 0x2) >> 1), \ + vgetq_lane_s64(vreinterpretq_s64_m128d(a), imm8 & 0x1))) +#endif + +// FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a, +// __constrange(0,255) int imm) +#if __has_builtin(__builtin_shufflevector) +#define _mm_shufflehi_epi16(a, imm) \ + __extension__({ \ + int16x8_t _input = vreinterpretq_s16_m128i(a); \ + int16x8_t _shuf = __builtin_shufflevector( \ + _input, _input, 0, 1, 2, 3, ((imm) & (0x3)) + 4, \ + (((imm) >> 2) & 0x3) + 4, (((imm) >> 4) & 0x3) + 4, \ + (((imm) >> 6) & 0x3) + 4); \ + vreinterpretq_m128i_s16(_shuf); \ + }) +#else // generic +#define _mm_shufflehi_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm)) +#endif + +// FORCE_INLINE __m128i _mm_shufflelo_epi16(__m128i a, +// __constrange(0,255) int imm) +#if __has_builtin(__builtin_shufflevector) +#define _mm_shufflelo_epi16(a, imm) \ + __extension__({ \ + int16x8_t _input = vreinterpretq_s16_m128i(a); \ + int16x8_t _shuf = __builtin_shufflevector( \ + _input, _input, ((imm) & (0x3)), (((imm) >> 2) & 0x3), \ + (((imm) >> 4) & 0x3), (((imm) >> 6) & 0x3), 4, 5, 6, 7); \ + vreinterpretq_m128i_s16(_shuf); \ + }) +#else // generic +#define _mm_shufflelo_epi16(a, imm) _mm_shufflelo_epi16_function((a), (imm)) +#endif + +// Shift packed 16-bit integers in a left by count while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// IF count[63:0] > 15 +// dst[i+15:i] := 0 +// ELSE +// dst[i+15:i] := ZeroExtend16(a[i+15:i] << count[63:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sll_epi16 +FORCE_INLINE __m128i _mm_sll_epi16(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (_sse2neon_unlikely(c & ~15)) + return _mm_setzero_si128(); + + int16x8_t vc = vdupq_n_s16((int16_t) c); + return vreinterpretq_m128i_s16(vshlq_s16(vreinterpretq_s16_m128i(a), vc)); +} + +// Shift packed 32-bit integers in a left by count while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// IF count[63:0] > 31 +// dst[i+31:i] := 0 +// ELSE +// dst[i+31:i] := ZeroExtend32(a[i+31:i] << count[63:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sll_epi32 +FORCE_INLINE __m128i _mm_sll_epi32(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (_sse2neon_unlikely(c & ~31)) + return _mm_setzero_si128(); + + int32x4_t vc = vdupq_n_s32((int32_t) c); + return vreinterpretq_m128i_s32(vshlq_s32(vreinterpretq_s32_m128i(a), vc)); +} + +// Shift packed 64-bit integers in a left by count while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// IF count[63:0] > 63 +// dst[i+63:i] := 0 +// ELSE +// dst[i+63:i] := ZeroExtend64(a[i+63:i] << count[63:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sll_epi64 +FORCE_INLINE __m128i _mm_sll_epi64(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (_sse2neon_unlikely(c & ~63)) + return _mm_setzero_si128(); + + int64x2_t vc = vdupq_n_s64((int64_t) c); + return vreinterpretq_m128i_s64(vshlq_s64(vreinterpretq_s64_m128i(a), vc)); +} + +// Shift packed 16-bit integers in a left by imm8 while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// IF imm8[7:0] > 15 +// dst[i+15:i] := 0 +// ELSE +// dst[i+15:i] := ZeroExtend16(a[i+15:i] << imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_slli_epi16 +FORCE_INLINE __m128i _mm_slli_epi16(__m128i a, int imm) +{ + if (_sse2neon_unlikely(imm & ~15)) + return _mm_setzero_si128(); + return vreinterpretq_m128i_s16( + vshlq_s16(vreinterpretq_s16_m128i(a), vdupq_n_s16(imm))); +} + +// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// IF imm8[7:0] > 31 +// dst[i+31:i] := 0 +// ELSE +// dst[i+31:i] := ZeroExtend32(a[i+31:i] << imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_slli_epi32 +FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, int imm) +{ + if (_sse2neon_unlikely(imm & ~31)) + return _mm_setzero_si128(); + return vreinterpretq_m128i_s32( + vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(imm))); +} + +// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// IF imm8[7:0] > 63 +// dst[i+63:i] := 0 +// ELSE +// dst[i+63:i] := ZeroExtend64(a[i+63:i] << imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_slli_epi64 +FORCE_INLINE __m128i _mm_slli_epi64(__m128i a, int imm) +{ + if (_sse2neon_unlikely(imm & ~63)) + return _mm_setzero_si128(); + return vreinterpretq_m128i_s64( + vshlq_s64(vreinterpretq_s64_m128i(a), vdupq_n_s64(imm))); +} + +// Shift a left by imm8 bytes while shifting in zeros, and store the results in +// dst. +// +// tmp := imm8[7:0] +// IF tmp > 15 +// tmp := 16 +// FI +// dst[127:0] := a[127:0] << (tmp*8) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_slli_si128 +FORCE_INLINE __m128i _mm_slli_si128(__m128i a, int imm) +{ + if (_sse2neon_unlikely(imm & ~15)) + return _mm_setzero_si128(); + uint8x16_t tmp[2] = {vdupq_n_u8(0), vreinterpretq_u8_m128i(a)}; + return vreinterpretq_m128i_u8( + vld1q_u8(((uint8_t const *) tmp) + (16 - imm))); +} + +// Compute the square root of packed double-precision (64-bit) floating-point +// elements in a, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_pd +FORCE_INLINE __m128d _mm_sqrt_pd(__m128d a) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vsqrtq_f64(vreinterpretq_f64_m128d(a))); +#else + double a0 = sqrt(((double *) &a)[0]); + double a1 = sqrt(((double *) &a)[1]); + return _mm_set_pd(a1, a0); +#endif +} + +// Compute the square root of the lower double-precision (64-bit) floating-point +// element in b, store the result in the lower element of dst, and copy the +// upper element from a to the upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_sd +FORCE_INLINE __m128d _mm_sqrt_sd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return _mm_move_sd(a, _mm_sqrt_pd(b)); +#else + return _mm_set_pd(((double *) &a)[1], sqrt(((double *) &b)[0])); +#endif +} + +// Shift packed 16-bit integers in a right by count while shifting in sign bits, +// and store the results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// IF count[63:0] > 15 +// dst[i+15:i] := (a[i+15] ? 0xFFFF : 0x0) +// ELSE +// dst[i+15:i] := SignExtend16(a[i+15:i] >> count[63:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sra_epi16 +FORCE_INLINE __m128i _mm_sra_epi16(__m128i a, __m128i count) +{ + int64_t c = (int64_t) vget_low_s64((int64x2_t) count); + if (_sse2neon_unlikely(c & ~15)) + return _mm_cmplt_epi16(a, _mm_setzero_si128()); + return vreinterpretq_m128i_s16(vshlq_s16((int16x8_t) a, vdupq_n_s16(-c))); +} + +// Shift packed 32-bit integers in a right by count while shifting in sign bits, +// and store the results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// IF count[63:0] > 31 +// dst[i+31:i] := (a[i+31] ? 0xFFFFFFFF : 0x0) +// ELSE +// dst[i+31:i] := SignExtend32(a[i+31:i] >> count[63:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sra_epi32 +FORCE_INLINE __m128i _mm_sra_epi32(__m128i a, __m128i count) +{ + int64_t c = (int64_t) vget_low_s64((int64x2_t) count); + if (_sse2neon_unlikely(c & ~31)) + return _mm_cmplt_epi32(a, _mm_setzero_si128()); + return vreinterpretq_m128i_s32(vshlq_s32((int32x4_t) a, vdupq_n_s32(-c))); +} + +// Shift packed 16-bit integers in a right by imm8 while shifting in sign +// bits, and store the results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// IF imm8[7:0] > 15 +// dst[i+15:i] := (a[i+15] ? 0xFFFF : 0x0) +// ELSE +// dst[i+15:i] := SignExtend16(a[i+15:i] >> imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi16 +FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int imm) +{ + const int count = (imm & ~15) ? 15 : imm; + return (__m128i) vshlq_s16((int16x8_t) a, vdupq_n_s16(-count)); +} + +// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, +// and store the results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// IF imm8[7:0] > 31 +// dst[i+31:i] := (a[i+31] ? 0xFFFFFFFF : 0x0) +// ELSE +// dst[i+31:i] := SignExtend32(a[i+31:i] >> imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi32 +// FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, __constrange(0,255) int imm) +#define _mm_srai_epi32(a, imm) \ + __extension__({ \ + __m128i ret; \ + if (_sse2neon_unlikely((imm) == 0)) { \ + ret = a; \ + } else if (_sse2neon_likely(0 < (imm) && (imm) < 32)) { \ + ret = vreinterpretq_m128i_s32( \ + vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(-imm))); \ + } else { \ + ret = vreinterpretq_m128i_s32( \ + vshrq_n_s32(vreinterpretq_s32_m128i(a), 31)); \ + } \ + ret; \ + }) + +// Shift packed 16-bit integers in a right by count while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// IF count[63:0] > 15 +// dst[i+15:i] := 0 +// ELSE +// dst[i+15:i] := ZeroExtend16(a[i+15:i] >> count[63:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srl_epi16 +FORCE_INLINE __m128i _mm_srl_epi16(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (_sse2neon_unlikely(c & ~15)) + return _mm_setzero_si128(); + + int16x8_t vc = vdupq_n_s16(-(int16_t) c); + return vreinterpretq_m128i_u16(vshlq_u16(vreinterpretq_u16_m128i(a), vc)); +} + +// Shift packed 32-bit integers in a right by count while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// IF count[63:0] > 31 +// dst[i+31:i] := 0 +// ELSE +// dst[i+31:i] := ZeroExtend32(a[i+31:i] >> count[63:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srl_epi32 +FORCE_INLINE __m128i _mm_srl_epi32(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (_sse2neon_unlikely(c & ~31)) + return _mm_setzero_si128(); + + int32x4_t vc = vdupq_n_s32(-(int32_t) c); + return vreinterpretq_m128i_u32(vshlq_u32(vreinterpretq_u32_m128i(a), vc)); +} + +// Shift packed 64-bit integers in a right by count while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// IF count[63:0] > 63 +// dst[i+63:i] := 0 +// ELSE +// dst[i+63:i] := ZeroExtend64(a[i+63:i] >> count[63:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srl_epi64 +FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (_sse2neon_unlikely(c & ~63)) + return _mm_setzero_si128(); + + int64x2_t vc = vdupq_n_s64(-(int64_t) c); + return vreinterpretq_m128i_u64(vshlq_u64(vreinterpretq_u64_m128i(a), vc)); +} + +// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// IF imm8[7:0] > 15 +// dst[i+15:i] := 0 +// ELSE +// dst[i+15:i] := ZeroExtend16(a[i+15:i] >> imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi16 +#define _mm_srli_epi16(a, imm) \ + __extension__({ \ + __m128i ret; \ + if (_sse2neon_unlikely((imm) & ~15)) { \ + ret = _mm_setzero_si128(); \ + } else { \ + ret = vreinterpretq_m128i_u16( \ + vshlq_u16(vreinterpretq_u16_m128i(a), vdupq_n_s16(-(imm)))); \ + } \ + ret; \ + }) + +// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// IF imm8[7:0] > 31 +// dst[i+31:i] := 0 +// ELSE +// dst[i+31:i] := ZeroExtend32(a[i+31:i] >> imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi32 +// FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, __constrange(0,255) int imm) +#define _mm_srli_epi32(a, imm) \ + __extension__({ \ + __m128i ret; \ + if (_sse2neon_unlikely((imm) & ~31)) { \ + ret = _mm_setzero_si128(); \ + } else { \ + ret = vreinterpretq_m128i_u32( \ + vshlq_u32(vreinterpretq_u32_m128i(a), vdupq_n_s32(-(imm)))); \ + } \ + ret; \ + }) + +// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// IF imm8[7:0] > 63 +// dst[i+63:i] := 0 +// ELSE +// dst[i+63:i] := ZeroExtend64(a[i+63:i] >> imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi64 +#define _mm_srli_epi64(a, imm) \ + __extension__({ \ + __m128i ret; \ + if (_sse2neon_unlikely((imm) & ~63)) { \ + ret = _mm_setzero_si128(); \ + } else { \ + ret = vreinterpretq_m128i_u64( \ + vshlq_u64(vreinterpretq_u64_m128i(a), vdupq_n_s64(-(imm)))); \ + } \ + ret; \ + }) + +// Shift a right by imm8 bytes while shifting in zeros, and store the results in +// dst. +// +// tmp := imm8[7:0] +// IF tmp > 15 +// tmp := 16 +// FI +// dst[127:0] := a[127:0] >> (tmp*8) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_si128 +FORCE_INLINE __m128i _mm_srli_si128(__m128i a, int imm) +{ + if (_sse2neon_unlikely(imm & ~15)) + return _mm_setzero_si128(); + uint8x16_t tmp[2] = {vreinterpretq_u8_m128i(a), vdupq_n_u8(0)}; + return vreinterpretq_m128i_u8(vld1q_u8(((uint8_t const *) tmp) + imm)); +} + +// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point +// elements) from a into memory. mem_addr must be aligned on a 16-byte boundary +// or a general-protection exception may be generated. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd +FORCE_INLINE void _mm_store_pd(double *mem_addr, __m128d a) +{ +#if defined(__aarch64__) + vst1q_f64((float64_t *) mem_addr, vreinterpretq_f64_m128d(a)); +#else + vst1q_f32((float32_t *) mem_addr, vreinterpretq_f32_m128d(a)); +#endif +} + +// Store the lower double-precision (64-bit) floating-point element from a into +// 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte +// boundary or a general-protection exception may be generated. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd1 +FORCE_INLINE void _mm_store_pd1(double *mem_addr, __m128d a) +{ +#if defined(__aarch64__) + float64x1_t a_low = vget_low_f64(vreinterpretq_f64_m128d(a)); + vst1q_f64((float64_t *) mem_addr, + vreinterpretq_f64_m128d(vcombine_f64(a_low, a_low))); +#else + float32x2_t a_low = vget_low_f32(vreinterpretq_f32_m128d(a)); + vst1q_f32((float32_t *) mem_addr, + vreinterpretq_f32_m128d(vcombine_f32(a_low, a_low))); +#endif +} + +// Store the lower double-precision (64-bit) floating-point element from a into +// memory. mem_addr does not need to be aligned on any particular boundary. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_store_sd +FORCE_INLINE void _mm_store_sd(double *mem_addr, __m128d a) +{ +#if defined(__aarch64__) + vst1_f64((float64_t *) mem_addr, vget_low_f64(vreinterpretq_f64_m128d(a))); +#else + vst1_u64((uint64_t *) mem_addr, vget_low_u64(vreinterpretq_u64_m128d(a))); +#endif +} + +// Stores four 32-bit integer values as (as a __m128i value) at the address p. +// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx +FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a) +{ + vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a)); +} + +// Store the lower double-precision (64-bit) floating-point element from a into +// 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte +// boundary or a general-protection exception may be generated. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=9,526,5601&text=_mm_store1_pd +#define _mm_store1_pd _mm_store_pd1 + +// Store the upper double-precision (64-bit) floating-point element from a into +// memory. +// +// MEM[mem_addr+63:mem_addr] := a[127:64] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeh_pd +FORCE_INLINE void _mm_storeh_pd(double *mem_addr, __m128d a) +{ +#if defined(__aarch64__) + vst1_f64((float64_t *) mem_addr, vget_high_f64(vreinterpretq_f64_m128d(a))); +#else + vst1_f32((float32_t *) mem_addr, vget_high_f32(vreinterpretq_f32_m128d(a))); +#endif +} + +// Reads the lower 64 bits of b and stores them into the lower 64 bits of a. +// https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx +FORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b) +{ + vst1_u64((uint64_t *) a, vget_low_u64(vreinterpretq_u64_m128i(b))); +} + +// Store the lower double-precision (64-bit) floating-point element from a into +// memory. +// +// MEM[mem_addr+63:mem_addr] := a[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storel_pd +FORCE_INLINE void _mm_storel_pd(double *mem_addr, __m128d a) +{ +#if defined(__aarch64__) + vst1_f64((float64_t *) mem_addr, vget_low_f64(vreinterpretq_f64_m128d(a))); +#else + vst1_f32((float32_t *) mem_addr, vget_low_f32(vreinterpretq_f32_m128d(a))); +#endif +} + +// Store 2 double-precision (64-bit) floating-point elements from a into memory +// in reverse order. mem_addr must be aligned on a 16-byte boundary or a +// general-protection exception may be generated. +// +// MEM[mem_addr+63:mem_addr] := a[127:64] +// MEM[mem_addr+127:mem_addr+64] := a[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_pd +FORCE_INLINE void _mm_storer_pd(double *mem_addr, __m128d a) +{ + float32x4_t f = vreinterpretq_f32_m128d(a); + _mm_store_pd(mem_addr, vreinterpretq_m128d_f32(vextq_f32(f, f, 2))); +} + +// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point +// elements) from a into memory. mem_addr does not need to be aligned on any +// particular boundary. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_pd +FORCE_INLINE void _mm_storeu_pd(double *mem_addr, __m128d a) +{ + _mm_store_pd(mem_addr, a); +} + +// Stores 128-bits of integer data a at the address p. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si128 +FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a) +{ + vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a)); +} + +// Stores 32-bits of integer data a at the address p. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si32 +FORCE_INLINE void _mm_storeu_si32(void *p, __m128i a) +{ + vst1q_lane_s32((int32_t *) p, vreinterpretq_s32_m128i(a), 0); +} + +// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point +// elements) from a into memory using a non-temporal memory hint. mem_addr must +// be aligned on a 16-byte boundary or a general-protection exception may be +// generated. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_pd +FORCE_INLINE void _mm_stream_pd(double *p, __m128d a) +{ +#if __has_builtin(__builtin_nontemporal_store) + __builtin_nontemporal_store(a, (float32x4_t *) p); +#elif defined(__aarch64__) + vst1q_f64(p, vreinterpretq_f64_m128d(a)); +#else + vst1q_s64((int64_t *) p, vreinterpretq_s64_m128d(a)); +#endif +} + +// Stores the data in a to the address p without polluting the caches. If the +// cache line containing address p is already in the cache, the cache will be +// updated. +// https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx +FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a) +{ +#if __has_builtin(__builtin_nontemporal_store) + __builtin_nontemporal_store(a, p); +#else + vst1q_s64((int64_t *) p, vreinterpretq_s64_m128i(a)); +#endif +} + +// Store 32-bit integer a into memory using a non-temporal hint to minimize +// cache pollution. If the cache line containing address mem_addr is already in +// the cache, the cache will be updated. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_si32 +FORCE_INLINE void _mm_stream_si32(int *p, int a) +{ + vst1q_lane_s32((int32_t *) p, vdupq_n_s32(a), 0); +} + +// Store 64-bit integer a into memory using a non-temporal hint to minimize +// cache pollution. If the cache line containing address mem_addr is already in +// the cache, the cache will be updated. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_si64 +FORCE_INLINE void _mm_stream_si64(__int64 *p, __int64 a) +{ + vst1_s64((int64_t *) p, vdup_n_s64((int64_t) a)); +} + +// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and +// store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi16 +FORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Subtracts the 4 signed or unsigned 32-bit integers of b from the 4 signed or @@ -2964,13 +6066,14 @@ FORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b) vsubq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } -// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and -// store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi16 -FORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b) +// Subtract 2 packed 64-bit integers in b from 2 packed 64-bit integers in a, +// and store the results in dst. +// r0 := a0 - b0 +// r1 := a1 - b1 +FORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b) { - return vreinterpretq_m128i_s16( - vsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); + return vreinterpretq_m128i_s64( + vsubq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); } // Subtract packed 8-bit integers in b from packed 8-bit integers in a, and @@ -2982,78 +6085,6 @@ FORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b) vsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } -// Subtract 64-bit integer b from 64-bit integer a, and store the result in dst. -// -// dst[63:0] := a[63:0] - b[63:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_si64 -FORCE_INLINE __m64 _mm_sub_si64(__m64 a, __m64 b) -{ - return vreinterpret_m64_s64( - vsub_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b))); -} - -// Subtracts the 8 unsigned 16-bit integers of bfrom the 8 unsigned 16-bit -// integers of a and saturates.. -// https://technet.microsoft.com/en-us/subscriptions/index/f44y0s19(v=vs.90).aspx -FORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u16( - vqsubq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); -} - -// Subtracts the 16 unsigned 8-bit integers of b from the 16 unsigned 8-bit -// integers of a and saturates. -// -// r0 := UnsignedSaturate(a0 - b0) -// r1 := UnsignedSaturate(a1 - b1) -// ... -// r15 := UnsignedSaturate(a15 - b15) -// -// https://technet.microsoft.com/en-us/subscriptions/yadkxc18(v=vs.90) -FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u8( - vqsubq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); -} - -#define _mm_ucomieq_sd _mm_comieq_sd -#define _mm_ucomige_sd _mm_comige_sd -#define _mm_ucomigt_sd _mm_comigt_sd -#define _mm_ucomile_sd _mm_comile_sd -#define _mm_ucomilt_sd _mm_comilt_sd -#define _mm_ucomineq_sd _mm_comineq_sd - -// Subtracts the 16 signed 8-bit integers of b from the 16 signed 8-bit integers -// of a and saturates. -// -// r0 := SignedSaturate(a0 - b0) -// r1 := SignedSaturate(a1 - b1) -// ... -// r15 := SignedSaturate(a15 - b15) -// -// https://technet.microsoft.com/en-us/subscriptions/by7kzks1(v=vs.90) -FORCE_INLINE __m128i _mm_subs_epi8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s8( - vqsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -} - -// Subtracts the 8 signed 16-bit integers of b from the 8 signed 16-bit integers -// of a and saturates. -// -// r0 := SignedSaturate(a0 - b0) -// r1 := SignedSaturate(a1 - b1) -// ... -// r7 := SignedSaturate(a7 - b7) -// -// https://technet.microsoft.com/en-us/subscriptions/3247z5b8(v=vs.90) -FORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s16( - vqsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -} - // Subtract packed double-precision (64-bit) floating-point elements in b from // packed double-precision (64-bit) floating-point elements in a, and store the // results in dst. @@ -3089,52 +6120,975 @@ FORCE_INLINE __m128d _mm_sub_sd(__m128d a, __m128d b) return _mm_move_sd(a, _mm_sub_pd(a, b)); } -// Add packed unsigned 16-bit integers in a and b using saturation, and store -// the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epu16 -FORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b) +// Subtract 64-bit integer b from 64-bit integer a, and store the result in dst. +// +// dst[63:0] := a[63:0] - b[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_si64 +FORCE_INLINE __m64 _mm_sub_si64(__m64 a, __m64 b) { - return vreinterpretq_m128i_u16( - vqaddq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); + return vreinterpret_m64_s64( + vsub_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b))); } -// Negate packed 8-bit integers in a when the corresponding signed -// 8-bit integer in b is negative, and store the results in dst. -// Element in dst are zeroed out when the corresponding element -// in b is zero. +// Subtracts the 8 signed 16-bit integers of b from the 8 signed 16-bit integers +// of a and saturates. // -// for i in 0..15 -// if b[i] < 0 -// r[i] := -a[i] -// else if b[i] == 0 -// r[i] := 0 -// else -// r[i] := a[i] -// fi -// done -FORCE_INLINE __m128i _mm_sign_epi8(__m128i _a, __m128i _b) +// r0 := SignedSaturate(a0 - b0) +// r1 := SignedSaturate(a1 - b1) +// ... +// r7 := SignedSaturate(a7 - b7) +// +// https://technet.microsoft.com/en-us/subscriptions/3247z5b8(v=vs.90) +FORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b) { - int8x16_t a = vreinterpretq_s8_m128i(_a); - int8x16_t b = vreinterpretq_s8_m128i(_b); + return vreinterpretq_m128i_s16( + vqsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} - // signed shift right: faster than vclt - // (b < 0) ? 0xFF : 0 - uint8x16_t ltMask = vreinterpretq_u8_s8(vshrq_n_s8(b, 7)); +// Subtracts the 16 signed 8-bit integers of b from the 16 signed 8-bit integers +// of a and saturates. +// +// r0 := SignedSaturate(a0 - b0) +// r1 := SignedSaturate(a1 - b1) +// ... +// r15 := SignedSaturate(a15 - b15) +// +// https://technet.microsoft.com/en-us/subscriptions/by7kzks1(v=vs.90) +FORCE_INLINE __m128i _mm_subs_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vqsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} - // (b == 0) ? 0xFF : 0 -#if defined(__aarch64__) - int8x16_t zeroMask = vreinterpretq_s8_u8(vceqzq_s8(b)); -#else - int8x16_t zeroMask = vreinterpretq_s8_u8(vceqq_s8(b, vdupq_n_s8(0))); +// Subtracts the 8 unsigned 16-bit integers of bfrom the 8 unsigned 16-bit +// integers of a and saturates.. +// https://technet.microsoft.com/en-us/subscriptions/index/f44y0s19(v=vs.90).aspx +FORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vqsubq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); +} + +// Subtracts the 16 unsigned 8-bit integers of b from the 16 unsigned 8-bit +// integers of a and saturates. +// +// r0 := UnsignedSaturate(a0 - b0) +// r1 := UnsignedSaturate(a1 - b1) +// ... +// r15 := UnsignedSaturate(a15 - b15) +// +// https://technet.microsoft.com/en-us/subscriptions/yadkxc18(v=vs.90) +FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vqsubq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +#define _mm_ucomieq_sd _mm_comieq_sd +#define _mm_ucomige_sd _mm_comige_sd +#define _mm_ucomigt_sd _mm_comigt_sd +#define _mm_ucomile_sd _mm_comile_sd +#define _mm_ucomilt_sd _mm_comilt_sd +#define _mm_ucomineq_sd _mm_comineq_sd + +// Return vector of type __m128d with undefined elements. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_pd +FORCE_INLINE __m128d _mm_undefined_pd(void) +{ +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" #endif + __m128d a; + return a; +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif +} - // bitwise select either a or nagative 'a' (vnegq_s8(a) return nagative 'a') - // based on ltMask - int8x16_t masked = vbslq_s8(ltMask, vnegq_s8(a), a); - // res = masked & (~zeroMask) - int8x16_t res = vbicq_s8(masked, zeroMask); +// Interleaves the upper 4 signed or unsigned 16-bit integers in a with the +// upper 4 signed or unsigned 16-bit integers in b. +// +// r0 := a4 +// r1 := b4 +// r2 := a5 +// r3 := b5 +// r4 := a6 +// r5 := b6 +// r6 := a7 +// r7 := b7 +// +// https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx +FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s16( + vzip2q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +#else + int16x4_t a1 = vget_high_s16(vreinterpretq_s16_m128i(a)); + int16x4_t b1 = vget_high_s16(vreinterpretq_s16_m128i(b)); + int16x4x2_t result = vzip_s16(a1, b1); + return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1])); +#endif +} - return vreinterpretq_m128i_s8(res); +// Interleaves the upper 2 signed or unsigned 32-bit integers in a with the +// upper 2 signed or unsigned 32-bit integers in b. +// https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx +FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s32( + vzip2q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +#else + int32x2_t a1 = vget_high_s32(vreinterpretq_s32_m128i(a)); + int32x2_t b1 = vget_high_s32(vreinterpretq_s32_m128i(b)); + int32x2x2_t result = vzip_s32(a1, b1); + return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1])); +#endif +} + +// Interleaves the upper signed or unsigned 64-bit integer in a with the +// upper signed or unsigned 64-bit integer in b. +// +// r0 := a1 +// r1 := b1 +FORCE_INLINE __m128i _mm_unpackhi_epi64(__m128i a, __m128i b) +{ + int64x1_t a_h = vget_high_s64(vreinterpretq_s64_m128i(a)); + int64x1_t b_h = vget_high_s64(vreinterpretq_s64_m128i(b)); + return vreinterpretq_m128i_s64(vcombine_s64(a_h, b_h)); +} + +// Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper +// 8 signed or unsigned 8-bit integers in b. +// +// r0 := a8 +// r1 := b8 +// r2 := a9 +// r3 := b9 +// ... +// r14 := a15 +// r15 := b15 +// +// https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx +FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s8( + vzip2q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +#else + int8x8_t a1 = + vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(a))); + int8x8_t b1 = + vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(b))); + int8x8x2_t result = vzip_s8(a1, b1); + return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1])); +#endif +} + +// Unpack and interleave double-precision (64-bit) floating-point elements from +// the high half of a and b, and store the results in dst. +// +// DEFINE INTERLEAVE_HIGH_QWORDS(src1[127:0], src2[127:0]) { +// dst[63:0] := src1[127:64] +// dst[127:64] := src2[127:64] +// RETURN dst[127:0] +// } +// dst[127:0] := INTERLEAVE_HIGH_QWORDS(a[127:0], b[127:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpackhi_pd +FORCE_INLINE __m128d _mm_unpackhi_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vzip2q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + return vreinterpretq_m128d_s64( + vcombine_s64(vget_high_s64(vreinterpretq_s64_m128d(a)), + vget_high_s64(vreinterpretq_s64_m128d(b)))); +#endif +} + +// Interleaves the lower 4 signed or unsigned 16-bit integers in a with the +// lower 4 signed or unsigned 16-bit integers in b. +// +// r0 := a0 +// r1 := b0 +// r2 := a1 +// r3 := b1 +// r4 := a2 +// r5 := b2 +// r6 := a3 +// r7 := b3 +// +// https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s16( + vzip1q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +#else + int16x4_t a1 = vget_low_s16(vreinterpretq_s16_m128i(a)); + int16x4_t b1 = vget_low_s16(vreinterpretq_s16_m128i(b)); + int16x4x2_t result = vzip_s16(a1, b1); + return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1])); +#endif +} + +// Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the +// lower 2 signed or unsigned 32 - bit integers in b. +// +// r0 := a0 +// r1 := b0 +// r2 := a1 +// r3 := b1 +// +// https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx +FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s32( + vzip1q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +#else + int32x2_t a1 = vget_low_s32(vreinterpretq_s32_m128i(a)); + int32x2_t b1 = vget_low_s32(vreinterpretq_s32_m128i(b)); + int32x2x2_t result = vzip_s32(a1, b1); + return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1])); +#endif +} + +FORCE_INLINE __m128i _mm_unpacklo_epi64(__m128i a, __m128i b) +{ + int64x1_t a_l = vget_low_s64(vreinterpretq_s64_m128i(a)); + int64x1_t b_l = vget_low_s64(vreinterpretq_s64_m128i(b)); + return vreinterpretq_m128i_s64(vcombine_s64(a_l, b_l)); +} + +// Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower +// 8 signed or unsigned 8-bit integers in b. +// +// r0 := a0 +// r1 := b0 +// r2 := a1 +// r3 := b1 +// ... +// r14 := a7 +// r15 := b7 +// +// https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s8( + vzip1q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +#else + int8x8_t a1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(a))); + int8x8_t b1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(b))); + int8x8x2_t result = vzip_s8(a1, b1); + return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1])); +#endif +} + +// Unpack and interleave double-precision (64-bit) floating-point elements from +// the low half of a and b, and store the results in dst. +// +// DEFINE INTERLEAVE_QWORDS(src1[127:0], src2[127:0]) { +// dst[63:0] := src1[63:0] +// dst[127:64] := src2[63:0] +// RETURN dst[127:0] +// } +// dst[127:0] := INTERLEAVE_QWORDS(a[127:0], b[127:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpacklo_pd +FORCE_INLINE __m128d _mm_unpacklo_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vzip1q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + return vreinterpretq_m128d_s64( + vcombine_s64(vget_low_s64(vreinterpretq_s64_m128d(a)), + vget_low_s64(vreinterpretq_s64_m128d(b)))); +#endif +} + +// Compute the bitwise XOR of packed double-precision (64-bit) floating-point +// elements in a and b, and store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// dst[i+63:i] := a[i+63:i] XOR b[i+63:i] +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_xor_pd +FORCE_INLINE __m128d _mm_xor_pd(__m128d a, __m128d b) +{ + return vreinterpretq_m128d_s64( + veorq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); +} + +// Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in +// b. https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx +FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + veorq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +/* SSE3 */ + +// Alternatively add and subtract packed double-precision (64-bit) +// floating-point elements in a to/from packed elements in b, and store the +// results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// IF ((j & 1) == 0) +// dst[i+63:i] := a[i+63:i] - b[i+63:i] +// ELSE +// dst[i+63:i] := a[i+63:i] + b[i+63:i] +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_addsub_pd +FORCE_INLINE __m128d _mm_addsub_pd(__m128d a, __m128d b) +{ + _sse2neon_const __m128d mask = _mm_set_pd(1.0f, -1.0f); +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vfmaq_f64(vreinterpretq_f64_m128d(a), + vreinterpretq_f64_m128d(b), + vreinterpretq_f64_m128d(mask))); +#else + return _mm_add_pd(_mm_mul_pd(b, mask), a); +#endif +} + +// Alternatively add and subtract packed single-precision (32-bit) +// floating-point elements in a to/from packed elements in b, and store the +// results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=addsub_ps +FORCE_INLINE __m128 _mm_addsub_ps(__m128 a, __m128 b) +{ + _sse2neon_const __m128 mask = _mm_setr_ps(-1.0f, 1.0f, -1.0f, 1.0f); +#if defined(__aarch64__) || defined(__ARM_FEATURE_FMA) /* VFPv4+ */ + return vreinterpretq_m128_f32(vfmaq_f32(vreinterpretq_f32_m128(a), + vreinterpretq_f32_m128(mask), + vreinterpretq_f32_m128(b))); +#else + return _mm_add_ps(_mm_mul_ps(b, mask), a); +#endif +} + +// Horizontally add adjacent pairs of double-precision (64-bit) floating-point +// elements in a and b, and pack the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pd +FORCE_INLINE __m128d _mm_hadd_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vpaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + double *da = (double *) &a; + double *db = (double *) &b; + double c[] = {da[0] + da[1], db[0] + db[1]}; + return vreinterpretq_m128d_u64(vld1q_u64((uint64_t *) c)); +#endif +} + +// Computes pairwise add of each argument as single-precision, floating-point +// values a and b. +// https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx +FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vpaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#else + float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); + float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a)); + float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); + float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_f32( + vcombine_f32(vpadd_f32(a10, a32), vpadd_f32(b10, b32))); +#endif +} + +// Horizontally subtract adjacent pairs of double-precision (64-bit) +// floating-point elements in a and b, and pack the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_pd +FORCE_INLINE __m128d _mm_hsub_pd(__m128d _a, __m128d _b) +{ +#if defined(__aarch64__) + float64x2_t a = vreinterpretq_f64_m128d(_a); + float64x2_t b = vreinterpretq_f64_m128d(_b); + return vreinterpretq_m128d_f64( + vsubq_f64(vuzp1q_f64(a, b), vuzp2q_f64(a, b))); +#else + double *da = (double *) &_a; + double *db = (double *) &_b; + double c[] = {da[0] - da[1], db[0] - db[1]}; + return vreinterpretq_m128d_u64(vld1q_u64((uint64_t *) c)); +#endif +} + +// Horizontally subtract adjacent pairs of single-precision (32-bit) +// floating-point elements in a and b, and pack the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_ps +FORCE_INLINE __m128 _mm_hsub_ps(__m128 _a, __m128 _b) +{ + float32x4_t a = vreinterpretq_f32_m128(_a); + float32x4_t b = vreinterpretq_f32_m128(_b); +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vsubq_f32(vuzp1q_f32(a, b), vuzp2q_f32(a, b))); +#else + float32x4x2_t c = vuzpq_f32(a, b); + return vreinterpretq_m128_f32(vsubq_f32(c.val[0], c.val[1])); +#endif +} + +// Load 128-bits of integer data from unaligned memory into dst. This intrinsic +// may perform better than _mm_loadu_si128 when the data crosses a cache line +// boundary. +// +// dst[127:0] := MEM[mem_addr+127:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lddqu_si128 +#define _mm_lddqu_si128 _mm_loadu_si128 + +// Load a double-precision (64-bit) floating-point element from memory into both +// elements of dst. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loaddup_pd +#define _mm_loaddup_pd _mm_load1_pd + +// Duplicate the low double-precision (64-bit) floating-point element from a, +// and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movedup_pd +FORCE_INLINE __m128d _mm_movedup_pd(__m128d a) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vdupq_laneq_f64(vreinterpretq_f64_m128d(a), 0)); +#else + return vreinterpretq_m128d_u64( + vdupq_n_u64(vgetq_lane_u64(vreinterpretq_u64_m128d(a), 0))); +#endif +} + +// Duplicate odd-indexed single-precision (32-bit) floating-point elements +// from a, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movehdup_ps +FORCE_INLINE __m128 _mm_movehdup_ps(__m128 a) +{ +#if __has_builtin(__builtin_shufflevector) + return vreinterpretq_m128_f32(__builtin_shufflevector( + vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 1, 1, 3, 3)); +#else + float32_t a1 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 1); + float32_t a3 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 3); + float ALIGN_STRUCT(16) data[4] = {a1, a1, a3, a3}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +#endif +} + +// Duplicate even-indexed single-precision (32-bit) floating-point elements +// from a, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_moveldup_ps +FORCE_INLINE __m128 _mm_moveldup_ps(__m128 a) +{ +#if __has_builtin(__builtin_shufflevector) + return vreinterpretq_m128_f32(__builtin_shufflevector( + vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 0, 0, 2, 2)); +#else + float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); + float32_t a2 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 2); + float ALIGN_STRUCT(16) data[4] = {a0, a0, a2, a2}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +#endif +} + +/* SSSE3 */ + +// Compute the absolute value of packed signed 16-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// dst[i+15:i] := ABS(a[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi16 +FORCE_INLINE __m128i _mm_abs_epi16(__m128i a) +{ + return vreinterpretq_m128i_s16(vabsq_s16(vreinterpretq_s16_m128i(a))); +} + +// Compute the absolute value of packed signed 32-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// dst[i+31:i] := ABS(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi32 +FORCE_INLINE __m128i _mm_abs_epi32(__m128i a) +{ + return vreinterpretq_m128i_s32(vabsq_s32(vreinterpretq_s32_m128i(a))); +} + +// Compute the absolute value of packed signed 8-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 15 +// i := j*8 +// dst[i+7:i] := ABS(a[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi8 +FORCE_INLINE __m128i _mm_abs_epi8(__m128i a) +{ + return vreinterpretq_m128i_s8(vabsq_s8(vreinterpretq_s8_m128i(a))); +} + +// Compute the absolute value of packed signed 16-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := ABS(a[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi16 +FORCE_INLINE __m64 _mm_abs_pi16(__m64 a) +{ + return vreinterpret_m64_s16(vabs_s16(vreinterpret_s16_m64(a))); +} + +// Compute the absolute value of packed signed 32-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 1 +// i := j*32 +// dst[i+31:i] := ABS(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi32 +FORCE_INLINE __m64 _mm_abs_pi32(__m64 a) +{ + return vreinterpret_m64_s32(vabs_s32(vreinterpret_s32_m64(a))); +} + +// Compute the absolute value of packed signed 8-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := ABS(a[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi8 +FORCE_INLINE __m64 _mm_abs_pi8(__m64 a) +{ + return vreinterpret_m64_s8(vabs_s8(vreinterpret_s8_m64(a))); +} + +// Concatenate 16-byte blocks in a and b into a 32-byte temporary result, shift +// the result right by imm8 bytes, and store the low 16 bytes in dst. +// +// tmp[255:0] := ((a[127:0] << 128)[255:0] OR b[127:0]) >> (imm8*8) +// dst[127:0] := tmp[127:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_epi8 +FORCE_INLINE __m128i _mm_alignr_epi8(__m128i a, __m128i b, int imm) +{ + if (_sse2neon_unlikely(imm & ~31)) + return _mm_setzero_si128(); + int idx; + uint8x16_t tmp[2]; + if (imm >= 16) { + idx = imm - 16; + tmp[0] = vreinterpretq_u8_m128i(a); + tmp[1] = vdupq_n_u8(0); + } else { + idx = imm; + tmp[0] = vreinterpretq_u8_m128i(b); + tmp[1] = vreinterpretq_u8_m128i(a); + } + return vreinterpretq_m128i_u8(vld1q_u8(((uint8_t const *) tmp) + idx)); +} + +// Concatenate 8-byte blocks in a and b into a 16-byte temporary result, shift +// the result right by imm8 bytes, and store the low 8 bytes in dst. +// +// tmp[127:0] := ((a[63:0] << 64)[127:0] OR b[63:0]) >> (imm8*8) +// dst[63:0] := tmp[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_pi8 +#define _mm_alignr_pi8(a, b, imm) \ + __extension__({ \ + __m64 ret; \ + if (_sse2neon_unlikely((imm) >= 16)) { \ + ret = vreinterpret_m64_s8(vdup_n_s8(0)); \ + } else { \ + uint8x8_t tmp_low, tmp_high; \ + if ((imm) >= 8) { \ + const int idx = (imm) -8; \ + tmp_low = vreinterpret_u8_m64(a); \ + tmp_high = vdup_n_u8(0); \ + ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \ + } else { \ + const int idx = (imm); \ + tmp_low = vreinterpret_u8_m64(b); \ + tmp_high = vreinterpret_u8_m64(a); \ + ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \ + } \ + } \ + ret; \ + }) + +// Computes pairwise add of each argument as a 16-bit signed or unsigned integer +// values a and b. +FORCE_INLINE __m128i _mm_hadd_epi16(__m128i _a, __m128i _b) +{ + int16x8_t a = vreinterpretq_s16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); +#if defined(__aarch64__) + return vreinterpretq_m128i_s16(vpaddq_s16(a, b)); +#else + return vreinterpretq_m128i_s16( + vcombine_s16(vpadd_s16(vget_low_s16(a), vget_high_s16(a)), + vpadd_s16(vget_low_s16(b), vget_high_s16(b)))); +#endif +} + +// Computes pairwise add of each argument as a 32-bit signed or unsigned integer +// values a and b. +FORCE_INLINE __m128i _mm_hadd_epi32(__m128i _a, __m128i _b) +{ + int32x4_t a = vreinterpretq_s32_m128i(_a); + int32x4_t b = vreinterpretq_s32_m128i(_b); + return vreinterpretq_m128i_s32( + vcombine_s32(vpadd_s32(vget_low_s32(a), vget_high_s32(a)), + vpadd_s32(vget_low_s32(b), vget_high_s32(b)))); +} + +// Horizontally add adjacent pairs of 16-bit integers in a and b, and pack the +// signed 16-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi16 +FORCE_INLINE __m64 _mm_hadd_pi16(__m64 a, __m64 b) +{ + return vreinterpret_m64_s16( + vpadd_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); +} + +// Horizontally add adjacent pairs of 32-bit integers in a and b, and pack the +// signed 32-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi32 +FORCE_INLINE __m64 _mm_hadd_pi32(__m64 a, __m64 b) +{ + return vreinterpret_m64_s32( + vpadd_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b))); +} + +// Computes saturated pairwise sub of each argument as a 16-bit signed +// integer values a and b. +FORCE_INLINE __m128i _mm_hadds_epi16(__m128i _a, __m128i _b) +{ +#if defined(__aarch64__) + int16x8_t a = vreinterpretq_s16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); + return vreinterpretq_s64_s16( + vqaddq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); +#else + int32x4_t a = vreinterpretq_s32_m128i(_a); + int32x4_t b = vreinterpretq_s32_m128i(_b); + // Interleave using vshrn/vmovn + // [a0|a2|a4|a6|b0|b2|b4|b6] + // [a1|a3|a5|a7|b1|b3|b5|b7] + int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); + int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); + // Saturated add + return vreinterpretq_m128i_s16(vqaddq_s16(ab0246, ab1357)); +#endif +} + +// Horizontally add adjacent pairs of signed 16-bit integers in a and b using +// saturation, and pack the signed 16-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadds_pi16 +FORCE_INLINE __m64 _mm_hadds_pi16(__m64 _a, __m64 _b) +{ + int16x4_t a = vreinterpret_s16_m64(_a); + int16x4_t b = vreinterpret_s16_m64(_b); +#if defined(__aarch64__) + return vreinterpret_s64_s16(vqadd_s16(vuzp1_s16(a, b), vuzp2_s16(a, b))); +#else + int16x4x2_t res = vuzp_s16(a, b); + return vreinterpret_s64_s16(vqadd_s16(res.val[0], res.val[1])); +#endif +} + +// Horizontally subtract adjacent pairs of 16-bit integers in a and b, and pack +// the signed 16-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_epi16 +FORCE_INLINE __m128i _mm_hsub_epi16(__m128i _a, __m128i _b) +{ + int16x8_t a = vreinterpretq_s16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); +#if defined(__aarch64__) + return vreinterpretq_m128i_s16( + vsubq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); +#else + int16x8x2_t c = vuzpq_s16(a, b); + return vreinterpretq_m128i_s16(vsubq_s16(c.val[0], c.val[1])); +#endif +} + +// Horizontally subtract adjacent pairs of 32-bit integers in a and b, and pack +// the signed 32-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_epi32 +FORCE_INLINE __m128i _mm_hsub_epi32(__m128i _a, __m128i _b) +{ + int32x4_t a = vreinterpretq_s32_m128i(_a); + int32x4_t b = vreinterpretq_s32_m128i(_b); +#if defined(__aarch64__) + return vreinterpretq_m128i_s32( + vsubq_s32(vuzp1q_s32(a, b), vuzp2q_s32(a, b))); +#else + int32x4x2_t c = vuzpq_s32(a, b); + return vreinterpretq_m128i_s32(vsubq_s32(c.val[0], c.val[1])); +#endif +} + +// Horizontally subtract adjacent pairs of 16-bit integers in a and b, and pack +// the signed 16-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_pi16 +FORCE_INLINE __m64 _mm_hsub_pi16(__m64 _a, __m64 _b) +{ + int16x4_t a = vreinterpret_s16_m64(_a); + int16x4_t b = vreinterpret_s16_m64(_b); +#if defined(__aarch64__) + return vreinterpret_m64_s16(vsub_s16(vuzp1_s16(a, b), vuzp2_s16(a, b))); +#else + int16x4x2_t c = vuzp_s16(a, b); + return vreinterpret_m64_s16(vsub_s16(c.val[0], c.val[1])); +#endif +} + +// Horizontally subtract adjacent pairs of 32-bit integers in a and b, and pack +// the signed 32-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_hsub_pi32 +FORCE_INLINE __m64 _mm_hsub_pi32(__m64 _a, __m64 _b) +{ + int32x2_t a = vreinterpret_s32_m64(_a); + int32x2_t b = vreinterpret_s32_m64(_b); +#if defined(__aarch64__) + return vreinterpret_m64_s32(vsub_s32(vuzp1_s32(a, b), vuzp2_s32(a, b))); +#else + int32x2x2_t c = vuzp_s32(a, b); + return vreinterpret_m64_s32(vsub_s32(c.val[0], c.val[1])); +#endif +} + +// Computes saturated pairwise difference of each argument as a 16-bit signed +// integer values a and b. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_epi16 +FORCE_INLINE __m128i _mm_hsubs_epi16(__m128i _a, __m128i _b) +{ + int16x8_t a = vreinterpretq_s16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); +#if defined(__aarch64__) + return vreinterpretq_m128i_s16( + vqsubq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); +#else + int16x8x2_t c = vuzpq_s16(a, b); + return vreinterpretq_m128i_s16(vqsubq_s16(c.val[0], c.val[1])); +#endif +} + +// Horizontally subtract adjacent pairs of signed 16-bit integers in a and b +// using saturation, and pack the signed 16-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_pi16 +FORCE_INLINE __m64 _mm_hsubs_pi16(__m64 _a, __m64 _b) +{ + int16x4_t a = vreinterpret_s16_m64(_a); + int16x4_t b = vreinterpret_s16_m64(_b); +#if defined(__aarch64__) + return vreinterpret_m64_s16(vqsub_s16(vuzp1_s16(a, b), vuzp2_s16(a, b))); +#else + int16x4x2_t c = vuzp_s16(a, b); + return vreinterpret_m64_s16(vqsub_s16(c.val[0], c.val[1])); +#endif +} + +// Vertically multiply each unsigned 8-bit integer from a with the corresponding +// signed 8-bit integer from b, producing intermediate signed 16-bit integers. +// Horizontally add adjacent pairs of intermediate signed 16-bit integers, +// and pack the saturated results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// dst[i+15:i] := Saturate_To_Int16( a[i+15:i+8]*b[i+15:i+8] + +// a[i+7:i]*b[i+7:i] ) +// ENDFOR +FORCE_INLINE __m128i _mm_maddubs_epi16(__m128i _a, __m128i _b) +{ +#if defined(__aarch64__) + uint8x16_t a = vreinterpretq_u8_m128i(_a); + int8x16_t b = vreinterpretq_s8_m128i(_b); + int16x8_t tl = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(a))), + vmovl_s8(vget_low_s8(b))); + int16x8_t th = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(a))), + vmovl_s8(vget_high_s8(b))); + return vreinterpretq_m128i_s16( + vqaddq_s16(vuzp1q_s16(tl, th), vuzp2q_s16(tl, th))); +#else + // This would be much simpler if x86 would choose to zero extend OR sign + // extend, not both. This could probably be optimized better. + uint16x8_t a = vreinterpretq_u16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); + + // Zero extend a + int16x8_t a_odd = vreinterpretq_s16_u16(vshrq_n_u16(a, 8)); + int16x8_t a_even = vreinterpretq_s16_u16(vbicq_u16(a, vdupq_n_u16(0xff00))); + + // Sign extend by shifting left then shifting right. + int16x8_t b_even = vshrq_n_s16(vshlq_n_s16(b, 8), 8); + int16x8_t b_odd = vshrq_n_s16(b, 8); + + // multiply + int16x8_t prod1 = vmulq_s16(a_even, b_even); + int16x8_t prod2 = vmulq_s16(a_odd, b_odd); + + // saturated add + return vreinterpretq_m128i_s16(vqaddq_s16(prod1, prod2)); +#endif +} + +// Vertically multiply each unsigned 8-bit integer from a with the corresponding +// signed 8-bit integer from b, producing intermediate signed 16-bit integers. +// Horizontally add adjacent pairs of intermediate signed 16-bit integers, and +// pack the saturated results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maddubs_pi16 +FORCE_INLINE __m64 _mm_maddubs_pi16(__m64 _a, __m64 _b) +{ + uint16x4_t a = vreinterpret_u16_m64(_a); + int16x4_t b = vreinterpret_s16_m64(_b); + + // Zero extend a + int16x4_t a_odd = vreinterpret_s16_u16(vshr_n_u16(a, 8)); + int16x4_t a_even = vreinterpret_s16_u16(vand_u16(a, vdup_n_u16(0xff))); + + // Sign extend by shifting left then shifting right. + int16x4_t b_even = vshr_n_s16(vshl_n_s16(b, 8), 8); + int16x4_t b_odd = vshr_n_s16(b, 8); + + // multiply + int16x4_t prod1 = vmul_s16(a_even, b_even); + int16x4_t prod2 = vmul_s16(a_odd, b_odd); + + // saturated add + return vreinterpret_m64_s16(vqadd_s16(prod1, prod2)); +} + +// Multiply packed signed 16-bit integers in a and b, producing intermediate +// signed 32-bit integers. Shift right by 15 bits while rounding up, and store +// the packed 16-bit integers in dst. +// +// r0 := Round(((int32_t)a0 * (int32_t)b0) >> 15) +// r1 := Round(((int32_t)a1 * (int32_t)b1) >> 15) +// r2 := Round(((int32_t)a2 * (int32_t)b2) >> 15) +// ... +// r7 := Round(((int32_t)a7 * (int32_t)b7) >> 15) +FORCE_INLINE __m128i _mm_mulhrs_epi16(__m128i a, __m128i b) +{ + // Has issues due to saturation + // return vreinterpretq_m128i_s16(vqrdmulhq_s16(a, b)); + + // Multiply + int32x4_t mul_lo = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)), + vget_low_s16(vreinterpretq_s16_m128i(b))); + int32x4_t mul_hi = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)), + vget_high_s16(vreinterpretq_s16_m128i(b))); + + // Rounding narrowing shift right + // narrow = (int16_t)((mul + 16384) >> 15); + int16x4_t narrow_lo = vrshrn_n_s32(mul_lo, 15); + int16x4_t narrow_hi = vrshrn_n_s32(mul_hi, 15); + + // Join together + return vreinterpretq_m128i_s16(vcombine_s16(narrow_lo, narrow_hi)); +} + +// Multiply packed signed 16-bit integers in a and b, producing intermediate +// signed 32-bit integers. Truncate each intermediate integer to the 18 most +// significant bits, round by adding 1, and store bits [16:1] to dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhrs_pi16 +FORCE_INLINE __m64 _mm_mulhrs_pi16(__m64 a, __m64 b) +{ + int32x4_t mul_extend = + vmull_s16((vreinterpret_s16_m64(a)), (vreinterpret_s16_m64(b))); + + // Rounding narrowing shift right + return vreinterpret_m64_s16(vrshrn_n_s32(mul_extend, 15)); +} + +// Shuffle packed 8-bit integers in a according to shuffle control mask in the +// corresponding 8-bit element of b, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8 +FORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b) +{ + int8x16_t tbl = vreinterpretq_s8_m128i(a); // input a + uint8x16_t idx = vreinterpretq_u8_m128i(b); // input b + uint8x16_t idx_masked = + vandq_u8(idx, vdupq_n_u8(0x8F)); // avoid using meaningless bits +#if defined(__aarch64__) + return vreinterpretq_m128i_s8(vqtbl1q_s8(tbl, idx_masked)); +#elif defined(__GNUC__) + int8x16_t ret; + // %e and %f represent the even and odd D registers + // respectively. + __asm__ __volatile__( + "vtbl.8 %e[ret], {%e[tbl], %f[tbl]}, %e[idx]\n" + "vtbl.8 %f[ret], {%e[tbl], %f[tbl]}, %f[idx]\n" + : [ret] "=&w"(ret) + : [tbl] "w"(tbl), [idx] "w"(idx_masked)); + return vreinterpretq_m128i_s8(ret); +#else + // use this line if testing on aarch64 + int8x8x2_t a_split = {vget_low_s8(tbl), vget_high_s8(tbl)}; + return vreinterpretq_m128i_s8( + vcombine_s8(vtbl2_s8(a_split, vget_low_u8(idx_masked)), + vtbl2_s8(a_split, vget_high_u8(idx_masked)))); +#endif +} + +// Shuffle packed 8-bit integers in a according to shuffle control mask in the +// corresponding 8-bit element of b, and store the results in dst. +// +// FOR j := 0 to 7 +// i := j*8 +// IF b[i+7] == 1 +// dst[i+7:i] := 0 +// ELSE +// index[2:0] := b[i+2:i] +// dst[i+7:i] := a[index*8+7:index*8] +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pi8 +FORCE_INLINE __m64 _mm_shuffle_pi8(__m64 a, __m64 b) +{ + const int8x8_t controlMask = + vand_s8(vreinterpret_s8_m64(b), vdup_n_s8((int8_t) (0x1 << 7 | 0x07))); + int8x8_t res = vtbl1_s8(vreinterpret_s8_m64(a), controlMask); + return vreinterpret_m64_s8(res); } // Negate packed 16-bit integers in a when the corresponding signed @@ -3212,6 +7166,45 @@ FORCE_INLINE __m128i _mm_sign_epi32(__m128i _a, __m128i _b) return vreinterpretq_m128i_s32(res); } +// Negate packed 8-bit integers in a when the corresponding signed +// 8-bit integer in b is negative, and store the results in dst. +// Element in dst are zeroed out when the corresponding element +// in b is zero. +// +// for i in 0..15 +// if b[i] < 0 +// r[i] := -a[i] +// else if b[i] == 0 +// r[i] := 0 +// else +// r[i] := a[i] +// fi +// done +FORCE_INLINE __m128i _mm_sign_epi8(__m128i _a, __m128i _b) +{ + int8x16_t a = vreinterpretq_s8_m128i(_a); + int8x16_t b = vreinterpretq_s8_m128i(_b); + + // signed shift right: faster than vclt + // (b < 0) ? 0xFF : 0 + uint8x16_t ltMask = vreinterpretq_u8_s8(vshrq_n_s8(b, 7)); + + // (b == 0) ? 0xFF : 0 +#if defined(__aarch64__) + int8x16_t zeroMask = vreinterpretq_s8_u8(vceqzq_s8(b)); +#else + int8x16_t zeroMask = vreinterpretq_s8_u8(vceqq_s8(b, vdupq_n_s8(0))); +#endif + + // bitwise select either a or negative 'a' (vnegq_s8(a) return negative 'a') + // based on ltMask + int8x16_t masked = vbslq_s8(ltMask, vnegq_s8(a), a); + // res = masked & (~zeroMask) + int8x16_t res = vbicq_s8(masked, zeroMask); + + return vreinterpretq_m128i_s8(res); +} + // Negate packed 16-bit integers in a when the corresponding signed 16-bit // integer in b is negative, and store the results in dst. Element in dst are // zeroed out when the corresponding element in b is zero. @@ -3244,7 +7237,7 @@ FORCE_INLINE __m64 _mm_sign_pi16(__m64 _a, __m64 _b) int16x4_t zeroMask = vreinterpret_s16_u16(vceq_s16(b, vdup_n_s16(0))); #endif - // bitwise select either a or nagative 'a' (vneg_s16(a) return nagative 'a') + // bitwise select either a or negative 'a' (vneg_s16(a) return negative 'a') // based on ltMask int16x4_t masked = vbsl_s16(ltMask, vneg_s16(a), a); // res = masked & (~zeroMask) @@ -3285,7 +7278,7 @@ FORCE_INLINE __m64 _mm_sign_pi32(__m64 _a, __m64 _b) int32x2_t zeroMask = vreinterpret_s32_u32(vceq_s32(b, vdup_n_s32(0))); #endif - // bitwise select either a or nagative 'a' (vneg_s32(a) return nagative 'a') + // bitwise select either a or negative 'a' (vneg_s32(a) return negative 'a') // based on ltMask int32x2_t masked = vbsl_s32(ltMask, vneg_s32(a), a); // res = masked & (~zeroMask) @@ -3326,7 +7319,7 @@ FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b) int8x8_t zeroMask = vreinterpret_s8_u8(vceq_s8(b, vdup_n_s8(0))); #endif - // bitwise select either a or nagative 'a' (vneg_s8(a) return nagative 'a') + // bitwise select either a or negative 'a' (vneg_s8(a) return negative 'a') // based on ltMask int8x8_t masked = vbsl_s8(ltMask, vneg_s8(a), a); // res = masked & (~zeroMask) @@ -3335,1423 +7328,346 @@ FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b) return vreinterpret_m64_s8(res); } -// Average packed unsigned 16-bit integers in a and b, and store the results in -// dst. -// -// FOR j := 0 to 3 -// i := j*16 -// dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu16 -FORCE_INLINE __m64 _mm_avg_pu16(__m64 a, __m64 b) -{ - return vreinterpret_m64_u16( - vrhadd_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b))); -} +/* SSE4.1 */ -// Average packed unsigned 8-bit integers in a and b, and store the results in -// dst. +// Blend packed 16-bit integers from a and b using control mask imm8, and store +// the results in dst. // // FOR j := 0 to 7 -// i := j*8 -// dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 +// i := j*16 +// IF imm8[j] +// dst[i+15:i] := b[i+15:i] +// ELSE +// dst[i+15:i] := a[i+15:i] +// FI // ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu8 -FORCE_INLINE __m64 _mm_avg_pu8(__m64 a, __m64 b) +// FORCE_INLINE __m128i _mm_blend_epi16(__m128i a, __m128i b, +// __constrange(0,255) int imm) +#define _mm_blend_epi16(a, b, imm) \ + __extension__({ \ + const uint16_t _mask[8] = {((imm) & (1 << 0)) ? (uint16_t) -1 : 0x0, \ + ((imm) & (1 << 1)) ? (uint16_t) -1 : 0x0, \ + ((imm) & (1 << 2)) ? (uint16_t) -1 : 0x0, \ + ((imm) & (1 << 3)) ? (uint16_t) -1 : 0x0, \ + ((imm) & (1 << 4)) ? (uint16_t) -1 : 0x0, \ + ((imm) & (1 << 5)) ? (uint16_t) -1 : 0x0, \ + ((imm) & (1 << 6)) ? (uint16_t) -1 : 0x0, \ + ((imm) & (1 << 7)) ? (uint16_t) -1 : 0x0}; \ + uint16x8_t _mask_vec = vld1q_u16(_mask); \ + uint16x8_t _a = vreinterpretq_u16_m128i(a); \ + uint16x8_t _b = vreinterpretq_u16_m128i(b); \ + vreinterpretq_m128i_u16(vbslq_u16(_mask_vec, _b, _a)); \ + }) + +// Blend packed double-precision (64-bit) floating-point elements from a and b +// using control mask imm8, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_pd +#define _mm_blend_pd(a, b, imm) \ + __extension__({ \ + const uint64_t _mask[2] = { \ + ((imm) & (1 << 0)) ? ~UINT64_C(0) : UINT64_C(0), \ + ((imm) & (1 << 1)) ? ~UINT64_C(0) : UINT64_C(0)}; \ + uint64x2_t _mask_vec = vld1q_u64(_mask); \ + uint64x2_t _a = vreinterpretq_u64_m128d(a); \ + uint64x2_t _b = vreinterpretq_u64_m128d(b); \ + vreinterpretq_m128d_u64(vbslq_u64(_mask_vec, _b, _a)); \ + }) + +// Blend packed single-precision (32-bit) floating-point elements from a and b +// using mask, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_ps +FORCE_INLINE __m128 _mm_blend_ps(__m128 _a, __m128 _b, const char imm8) { - return vreinterpret_m64_u8( - vrhadd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); + const uint32_t ALIGN_STRUCT(16) + data[4] = {((imm8) & (1 << 0)) ? UINT32_MAX : 0, + ((imm8) & (1 << 1)) ? UINT32_MAX : 0, + ((imm8) & (1 << 2)) ? UINT32_MAX : 0, + ((imm8) & (1 << 3)) ? UINT32_MAX : 0}; + uint32x4_t mask = vld1q_u32(data); + float32x4_t a = vreinterpretq_f32_m128(_a); + float32x4_t b = vreinterpretq_f32_m128(_b); + return vreinterpretq_m128_f32(vbslq_f32(mask, b, a)); } -// Average packed unsigned 8-bit integers in a and b, and store the results in +// Blend packed 8-bit integers from a and b using mask, and store the results in // dst. // -// FOR j := 0 to 7 -// i := j*8 -// dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgb -#define _m_pavgb(a, b) _mm_avg_pu8(a, b) - -// Average packed unsigned 16-bit integers in a and b, and store the results in -// dst. -// -// FOR j := 0 to 3 -// i := j*16 -// dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgw -#define _m_pavgw(a, b) _mm_avg_pu16(a, b) - -// Extract a 16-bit integer from a, selected with imm8, and store the result in -// the lower element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pextrw -#define _m_pextrw(a, imm) _mm_extract_pi16(a, imm) - -// Copy a to dst, and insert the 16-bit integer i into dst at the location -// specified by imm8. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_pinsrw -#define _m_pinsrw(a, i, imm) _mm_insert_pi16(a, i, imm) - -// Compare packed signed 16-bit integers in a and b, and store packed maximum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxsw -#define _m_pmaxsw(a, b) _mm_max_pi16(a, b) - -// Compare packed unsigned 8-bit integers in a and b, and store packed maximum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxub -#define _m_pmaxub(a, b) _mm_max_pu8(a, b) - -// Compare packed signed 16-bit integers in a and b, and store packed minimum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminsw -#define _m_pminsw(a, b) _mm_min_pi16(a, b) - -// Compare packed unsigned 8-bit integers in a and b, and store packed minimum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminub -#define _m_pminub(a, b) _mm_min_pu8(a, b) - -// Create mask from the most significant bit of each 8-bit element in a, and -// store the result in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmovmskb -#define _m_pmovmskb(a) _mm_movemask_pi8(a) - -// Multiply the packed unsigned 16-bit integers in a and b, producing -// intermediate 32-bit integers, and store the high 16 bits of the intermediate -// integers in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmulhuw -#define _m_pmulhuw(a, b) _mm_mulhi_pu16(a, b) - -// Compute the absolute differences of packed unsigned 8-bit integers in a and -// b, then horizontally sum each consecutive 8 differences to produce four -// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low -// 16 bits of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_psadbw -#define _m_psadbw(a, b) _mm_sad_pu8(a, b) - -// Computes the average of the 16 unsigned 8-bit integers in a and the 16 -// unsigned 8-bit integers in b and rounds. -// -// r0 := (a0 + b0) / 2 -// r1 := (a1 + b1) / 2 -// ... -// r15 := (a15 + b15) / 2 -// -// https://msdn.microsoft.com/en-us/library/vstudio/8zwh554a(v%3dvs.90).aspx -FORCE_INLINE __m128i _mm_avg_epu8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u8( - vrhaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); -} - -// Shift a left by imm8 bytes while shifting in zeros, and store the results in -// dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_bslli_si128 -#define _mm_bslli_si128(a, imm) _mm_slli_si128(a, imm) - -// Shift a right by imm8 bytes while shifting in zeros, and store the results in -// dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_bsrli_si128 -#define _mm_bsrli_si128(a, imm) _mm_srli_si128(a, imm) - -// Computes the average of the 8 unsigned 16-bit integers in a and the 8 -// unsigned 16-bit integers in b and rounds. -// -// r0 := (a0 + b0) / 2 -// r1 := (a1 + b1) / 2 -// ... -// r7 := (a7 + b7) / 2 -// -// https://msdn.microsoft.com/en-us/library/vstudio/y13ca3c8(v=vs.90).aspx -FORCE_INLINE __m128i _mm_avg_epu16(__m128i a, __m128i b) -{ - return (__m128i) vrhaddq_u16(vreinterpretq_u16_m128i(a), - vreinterpretq_u16_m128i(b)); -} - -// Adds the four single-precision, floating-point values of a and b. -// -// r0 := a0 + b0 -// r1 := a1 + b1 -// r2 := a2 + b2 -// r3 := a3 + b3 -// -// https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx -FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_f32( - vaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -} - -// Add packed double-precision (64-bit) floating-point elements in a and b, and -// store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_pd -FORCE_INLINE __m128d _mm_add_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - double *da = (double *) &a; - double *db = (double *) &b; - double c[2]; - c[0] = da[0] + db[0]; - c[1] = da[1] + db[1]; - return vld1q_f32((float32_t *) c); -#endif -} - -// Add the lower double-precision (64-bit) floating-point element in a and b, -// store the result in the lower element of dst, and copy the upper element from -// a to the upper element of dst. -// -// dst[63:0] := a[63:0] + b[63:0] -// dst[127:64] := a[127:64] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_sd -FORCE_INLINE __m128d _mm_add_sd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return _mm_move_sd(a, _mm_add_pd(a, b)); -#else - double *da = (double *) &a; - double *db = (double *) &b; - double c[2]; - c[0] = da[0] + db[0]; - c[1] = da[1]; - return vld1q_f32((float32_t *) c); -#endif -} - -// Add 64-bit integers a and b, and store the result in dst. -// -// dst[63:0] := a[63:0] + b[63:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_si64 -FORCE_INLINE __m64 _mm_add_si64(__m64 a, __m64 b) -{ - return vreinterpret_m64_s64( - vadd_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b))); -} - -// adds the scalar single-precision floating point values of a and b. -// https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx -FORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b) -{ - float32_t b0 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 0); - float32x4_t value = vsetq_lane_f32(b0, vdupq_n_f32(0), 0); - // the upper values in the result must be the remnants of . - return vreinterpretq_m128_f32(vaddq_f32(a, value)); -} - -// Adds the 4 signed or unsigned 64-bit integers in a to the 4 signed or -// unsigned 32-bit integers in b. -// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx -FORCE_INLINE __m128i _mm_add_epi64(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s64( - vaddq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); -} - -// Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or -// unsigned 32-bit integers in b. -// -// r0 := a0 + b0 -// r1 := a1 + b1 -// r2 := a2 + b2 -// r3 := a3 + b3 -// -// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx -FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s32( - vaddq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -} - -// Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or -// unsigned 16-bit integers in b. -// https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx -FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s16( - vaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -} - -// Adds the 16 signed or unsigned 8-bit integers in a to the 16 signed or -// unsigned 8-bit integers in b. -// https://technet.microsoft.com/en-us/subscriptions/yc7tcyzs(v=vs.90) -FORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s8( - vaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -} - -// Adds the 8 signed 16-bit integers in a to the 8 signed 16-bit integers in b -// and saturates. -// -// r0 := SignedSaturate(a0 + b0) -// r1 := SignedSaturate(a1 + b1) -// ... -// r7 := SignedSaturate(a7 + b7) -// -// https://msdn.microsoft.com/en-us/library/1a306ef8(v=vs.100).aspx -FORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s16( - vqaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -} - -// Add packed signed 8-bit integers in a and b using saturation, and store the -// results in dst. -// // FOR j := 0 to 15 -// i := j*8 -// dst[i+7:i] := Saturate8( a[i+7:i] + b[i+7:i] ) +// i := j*8 +// IF mask[i+7] +// dst[i+7:i] := b[i+7:i] +// ELSE +// dst[i+7:i] := a[i+7:i] +// FI // ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epi8 -FORCE_INLINE __m128i _mm_adds_epi8(__m128i a, __m128i b) +FORCE_INLINE __m128i _mm_blendv_epi8(__m128i _a, __m128i _b, __m128i _mask) { - return vreinterpretq_m128i_s8( - vqaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -} - -// Adds the 16 unsigned 8-bit integers in a to the 16 unsigned 8-bit integers in -// b and saturates.. -// https://msdn.microsoft.com/en-us/library/9hahyddy(v=vs.100).aspx -FORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u8( - vqaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); -} - -// Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or -// unsigned 16-bit integers from b. -// -// r0 := (a0 * b0)[15:0] -// r1 := (a1 * b1)[15:0] -// ... -// r7 := (a7 * b7)[15:0] -// -// https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx -FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s16( - vmulq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -} - -// Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or -// unsigned 32-bit integers from b. -// https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx -FORCE_INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s32( - vmulq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -} - -// Multiply the packed unsigned 16-bit integers in a and b, producing -// intermediate 32-bit integers, and store the high 16 bits of the intermediate -// integers in dst. -// -// FOR j := 0 to 3 -// i := j*16 -// tmp[31:0] := a[i+15:i] * b[i+15:i] -// dst[i+15:i] := tmp[31:16] -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmulhuw -#define _m_pmulhuw(a, b) _mm_mulhi_pu16(a, b) - -// Multiplies the four single-precision, floating-point values of a and b. -// -// r0 := a0 * b0 -// r1 := a1 * b1 -// r2 := a2 * b2 -// r3 := a3 * b3 -// -// https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx -FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_f32( - vmulq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -} - -// Multiply packed double-precision (64-bit) floating-point elements in a and b, -// and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_pd -FORCE_INLINE __m128d _mm_mul_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vmulq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - double *da = (double *) &a; - double *db = (double *) &b; - double c[2]; - c[0] = da[0] * db[0]; - c[1] = da[1] * db[1]; - return vld1q_f32((float32_t *) c); -#endif -} - -// Multiply the lower double-precision (64-bit) floating-point element in a and -// b, store the result in the lower element of dst, and copy the upper element -// from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mul_sd -FORCE_INLINE __m128d _mm_mul_sd(__m128d a, __m128d b) -{ - return _mm_move_sd(a, _mm_mul_pd(a, b)); -} - -// Multiply the lower single-precision (32-bit) floating-point element in a and -// b, store the result in the lower element of dst, and copy the upper 3 packed -// elements from a to the upper elements of dst. -// -// dst[31:0] := a[31:0] * b[31:0] -// dst[127:32] := a[127:32] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_ss -FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b) -{ - return _mm_move_ss(a, _mm_mul_ps(a, b)); -} - -// Multiply the low unsigned 32-bit integers from each packed 64-bit element in -// a and b, and store the unsigned 64-bit results in dst. -// -// r0 := (a0 & 0xFFFFFFFF) * (b0 & 0xFFFFFFFF) -// r1 := (a2 & 0xFFFFFFFF) * (b2 & 0xFFFFFFFF) -FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b) -{ - // vmull_u32 upcasts instead of masking, so we downcast. - uint32x2_t a_lo = vmovn_u64(vreinterpretq_u64_m128i(a)); - uint32x2_t b_lo = vmovn_u64(vreinterpretq_u64_m128i(b)); - return vreinterpretq_m128i_u64(vmull_u32(a_lo, b_lo)); -} - -// Multiply the low unsigned 32-bit integers from a and b, and store the -// unsigned 64-bit result in dst. -// -// dst[63:0] := a[31:0] * b[31:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_su32 -FORCE_INLINE __m64 _mm_mul_su32(__m64 a, __m64 b) -{ - return vreinterpret_m64_u64(vget_low_u64( - vmull_u32(vreinterpret_u32_m64(a), vreinterpret_u32_m64(b)))); -} - -// Multiply the low signed 32-bit integers from each packed 64-bit element in -// a and b, and store the signed 64-bit results in dst. -// -// r0 := (int64_t)(int32_t)a0 * (int64_t)(int32_t)b0 -// r1 := (int64_t)(int32_t)a2 * (int64_t)(int32_t)b2 -FORCE_INLINE __m128i _mm_mul_epi32(__m128i a, __m128i b) -{ - // vmull_s32 upcasts instead of masking, so we downcast. - int32x2_t a_lo = vmovn_s64(vreinterpretq_s64_m128i(a)); - int32x2_t b_lo = vmovn_s64(vreinterpretq_s64_m128i(b)); - return vreinterpretq_m128i_s64(vmull_s32(a_lo, b_lo)); -} - -// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit -// integers from b. -// -// r0 := (a0 * b0) + (a1 * b1) -// r1 := (a2 * b2) + (a3 * b3) -// r2 := (a4 * b4) + (a5 * b5) -// r3 := (a6 * b6) + (a7 * b7) -// https://msdn.microsoft.com/en-us/library/yht36sa6(v=vs.90).aspx -FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b) -{ - int32x4_t low = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)), - vget_low_s16(vreinterpretq_s16_m128i(b))); - int32x4_t high = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)), - vget_high_s16(vreinterpretq_s16_m128i(b))); - - int32x2_t low_sum = vpadd_s32(vget_low_s32(low), vget_high_s32(low)); - int32x2_t high_sum = vpadd_s32(vget_low_s32(high), vget_high_s32(high)); - - return vreinterpretq_m128i_s32(vcombine_s32(low_sum, high_sum)); -} - -// Conditionally store 8-bit integer elements from a into memory using mask -// (elements are not stored when the highest bit is not set in the corresponding -// element) and a non-temporal memory hint. mem_addr does not need to be aligned -// on any particular boundary. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskmoveu_si128 -FORCE_INLINE void _mm_maskmoveu_si128(__m128i a, __m128i mask, char *mem_addr) -{ - int8x16_t shr_mask = vshrq_n_s8(vreinterpretq_s8_m128i(mask), 7); - __m128 b = _mm_load_ps((const float *) mem_addr); - int8x16_t masked = - vbslq_s8(vreinterpretq_u8_s8(shr_mask), vreinterpretq_s8_m128i(a), - vreinterpretq_s8_m128(b)); - vst1q_s8((int8_t *) mem_addr, masked); -} - -// Multiply packed signed 16-bit integers in a and b, producing intermediate -// signed 32-bit integers. Shift right by 15 bits while rounding up, and store -// the packed 16-bit integers in dst. -// -// r0 := Round(((int32_t)a0 * (int32_t)b0) >> 15) -// r1 := Round(((int32_t)a1 * (int32_t)b1) >> 15) -// r2 := Round(((int32_t)a2 * (int32_t)b2) >> 15) -// ... -// r7 := Round(((int32_t)a7 * (int32_t)b7) >> 15) -FORCE_INLINE __m128i _mm_mulhrs_epi16(__m128i a, __m128i b) -{ - // Has issues due to saturation - // return vreinterpretq_m128i_s16(vqrdmulhq_s16(a, b)); - - // Multiply - int32x4_t mul_lo = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)), - vget_low_s16(vreinterpretq_s16_m128i(b))); - int32x4_t mul_hi = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)), - vget_high_s16(vreinterpretq_s16_m128i(b))); - - // Rounding narrowing shift right - // narrow = (int16_t)((mul + 16384) >> 15); - int16x4_t narrow_lo = vrshrn_n_s32(mul_lo, 15); - int16x4_t narrow_hi = vrshrn_n_s32(mul_hi, 15); - - // Join together - return vreinterpretq_m128i_s16(vcombine_s16(narrow_lo, narrow_hi)); -} - -// Vertically multiply each unsigned 8-bit integer from a with the corresponding -// signed 8-bit integer from b, producing intermediate signed 16-bit integers. -// Horizontally add adjacent pairs of intermediate signed 16-bit integers, -// and pack the saturated results in dst. -// -// FOR j := 0 to 7 -// i := j*16 -// dst[i+15:i] := Saturate_To_Int16( a[i+15:i+8]*b[i+15:i+8] + -// a[i+7:i]*b[i+7:i] ) -// ENDFOR -FORCE_INLINE __m128i _mm_maddubs_epi16(__m128i _a, __m128i _b) -{ -#if defined(__aarch64__) + // Use a signed shift right to create a mask with the sign bit + uint8x16_t mask = + vreinterpretq_u8_s8(vshrq_n_s8(vreinterpretq_s8_m128i(_mask), 7)); uint8x16_t a = vreinterpretq_u8_m128i(_a); - int8x16_t b = vreinterpretq_s8_m128i(_b); - int16x8_t tl = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(a))), - vmovl_s8(vget_low_s8(b))); - int16x8_t th = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(a))), - vmovl_s8(vget_high_s8(b))); - return vreinterpretq_m128i_s16( - vqaddq_s16(vuzp1q_s16(tl, th), vuzp2q_s16(tl, th))); + uint8x16_t b = vreinterpretq_u8_m128i(_b); + return vreinterpretq_m128i_u8(vbslq_u8(mask, b, a)); +} + +// Blend packed double-precision (64-bit) floating-point elements from a and b +// using mask, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_pd +FORCE_INLINE __m128d _mm_blendv_pd(__m128d _a, __m128d _b, __m128d _mask) +{ + uint64x2_t mask = + vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_m128d(_mask), 63)); +#if defined(__aarch64__) + float64x2_t a = vreinterpretq_f64_m128d(_a); + float64x2_t b = vreinterpretq_f64_m128d(_b); + return vreinterpretq_m128d_f64(vbslq_f64(mask, b, a)); #else - // This would be much simpler if x86 would choose to zero extend OR sign - // extend, not both. This could probably be optimized better. - uint16x8_t a = vreinterpretq_u16_m128i(_a); - int16x8_t b = vreinterpretq_s16_m128i(_b); - - // Zero extend a - int16x8_t a_odd = vreinterpretq_s16_u16(vshrq_n_u16(a, 8)); - int16x8_t a_even = vreinterpretq_s16_u16(vbicq_u16(a, vdupq_n_u16(0xff00))); - - // Sign extend by shifting left then shifting right. - int16x8_t b_even = vshrq_n_s16(vshlq_n_s16(b, 8), 8); - int16x8_t b_odd = vshrq_n_s16(b, 8); - - // multiply - int16x8_t prod1 = vmulq_s16(a_even, b_even); - int16x8_t prod2 = vmulq_s16(a_odd, b_odd); - - // saturated add - return vreinterpretq_m128i_s16(vqaddq_s16(prod1, prod2)); + uint64x2_t a = vreinterpretq_u64_m128d(_a); + uint64x2_t b = vreinterpretq_u64_m128d(_b); + return vreinterpretq_m128d_u64(vbslq_u64(mask, b, a)); #endif } -// Computes the fused multiple add product of 32-bit floating point numbers. -// -// Return Value -// Multiplies A and B, and adds C to the temporary result before returning it. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd -FORCE_INLINE __m128 _mm_fmadd_ps(__m128 a, __m128 b, __m128 c) +// Blend packed single-precision (32-bit) floating-point elements from a and b +// using mask, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_ps +FORCE_INLINE __m128 _mm_blendv_ps(__m128 _a, __m128 _b, __m128 _mask) +{ + // Use a signed shift right to create a mask with the sign bit + uint32x4_t mask = + vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_m128(_mask), 31)); + float32x4_t a = vreinterpretq_f32_m128(_a); + float32x4_t b = vreinterpretq_f32_m128(_b); + return vreinterpretq_m128_f32(vbslq_f32(mask, b, a)); +} + +// Round the packed double-precision (64-bit) floating-point elements in a up +// to an integer value, and store the results as packed double-precision +// floating-point elements in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_pd +FORCE_INLINE __m128d _mm_ceil_pd(__m128d a) { #if defined(__aarch64__) - return vreinterpretq_m128_f32(vfmaq_f32(vreinterpretq_f32_m128(c), - vreinterpretq_f32_m128(b), - vreinterpretq_f32_m128(a))); + return vreinterpretq_m128d_f64(vrndpq_f64(vreinterpretq_f64_m128d(a))); #else - return _mm_add_ps(_mm_mul_ps(a, b), c); + double *f = (double *) &a; + return _mm_set_pd(ceil(f[1]), ceil(f[0])); #endif } -// Alternatively add and subtract packed double-precision (64-bit) -// floating-point elements in a to/from packed elements in b, and store the -// results in dst. -// -// FOR j := 0 to 1 -// i := j*64 -// IF ((j & 1) == 0) -// dst[i+63:i] := a[i+63:i] - b[i+63:i] -// ELSE -// dst[i+63:i] := a[i+63:i] + b[i+63:i] -// FI -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_addsub_pd -FORCE_INLINE __m128d _mm_addsub_pd(__m128d a, __m128d b) +// Round the packed single-precision (32-bit) floating-point elements in a up to +// an integer value, and store the results as packed single-precision +// floating-point elements in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ps +FORCE_INLINE __m128 _mm_ceil_ps(__m128 a) { - __m128d mask = _mm_set_pd(1.0f, -1.0f); -#if defined(__aarch64__) - return vreinterpretq_m128d_f64(vfmaq_f64(vreinterpretq_f64_m128d(a), - vreinterpretq_f64_m128d(b), - vreinterpretq_f64_m128d(mask))); +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) + return vreinterpretq_m128_f32(vrndpq_f32(vreinterpretq_f32_m128(a))); #else - return _mm_add_pd(_mm_mul_pd(b, mask), a); + float *f = (float *) &a; + return _mm_set_ps(ceilf(f[3]), ceilf(f[2]), ceilf(f[1]), ceilf(f[0])); #endif } -// Alternatively add and subtract packed single-precision (32-bit) -// floating-point elements in a to/from packed elements in b, and store the -// results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=addsub_ps -FORCE_INLINE __m128 _mm_addsub_ps(__m128 a, __m128 b) +// Round the lower double-precision (64-bit) floating-point element in b up to +// an integer value, store the result as a double-precision floating-point +// element in the lower element of dst, and copy the upper element from a to the +// upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_sd +FORCE_INLINE __m128d _mm_ceil_sd(__m128d a, __m128d b) { - __m128 mask = {-1.0f, 1.0f, -1.0f, 1.0f}; - return _mm_fmadd_ps(b, mask, a); + return _mm_move_sd(a, _mm_ceil_pd(b)); } -// Horizontally add adjacent pairs of double-precision (64-bit) floating-point -// elements in a and b, and pack the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pd -FORCE_INLINE __m128d _mm_hadd_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vpaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - double *da = (double *) &a; - double *db = (double *) &b; - double c[] = {da[0] + da[1], db[0] + db[1]}; - return vreinterpretq_m128d_u64(vld1q_u64((uint64_t *) c)); -#endif -} - -// Compute the absolute differences of packed unsigned 8-bit integers in a and -// b, then horizontally sum each consecutive 8 differences to produce two -// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low -// 16 bits of 64-bit elements in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_epu8 -FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b) -{ - uint16x8_t t = vpaddlq_u8(vabdq_u8((uint8x16_t) a, (uint8x16_t) b)); - uint16_t r0 = t[0] + t[1] + t[2] + t[3]; - uint16_t r4 = t[4] + t[5] + t[6] + t[7]; - uint16x8_t r = vsetq_lane_u16(r0, vdupq_n_u16(0), 0); - return (__m128i) vsetq_lane_u16(r4, r, 4); -} - -// Compute the absolute differences of packed unsigned 8-bit integers in a and -// b, then horizontally sum each consecutive 8 differences to produce four -// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low -// 16 bits of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_pu8 -FORCE_INLINE __m64 _mm_sad_pu8(__m64 a, __m64 b) -{ - uint16x4_t t = - vpaddl_u8(vabd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); - uint16_t r0 = t[0] + t[1] + t[2] + t[3]; - return vreinterpret_m64_u16(vset_lane_u16(r0, vdup_n_u16(0), 0)); -} - -// Compute the absolute differences of packed unsigned 8-bit integers in a and -// b, then horizontally sum each consecutive 8 differences to produce four -// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low -// 16 bits of dst. +// Round the lower single-precision (32-bit) floating-point element in b up to +// an integer value, store the result as a single-precision floating-point +// element in the lower element of dst, and copy the upper 3 packed elements +// from a to the upper elements of dst. // -// FOR j := 0 to 7 -// i := j*8 -// tmp[i+7:i] := ABS(a[i+7:i] - b[i+7:i]) -// ENDFOR -// dst[15:0] := tmp[7:0] + tmp[15:8] + tmp[23:16] + tmp[31:24] + tmp[39:32] + -// tmp[47:40] + tmp[55:48] + tmp[63:56] dst[63:16] := 0 -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_psadbw -#define _m_psadbw(a, b) _mm_sad_pu8(a, b) - -// Divides the four single-precision, floating-point values of a and b. -// -// r0 := a0 / b0 -// r1 := a1 / b1 -// r2 := a2 / b2 -// r3 := a3 / b3 -// -// https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx -FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b) -{ -#if defined(__aarch64__) && !SSE2NEON_PRECISE_DIV - return vreinterpretq_m128_f32( - vdivq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -#else - float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(b)); - recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b))); -#if SSE2NEON_PRECISE_DIV - // Additional Netwon-Raphson iteration for accuracy - recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b))); -#endif - return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(a), recip)); -#endif -} - -// Divides the scalar single-precision floating point value of a by b. -// https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx -FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b) -{ - float32_t value = - vgetq_lane_f32(vreinterpretq_f32_m128(_mm_div_ps(a, b)), 0); - return vreinterpretq_m128_f32( - vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); -} - -// Divide packed double-precision (64-bit) floating-point elements in a by -// packed elements in b, and store the results in dst. -// -// FOR j := 0 to 1 -// i := 64*j -// dst[i+63:i] := a[i+63:i] / b[i+63:i] -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_pd -FORCE_INLINE __m128d _mm_div_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - double *da = (double *) &a; - double *db = (double *) &b; - double c[2]; - c[0] = da[0] / db[0]; - c[1] = da[1] / db[1]; - return vld1q_f32((float32_t *) c); -#endif -} - -// Divide the lower double-precision (64-bit) floating-point element in a by the -// lower double-precision (64-bit) floating-point element in b, store the result -// in the lower element of dst, and copy the upper element from a to the upper -// element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_sd -FORCE_INLINE __m128d _mm_div_sd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - float64x2_t tmp = - vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)); - return vreinterpretq_m128d_f64( - vsetq_lane_f64(vgetq_lane_f64(vreinterpretq_f64_m128d(a), 1), tmp, 1)); -#else - return _mm_move_sd(a, _mm_div_pd(a, b)); -#endif -} - -// Compute the approximate reciprocal of packed single-precision (32-bit) -// floating-point elements in a, and store the results in dst. The maximum -// relative error for this approximation is less than 1.5*2^-12. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ps -FORCE_INLINE __m128 _mm_rcp_ps(__m128 in) -{ - float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in)); - recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in))); -#if SSE2NEON_PRECISE_DIV - // Additional Netwon-Raphson iteration for accuracy - recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in))); -#endif - return vreinterpretq_m128_f32(recip); -} - -// Compute the approximate reciprocal of the lower single-precision (32-bit) -// floating-point element in a, store the result in the lower element of dst, -// and copy the upper 3 packed elements from a to the upper elements of dst. The -// maximum relative error for this approximation is less than 1.5*2^-12. -// -// dst[31:0] := (1.0 / a[31:0]) +// dst[31:0] := CEIL(b[31:0]) // dst[127:32] := a[127:32] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ss -FORCE_INLINE __m128 _mm_rcp_ss(__m128 a) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ss +FORCE_INLINE __m128 _mm_ceil_ss(__m128 a, __m128 b) { - return _mm_move_ss(a, _mm_rcp_ps(a)); + return _mm_move_ss(a, _mm_ceil_ps(b)); } -// Computes the approximations of square roots of the four single-precision, -// floating-point values of a. First computes reciprocal square roots and then -// reciprocals of the four values. -// -// r0 := sqrt(a0) -// r1 := sqrt(a1) -// r2 := sqrt(a2) -// r3 := sqrt(a3) -// -// https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx -FORCE_INLINE __m128 _mm_sqrt_ps(__m128 in) -{ -#if SSE2NEON_PRECISE_SQRT - float32x4_t recip = vrsqrteq_f32(vreinterpretq_f32_m128(in)); - - // Test for vrsqrteq_f32(0) -> positive infinity case. - // Change to zero, so that s * 1/sqrt(s) result is zero too. - const uint32x4_t pos_inf = vdupq_n_u32(0x7F800000); - const uint32x4_t div_by_zero = - vceqq_u32(pos_inf, vreinterpretq_u32_f32(recip)); - recip = vreinterpretq_f32_u32( - vandq_u32(vmvnq_u32(div_by_zero), vreinterpretq_u32_f32(recip))); - - // Additional Netwon-Raphson iteration for accuracy - recip = vmulq_f32( - vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)), - recip); - recip = vmulq_f32( - vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)), - recip); - - // sqrt(s) = s * 1/sqrt(s) - return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(in), recip)); -#elif defined(__aarch64__) - return vreinterpretq_m128_f32(vsqrtq_f32(vreinterpretq_f32_m128(in))); -#else - float32x4_t recipsq = vrsqrteq_f32(vreinterpretq_f32_m128(in)); - float32x4_t sq = vrecpeq_f32(recipsq); - return vreinterpretq_m128_f32(sq); -#endif -} - -// Computes the approximation of the square root of the scalar single-precision -// floating point value of in. -// https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx -FORCE_INLINE __m128 _mm_sqrt_ss(__m128 in) -{ - float32_t value = - vgetq_lane_f32(vreinterpretq_f32_m128(_mm_sqrt_ps(in)), 0); - return vreinterpretq_m128_f32( - vsetq_lane_f32(value, vreinterpretq_f32_m128(in), 0)); -} - -// Computes the approximations of the reciprocal square roots of the four -// single-precision floating point values of in. -// The current precision is 1% error. -// https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx -FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in) -{ - float32x4_t out = vrsqrteq_f32(vreinterpretq_f32_m128(in)); -#if SSE2NEON_PRECISE_SQRT - // Additional Netwon-Raphson iteration for accuracy - out = vmulq_f32( - out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out)); - out = vmulq_f32( - out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out)); -#endif - return vreinterpretq_m128_f32(out); -} - -// Compute the approximate reciprocal square root of the lower single-precision -// (32-bit) floating-point element in a, store the result in the lower element -// of dst, and copy the upper 3 packed elements from a to the upper elements of -// dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt_ss -FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in) -{ - return vsetq_lane_f32(vgetq_lane_f32(_mm_rsqrt_ps(in), 0), in, 0); -} - -// Compare packed signed 16-bit integers in a and b, and store packed maximum -// values in dst. -// -// FOR j := 0 to 3 -// i := j*16 -// dst[i+15:i] := MAX(a[i+15:i], b[i+15:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16 -FORCE_INLINE __m64 _mm_max_pi16(__m64 a, __m64 b) -{ - return vreinterpret_m64_s16( - vmax_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); -} - -// Compare packed signed 16-bit integers in a and b, and store packed maximum -// values in dst. -// -// FOR j := 0 to 3 -// i := j*16 -// dst[i+15:i] := MAX(a[i+15:i], b[i+15:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16 -#define _m_pmaxsw(a, b) _mm_max_pi16(a, b) - -// Computes the maximums of the four single-precision, floating-point values of -// a and b. -// https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx -FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b) -{ -#if SSE2NEON_PRECISE_MINMAX - float32x4_t _a = vreinterpretq_f32_m128(a); - float32x4_t _b = vreinterpretq_f32_m128(b); - return vbslq_f32(vcltq_f32(_b, _a), _a, _b); -#else - return vreinterpretq_m128_f32( - vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -#endif -} - -// Compare packed unsigned 8-bit integers in a and b, and store packed maximum -// values in dst. -// -// FOR j := 0 to 7 -// i := j*8 -// dst[i+7:i] := MAX(a[i+7:i], b[i+7:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8 -FORCE_INLINE __m64 _mm_max_pu8(__m64 a, __m64 b) -{ - return vreinterpret_m64_u8( - vmax_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); -} - -// Compare packed unsigned 8-bit integers in a and b, and store packed maximum -// values in dst. -// -// FOR j := 0 to 7 -// i := j*8 -// dst[i+7:i] := MAX(a[i+7:i], b[i+7:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8 -#define _m_pmaxub(a, b) _mm_max_pu8(a, b) - -// Compare packed signed 16-bit integers in a and b, and store packed minimum -// values in dst. -// -// FOR j := 0 to 3 -// i := j*16 -// dst[i+15:i] := MIN(a[i+15:i], b[i+15:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16 -FORCE_INLINE __m64 _mm_min_pi16(__m64 a, __m64 b) -{ - return vreinterpret_m64_s16( - vmin_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); -} - -// Compare packed signed 16-bit integers in a and b, and store packed minimum -// values in dst. -// -// FOR j := 0 to 3 -// i := j*16 -// dst[i+15:i] := MIN(a[i+15:i], b[i+15:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16 -#define _m_pminsw(a, b) _mm_min_pi16(a, b) - -// Computes the minima of the four single-precision, floating-point values of a -// and b. -// https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx -FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b) -{ -#if SSE2NEON_PRECISE_MINMAX - float32x4_t _a = vreinterpretq_f32_m128(a); - float32x4_t _b = vreinterpretq_f32_m128(b); - return vbslq_f32(vcltq_f32(_a, _b), _a, _b); -#else - return vreinterpretq_m128_f32( - vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -#endif -} - -// Compare packed unsigned 8-bit integers in a and b, and store packed minimum -// values in dst. -// -// FOR j := 0 to 7 -// i := j*8 -// dst[i+7:i] := MIN(a[i+7:i], b[i+7:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8 -FORCE_INLINE __m64 _mm_min_pu8(__m64 a, __m64 b) -{ - return vreinterpret_m64_u8( - vmin_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); -} - -// Compare packed unsigned 8-bit integers in a and b, and store packed minimum -// values in dst. -// -// FOR j := 0 to 7 -// i := j*8 -// dst[i+7:i] := MIN(a[i+7:i], b[i+7:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8 -#define _m_pminub(a, b) _mm_min_pu8(a, b) - -// Computes the maximum of the two lower scalar single-precision floating point -// values of a and b. -// https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx -FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b) -{ - float32_t value = vgetq_lane_f32(_mm_max_ps(a, b), 0); - return vreinterpretq_m128_f32( - vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); -} - -// Computes the minimum of the two lower scalar single-precision floating point -// values of a and b. -// https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx -FORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b) -{ - float32_t value = vgetq_lane_f32(_mm_min_ps(a, b), 0); - return vreinterpretq_m128_f32( - vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); -} - -// Computes the pairwise maxima of the 16 unsigned 8-bit integers from a and the -// 16 unsigned 8-bit integers from b. -// https://msdn.microsoft.com/en-us/library/st6634za(v=vs.100).aspx -FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u8( - vmaxq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); -} - -// Compare packed double-precision (64-bit) floating-point elements in a and b, -// and store packed maximum values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pd -FORCE_INLINE __m128d _mm_max_pd(__m128d a, __m128d b) +// Compare packed 64-bit integers in a and b for equality, and store the results +// in dst +FORCE_INLINE __m128i _mm_cmpeq_epi64(__m128i a, __m128i b) { #if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vmaxq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); + return vreinterpretq_m128i_u64( + vceqq_u64(vreinterpretq_u64_m128i(a), vreinterpretq_u64_m128i(b))); #else - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) > (*(double *) &b0) ? a0 : b0; - d[1] = (*(double *) &a1) > (*(double *) &b1) ? a1 : b1; - - return vreinterpretq_m128d_u64(vld1q_u64(d)); + // ARMv7 lacks vceqq_u64 + // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) + uint32x4_t cmp = + vceqq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b)); + uint32x4_t swapped = vrev64q_u32(cmp); + return vreinterpretq_m128i_u32(vandq_u32(cmp, swapped)); #endif } -// Compare the lower double-precision (64-bit) floating-point elements in a and -// b, store the maximum value in the lower element of dst, and copy the upper -// element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_sd -FORCE_INLINE __m128d _mm_max_sd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return _mm_move_sd(a, _mm_max_pd(a, b)); -#else - double *da = (double *) &a; - double *db = (double *) &b; - double c[2] = {fmax(da[0], db[0]), da[1]}; - return vld1q_f32((float32_t *) c); -#endif -} - -// Computes the pairwise minima of the 16 unsigned 8-bit integers from a and the -// 16 unsigned 8-bit integers from b. -// https://msdn.microsoft.com/ko-kr/library/17k8cf58(v=vs.100).aspxx -FORCE_INLINE __m128i _mm_min_epu8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u8( - vminq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); -} - -// Compare packed double-precision (64-bit) floating-point elements in a and b, -// and store packed minimum values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pd -FORCE_INLINE __m128d _mm_min_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vminq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) < (*(double *) &b0) ? a0 : b0; - d[1] = (*(double *) &a1) < (*(double *) &b1) ? a1 : b1; - return vreinterpretq_m128d_u64(vld1q_u64(d)); -#endif -} - -// Compare the lower double-precision (64-bit) floating-point elements in a and -// b, store the minimum value in the lower element of dst, and copy the upper -// element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_sd -FORCE_INLINE __m128d _mm_min_sd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return _mm_move_sd(a, _mm_min_pd(a, b)); -#else - double *da = (double *) &a; - double *db = (double *) &b; - double c[2] = {fmin(da[0], db[0]), da[1]}; - return vld1q_f32((float32_t *) c); -#endif -} - -// Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8 -// signed 16-bit integers from b. -// https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx -FORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s16( - vminq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -} - -// Compare packed signed 8-bit integers in a and b, and store packed maximum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epi8 -FORCE_INLINE __m128i _mm_max_epi8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s8( - vmaxq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -} - -// Compare packed unsigned 16-bit integers in a and b, and store packed maximum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu16 -FORCE_INLINE __m128i _mm_max_epu16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u16( - vmaxq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); -} - -// Compare packed signed 8-bit integers in a and b, and store packed minimum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epi8 -FORCE_INLINE __m128i _mm_min_epi8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s8( - vminq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -} - -// Compare packed unsigned 16-bit integers in a and b, and store packed minimum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epu16 -FORCE_INLINE __m128i _mm_min_epu16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u16( - vminq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); -} - -// Computes the pairwise maxima of the 8 signed 16-bit integers from a and the 8 -// signed 16-bit integers from b. -// https://msdn.microsoft.com/en-us/LIBRary/3x060h7c(v=vs.100).aspx -FORCE_INLINE __m128i _mm_max_epi16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s16( - vmaxq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -} - -// epi versions of min/max -// Computes the pariwise maximums of the four signed 32-bit integer values of a -// and b. -// -// A 128-bit parameter that can be defined with the following equations: -// r0 := (a0 > b0) ? a0 : b0 -// r1 := (a1 > b1) ? a1 : b1 -// r2 := (a2 > b2) ? a2 : b2 -// r3 := (a3 > b3) ? a3 : b3 -// -// https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx -FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b) +// Converts the four signed 16-bit integers in the lower 64 bits to four signed +// 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepi16_epi32(__m128i a) { return vreinterpretq_m128i_s32( - vmaxq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); + vmovl_s16(vget_low_s16(vreinterpretq_s16_m128i(a)))); } -// Computes the pariwise minima of the four signed 32-bit integer values of a -// and b. -// -// A 128-bit parameter that can be defined with the following equations: -// r0 := (a0 < b0) ? a0 : b0 -// r1 := (a1 < b1) ? a1 : b1 -// r2 := (a2 < b2) ? a2 : b2 -// r3 := (a3 < b3) ? a3 : b3 -// -// https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx -FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b) +// Converts the two signed 16-bit integers in the lower 32 bits two signed +// 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepi16_epi64(__m128i a) { - return vreinterpretq_m128i_s32( - vminq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); + int16x8_t s16x8 = vreinterpretq_s16_m128i(a); /* xxxx xxxx xxxx 0B0A */ + int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */ + int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */ + return vreinterpretq_m128i_s64(s64x2); } -// Compare packed unsigned 32-bit integers in a and b, and store packed maximum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 -FORCE_INLINE __m128i _mm_max_epu32(__m128i a, __m128i b) +// Converts the two signed 32-bit integers in the lower 64 bits to two signed +// 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepi32_epi64(__m128i a) +{ + return vreinterpretq_m128i_s64( + vmovl_s32(vget_low_s32(vreinterpretq_s32_m128i(a)))); +} + +// Converts the four unsigned 8-bit integers in the lower 16 bits to four +// unsigned 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepi8_epi16(__m128i a) +{ + int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */ + int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */ + return vreinterpretq_m128i_s16(s16x8); +} + +// Converts the four unsigned 8-bit integers in the lower 32 bits to four +// unsigned 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepi8_epi32(__m128i a) +{ + int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */ + int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */ + int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000D 000C 000B 000A */ + return vreinterpretq_m128i_s32(s32x4); +} + +// Converts the two signed 8-bit integers in the lower 32 bits to four +// signed 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepi8_epi64(__m128i a) +{ + int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx xxBA */ + int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0x0x 0B0A */ + int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */ + int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */ + return vreinterpretq_m128i_s64(s64x2); +} + +// Converts the four unsigned 16-bit integers in the lower 64 bits to four +// unsigned 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepu16_epi32(__m128i a) { return vreinterpretq_m128i_u32( - vmaxq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b))); + vmovl_u16(vget_low_u16(vreinterpretq_u16_m128i(a)))); } -// Compare packed unsigned 32-bit integers in a and b, and store packed minimum -// values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 -FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b) +// Converts the two unsigned 16-bit integers in the lower 32 bits to two +// unsigned 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepu16_epi64(__m128i a) { - return vreinterpretq_m128i_u32( - vminq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b))); + uint16x8_t u16x8 = vreinterpretq_u16_m128i(a); /* xxxx xxxx xxxx 0B0A */ + uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */ + uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */ + return vreinterpretq_m128i_u64(u64x2); } -// Multiply the packed unsigned 16-bit integers in a and b, producing -// intermediate 32-bit integers, and store the high 16 bits of the intermediate -// integers in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_pu16 -FORCE_INLINE __m64 _mm_mulhi_pu16(__m64 a, __m64 b) +// Converts the two unsigned 32-bit integers in the lower 64 bits to two +// unsigned 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepu32_epi64(__m128i a) { - return vreinterpret_m64_u16(vshrn_n_u32( - vmull_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b)), 16)); + return vreinterpretq_m128i_u64( + vmovl_u32(vget_low_u32(vreinterpretq_u32_m128i(a)))); } -// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit -// integers from b. -// -// r0 := (a0 * b0)[31:16] -// r1 := (a1 * b1)[31:16] -// ... -// r7 := (a7 * b7)[31:16] -// -// https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx -FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b) +// Zero extend packed unsigned 8-bit integers in a to packed 16-bit integers, +// and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtepu8_epi16 +FORCE_INLINE __m128i _mm_cvtepu8_epi16(__m128i a) { - /* FIXME: issue with large values because of result saturation */ - // int16x8_t ret = vqdmulhq_s16(vreinterpretq_s16_m128i(a), - // vreinterpretq_s16_m128i(b)); /* =2*a*b */ return - // vreinterpretq_m128i_s16(vshrq_n_s16(ret, 1)); - int16x4_t a3210 = vget_low_s16(vreinterpretq_s16_m128i(a)); - int16x4_t b3210 = vget_low_s16(vreinterpretq_s16_m128i(b)); - int32x4_t ab3210 = vmull_s16(a3210, b3210); /* 3333222211110000 */ - int16x4_t a7654 = vget_high_s16(vreinterpretq_s16_m128i(a)); - int16x4_t b7654 = vget_high_s16(vreinterpretq_s16_m128i(b)); - int32x4_t ab7654 = vmull_s16(a7654, b7654); /* 7777666655554444 */ - uint16x8x2_t r = - vuzpq_u16(vreinterpretq_u16_s32(ab3210), vreinterpretq_u16_s32(ab7654)); - return vreinterpretq_m128i_u16(r.val[1]); + uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx HGFE DCBA */ + uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0H0G 0F0E 0D0C 0B0A */ + return vreinterpretq_m128i_u16(u16x8); } -// Multiply the packed unsigned 16-bit integers in a and b, producing -// intermediate 32-bit integers, and store the high 16 bits of the intermediate -// integers in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_epu16 -FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b) +// Converts the four unsigned 8-bit integers in the lower 32 bits to four +// unsigned 32-bit integers. +// https://msdn.microsoft.com/en-us/library/bb531467%28v=vs.100%29.aspx +FORCE_INLINE __m128i _mm_cvtepu8_epi32(__m128i a) { - uint16x4_t a3210 = vget_low_u16(vreinterpretq_u16_m128i(a)); - uint16x4_t b3210 = vget_low_u16(vreinterpretq_u16_m128i(b)); - uint32x4_t ab3210 = vmull_u16(a3210, b3210); -#if defined(__aarch64__) - uint32x4_t ab7654 = - vmull_high_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)); - uint16x8_t r = vuzp2q_u16(vreinterpretq_u16_u32(ab3210), - vreinterpretq_u16_u32(ab7654)); - return vreinterpretq_m128i_u16(r); -#else - uint16x4_t a7654 = vget_high_u16(vreinterpretq_u16_m128i(a)); - uint16x4_t b7654 = vget_high_u16(vreinterpretq_u16_m128i(b)); - uint32x4_t ab7654 = vmull_u16(a7654, b7654); - uint16x8x2_t r = - vuzpq_u16(vreinterpretq_u16_u32(ab3210), vreinterpretq_u16_u32(ab7654)); - return vreinterpretq_m128i_u16(r.val[1]); + uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx DCBA */ + uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */ + uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000D 000C 000B 000A */ + return vreinterpretq_m128i_u32(u32x4); +} + +// Converts the two unsigned 8-bit integers in the lower 16 bits to two +// unsigned 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepu8_epi64(__m128i a) +{ + uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx xxBA */ + uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0x0x 0B0A */ + uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */ + uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */ + return vreinterpretq_m128i_u64(u64x2); +} + +// Conditionally multiply the packed double-precision (64-bit) floating-point +// elements in a and b using the high 4 bits in imm8, sum the four products, and +// conditionally store the sum in dst using the low 4 bits of imm8. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_dp_pd +FORCE_INLINE __m128d _mm_dp_pd(__m128d a, __m128d b, const int imm) +{ + // Generate mask value from constant immediate bit value + const int64_t bit0Mask = imm & 0x01 ? UINT64_MAX : 0; + const int64_t bit1Mask = imm & 0x02 ? UINT64_MAX : 0; +#if !SSE2NEON_PRECISE_DP + const int64_t bit4Mask = imm & 0x10 ? UINT64_MAX : 0; + const int64_t bit5Mask = imm & 0x20 ? UINT64_MAX : 0; #endif -} - -// Computes pairwise add of each argument as single-precision, floating-point -// values a and b. -// https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx -FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128_f32( - vpaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); + // Conditional multiplication +#if !SSE2NEON_PRECISE_DP + __m128d mul = _mm_mul_pd(a, b); + const __m128d mulMask = + _mm_castsi128_pd(_mm_set_epi64x(bit5Mask, bit4Mask)); + __m128d tmp = _mm_and_pd(mul, mulMask); #else - float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); - float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a)); - float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); - float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b)); - return vreinterpretq_m128_f32( - vcombine_f32(vpadd_f32(a10, a32), vpadd_f32(b10, b32))); -#endif -} - -// Computes pairwise add of each argument as a 16-bit signed or unsigned integer -// values a and b. -FORCE_INLINE __m128i _mm_hadd_epi16(__m128i _a, __m128i _b) -{ - int16x8_t a = vreinterpretq_s16_m128i(_a); - int16x8_t b = vreinterpretq_s16_m128i(_b); #if defined(__aarch64__) - return vreinterpretq_m128i_s16(vpaddq_s16(a, b)); + double d0 = (imm & 0x10) ? vgetq_lane_f64(vreinterpretq_f64_m128d(a), 0) * + vgetq_lane_f64(vreinterpretq_f64_m128d(b), 0) + : 0; + double d1 = (imm & 0x20) ? vgetq_lane_f64(vreinterpretq_f64_m128d(a), 1) * + vgetq_lane_f64(vreinterpretq_f64_m128d(b), 1) + : 0; #else - return vreinterpretq_m128i_s16( - vcombine_s16(vpadd_s16(vget_low_s16(a), vget_high_s16(a)), - vpadd_s16(vget_low_s16(b), vget_high_s16(b)))); + double d0 = (imm & 0x10) ? ((double *) &a)[0] * ((double *) &b)[0] : 0; + double d1 = (imm & 0x20) ? ((double *) &a)[1] * ((double *) &b)[1] : 0; #endif -} - -// Horizontally subtract adjacent pairs of double-precision (64-bit) -// floating-point elements in a and b, and pack the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_pd -FORCE_INLINE __m128d _mm_hsub_pd(__m128d _a, __m128d _b) -{ + __m128d tmp = _mm_set_pd(d1, d0); +#endif + // Sum the products #if defined(__aarch64__) - return vreinterpretq_m128d_f64(vsubq_f64( - vuzp1q_f64(vreinterpretq_f64_m128d(_a), vreinterpretq_f64_m128d(_b)), - vuzp2q_f64(vreinterpretq_f64_m128d(_a), vreinterpretq_f64_m128d(_b)))); + double sum = vpaddd_f64(vreinterpretq_f64_m128d(tmp)); #else - double *da = (double *) &_a; - double *db = (double *) &_b; - double c[] = {da[0] - da[1], db[0] - db[1]}; - return vreinterpretq_m128d_u64(vld1q_u64((uint64_t *) c)); + double sum = *((double *) &tmp) + *(((double *) &tmp) + 1); #endif -} - -// Horizontally substract adjacent pairs of single-precision (32-bit) -// floating-point elements in a and b, and pack the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_ps -FORCE_INLINE __m128 _mm_hsub_ps(__m128 _a, __m128 _b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128_f32(vsubq_f32( - vuzp1q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)), - vuzp2q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)))); -#else - float32x4x2_t c = - vuzpq_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)); - return vreinterpretq_m128_f32(vsubq_f32(c.val[0], c.val[1])); -#endif -} - -// Horizontally add adjacent pairs of 16-bit integers in a and b, and pack the -// signed 16-bit results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi16 -FORCE_INLINE __m64 _mm_hadd_pi16(__m64 a, __m64 b) -{ - return vreinterpret_m64_s16( - vpadd_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); -} - -// Horizontally add adjacent pairs of 32-bit integers in a and b, and pack the -// signed 32-bit results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi32 -FORCE_INLINE __m64 _mm_hadd_pi32(__m64 a, __m64 b) -{ - return vreinterpret_m64_s32( - vpadd_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b))); -} - -// Computes pairwise difference of each argument as a 16-bit signed or unsigned -// integer values a and b. -FORCE_INLINE __m128i _mm_hsub_epi16(__m128i _a, __m128i _b) -{ - int32x4_t a = vreinterpretq_s32_m128i(_a); - int32x4_t b = vreinterpretq_s32_m128i(_b); - // Interleave using vshrn/vmovn - // [a0|a2|a4|a6|b0|b2|b4|b6] - // [a1|a3|a5|a7|b1|b3|b5|b7] - int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); - int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); - // Subtract - return vreinterpretq_m128i_s16(vsubq_s16(ab0246, ab1357)); -} - -// Computes saturated pairwise sub of each argument as a 16-bit signed -// integer values a and b. -FORCE_INLINE __m128i _mm_hadds_epi16(__m128i _a, __m128i _b) -{ -#if defined(__aarch64__) - int16x8_t a = vreinterpretq_s16_m128i(_a); - int16x8_t b = vreinterpretq_s16_m128i(_b); - return vreinterpretq_s64_s16( - vqaddq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); -#else - int32x4_t a = vreinterpretq_s32_m128i(_a); - int32x4_t b = vreinterpretq_s32_m128i(_b); - // Interleave using vshrn/vmovn - // [a0|a2|a4|a6|b0|b2|b4|b6] - // [a1|a3|a5|a7|b1|b3|b5|b7] - int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); - int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); - // Saturated add - return vreinterpretq_m128i_s16(vqaddq_s16(ab0246, ab1357)); -#endif -} - -// Computes saturated pairwise difference of each argument as a 16-bit signed -// integer values a and b. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_epi16 -FORCE_INLINE __m128i _mm_hsubs_epi16(__m128i _a, __m128i _b) -{ -#if defined(__aarch64__) - int16x8_t a = vreinterpretq_s16_m128i(_a); - int16x8_t b = vreinterpretq_s16_m128i(_b); - return vreinterpretq_s64_s16( - vqsubq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); -#else - int32x4_t a = vreinterpretq_s32_m128i(_a); - int32x4_t b = vreinterpretq_s32_m128i(_b); - // Interleave using vshrn/vmovn - // [a0|a2|a4|a6|b0|b2|b4|b6] - // [a1|a3|a5|a7|b1|b3|b5|b7] - int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); - int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); - // Saturated subtract - return vreinterpretq_m128i_s16(vqsubq_s16(ab0246, ab1357)); -#endif -} - -// Computes pairwise add of each argument as a 32-bit signed or unsigned integer -// values a and b. -FORCE_INLINE __m128i _mm_hadd_epi32(__m128i _a, __m128i _b) -{ - int32x4_t a = vreinterpretq_s32_m128i(_a); - int32x4_t b = vreinterpretq_s32_m128i(_b); - return vreinterpretq_m128i_s32( - vcombine_s32(vpadd_s32(vget_low_s32(a), vget_high_s32(a)), - vpadd_s32(vget_low_s32(b), vget_high_s32(b)))); -} - -// Computes pairwise difference of each argument as a 32-bit signed or unsigned -// integer values a and b. -FORCE_INLINE __m128i _mm_hsub_epi32(__m128i _a, __m128i _b) -{ - int64x2_t a = vreinterpretq_s64_m128i(_a); - int64x2_t b = vreinterpretq_s64_m128i(_b); - // Interleave using vshrn/vmovn - // [a0|a2|b0|b2] - // [a1|a2|b1|b3] - int32x4_t ab02 = vcombine_s32(vmovn_s64(a), vmovn_s64(b)); - int32x4_t ab13 = vcombine_s32(vshrn_n_s64(a, 32), vshrn_n_s64(b, 32)); - // Subtract - return vreinterpretq_m128i_s32(vsubq_s32(ab02, ab13)); -} - -// Kahan summation for accurate summation of floating-point numbers. -// http://blog.zachbjornson.com/2019/08/11/fast-float-summation.html -FORCE_INLINE void _sse2neon_kadd_f32(float *sum, float *c, float y) -{ - y -= *c; - float t = *sum + y; - *c = (t - *sum) - y; - *sum = t; + // Conditionally store the sum + const __m128d sumMask = + _mm_castsi128_pd(_mm_set_epi64x(bit1Mask, bit0Mask)); + __m128d res = _mm_and_pd(_mm_set_pd1(sum), sumMask); + return res; } // Conditionally multiply the packed single-precision (32-bit) floating-point @@ -4798,1611 +7714,64 @@ FORCE_INLINE __m128 _mm_dp_ps(__m128 a, __m128 b, const int imm) return vreinterpretq_m128_f32(res); } -/* Compare operations */ - -// Compares for less than -// https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx -FORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_u32( - vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -} - -// Compares for less than -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fy94wye7(v=vs.100) -FORCE_INLINE __m128 _mm_cmplt_ss(__m128 a, __m128 b) -{ - return _mm_move_ss(a, _mm_cmplt_ps(a, b)); -} - -// Compares for greater than. -// -// r0 := (a0 > b0) ? 0xffffffff : 0x0 -// r1 := (a1 > b1) ? 0xffffffff : 0x0 -// r2 := (a2 > b2) ? 0xffffffff : 0x0 -// r3 := (a3 > b3) ? 0xffffffff : 0x0 -// -// https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx -FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_u32( - vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -} - -// Compares for greater than. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/1xyyyy9e(v=vs.100) -FORCE_INLINE __m128 _mm_cmpgt_ss(__m128 a, __m128 b) -{ - return _mm_move_ss(a, _mm_cmpgt_ps(a, b)); -} - -// Compares for greater than or equal. -// https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx -FORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_u32( - vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -} - -// Compares for greater than or equal. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/kesh3ddc(v=vs.100) -FORCE_INLINE __m128 _mm_cmpge_ss(__m128 a, __m128 b) -{ - return _mm_move_ss(a, _mm_cmpge_ps(a, b)); -} - -// Compares for less than or equal. -// -// r0 := (a0 <= b0) ? 0xffffffff : 0x0 -// r1 := (a1 <= b1) ? 0xffffffff : 0x0 -// r2 := (a2 <= b2) ? 0xffffffff : 0x0 -// r3 := (a3 <= b3) ? 0xffffffff : 0x0 -// -// https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx -FORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_u32( - vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -} - -// Compares for less than or equal. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/a7x0hbhw(v=vs.100) -FORCE_INLINE __m128 _mm_cmple_ss(__m128 a, __m128 b) -{ - return _mm_move_ss(a, _mm_cmple_ps(a, b)); -} - -// Compares for equality. -// https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx -FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_u32( - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -} - -// Compares for equality. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/k423z28e(v=vs.100) -FORCE_INLINE __m128 _mm_cmpeq_ss(__m128 a, __m128 b) -{ - return _mm_move_ss(a, _mm_cmpeq_ps(a, b)); -} - -// Compares for inequality. -// https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx -FORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b) -{ - return vreinterpretq_m128_u32(vmvnq_u32( - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)))); -} - -// Compares for inequality. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ekya8fh4(v=vs.100) -FORCE_INLINE __m128 _mm_cmpneq_ss(__m128 a, __m128 b) -{ - return _mm_move_ss(a, _mm_cmpneq_ps(a, b)); -} - -// Compares for not greater than or equal. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/wsexys62(v=vs.100) -FORCE_INLINE __m128 _mm_cmpnge_ps(__m128 a, __m128 b) -{ - return _mm_cmplt_ps(a, b); -} - -// Compares for not greater than or equal. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fk2y80s8(v=vs.100) -FORCE_INLINE __m128 _mm_cmpnge_ss(__m128 a, __m128 b) -{ - return _mm_cmplt_ss(a, b); -} - -// Compares for not greater than. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/d0xh7w0s(v=vs.100) -FORCE_INLINE __m128 _mm_cmpngt_ps(__m128 a, __m128 b) -{ - return _mm_cmple_ps(a, b); -} - -// Compares for not greater than. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100) -FORCE_INLINE __m128 _mm_cmpngt_ss(__m128 a, __m128 b) -{ - return _mm_cmple_ss(a, b); -} - -// Compares for not less than or equal. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/6a330kxw(v=vs.100) -FORCE_INLINE __m128 _mm_cmpnle_ps(__m128 a, __m128 b) -{ - return _mm_cmpgt_ps(a, b); -} - -// Compares for not less than or equal. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100) -FORCE_INLINE __m128 _mm_cmpnle_ss(__m128 a, __m128 b) -{ - return _mm_cmpgt_ss(a, b); -} - -// Compares for not less than. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/4686bbdw(v=vs.100) -FORCE_INLINE __m128 _mm_cmpnlt_ps(__m128 a, __m128 b) -{ - return _mm_cmpge_ps(a, b); -} - -// Compares for not less than. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/56b9z2wf(v=vs.100) -FORCE_INLINE __m128 _mm_cmpnlt_ss(__m128 a, __m128 b) -{ - return _mm_cmpge_ss(a, b); -} - -// Compares the 16 signed or unsigned 8-bit integers in a and the 16 signed or -// unsigned 8-bit integers in b for equality. -// https://msdn.microsoft.com/en-us/library/windows/desktop/bz5xk21a(v=vs.90).aspx -FORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u8( - vceqq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -} - -// Compare packed double-precision (64-bit) floating-point elements in a and b -// for equality, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_pd -FORCE_INLINE __m128d _mm_cmpeq_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_u64( - vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) - uint32x4_t cmp = - vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); - uint32x4_t swapped = vrev64q_u32(cmp); - return vreinterpretq_m128d_u32(vandq_u32(cmp, swapped)); -#endif -} - -// Compare the lower double-precision (64-bit) floating-point elements in a and -// b for equality, store the result in the lower element of dst, and copy the -// upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_sd -FORCE_INLINE __m128d _mm_cmpeq_sd(__m128d a, __m128d b) -{ - return _mm_move_sd(a, _mm_cmpeq_pd(a, b)); -} - -// Compare packed double-precision (64-bit) floating-point elements in a and b -// for greater-than-or-equal, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpge_pd -FORCE_INLINE __m128d _mm_cmpge_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_u64( - vcgeq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) >= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); - d[1] = (*(double *) &a1) >= (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); - - return vreinterpretq_m128d_u64(vld1q_u64(d)); -#endif -} - -// Compare the lower double-precision (64-bit) floating-point elements in a and -// b for greater-than-or-equal, store the result in the lower element of dst, -// and copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpge_sd -FORCE_INLINE __m128d _mm_cmpge_sd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return _mm_move_sd(a, _mm_cmpge_pd(a, b)); -#else - // expand "_mm_cmpge_pd()" to reduce unnecessary operations - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) >= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); - d[1] = a1; - - return vreinterpretq_m128d_u64(vld1q_u64(d)); -#endif -} - -// Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or -// unsigned 16-bit integers in b for equality. -// https://msdn.microsoft.com/en-us/library/2ay060te(v=vs.100).aspx -FORCE_INLINE __m128i _mm_cmpeq_epi16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u16( - vceqq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -} - -// Compare packed 32-bit integers in a and b for equality, and store the results -// in dst -FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u32( - vceqq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -} - -// Compare packed 64-bit integers in a and b for equality, and store the results -// in dst -FORCE_INLINE __m128i _mm_cmpeq_epi64(__m128i a, __m128i b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128i_u64( - vceqq_u64(vreinterpretq_u64_m128i(a), vreinterpretq_u64_m128i(b))); -#else - // ARMv7 lacks vceqq_u64 - // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) - uint32x4_t cmp = - vceqq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b)); - uint32x4_t swapped = vrev64q_u32(cmp); - return vreinterpretq_m128i_u32(vandq_u32(cmp, swapped)); -#endif -} - -// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers -// in b for lesser than. -// https://msdn.microsoft.com/en-us/library/windows/desktop/9s46csht(v=vs.90).aspx -FORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u8( - vcltq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -} - -// Compare packed double-precision (64-bit) floating-point elements in a and b -// for less-than, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmplt_pd -FORCE_INLINE __m128d _mm_cmplt_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_u64( - vcltq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) < (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); - d[1] = (*(double *) &a1) < (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); - - return vreinterpretq_m128d_u64(vld1q_u64(d)); -#endif -} - -// Compare the lower double-precision (64-bit) floating-point elements in a and -// b for less-than, store the result in the lower element of dst, and copy the -// upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmplt_sd -FORCE_INLINE __m128d _mm_cmplt_sd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return _mm_move_sd(a, _mm_cmplt_pd(a, b)); -#else - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) < (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); - d[1] = a1; - - return vreinterpretq_m128d_u64(vld1q_u64(d)); -#endif -} - -// Compare packed double-precision (64-bit) floating-point elements in a and b -// for not-equal, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpneq_pd -FORCE_INLINE __m128d _mm_cmpneq_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_s32(vmvnq_s32(vreinterpretq_s32_u64( - vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))))); -#else - // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) - uint32x4_t cmp = - vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); - uint32x4_t swapped = vrev64q_u32(cmp); - return vreinterpretq_m128d_u32(vmvnq_u32(vandq_u32(cmp, swapped))); -#endif -} - -// Compare the lower double-precision (64-bit) floating-point elements in a and -// b for not-equal, store the result in the lower element of dst, and copy the -// upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpneq_sd -FORCE_INLINE __m128d _mm_cmpneq_sd(__m128d a, __m128d b) -{ - return _mm_move_sd(a, _mm_cmpneq_pd(a, b)); -} - -// Compare packed double-precision (64-bit) floating-point elements in a and b -// for not-greater-than-or-equal, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnge_pd -FORCE_INLINE __m128d _mm_cmpnge_pd(__m128d a, __m128d b) -{ - return _mm_cmplt_pd(a, b); -} - -// Compare the lower double-precision (64-bit) floating-point elements in a and -// b for not-greater-than-or-equal, store the result in the lower element of -// dst, and copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnge_sd -FORCE_INLINE __m128d _mm_cmpnge_sd(__m128d a, __m128d b) -{ - return _mm_cmplt_sd(a, b); -} - -// Compare the lower double-precision (64-bit) floating-point element in a and b -// for equality, and return the boolean result (0 or 1). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comieq_sd -FORCE_INLINE int _mm_comieq_sd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return !!vgetq_lane_u64(vceqq_f64(a, b), 0); -#else - uint32x4_t a_not_nan = - vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(a)); - uint32x4_t b_not_nan = - vceqq_u32(vreinterpretq_u32_m128d(b), vreinterpretq_u32_m128d(b)); - uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); - uint32x4_t a_eq_b = - vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); - uint64x2_t and_results = vandq_u64(vreinterpretq_u64_u32(a_and_b_not_nan), - vreinterpretq_u64_u32(a_eq_b)); - return !!vgetq_lane_u64(and_results, 0); -#endif -} - -// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers -// in b for greater than. -// -// r0 := (a0 > b0) ? 0xff : 0x0 -// r1 := (a1 > b1) ? 0xff : 0x0 -// ... -// r15 := (a15 > b15) ? 0xff : 0x0 -// -// https://msdn.microsoft.com/zh-tw/library/wf45zt2b(v=vs.100).aspx -FORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u8( - vcgtq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -} - -// Compare packed double-precision (64-bit) floating-point elements in a and b -// for greater-than, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpgt_pd -FORCE_INLINE __m128d _mm_cmpgt_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_u64( - vcgtq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) > (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); - d[1] = (*(double *) &a1) > (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); - - return vreinterpretq_m128d_u64(vld1q_u64(d)); -#endif -} - -// Compare the lower double-precision (64-bit) floating-point elements in a and -// b for greater-than, store the result in the lower element of dst, and copy -// the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpgt_sd -FORCE_INLINE __m128d _mm_cmpgt_sd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return _mm_move_sd(a, _mm_cmpgt_pd(a, b)); -#else - // expand "_mm_cmpge_pd()" to reduce unnecessary operations - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) > (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); - d[1] = a1; - - return vreinterpretq_m128d_u64(vld1q_u64(d)); -#endif -} - -// Compare packed double-precision (64-bit) floating-point elements in a and b -// for less-than-or-equal, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmple_pd -FORCE_INLINE __m128d _mm_cmple_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_u64( - vcleq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) <= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); - d[1] = (*(double *) &a1) <= (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); - - return vreinterpretq_m128d_u64(vld1q_u64(d)); -#endif -} - -// Compare the lower double-precision (64-bit) floating-point elements in a and -// b for less-than-or-equal, store the result in the lower element of dst, and -// copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmple_sd -FORCE_INLINE __m128d _mm_cmple_sd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return _mm_move_sd(a, _mm_cmple_pd(a, b)); -#else - // expand "_mm_cmpge_pd()" to reduce unnecessary operations - uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); - uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); - uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); - uint64_t d[2]; - d[0] = (*(double *) &a0) <= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); - d[1] = a1; - - return vreinterpretq_m128d_u64(vld1q_u64(d)); -#endif -} - -// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers -// in b for less than. -// -// r0 := (a0 < b0) ? 0xffff : 0x0 -// r1 := (a1 < b1) ? 0xffff : 0x0 -// ... -// r7 := (a7 < b7) ? 0xffff : 0x0 -// -// https://technet.microsoft.com/en-us/library/t863edb2(v=vs.100).aspx -FORCE_INLINE __m128i _mm_cmplt_epi16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u16( - vcltq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -} - -// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers -// in b for greater than. -// -// r0 := (a0 > b0) ? 0xffff : 0x0 -// r1 := (a1 > b1) ? 0xffff : 0x0 -// ... -// r7 := (a7 > b7) ? 0xffff : 0x0 -// -// https://technet.microsoft.com/en-us/library/xd43yfsa(v=vs.100).aspx -FORCE_INLINE __m128i _mm_cmpgt_epi16(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u16( - vcgtq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -} - - -// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers -// in b for less than. -// https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx -FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u32( - vcltq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -} - -// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers -// in b for greater than. -// https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx -FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_u32( - vcgtq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -} - -// Compares the 2 signed 64-bit integers in a and the 2 signed 64-bit integers -// in b for greater than. -FORCE_INLINE __m128i _mm_cmpgt_epi64(__m128i a, __m128i b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128i_u64( - vcgtq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); -#else - return vreinterpretq_m128i_s64(vshrq_n_s64( - vqsubq_s64(vreinterpretq_s64_m128i(b), vreinterpretq_s64_m128i(a)), - 63)); -#endif -} - -// Compares the four 32-bit floats in a and b to check if any values are NaN. -// Ordered compare between each value returns true for "orderable" and false for -// "not orderable" (NaN). -// https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx see -// also: -// http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean -// http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics -FORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b) -{ - // Note: NEON does not have ordered compare builtin - // Need to compare a eq a and b eq b to check for NaN - // Do AND of results to get final - uint32x4_t ceqaa = - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); - uint32x4_t ceqbb = - vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); - return vreinterpretq_m128_u32(vandq_u32(ceqaa, ceqbb)); -} - -// Compares for ordered. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/343t62da(v=vs.100) -FORCE_INLINE __m128 _mm_cmpord_ss(__m128 a, __m128 b) -{ - return _mm_move_ss(a, _mm_cmpord_ps(a, b)); -} - -// Compares for unordered. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/khy6fk1t(v=vs.100) -FORCE_INLINE __m128 _mm_cmpunord_ps(__m128 a, __m128 b) -{ - uint32x4_t f32a = - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); - uint32x4_t f32b = - vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); - return vreinterpretq_m128_u32(vmvnq_u32(vandq_u32(f32a, f32b))); -} - -// Compares for unordered. -// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/2as2387b(v=vs.100) -FORCE_INLINE __m128 _mm_cmpunord_ss(__m128 a, __m128 b) -{ - return _mm_move_ss(a, _mm_cmpunord_ps(a, b)); -} - -// Compares the lower single-precision floating point scalar values of a and b -// using a less than operation. : -// https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx Important -// note!! The documentation on MSDN is incorrect! If either of the values is a -// NAN the docs say you will get a one, but in fact, it will return a zero!! -FORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b) -{ - uint32x4_t a_not_nan = - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); - uint32x4_t b_not_nan = - vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); - uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); - uint32x4_t a_lt_b = - vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); - return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_lt_b), 0) != 0) ? 1 : 0; -} - -// Compares the lower single-precision floating point scalar values of a and b -// using a greater than operation. : -// https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx -FORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b) -{ - // return vgetq_lane_u32(vcgtq_f32(vreinterpretq_f32_m128(a), - // vreinterpretq_f32_m128(b)), 0); - uint32x4_t a_not_nan = - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); - uint32x4_t b_not_nan = - vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); - uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); - uint32x4_t a_gt_b = - vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); - return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_gt_b), 0) != 0) ? 1 : 0; -} - -// Compares the lower single-precision floating point scalar values of a and b -// using a less than or equal operation. : -// https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx -FORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b) -{ - // return vgetq_lane_u32(vcleq_f32(vreinterpretq_f32_m128(a), - // vreinterpretq_f32_m128(b)), 0); - uint32x4_t a_not_nan = - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); - uint32x4_t b_not_nan = - vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); - uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); - uint32x4_t a_le_b = - vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); - return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_le_b), 0) != 0) ? 1 : 0; -} - -// Compares the lower single-precision floating point scalar values of a and b -// using a greater than or equal operation. : -// https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx -FORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b) -{ - // return vgetq_lane_u32(vcgeq_f32(vreinterpretq_f32_m128(a), - // vreinterpretq_f32_m128(b)), 0); - uint32x4_t a_not_nan = - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); - uint32x4_t b_not_nan = - vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); - uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); - uint32x4_t a_ge_b = - vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); - return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_ge_b), 0) != 0) ? 1 : 0; -} - -// Compares the lower single-precision floating point scalar values of a and b -// using an equality operation. : -// https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx -FORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b) -{ - // return vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a), - // vreinterpretq_f32_m128(b)), 0); - uint32x4_t a_not_nan = - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); - uint32x4_t b_not_nan = - vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); - uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); - uint32x4_t a_eq_b = - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); - return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_eq_b), 0) != 0) ? 1 : 0; -} - -// Compares the lower single-precision floating point scalar values of a and b -// using an inequality operation. : -// https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx -FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b) -{ - // return !vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a), - // vreinterpretq_f32_m128(b)), 0); - uint32x4_t a_not_nan = - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); - uint32x4_t b_not_nan = - vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); - uint32x4_t a_or_b_nan = vmvnq_u32(vandq_u32(a_not_nan, b_not_nan)); - uint32x4_t a_neq_b = vmvnq_u32( - vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); - return (vgetq_lane_u32(vorrq_u32(a_or_b_nan, a_neq_b), 0) != 0) ? 1 : 0; -} - -// according to the documentation, these intrinsics behave the same as the -// non-'u' versions. We'll just alias them here. -#define _mm_ucomieq_ss _mm_comieq_ss -#define _mm_ucomige_ss _mm_comige_ss -#define _mm_ucomigt_ss _mm_comigt_ss -#define _mm_ucomile_ss _mm_comile_ss -#define _mm_ucomilt_ss _mm_comilt_ss -#define _mm_ucomineq_ss _mm_comineq_ss - -/* Conversions */ - -// Convert packed signed 32-bit integers in b to packed single-precision -// (32-bit) floating-point elements, store the results in the lower 2 elements -// of dst, and copy the upper 2 packed elements from a to the upper elements of -// dst. -// -// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) -// dst[63:32] := Convert_Int32_To_FP32(b[63:32]) -// dst[95:64] := a[95:64] -// dst[127:96] := a[127:96] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_pi2ps -FORCE_INLINE __m128 _mm_cvt_pi2ps(__m128 a, __m64 b) -{ - return vreinterpretq_m128_f32( - vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)), - vget_high_f32(vreinterpretq_f32_m128(a)))); -} - -// Convert the signed 32-bit integer b to a single-precision (32-bit) -// floating-point element, store the result in the lower element of dst, and -// copy the upper 3 packed elements from a to the upper elements of dst. -// -// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) -// dst[127:32] := a[127:32] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_si2ss -FORCE_INLINE __m128 _mm_cvt_si2ss(__m128 a, int b) -{ - return vreinterpretq_m128_f32( - vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0)); -} - -// Convert the signed 32-bit integer b to a single-precision (32-bit) -// floating-point element, store the result in the lower element of dst, and -// copy the upper 3 packed elements from a to the upper elements of dst. -// -// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) -// dst[127:32] := a[127:32] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_ss -#define _mm_cvtsi32_ss(a, b) _mm_cvt_si2ss(a, b) - -// Convert the signed 64-bit integer b to a single-precision (32-bit) -// floating-point element, store the result in the lower element of dst, and -// copy the upper 3 packed elements from a to the upper elements of dst. -// -// dst[31:0] := Convert_Int64_To_FP32(b[63:0]) -// dst[127:32] := a[127:32] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_ss -FORCE_INLINE __m128 _mm_cvtsi64_ss(__m128 a, int64_t b) -{ - return vreinterpretq_m128_f32( - vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0)); -} - -// Convert the lower single-precision (32-bit) floating-point element in a to a -// 32-bit integer, and store the result in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ss2si -FORCE_INLINE int _mm_cvt_ss2si(__m128 a) -{ -#if defined(__aarch64__) - return vgetq_lane_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a)), 0); -#else - float32_t data = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); - float32_t diff = data - floor(data); - if (diff > 0.5) - return (int32_t) ceil(data); - if (unlikely(diff == 0.5)) { - int32_t f = (int32_t) floor(data); - int32_t c = (int32_t) ceil(data); - return c & 1 ? f : c; - } - return (int32_t) floor(data); -#endif -} - -// Convert packed 16-bit integers in a to packed single-precision (32-bit) -// floating-point elements, and store the results in dst. -// -// FOR j := 0 to 3 -// i := j*16 -// m := j*32 -// dst[m+31:m] := Convert_Int16_To_FP32(a[i+15:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi16_ps -FORCE_INLINE __m128 _mm_cvtpi16_ps(__m64 a) -{ - return vreinterpretq_m128_f32( - vcvtq_f32_s32(vmovl_s16(vreinterpret_s16_m64(a)))); -} - -// Convert packed 32-bit integers in b to packed single-precision (32-bit) -// floating-point elements, store the results in the lower 2 elements of dst, -// and copy the upper 2 packed elements from a to the upper elements of dst. -// -// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) -// dst[63:32] := Convert_Int32_To_FP32(b[63:32]) -// dst[95:64] := a[95:64] -// dst[127:96] := a[127:96] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_ps -FORCE_INLINE __m128 _mm_cvtpi32_ps(__m128 a, __m64 b) -{ - return vreinterpretq_m128_f32( - vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)), - vget_high_f32(vreinterpretq_f32_m128(a)))); -} - -// Convert packed signed 32-bit integers in a to packed single-precision -// (32-bit) floating-point elements, store the results in the lower 2 elements -// of dst, then covert the packed signed 32-bit integers in b to -// single-precision (32-bit) floating-point element, and store the results in -// the upper 2 elements of dst. -// -// dst[31:0] := Convert_Int32_To_FP32(a[31:0]) -// dst[63:32] := Convert_Int32_To_FP32(a[63:32]) -// dst[95:64] := Convert_Int32_To_FP32(b[31:0]) -// dst[127:96] := Convert_Int32_To_FP32(b[63:32]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32x2_ps -FORCE_INLINE __m128 _mm_cvtpi32x2_ps(__m64 a, __m64 b) -{ - return vreinterpretq_m128_f32(vcvtq_f32_s32( - vcombine_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b)))); -} - -// Convert the lower packed 8-bit integers in a to packed single-precision -// (32-bit) floating-point elements, and store the results in dst. -// -// FOR j := 0 to 3 -// i := j*8 -// m := j*32 -// dst[m+31:m] := Convert_Int8_To_FP32(a[i+7:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi8_ps -FORCE_INLINE __m128 _mm_cvtpi8_ps(__m64 a) -{ - return vreinterpretq_m128_f32(vcvtq_f32_s32( - vmovl_s16(vget_low_s16(vmovl_s8(vreinterpret_s8_m64(a)))))); -} - -// Convert packed unsigned 16-bit integers in a to packed single-precision -// (32-bit) floating-point elements, and store the results in dst. -// -// FOR j := 0 to 3 -// i := j*16 -// m := j*32 -// dst[m+31:m] := Convert_UInt16_To_FP32(a[i+15:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu16_ps -FORCE_INLINE __m128 _mm_cvtpu16_ps(__m64 a) -{ - return vreinterpretq_m128_f32( - vcvtq_f32_u32(vmovl_u16(vreinterpret_u16_m64(a)))); -} - -// Convert the lower packed unsigned 8-bit integers in a to packed -// single-precision (32-bit) floating-point elements, and store the results in -// dst. -// -// FOR j := 0 to 3 -// i := j*8 -// m := j*32 -// dst[m+31:m] := Convert_UInt8_To_FP32(a[i+7:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu8_ps -FORCE_INLINE __m128 _mm_cvtpu8_ps(__m64 a) -{ - return vreinterpretq_m128_f32(vcvtq_f32_u32( - vmovl_u16(vget_low_u16(vmovl_u8(vreinterpret_u8_m64(a)))))); -} - -// Converts the four single-precision, floating-point values of a to signed -// 32-bit integer values using truncate. -// https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx -FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a) -{ - return vreinterpretq_m128i_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a))); -} - -// Convert the lower double-precision (64-bit) floating-point element in a to a -// 64-bit integer with truncation, and store the result in dst. -// -// dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64 -FORCE_INLINE int64_t _mm_cvttsd_si64(__m128d a) -{ -#if defined(__aarch64__) - return vgetq_lane_s64(vcvtq_s64_f64(vreinterpretq_f64_m128d(a)), 0); -#else - double ret = *((double *) &a); - return (int64_t) ret; -#endif -} - -// Convert the lower double-precision (64-bit) floating-point element in a to a -// 64-bit integer with truncation, and store the result in dst. -// -// dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64x -#define _mm_cvttsd_si64x(a) _mm_cvttsd_si64(a) - -// Converts the four signed 32-bit integer values of a to single-precision, -// floating-point values -// https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx -FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a) -{ - return vreinterpretq_m128_f32(vcvtq_f32_s32(vreinterpretq_s32_m128i(a))); -} - -// Convert packed signed 32-bit integers in a to packed double-precision -// (64-bit) floating-point elements, and store the results in dst. -// -// FOR j := 0 to 1 -// i := j*32 -// m := j*64 -// dst[m+63:m] := Convert_Int32_To_FP64(a[i+31:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtepi32_pd -FORCE_INLINE __m128d _mm_cvtepi32_pd(__m128i a) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vcvtq_f64_s64(vmovl_s32(vget_low_s32(vreinterpretq_s32_m128i(a))))); -#else - double a0 = (double) vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0); - double a1 = (double) vgetq_lane_s32(vreinterpretq_s32_m128i(a), 1); - return _mm_set_pd(a1, a0); -#endif -} - -// Convert packed signed 32-bit integers in a to packed double-precision -// (64-bit) floating-point elements, and store the results in dst. -// -// FOR j := 0 to 1 -// i := j*32 -// m := j*64 -// dst[m+63:m] := Convert_Int32_To_FP64(a[i+31:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_pd -FORCE_INLINE __m128d _mm_cvtpi32_pd(__m64 a) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vcvtq_f64_s64(vmovl_s32(vreinterpret_s32_m64(a)))); -#else - double a0 = (double) vget_lane_s32(vreinterpret_s32_m64(a), 0); - double a1 = (double) vget_lane_s32(vreinterpret_s32_m64(a), 1); - return _mm_set_pd(a1, a0); -#endif -} - -// Converts the four unsigned 8-bit integers in the lower 16 bits to four -// unsigned 32-bit integers. -FORCE_INLINE __m128i _mm_cvtepu8_epi16(__m128i a) -{ - uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx DCBA */ - uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */ - return vreinterpretq_m128i_u16(u16x8); -} - -// Converts the four unsigned 8-bit integers in the lower 32 bits to four -// unsigned 32-bit integers. -// https://msdn.microsoft.com/en-us/library/bb531467%28v=vs.100%29.aspx -FORCE_INLINE __m128i _mm_cvtepu8_epi32(__m128i a) -{ - uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx DCBA */ - uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */ - uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000D 000C 000B 000A */ - return vreinterpretq_m128i_u32(u32x4); -} - -// Converts the two unsigned 8-bit integers in the lower 16 bits to two -// unsigned 64-bit integers. -FORCE_INLINE __m128i _mm_cvtepu8_epi64(__m128i a) -{ - uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx xxBA */ - uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0x0x 0B0A */ - uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */ - uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */ - return vreinterpretq_m128i_u64(u64x2); -} - -// Converts the four unsigned 8-bit integers in the lower 16 bits to four -// unsigned 32-bit integers. -FORCE_INLINE __m128i _mm_cvtepi8_epi16(__m128i a) -{ - int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */ - int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */ - return vreinterpretq_m128i_s16(s16x8); -} - -// Converts the four unsigned 8-bit integers in the lower 32 bits to four -// unsigned 32-bit integers. -FORCE_INLINE __m128i _mm_cvtepi8_epi32(__m128i a) -{ - int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */ - int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */ - int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000D 000C 000B 000A */ - return vreinterpretq_m128i_s32(s32x4); -} - -// Converts the two signed 8-bit integers in the lower 32 bits to four -// signed 64-bit integers. -FORCE_INLINE __m128i _mm_cvtepi8_epi64(__m128i a) -{ - int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx xxBA */ - int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0x0x 0B0A */ - int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */ - int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */ - return vreinterpretq_m128i_s64(s64x2); -} - -// Converts the four signed 16-bit integers in the lower 64 bits to four signed -// 32-bit integers. -FORCE_INLINE __m128i _mm_cvtepi16_epi32(__m128i a) -{ - return vreinterpretq_m128i_s32( - vmovl_s16(vget_low_s16(vreinterpretq_s16_m128i(a)))); -} - -// Converts the two signed 16-bit integers in the lower 32 bits two signed -// 32-bit integers. -FORCE_INLINE __m128i _mm_cvtepi16_epi64(__m128i a) -{ - int16x8_t s16x8 = vreinterpretq_s16_m128i(a); /* xxxx xxxx xxxx 0B0A */ - int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */ - int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */ - return vreinterpretq_m128i_s64(s64x2); -} - -// Converts the four unsigned 16-bit integers in the lower 64 bits to four -// unsigned 32-bit integers. -FORCE_INLINE __m128i _mm_cvtepu16_epi32(__m128i a) -{ - return vreinterpretq_m128i_u32( - vmovl_u16(vget_low_u16(vreinterpretq_u16_m128i(a)))); -} - -// Converts the two unsigned 16-bit integers in the lower 32 bits to two -// unsigned 64-bit integers. -FORCE_INLINE __m128i _mm_cvtepu16_epi64(__m128i a) -{ - uint16x8_t u16x8 = vreinterpretq_u16_m128i(a); /* xxxx xxxx xxxx 0B0A */ - uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */ - uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */ - return vreinterpretq_m128i_u64(u64x2); -} - -// Converts the two unsigned 32-bit integers in the lower 64 bits to two -// unsigned 64-bit integers. -FORCE_INLINE __m128i _mm_cvtepu32_epi64(__m128i a) -{ - return vreinterpretq_m128i_u64( - vmovl_u32(vget_low_u32(vreinterpretq_u32_m128i(a)))); -} - -// Converts the two signed 32-bit integers in the lower 64 bits to two signed -// 64-bit integers. -FORCE_INLINE __m128i _mm_cvtepi32_epi64(__m128i a) -{ - return vreinterpretq_m128i_s64( - vmovl_s32(vget_low_s32(vreinterpretq_s32_m128i(a)))); -} - -// Converts the four single-precision, floating-point values of a to signed -// 32-bit integer values. -// -// r0 := (int) a0 -// r1 := (int) a1 -// r2 := (int) a2 -// r3 := (int) a3 -// -// https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx -// *NOTE*. The default rounding mode on SSE is 'round to even', which ARMv7-A -// does not support! It is supported on ARMv8-A however. -FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a) -{ -#if defined(__aarch64__) - return vreinterpretq_m128i_s32(vcvtnq_s32_f32(a)); -#else - uint32x4_t signmask = vdupq_n_u32(0x80000000); - float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a), - vdupq_n_f32(0.5f)); /* +/- 0.5 */ - int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32( - vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/ - int32x4_t r_trunc = - vcvtq_s32_f32(vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */ - int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32( - vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */ - int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone), - vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */ - float32x4_t delta = vsubq_f32( - vreinterpretq_f32_m128(a), - vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */ - uint32x4_t is_delta_half = vceqq_f32(delta, half); /* delta == +/- 0.5 */ - return vreinterpretq_m128i_s32(vbslq_s32(is_delta_half, r_even, r_normal)); -#endif -} - -// Convert packed single-precision (32-bit) floating-point elements in a to -// packed 16-bit integers, and store the results in dst. Note: this intrinsic -// will generate 0x7FFF, rather than 0x8000, for input values between 0x7FFF and -// 0x7FFFFFFF. -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi16 -FORCE_INLINE __m64 _mm_cvtps_pi16(__m128 a) -{ - return vreinterpret_m64_s16( - vmovn_s32(vreinterpretq_s32_m128i(_mm_cvtps_epi32(a)))); -} - -// Copy the lower 32-bit integer in a to dst. -// -// dst[31:0] := a[31:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si32 -FORCE_INLINE int _mm_cvtsi128_si32(__m128i a) -{ - return vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0); -} - -// Copy the lower 64-bit integer in a to dst. -// -// dst[63:0] := a[63:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64 -FORCE_INLINE int64_t _mm_cvtsi128_si64(__m128i a) -{ - return vgetq_lane_s64(vreinterpretq_s64_m128i(a), 0); -} - -// Copy the lower 64-bit integer in a to dst. -// -// dst[63:0] := a[63:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x -#define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a) - -// Moves 32-bit integer a to the least significant 32 bits of an __m128 object, -// zero extending the upper bits. -// -// r0 := a -// r1 := 0x0 -// r2 := 0x0 -// r3 := 0x0 -// -// https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx -FORCE_INLINE __m128i _mm_cvtsi32_si128(int a) -{ - return vreinterpretq_m128i_s32(vsetq_lane_s32(a, vdupq_n_s32(0), 0)); -} - -// Moves 64-bit integer a to the least significant 64 bits of an __m128 object, -// zero extending the upper bits. -// -// r0 := a -// r1 := 0x0 -FORCE_INLINE __m128i _mm_cvtsi64_si128(int64_t a) -{ - return vreinterpretq_m128i_s64(vsetq_lane_s64(a, vdupq_n_s64(0), 0)); -} - -// Cast vector of type __m128 to type __m128d. This intrinsic is only used for -// compilation and does not generate any instructions, thus it has zero latency. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castps_pd -FORCE_INLINE __m128d _mm_castps_pd(__m128 a) -{ - return vreinterpretq_m128d_s32(vreinterpretq_s32_m128(a)); -} - -// Applies a type cast to reinterpret four 32-bit floating point values passed -// in as a 128-bit parameter as packed 32-bit integers. -// https://msdn.microsoft.com/en-us/library/bb514099.aspx -FORCE_INLINE __m128i _mm_castps_si128(__m128 a) -{ - return vreinterpretq_m128i_s32(vreinterpretq_s32_m128(a)); -} - -// Cast vector of type __m128i to type __m128d. This intrinsic is only used for -// compilation and does not generate any instructions, thus it has zero latency. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castsi128_pd -FORCE_INLINE __m128d _mm_castsi128_pd(__m128i a) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64(vreinterpretq_f64_m128i(a)); -#else - return vreinterpretq_m128d_f32(vreinterpretq_f32_m128i(a)); -#endif -} - -// Applies a type cast to reinterpret four 32-bit integers passed in as a -// 128-bit parameter as packed 32-bit floating point values. -// https://msdn.microsoft.com/en-us/library/bb514029.aspx -FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a) -{ - return vreinterpretq_m128_s32(vreinterpretq_s32_m128i(a)); -} - -// Loads 128-bit value. : -// https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx -FORCE_INLINE __m128i _mm_load_si128(const __m128i *p) -{ - return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p)); -} - -// Load a double-precision (64-bit) floating-point element from memory into both -// elements of dst. -// -// dst[63:0] := MEM[mem_addr+63:mem_addr] -// dst[127:64] := MEM[mem_addr+63:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load1_pd -FORCE_INLINE __m128d _mm_load1_pd(const double *p) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64(vld1q_dup_f64(p)); -#else - return vreinterpretq_m128d_s64(vdupq_n_s64(*(const int64_t *) p)); -#endif -} - -// Load a double-precision (64-bit) floating-point element from memory into both -// elements of dst. -// -// dst[63:0] := MEM[mem_addr+63:mem_addr] -// dst[127:64] := MEM[mem_addr+63:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1 -#define _mm_load_pd1 _mm_load1_pd - -// Load a double-precision (64-bit) floating-point element from memory into both -// elements of dst. -// -// dst[63:0] := MEM[mem_addr+63:mem_addr] -// dst[127:64] := MEM[mem_addr+63:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loaddup_pd -#define _mm_loaddup_pd _mm_load1_pd - -// Load a double-precision (64-bit) floating-point element from memory into the -// upper element of dst, and copy the lower element from a to dst. mem_addr does -// not need to be aligned on any particular boundary. -// -// dst[63:0] := a[63:0] -// dst[127:64] := MEM[mem_addr+63:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadh_pd -FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double *p) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vcombine_f64(vget_low_f64(vreinterpretq_f64_m128d(a)), vld1_f64(p))); -#else - return vreinterpretq_m128d_f32(vcombine_f32( - vget_low_f32(vreinterpretq_f32_m128d(a)), vld1_f32((const float *) p))); -#endif -} - -// Load a double-precision (64-bit) floating-point element from memory into both -// elements of dst. -// -// dst[63:0] := MEM[mem_addr+63:mem_addr] -// dst[127:64] := MEM[mem_addr+63:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1 -#define _mm_load_pd1 _mm_load1_pd - -// Load a double-precision (64-bit) floating-point element from memory into both -// elements of dst. -// -// dst[63:0] := MEM[mem_addr+63:mem_addr] -// dst[127:64] := MEM[mem_addr+63:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loaddup_pd -#define _mm_loaddup_pd _mm_load1_pd - -// Loads 128-bit value. : -// https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx -FORCE_INLINE __m128i _mm_loadu_si128(const __m128i *p) -{ - return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p)); -} - -// Load unaligned 32-bit integer from memory into the first element of dst. -// -// dst[31:0] := MEM[mem_addr+31:mem_addr] -// dst[MAX:32] := 0 -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si32 -FORCE_INLINE __m128i _mm_loadu_si32(const void *p) -{ - return vreinterpretq_m128i_s32( - vsetq_lane_s32(*(const int32_t *) p, vdupq_n_s32(0), 0)); -} - -// Convert packed double-precision (64-bit) floating-point elements in a to -// packed single-precision (32-bit) floating-point elements, and store the -// results in dst. -// -// FOR j := 0 to 1 -// i := 32*j -// k := 64*j -// dst[i+31:i] := Convert_FP64_To_FP32(a[k+64:k]) -// ENDFOR -// dst[127:64] := 0 -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_ps -FORCE_INLINE __m128 _mm_cvtpd_ps(__m128d a) -{ -#if defined(__aarch64__) - float32x2_t tmp = vcvt_f32_f64(vreinterpretq_f64_m128d(a)); - return vreinterpretq_m128_f32(vcombine_f32(tmp, vdup_n_f32(0))); -#else - float a0 = (float) ((double *) &a)[0]; - float a1 = (float) ((double *) &a)[1]; - return _mm_set_ps(0, 0, a1, a0); -#endif -} - -// Copy the lower double-precision (64-bit) floating-point element of a to dst. -// -// dst[63:0] := a[63:0] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_f64 -FORCE_INLINE double _mm_cvtsd_f64(__m128d a) -{ -#if defined(__aarch64__) - return (double) vgetq_lane_f64(vreinterpretq_f64_m128d(a), 0); -#else - return ((double *) &a)[0]; -#endif -} - -// Convert packed single-precision (32-bit) floating-point elements in a to -// packed double-precision (64-bit) floating-point elements, and store the -// results in dst. -// -// FOR j := 0 to 1 -// i := 64*j -// k := 32*j -// dst[i+63:i] := Convert_FP32_To_FP64(a[k+31:k]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pd -FORCE_INLINE __m128d _mm_cvtps_pd(__m128 a) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vcvt_f64_f32(vget_low_f32(vreinterpretq_f32_m128(a)))); -#else - double a0 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); - double a1 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 1); - return _mm_set_pd(a1, a0); -#endif -} - -// Cast vector of type __m128d to type __m128i. This intrinsic is only used for -// compilation and does not generate any instructions, thus it has zero latency. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_si128 -FORCE_INLINE __m128i _mm_castpd_si128(__m128d a) -{ - return vreinterpretq_m128i_s64(vreinterpretq_s64_m128d(a)); -} - -// Cast vector of type __m128d to type __m128. This intrinsic is only used for -// compilation and does not generate any instructions, thus it has zero latency. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_ps -FORCE_INLINE __m128 _mm_castpd_ps(__m128d a) -{ - return vreinterpretq_m128_s64(vreinterpretq_s64_m128d(a)); -} - -// Blend packed single-precision (32-bit) floating-point elements from a and b -// using mask, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_ps -FORCE_INLINE __m128 _mm_blendv_ps(__m128 _a, __m128 _b, __m128 _mask) -{ - // Use a signed shift right to create a mask with the sign bit - uint32x4_t mask = - vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_m128(_mask), 31)); - float32x4_t a = vreinterpretq_f32_m128(_a); - float32x4_t b = vreinterpretq_f32_m128(_b); - return vreinterpretq_m128_f32(vbslq_f32(mask, b, a)); -} - -// Blend packed single-precision (32-bit) floating-point elements from a and b -// using mask, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_ps -FORCE_INLINE __m128 _mm_blend_ps(__m128 _a, __m128 _b, const char imm8) -{ - const uint32_t ALIGN_STRUCT(16) - data[4] = {((imm8) & (1 << 0)) ? UINT32_MAX : 0, - ((imm8) & (1 << 1)) ? UINT32_MAX : 0, - ((imm8) & (1 << 2)) ? UINT32_MAX : 0, - ((imm8) & (1 << 3)) ? UINT32_MAX : 0}; - uint32x4_t mask = vld1q_u32(data); - float32x4_t a = vreinterpretq_f32_m128(_a); - float32x4_t b = vreinterpretq_f32_m128(_b); - return vreinterpretq_m128_f32(vbslq_f32(mask, b, a)); -} - -// Blend packed double-precision (64-bit) floating-point elements from a and b -// using mask, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_pd -FORCE_INLINE __m128d _mm_blendv_pd(__m128d _a, __m128d _b, __m128d _mask) -{ - uint64x2_t mask = - vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_m128d(_mask), 63)); -#if defined(__aarch64__) - float64x2_t a = vreinterpretq_f64_m128d(_a); - float64x2_t b = vreinterpretq_f64_m128d(_b); - return vreinterpretq_m128d_f64(vbslq_f64(mask, b, a)); -#else - uint64x2_t a = vreinterpretq_u64_m128d(_a); - uint64x2_t b = vreinterpretq_u64_m128d(_b); - return vreinterpretq_m128d_u64(vbslq_u64(mask, b, a)); -#endif -} - -typedef struct { - uint16_t res0; - uint8_t res1 : 6; - uint8_t bit22 : 1; - uint8_t bit23 : 1; - uint8_t res2; -#if defined(__aarch64__) - uint32_t res3; -#endif -} fpcr_bitfield; - -// Macro: Set the rounding mode bits of the MXCSR control and status register to -// the value in unsigned 32-bit integer a. The rounding mode may contain any of -// the following flags: _MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, -// _MM_ROUND_TOWARD_ZERO -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_SET_ROUNDING_MODE -FORCE_INLINE void _MM_SET_ROUNDING_MODE(int rounding) -{ - union { - fpcr_bitfield field; -#if defined(__aarch64__) - uint64_t value; -#else - uint32_t value; -#endif - } r; - -#if defined(__aarch64__) - asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */ -#else - asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ -#endif - - switch (rounding) { - case _MM_ROUND_TOWARD_ZERO: - r.field.bit22 = 1; - r.field.bit23 = 1; - break; - case _MM_ROUND_DOWN: - r.field.bit22 = 0; - r.field.bit23 = 1; - break; - case _MM_ROUND_UP: - r.field.bit22 = 1; - r.field.bit23 = 0; - break; - default: //_MM_ROUND_NEAREST - r.field.bit22 = 0; - r.field.bit23 = 0; - } - -#if defined(__aarch64__) - asm volatile("msr FPCR, %0" ::"r"(r)); /* write */ -#else - asm volatile("vmsr FPSCR, %0" ::"r"(r)); /* write */ -#endif -} - -FORCE_INLINE void _mm_setcsr(unsigned int a) -{ - _MM_SET_ROUNDING_MODE(a); -} - -// Round the packed single-precision (32-bit) floating-point elements in a using -// the rounding parameter, and store the results as packed single-precision +// Extracts the selected signed or unsigned 32-bit integer from a and zero +// extends. +// FORCE_INLINE int _mm_extract_epi32(__m128i a, __constrange(0,4) int imm) +#define _mm_extract_epi32(a, imm) \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)) + +// Extracts the selected signed or unsigned 64-bit integer from a and zero +// extends. +// FORCE_INLINE __int64 _mm_extract_epi64(__m128i a, __constrange(0,2) int imm) +#define _mm_extract_epi64(a, imm) \ + vgetq_lane_s64(vreinterpretq_s64_m128i(a), (imm)) + +// Extracts the selected signed or unsigned 8-bit integer from a and zero +// extends. +// FORCE_INLINE int _mm_extract_epi8(__m128i a, __constrange(0,16) int imm) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_extract_epi8 +#define _mm_extract_epi8(a, imm) vgetq_lane_u8(vreinterpretq_u8_m128i(a), (imm)) + +// Extracts the selected single-precision (32-bit) floating-point from a. +// FORCE_INLINE int _mm_extract_ps(__m128 a, __constrange(0,4) int imm) +#define _mm_extract_ps(a, imm) vgetq_lane_s32(vreinterpretq_s32_m128(a), (imm)) + +// Round the packed double-precision (64-bit) floating-point elements in a down +// to an integer value, and store the results as packed double-precision // floating-point elements in dst. -// software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ps -FORCE_INLINE __m128 _mm_round_ps(__m128 a, int rounding) +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_pd +FORCE_INLINE __m128d _mm_floor_pd(__m128d a) { #if defined(__aarch64__) - switch (rounding) { - case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC): - return vreinterpretq_m128_f32(vrndnq_f32(vreinterpretq_f32_m128(a))); - case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC): - return vreinterpretq_m128_f32(vrndmq_f32(vreinterpretq_f32_m128(a))); - case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC): - return vreinterpretq_m128_f32(vrndpq_f32(vreinterpretq_f32_m128(a))); - case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC): - return vreinterpretq_m128_f32(vrndq_f32(vreinterpretq_f32_m128(a))); - default: //_MM_FROUND_CUR_DIRECTION - return vreinterpretq_m128_f32(vrndiq_f32(vreinterpretq_f32_m128(a))); - } + return vreinterpretq_m128d_f64(vrndmq_f64(vreinterpretq_f64_m128d(a))); #else - float *v_float = (float *) &a; - __m128 zero, neg_inf, pos_inf; - - switch (rounding) { - case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC): - return _mm_cvtepi32_ps(_mm_cvtps_epi32(a)); - case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC): - return (__m128){floorf(v_float[0]), floorf(v_float[1]), - floorf(v_float[2]), floorf(v_float[3])}; - case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC): - return (__m128){ceilf(v_float[0]), ceilf(v_float[1]), ceilf(v_float[2]), - ceilf(v_float[3])}; - case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC): - zero = _mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f); - neg_inf = _mm_set_ps(floorf(v_float[0]), floorf(v_float[1]), - floorf(v_float[2]), floorf(v_float[3])); - pos_inf = _mm_set_ps(ceilf(v_float[0]), ceilf(v_float[1]), - ceilf(v_float[2]), ceilf(v_float[3])); - return _mm_blendv_ps(pos_inf, neg_inf, _mm_cmple_ps(a, zero)); - default: //_MM_FROUND_CUR_DIRECTION - return (__m128){roundf(v_float[0]), roundf(v_float[1]), - roundf(v_float[2]), roundf(v_float[3])}; - } + double *f = (double *) &a; + return _mm_set_pd(floor(f[1]), floor(f[0])); #endif } -// Convert packed single-precision (32-bit) floating-point elements in a to -// packed 32-bit integers, and store the results in dst. -// -// FOR j := 0 to 1 -// i := 32*j -// dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ps2pi -FORCE_INLINE __m64 _mm_cvt_ps2pi(__m128 a) -{ -#if defined(__aarch64__) - return vreinterpret_m64_s32( - vget_low_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a)))); -#else - return vreinterpret_m64_s32( - vcvt_s32_f32(vget_low_f32(vreinterpretq_f32_m128( - _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC))))); -#endif -} - -// Convert packed single-precision (32-bit) floating-point elements in a to -// packed 32-bit integers, and store the results in dst. -// -// FOR j := 0 to 1 -// i := 32*j -// dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i]) -// ENDFOR -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi32 -#define _mm_cvtps_pi32(a) _mm_cvt_ps2pi(a) - -// Round the packed single-precision (32-bit) floating-point elements in a up to -// an integer value, and store the results as packed single-precision -// floating-point elements in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ps -FORCE_INLINE __m128 _mm_ceil_ps(__m128 a) -{ - return _mm_round_ps(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); -} - -// Round the lower single-precision (32-bit) floating-point element in b up to -// an integer value, store the result as a single-precision floating-point -// element in the lower element of dst, and copy the upper 3 packed elements -// from a to the upper elements of dst. -// -// dst[31:0] := CEIL(b[31:0]) -// dst[127:32] := a[127:32] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ss -FORCE_INLINE __m128 _mm_ceil_ss(__m128 a, __m128 b) -{ - return _mm_move_ss( - a, _mm_round_ps(b, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC)); -} - // Round the packed single-precision (32-bit) floating-point elements in a down // to an integer value, and store the results as packed single-precision // floating-point elements in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ps FORCE_INLINE __m128 _mm_floor_ps(__m128 a) { - return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) + return vreinterpretq_m128_f32(vrndmq_f32(vreinterpretq_f32_m128(a))); +#else + float *f = (float *) &a; + return _mm_set_ps(floorf(f[3]), floorf(f[2]), floorf(f[1]), floorf(f[0])); +#endif +} + +// Round the lower double-precision (64-bit) floating-point element in b down to +// an integer value, store the result as a double-precision floating-point +// element in the lower element of dst, and copy the upper element from a to the +// upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_sd +FORCE_INLINE __m128d _mm_floor_sd(__m128d a, __m128d b) +{ + return _mm_move_sd(a, _mm_floor_pd(b)); } // Round the lower single-precision (32-bit) floating-point element in b down to @@ -6416,372 +7785,147 @@ FORCE_INLINE __m128 _mm_floor_ps(__m128 a) // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ss FORCE_INLINE __m128 _mm_floor_ss(__m128 a, __m128 b) { - return _mm_move_ss( - a, _mm_round_ps(b, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC)); + return _mm_move_ss(a, _mm_floor_ps(b)); } -// Load 128-bits of integer data from unaligned memory into dst. This intrinsic -// may perform better than _mm_loadu_si128 when the data crosses a cache line -// boundary. -// -// dst[127:0] := MEM[mem_addr+127:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lddqu_si128 -#define _mm_lddqu_si128 _mm_loadu_si128 +// Inserts the least significant 32 bits of b into the selected 32-bit integer +// of a. +// FORCE_INLINE __m128i _mm_insert_epi32(__m128i a, int b, +// __constrange(0,4) int imm) +#define _mm_insert_epi32(a, b, imm) \ + __extension__({ \ + vreinterpretq_m128i_s32( \ + vsetq_lane_s32((b), vreinterpretq_s32_m128i(a), (imm))); \ + }) -/* Miscellaneous Operations */ +// Inserts the least significant 64 bits of b into the selected 64-bit integer +// of a. +// FORCE_INLINE __m128i _mm_insert_epi64(__m128i a, __int64 b, +// __constrange(0,2) int imm) +#define _mm_insert_epi64(a, b, imm) \ + __extension__({ \ + vreinterpretq_m128i_s64( \ + vsetq_lane_s64((b), vreinterpretq_s64_m128i(a), (imm))); \ + }) -// Shifts the 8 signed 16-bit integers in a right by count bits while shifting -// in the sign bit. +// Inserts the least significant 8 bits of b into the selected 8-bit integer +// of a. +// FORCE_INLINE __m128i _mm_insert_epi8(__m128i a, int b, +// __constrange(0,16) int imm) +#define _mm_insert_epi8(a, b, imm) \ + __extension__({ \ + vreinterpretq_m128i_s8( \ + vsetq_lane_s8((b), vreinterpretq_s8_m128i(a), (imm))); \ + }) + +// Copy a to tmp, then insert a single-precision (32-bit) floating-point +// element from b into tmp using the control in imm8. Store tmp to dst using +// the mask in imm8 (elements are zeroed out when the corresponding bit is set). +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=insert_ps +#define _mm_insert_ps(a, b, imm8) \ + __extension__({ \ + float32x4_t tmp1 = \ + vsetq_lane_f32(vgetq_lane_f32(b, (imm8 >> 6) & 0x3), \ + vreinterpretq_f32_m128(a), 0); \ + float32x4_t tmp2 = \ + vsetq_lane_f32(vgetq_lane_f32(tmp1, 0), vreinterpretq_f32_m128(a), \ + ((imm8 >> 4) & 0x3)); \ + const uint32_t data[4] = {((imm8) & (1 << 0)) ? UINT32_MAX : 0, \ + ((imm8) & (1 << 1)) ? UINT32_MAX : 0, \ + ((imm8) & (1 << 2)) ? UINT32_MAX : 0, \ + ((imm8) & (1 << 3)) ? UINT32_MAX : 0}; \ + uint32x4_t mask = vld1q_u32(data); \ + float32x4_t all_zeros = vdupq_n_f32(0); \ + \ + vreinterpretq_m128_f32( \ + vbslq_f32(mask, all_zeros, vreinterpretq_f32_m128(tmp2))); \ + }) + +// epi versions of min/max +// Computes the pariwise maximums of the four signed 32-bit integer values of a +// and b. // -// r0 := a0 >> count -// r1 := a1 >> count -// ... -// r7 := a7 >> count +// A 128-bit parameter that can be defined with the following equations: +// r0 := (a0 > b0) ? a0 : b0 +// r1 := (a1 > b1) ? a1 : b1 +// r2 := (a2 > b2) ? a2 : b2 +// r3 := (a3 > b3) ? a3 : b3 // -// https://msdn.microsoft.com/en-us/library/3c9997dk(v%3dvs.90).aspx -FORCE_INLINE __m128i _mm_sra_epi16(__m128i a, __m128i count) +// https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx +FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b) { - int64_t c = (int64_t) vget_low_s64((int64x2_t) count); - if (unlikely(c > 15)) - return _mm_cmplt_epi16(a, _mm_setzero_si128()); - return vreinterpretq_m128i_s16(vshlq_s16((int16x8_t) a, vdupq_n_s16(-c))); + return vreinterpretq_m128i_s32( + vmaxq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } -// Shifts the 4 signed 32-bit integers in a right by count bits while shifting -// in the sign bit. -// -// r0 := a0 >> count -// r1 := a1 >> count -// r2 := a2 >> count -// r3 := a3 >> count -// -// https://msdn.microsoft.com/en-us/library/ce40009e(v%3dvs.100).aspx -FORCE_INLINE __m128i _mm_sra_epi32(__m128i a, __m128i count) -{ - int64_t c = (int64_t) vget_low_s64((int64x2_t) count); - if (unlikely(c > 31)) - return _mm_cmplt_epi32(a, _mm_setzero_si128()); - return vreinterpretq_m128i_s32(vshlq_s32((int32x4_t) a, vdupq_n_s32(-c))); -} - -// Packs the 16 signed 16-bit integers from a and b into 8-bit integers and -// saturates. -// https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx -FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b) +// Compare packed signed 8-bit integers in a and b, and store packed maximum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epi8 +FORCE_INLINE __m128i _mm_max_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( - vcombine_s8(vqmovn_s16(vreinterpretq_s16_m128i(a)), - vqmovn_s16(vreinterpretq_s16_m128i(b)))); + vmaxq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } -// Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned -// integers and saturates. -// -// r0 := UnsignedSaturate(a0) -// r1 := UnsignedSaturate(a1) -// ... -// r7 := UnsignedSaturate(a7) -// r8 := UnsignedSaturate(b0) -// r9 := UnsignedSaturate(b1) -// ... -// r15 := UnsignedSaturate(b7) -// -// https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx -FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b) -{ - return vreinterpretq_m128i_u8( - vcombine_u8(vqmovun_s16(vreinterpretq_s16_m128i(a)), - vqmovun_s16(vreinterpretq_s16_m128i(b)))); -} - -// Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers -// and saturates. -// -// r0 := SignedSaturate(a0) -// r1 := SignedSaturate(a1) -// r2 := SignedSaturate(a2) -// r3 := SignedSaturate(a3) -// r4 := SignedSaturate(b0) -// r5 := SignedSaturate(b1) -// r6 := SignedSaturate(b2) -// r7 := SignedSaturate(b3) -// -// https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx -FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b) -{ - return vreinterpretq_m128i_s16( - vcombine_s16(vqmovn_s32(vreinterpretq_s32_m128i(a)), - vqmovn_s32(vreinterpretq_s32_m128i(b)))); -} - -// Packs the 8 unsigned 32-bit integers from a and b into unsigned 16-bit -// integers and saturates. -// -// r0 := UnsignedSaturate(a0) -// r1 := UnsignedSaturate(a1) -// r2 := UnsignedSaturate(a2) -// r3 := UnsignedSaturate(a3) -// r4 := UnsignedSaturate(b0) -// r5 := UnsignedSaturate(b1) -// r6 := UnsignedSaturate(b2) -// r7 := UnsignedSaturate(b3) -FORCE_INLINE __m128i _mm_packus_epi32(__m128i a, __m128i b) +// Compare packed unsigned 16-bit integers in a and b, and store packed maximum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu16 +FORCE_INLINE __m128i _mm_max_epu16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( - vcombine_u16(vqmovun_s32(vreinterpretq_s32_m128i(a)), - vqmovun_s32(vreinterpretq_s32_m128i(b)))); + vmaxq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); } -// Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower -// 8 signed or unsigned 8-bit integers in b. -// -// r0 := a0 -// r1 := b0 -// r2 := a1 -// r3 := b1 -// ... -// r14 := a7 -// r15 := b7 -// -// https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx -FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b) +// Compare packed unsigned 32-bit integers in a and b, and store packed maximum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 +FORCE_INLINE __m128i _mm_max_epu32(__m128i a, __m128i b) { -#if defined(__aarch64__) - return vreinterpretq_m128i_s8( - vzip1q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -#else - int8x8_t a1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(a))); - int8x8_t b1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(b))); - int8x8x2_t result = vzip_s8(a1, b1); - return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1])); -#endif + return vreinterpretq_m128i_u32( + vmaxq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b))); } -// Interleaves the lower 4 signed or unsigned 16-bit integers in a with the -// lower 4 signed or unsigned 16-bit integers in b. +// Computes the pariwise minima of the four signed 32-bit integer values of a +// and b. // -// r0 := a0 -// r1 := b0 -// r2 := a1 -// r3 := b1 -// r4 := a2 -// r5 := b2 -// r6 := a3 -// r7 := b3 +// A 128-bit parameter that can be defined with the following equations: +// r0 := (a0 < b0) ? a0 : b0 +// r1 := (a1 < b1) ? a1 : b1 +// r2 := (a2 < b2) ? a2 : b2 +// r3 := (a3 < b3) ? a3 : b3 // -// https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx -FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b) +// https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx +FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b) { -#if defined(__aarch64__) - return vreinterpretq_m128i_s16( - vzip1q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -#else - int16x4_t a1 = vget_low_s16(vreinterpretq_s16_m128i(a)); - int16x4_t b1 = vget_low_s16(vreinterpretq_s16_m128i(b)); - int16x4x2_t result = vzip_s16(a1, b1); - return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1])); -#endif -} - -// Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the -// lower 2 signed or unsigned 32 - bit integers in b. -// -// r0 := a0 -// r1 := b0 -// r2 := a1 -// r3 := b1 -// -// https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx -FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b) -{ -#if defined(__aarch64__) return vreinterpretq_m128i_s32( - vzip1q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -#else - int32x2_t a1 = vget_low_s32(vreinterpretq_s32_m128i(a)); - int32x2_t b1 = vget_low_s32(vreinterpretq_s32_m128i(b)); - int32x2x2_t result = vzip_s32(a1, b1); - return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1])); -#endif + vminq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } -FORCE_INLINE __m128i _mm_unpacklo_epi64(__m128i a, __m128i b) +// Compare packed signed 8-bit integers in a and b, and store packed minimum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epi8 +FORCE_INLINE __m128i _mm_min_epi8(__m128i a, __m128i b) { - int64x1_t a_l = vget_low_s64(vreinterpretq_s64_m128i(a)); - int64x1_t b_l = vget_low_s64(vreinterpretq_s64_m128i(b)); - return vreinterpretq_m128i_s64(vcombine_s64(a_l, b_l)); -} - -// Selects and interleaves the lower two single-precision, floating-point values -// from a and b. -// -// r0 := a0 -// r1 := b0 -// r2 := a1 -// r3 := b1 -// -// https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx -FORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128_f32( - vzip1q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -#else - float32x2_t a1 = vget_low_f32(vreinterpretq_f32_m128(a)); - float32x2_t b1 = vget_low_f32(vreinterpretq_f32_m128(b)); - float32x2x2_t result = vzip_f32(a1, b1); - return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1])); -#endif -} - -// Unpack and interleave double-precision (64-bit) floating-point elements from -// the low half of a and b, and store the results in dst. -// -// DEFINE INTERLEAVE_QWORDS(src1[127:0], src2[127:0]) { -// dst[63:0] := src1[63:0] -// dst[127:64] := src2[63:0] -// RETURN dst[127:0] -// } -// dst[127:0] := INTERLEAVE_QWORDS(a[127:0], b[127:0]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpacklo_pd -FORCE_INLINE __m128d _mm_unpacklo_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vzip1q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - return vreinterpretq_m128d_s64( - vcombine_s64(vget_low_s64(vreinterpretq_s64_m128d(a)), - vget_low_s64(vreinterpretq_s64_m128d(b)))); -#endif -} - -// Unpack and interleave double-precision (64-bit) floating-point elements from -// the high half of a and b, and store the results in dst. -// -// DEFINE INTERLEAVE_HIGH_QWORDS(src1[127:0], src2[127:0]) { -// dst[63:0] := src1[127:64] -// dst[127:64] := src2[127:64] -// RETURN dst[127:0] -// } -// dst[127:0] := INTERLEAVE_HIGH_QWORDS(a[127:0], b[127:0]) -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpackhi_pd -FORCE_INLINE __m128d _mm_unpackhi_pd(__m128d a, __m128d b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128d_f64( - vzip2q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); -#else - return vreinterpretq_m128d_s64( - vcombine_s64(vget_high_s64(vreinterpretq_s64_m128d(a)), - vget_high_s64(vreinterpretq_s64_m128d(b)))); -#endif -} - -// Selects and interleaves the upper two single-precision, floating-point values -// from a and b. -// -// r0 := a2 -// r1 := b2 -// r2 := a3 -// r3 := b3 -// -// https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx -FORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b) -{ -#if defined(__aarch64__) - return vreinterpretq_m128_f32( - vzip2q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); -#else - float32x2_t a1 = vget_high_f32(vreinterpretq_f32_m128(a)); - float32x2_t b1 = vget_high_f32(vreinterpretq_f32_m128(b)); - float32x2x2_t result = vzip_f32(a1, b1); - return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1])); -#endif -} - -// Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper -// 8 signed or unsigned 8-bit integers in b. -// -// r0 := a8 -// r1 := b8 -// r2 := a9 -// r3 := b9 -// ... -// r14 := a15 -// r15 := b15 -// -// https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx -FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b) -{ -#if defined(__aarch64__) return vreinterpretq_m128i_s8( - vzip2q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); -#else - int8x8_t a1 = - vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(a))); - int8x8_t b1 = - vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(b))); - int8x8x2_t result = vzip_s8(a1, b1); - return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1])); -#endif + vminq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } -// Interleaves the upper 4 signed or unsigned 16-bit integers in a with the -// upper 4 signed or unsigned 16-bit integers in b. -// -// r0 := a4 -// r1 := b4 -// r2 := a5 -// r3 := b5 -// r4 := a6 -// r5 := b6 -// r6 := a7 -// r7 := b7 -// -// https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx -FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b) +// Compare packed unsigned 16-bit integers in a and b, and store packed minimum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epu16 +FORCE_INLINE __m128i _mm_min_epu16(__m128i a, __m128i b) { -#if defined(__aarch64__) - return vreinterpretq_m128i_s16( - vzip2q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); -#else - int16x4_t a1 = vget_high_s16(vreinterpretq_s16_m128i(a)); - int16x4_t b1 = vget_high_s16(vreinterpretq_s16_m128i(b)); - int16x4x2_t result = vzip_s16(a1, b1); - return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1])); -#endif + return vreinterpretq_m128i_u16( + vminq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); } -// Interleaves the upper 2 signed or unsigned 32-bit integers in a with the -// upper 2 signed or unsigned 32-bit integers in b. -// https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx -FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b) +// Compare packed unsigned 32-bit integers in a and b, and store packed minimum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 +FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b) { -#if defined(__aarch64__) - return vreinterpretq_m128i_s32( - vzip2q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); -#else - int32x2_t a1 = vget_high_s32(vreinterpretq_s32_m128i(a)); - int32x2_t b1 = vget_high_s32(vreinterpretq_s32_m128i(b)); - int32x2x2_t result = vzip_s32(a1, b1); - return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1])); -#endif -} - -// Interleaves the upper signed or unsigned 64-bit integer in a with the -// upper signed or unsigned 64-bit integer in b. -// -// r0 := a1 -// r1 := b1 -FORCE_INLINE __m128i _mm_unpackhi_epi64(__m128i a, __m128i b) -{ - int64x1_t a_h = vget_high_s64(vreinterpretq_s64_m128i(a)); - int64x1_t b_h = vget_high_s64(vreinterpretq_s64_m128i(b)); - return vreinterpretq_m128i_s64(vcombine_s64(a_h, b_h)); + return vreinterpretq_m128i_u32( + vminq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b))); } // Horizontally compute the minimum amongst the packed unsigned 16-bit integers @@ -6837,6 +7981,339 @@ FORCE_INLINE __m128i _mm_minpos_epu16(__m128i a) return dst; } +// Compute the sum of absolute differences (SADs) of quadruplets of unsigned +// 8-bit integers in a compared to those in b, and store the 16-bit results in +// dst. Eight SADs are performed using one quadruplet from b and eight +// quadruplets from a. One quadruplet is selected from b starting at on the +// offset specified in imm8. Eight quadruplets are formed from sequential 8-bit +// integers selected from a starting at the offset specified in imm8. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mpsadbw_epu8 +FORCE_INLINE __m128i _mm_mpsadbw_epu8(__m128i a, __m128i b, const int imm) +{ + uint8x16_t _a, _b; + + switch (imm & 0x4) { + case 0: + // do nothing + _a = vreinterpretq_u8_m128i(a); + break; + case 4: + _a = vreinterpretq_u8_u32(vextq_u32(vreinterpretq_u32_m128i(a), + vreinterpretq_u32_m128i(a), 1)); + break; + default: +#if defined(__GNUC__) || defined(__clang__) + __builtin_unreachable(); +#endif + break; + } + + switch (imm & 0x3) { + case 0: + _b = vreinterpretq_u8_u32( + vdupq_n_u32(vgetq_lane_u32(vreinterpretq_u32_m128i(b), 0))); + break; + case 1: + _b = vreinterpretq_u8_u32( + vdupq_n_u32(vgetq_lane_u32(vreinterpretq_u32_m128i(b), 1))); + break; + case 2: + _b = vreinterpretq_u8_u32( + vdupq_n_u32(vgetq_lane_u32(vreinterpretq_u32_m128i(b), 2))); + break; + case 3: + _b = vreinterpretq_u8_u32( + vdupq_n_u32(vgetq_lane_u32(vreinterpretq_u32_m128i(b), 3))); + break; + default: +#if defined(__GNUC__) || defined(__clang__) + __builtin_unreachable(); +#endif + break; + } + + int16x8_t c04, c15, c26, c37; + uint8x8_t low_b = vget_low_u8(_b); + c04 = vabsq_s16(vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(_a), low_b))); + _a = vextq_u8(_a, _a, 1); + c15 = vabsq_s16(vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(_a), low_b))); + _a = vextq_u8(_a, _a, 1); + c26 = vabsq_s16(vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(_a), low_b))); + _a = vextq_u8(_a, _a, 1); + c37 = vabsq_s16(vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(_a), low_b))); +#if defined(__aarch64__) + // |0|4|2|6| + c04 = vpaddq_s16(c04, c26); + // |1|5|3|7| + c15 = vpaddq_s16(c15, c37); + + int32x4_t trn1_c = + vtrn1q_s32(vreinterpretq_s32_s16(c04), vreinterpretq_s32_s16(c15)); + int32x4_t trn2_c = + vtrn2q_s32(vreinterpretq_s32_s16(c04), vreinterpretq_s32_s16(c15)); + return vreinterpretq_m128i_s16(vpaddq_s16(vreinterpretq_s16_s32(trn1_c), + vreinterpretq_s16_s32(trn2_c))); +#else + int16x4_t c01, c23, c45, c67; + c01 = vpadd_s16(vget_low_s16(c04), vget_low_s16(c15)); + c23 = vpadd_s16(vget_low_s16(c26), vget_low_s16(c37)); + c45 = vpadd_s16(vget_high_s16(c04), vget_high_s16(c15)); + c67 = vpadd_s16(vget_high_s16(c26), vget_high_s16(c37)); + + return vreinterpretq_m128i_s16( + vcombine_s16(vpadd_s16(c01, c23), vpadd_s16(c45, c67))); +#endif +} + +// Multiply the low signed 32-bit integers from each packed 64-bit element in +// a and b, and store the signed 64-bit results in dst. +// +// r0 := (int64_t)(int32_t)a0 * (int64_t)(int32_t)b0 +// r1 := (int64_t)(int32_t)a2 * (int64_t)(int32_t)b2 +FORCE_INLINE __m128i _mm_mul_epi32(__m128i a, __m128i b) +{ + // vmull_s32 upcasts instead of masking, so we downcast. + int32x2_t a_lo = vmovn_s64(vreinterpretq_s64_m128i(a)); + int32x2_t b_lo = vmovn_s64(vreinterpretq_s64_m128i(b)); + return vreinterpretq_m128i_s64(vmull_s32(a_lo, b_lo)); +} + +// Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or +// unsigned 32-bit integers from b. +// https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx +FORCE_INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vmulq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Packs the 8 unsigned 32-bit integers from a and b into unsigned 16-bit +// integers and saturates. +// +// r0 := UnsignedSaturate(a0) +// r1 := UnsignedSaturate(a1) +// r2 := UnsignedSaturate(a2) +// r3 := UnsignedSaturate(a3) +// r4 := UnsignedSaturate(b0) +// r5 := UnsignedSaturate(b1) +// r6 := UnsignedSaturate(b2) +// r7 := UnsignedSaturate(b3) +FORCE_INLINE __m128i _mm_packus_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vcombine_u16(vqmovun_s32(vreinterpretq_s32_m128i(a)), + vqmovun_s32(vreinterpretq_s32_m128i(b)))); +} + +// Round the packed double-precision (64-bit) floating-point elements in a using +// the rounding parameter, and store the results as packed double-precision +// floating-point elements in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_pd +FORCE_INLINE __m128d _mm_round_pd(__m128d a, int rounding) +{ +#if defined(__aarch64__) + switch (rounding) { + case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC): + return vreinterpretq_m128d_f64(vrndnq_f64(vreinterpretq_f64_m128d(a))); + case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC): + return _mm_floor_pd(a); + case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC): + return _mm_ceil_pd(a); + case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC): + return vreinterpretq_m128d_f64(vrndq_f64(vreinterpretq_f64_m128d(a))); + default: //_MM_FROUND_CUR_DIRECTION + return vreinterpretq_m128d_f64(vrndiq_f64(vreinterpretq_f64_m128d(a))); + } +#else + double *v_double = (double *) &a; + + if (rounding == (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) || + (rounding == _MM_FROUND_CUR_DIRECTION && + _MM_GET_ROUNDING_MODE() == _MM_ROUND_NEAREST)) { + double res[2], tmp; + for (int i = 0; i < 2; i++) { + tmp = (v_double[i] < 0) ? -v_double[i] : v_double[i]; + double roundDown = floor(tmp); // Round down value + double roundUp = ceil(tmp); // Round up value + double diffDown = tmp - roundDown; + double diffUp = roundUp - tmp; + if (diffDown < diffUp) { + /* If it's closer to the round down value, then use it */ + res[i] = roundDown; + } else if (diffDown > diffUp) { + /* If it's closer to the round up value, then use it */ + res[i] = roundUp; + } else { + /* If it's equidistant between round up and round down value, + * pick the one which is an even number */ + double half = roundDown / 2; + if (half != floor(half)) { + /* If the round down value is odd, return the round up value + */ + res[i] = roundUp; + } else { + /* If the round up value is odd, return the round down value + */ + res[i] = roundDown; + } + } + res[i] = (v_double[i] < 0) ? -res[i] : res[i]; + } + return _mm_set_pd(res[1], res[0]); + } else if (rounding == (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC) || + (rounding == _MM_FROUND_CUR_DIRECTION && + _MM_GET_ROUNDING_MODE() == _MM_ROUND_DOWN)) { + return _mm_floor_pd(a); + } else if (rounding == (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC) || + (rounding == _MM_FROUND_CUR_DIRECTION && + _MM_GET_ROUNDING_MODE() == _MM_ROUND_UP)) { + return _mm_ceil_pd(a); + } + return _mm_set_pd(v_double[1] > 0 ? floor(v_double[1]) : ceil(v_double[1]), + v_double[0] > 0 ? floor(v_double[0]) : ceil(v_double[0])); +#endif +} + +// Round the packed single-precision (32-bit) floating-point elements in a using +// the rounding parameter, and store the results as packed single-precision +// floating-point elements in dst. +// software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ps +FORCE_INLINE __m128 _mm_round_ps(__m128 a, int rounding) +{ +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) + switch (rounding) { + case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC): + return vreinterpretq_m128_f32(vrndnq_f32(vreinterpretq_f32_m128(a))); + case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC): + return _mm_floor_ps(a); + case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC): + return _mm_ceil_ps(a); + case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC): + return vreinterpretq_m128_f32(vrndq_f32(vreinterpretq_f32_m128(a))); + default: //_MM_FROUND_CUR_DIRECTION + return vreinterpretq_m128_f32(vrndiq_f32(vreinterpretq_f32_m128(a))); + } +#else + float *v_float = (float *) &a; + + if (rounding == (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) || + (rounding == _MM_FROUND_CUR_DIRECTION && + _MM_GET_ROUNDING_MODE() == _MM_ROUND_NEAREST)) { + uint32x4_t signmask = vdupq_n_u32(0x80000000); + float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a), + vdupq_n_f32(0.5f)); /* +/- 0.5 */ + int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32( + vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/ + int32x4_t r_trunc = vcvtq_s32_f32( + vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */ + int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32( + vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */ + int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone), + vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */ + float32x4_t delta = vsubq_f32( + vreinterpretq_f32_m128(a), + vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */ + uint32x4_t is_delta_half = + vceqq_f32(delta, half); /* delta == +/- 0.5 */ + return vreinterpretq_m128_f32( + vcvtq_f32_s32(vbslq_s32(is_delta_half, r_even, r_normal))); + } else if (rounding == (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC) || + (rounding == _MM_FROUND_CUR_DIRECTION && + _MM_GET_ROUNDING_MODE() == _MM_ROUND_DOWN)) { + return _mm_floor_ps(a); + } else if (rounding == (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC) || + (rounding == _MM_FROUND_CUR_DIRECTION && + _MM_GET_ROUNDING_MODE() == _MM_ROUND_UP)) { + return _mm_ceil_ps(a); + } + return _mm_set_ps(v_float[3] > 0 ? floorf(v_float[3]) : ceilf(v_float[3]), + v_float[2] > 0 ? floorf(v_float[2]) : ceilf(v_float[2]), + v_float[1] > 0 ? floorf(v_float[1]) : ceilf(v_float[1]), + v_float[0] > 0 ? floorf(v_float[0]) : ceilf(v_float[0])); +#endif +} + +// Round the lower double-precision (64-bit) floating-point element in b using +// the rounding parameter, store the result as a double-precision floating-point +// element in the lower element of dst, and copy the upper element from a to the +// upper element of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_sd +FORCE_INLINE __m128d _mm_round_sd(__m128d a, __m128d b, int rounding) +{ + return _mm_move_sd(a, _mm_round_pd(b, rounding)); +} + +// Round the lower single-precision (32-bit) floating-point element in b using +// the rounding parameter, store the result as a single-precision floating-point +// element in the lower element of dst, and copy the upper 3 packed elements +// from a to the upper elements of dst. Rounding is done according to the +// rounding[3:0] parameter, which can be one of: +// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and +// suppress exceptions +// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and +// suppress exceptions +// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress +// exceptions +// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress +// exceptions _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see +// _MM_SET_ROUNDING_MODE +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ss +FORCE_INLINE __m128 _mm_round_ss(__m128 a, __m128 b, int rounding) +{ + return _mm_move_ss(a, _mm_round_ps(b, rounding)); +} + +// Load 128-bits of integer data from memory into dst using a non-temporal +// memory hint. mem_addr must be aligned on a 16-byte boundary or a +// general-protection exception may be generated. +// +// dst[127:0] := MEM[mem_addr+127:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_load_si128 +FORCE_INLINE __m128i _mm_stream_load_si128(__m128i *p) +{ +#if __has_builtin(__builtin_nontemporal_store) + return __builtin_nontemporal_load(p); +#else + return vreinterpretq_m128i_s64(vld1q_s64((int64_t *) p)); +#endif +} + +// Compute the bitwise NOT of a and then AND with a 128-bit vector containing +// all 1's, and return 1 if the result is zero, otherwise return 0. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_ones +FORCE_INLINE int _mm_test_all_ones(__m128i a) +{ + return (uint64_t) (vgetq_lane_s64(a, 0) & vgetq_lane_s64(a, 1)) == + ~(uint64_t) 0; +} + +// Compute the bitwise AND of 128 bits (representing integer data) in a and +// mask, and return 1 if the result is zero, otherwise return 0. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_zeros +FORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask) +{ + int64x2_t a_and_mask = + vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(mask)); + return !(vgetq_lane_s64(a_and_mask, 0) | vgetq_lane_s64(a_and_mask, 1)); +} + +// Compute the bitwise AND of 128 bits (representing integer data) in a and +// mask, and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute +// the bitwise NOT of a and then AND with mask, and set CF to 1 if the result is +// zero, otherwise set CF to 0. Return 1 if both the ZF and CF values are zero, +// otherwise return 0. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_test_mix_ones_zero +FORCE_INLINE int _mm_test_mix_ones_zeros(__m128i a, __m128i mask) +{ + uint64x2_t zf = + vandq_u64(vreinterpretq_u64_m128i(mask), vreinterpretq_u64_m128i(a)); + uint64x2_t cf = + vbicq_u64(vreinterpretq_u64_m128i(mask), vreinterpretq_u64_m128i(a)); + uint64x2_t result = vandq_u64(zf, cf); + return !(vgetq_lane_u64(result, 0) | vgetq_lane_u64(result, 1)); +} + // Compute the bitwise AND of 128 bits (representing integer data) in a and b, // and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the // bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, @@ -6850,6 +8327,14 @@ FORCE_INLINE int _mm_testc_si128(__m128i a, __m128i b) return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1)); } +// Compute the bitwise AND of 128 bits (representing integer data) in a and b, +// and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the +// bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, +// otherwise set CF to 0. Return 1 if both the ZF and CF values are zero, +// otherwise return 0. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testnzc_si128 +#define _mm_testnzc_si128(a, b) _mm_test_mix_ones_zeros(a, b) + // Compute the bitwise AND of 128 bits (representing integer data) in a and b, // and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the // bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, @@ -6862,305 +8347,99 @@ FORCE_INLINE int _mm_testz_si128(__m128i a, __m128i b) return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1)); } -// Extracts the selected signed or unsigned 8-bit integer from a and zero -// extends. -// FORCE_INLINE int _mm_extract_epi8(__m128i a, __constrange(0,16) int imm) -#define _mm_extract_epi8(a, imm) vgetq_lane_u8(vreinterpretq_u8_m128i(a), (imm)) +/* SSE4.2 */ -// Inserts the least significant 8 bits of b into the selected 8-bit integer -// of a. -// FORCE_INLINE __m128i _mm_insert_epi8(__m128i a, int b, -// __constrange(0,16) int imm) -#define _mm_insert_epi8(a, b, imm) \ - __extension__({ \ - vreinterpretq_m128i_s8( \ - vsetq_lane_s8((b), vreinterpretq_s8_m128i(a), (imm))); \ - }) - -// Extracts the selected signed or unsigned 16-bit integer from a and zero -// extends. -// https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx -// FORCE_INLINE int _mm_extract_epi16(__m128i a, __constrange(0,8) int imm) -#define _mm_extract_epi16(a, imm) \ - vgetq_lane_u16(vreinterpretq_u16_m128i(a), (imm)) - -// Extract a 16-bit integer from a, selected with imm8, and store the result in -// the lower element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_extract_pi16 -#define _mm_extract_pi16(a, imm) \ - (int32_t) vget_lane_u16(vreinterpret_u16_m64(a), (imm)) - -// Inserts the least significant 16 bits of b into the selected 16-bit integer -// of a. -// https://msdn.microsoft.com/en-us/library/kaze8hz1%28v=vs.100%29.aspx -// FORCE_INLINE __m128i _mm_insert_epi16(__m128i a, int b, -// __constrange(0,8) int imm) -#define _mm_insert_epi16(a, b, imm) \ - __extension__({ \ - vreinterpretq_m128i_s16( \ - vsetq_lane_s16((b), vreinterpretq_s16_m128i(a), (imm))); \ - }) - -// Copy a to dst, and insert the 16-bit integer i into dst at the location -// specified by imm8. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_insert_pi16 -#define _mm_insert_pi16(a, b, imm) \ - __extension__({ \ - vreinterpret_m64_s16( \ - vset_lane_s16((b), vreinterpret_s16_m64(a), (imm))); \ - }) - -// Extracts the selected signed or unsigned 32-bit integer from a and zero -// extends. -// FORCE_INLINE int _mm_extract_epi32(__m128i a, __constrange(0,4) int imm) -#define _mm_extract_epi32(a, imm) \ - vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)) - -// Extracts the selected single-precision (32-bit) floating-point from a. -// FORCE_INLINE int _mm_extract_ps(__m128 a, __constrange(0,4) int imm) -#define _mm_extract_ps(a, imm) vgetq_lane_s32(vreinterpretq_s32_m128(a), (imm)) - -// Inserts the least significant 32 bits of b into the selected 32-bit integer -// of a. -// FORCE_INLINE __m128i _mm_insert_epi32(__m128i a, int b, -// __constrange(0,4) int imm) -#define _mm_insert_epi32(a, b, imm) \ - __extension__({ \ - vreinterpretq_m128i_s32( \ - vsetq_lane_s32((b), vreinterpretq_s32_m128i(a), (imm))); \ - }) - -// Extracts the selected signed or unsigned 64-bit integer from a and zero -// extends. -// FORCE_INLINE __int64 _mm_extract_epi64(__m128i a, __constrange(0,2) int imm) -#define _mm_extract_epi64(a, imm) \ - vgetq_lane_s64(vreinterpretq_s64_m128i(a), (imm)) - -// Inserts the least significant 64 bits of b into the selected 64-bit integer -// of a. -// FORCE_INLINE __m128i _mm_insert_epi64(__m128i a, __int64 b, -// __constrange(0,2) int imm) -#define _mm_insert_epi64(a, b, imm) \ - __extension__({ \ - vreinterpretq_m128i_s64( \ - vsetq_lane_s64((b), vreinterpretq_s64_m128i(a), (imm))); \ - }) - -// Count the number of bits set to 1 in unsigned 32-bit integer a, and -// return that count in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u32 -FORCE_INLINE int _mm_popcnt_u32(unsigned int a) +// Compares the 2 signed 64-bit integers in a and the 2 signed 64-bit integers +// in b for greater than. +FORCE_INLINE __m128i _mm_cmpgt_epi64(__m128i a, __m128i b) { #if defined(__aarch64__) -#if __has_builtin(__builtin_popcount) - return __builtin_popcount(a); + return vreinterpretq_m128i_u64( + vcgtq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); #else - return (int) vaddlv_u8(vcnt_u8(vcreate_u8((uint64_t) a))); -#endif -#else - uint32_t count = 0; - uint8x8_t input_val, count8x8_val; - uint16x4_t count16x4_val; - uint32x2_t count32x2_val; - - input_val = vld1_u8((uint8_t *) &a); - count8x8_val = vcnt_u8(input_val); - count16x4_val = vpaddl_u8(count8x8_val); - count32x2_val = vpaddl_u16(count16x4_val); - - vst1_u32(&count, count32x2_val); - return count; + return vreinterpretq_m128i_s64(vshrq_n_s64( + vqsubq_s64(vreinterpretq_s64_m128i(b), vreinterpretq_s64_m128i(a)), + 63)); #endif } -// Count the number of bits set to 1 in unsigned 64-bit integer a, and -// return that count in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u64 -FORCE_INLINE int64_t _mm_popcnt_u64(uint64_t a) +// Starting with the initial value in crc, accumulates a CRC32 value for +// unsigned 16-bit integer v. +// https://msdn.microsoft.com/en-us/library/bb531411(v=vs.100) +FORCE_INLINE uint32_t _mm_crc32_u16(uint32_t crc, uint16_t v) { -#if defined(__aarch64__) -#if __has_builtin(__builtin_popcountll) - return __builtin_popcountll(a); +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + __asm__ __volatile__("crc32ch %w[c], %w[c], %w[v]\n\t" + : [c] "+r"(crc) + : [v] "r"(v)); +#elif (__ARM_ARCH == 8) && defined(__ARM_FEATURE_CRC32) + crc = __crc32ch(crc, v); #else - return (int64_t) vaddlv_u8(vcnt_u8(vcreate_u8(a))); -#endif -#else - uint64_t count = 0; - uint8x8_t input_val, count8x8_val; - uint16x4_t count16x4_val; - uint32x2_t count32x2_val; - uint64x1_t count64x1_val; - - input_val = vld1_u8((uint8_t *) &a); - count8x8_val = vcnt_u8(input_val); - count16x4_val = vpaddl_u8(count8x8_val); - count32x2_val = vpaddl_u16(count16x4_val); - count64x1_val = vpaddl_u32(count32x2_val); - vst1_u64(&count, count64x1_val); - return count; + crc = _mm_crc32_u8(crc, v & 0xff); + crc = _mm_crc32_u8(crc, (v >> 8) & 0xff); #endif + return crc; } -// Macro: Transpose the 4x4 matrix formed by the 4 rows of single-precision -// (32-bit) floating-point elements in row0, row1, row2, and row3, and store the -// transposed matrix in these vectors (row0 now contains column 0, etc.). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=MM_TRANSPOSE4_PS -#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \ - do { \ - float32x4x2_t ROW01 = vtrnq_f32(row0, row1); \ - float32x4x2_t ROW23 = vtrnq_f32(row2, row3); \ - row0 = vcombine_f32(vget_low_f32(ROW01.val[0]), \ - vget_low_f32(ROW23.val[0])); \ - row1 = vcombine_f32(vget_low_f32(ROW01.val[1]), \ - vget_low_f32(ROW23.val[1])); \ - row2 = vcombine_f32(vget_high_f32(ROW01.val[0]), \ - vget_high_f32(ROW23.val[0])); \ - row3 = vcombine_f32(vget_high_f32(ROW01.val[1]), \ - vget_high_f32(ROW23.val[1])); \ - } while (0) - -/* Crypto Extensions */ - -#if defined(__ARM_FEATURE_CRYPTO) -// Wraps vmull_p64 -FORCE_INLINE uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b) +// Starting with the initial value in crc, accumulates a CRC32 value for +// unsigned 32-bit integer v. +// https://msdn.microsoft.com/en-us/library/bb531394(v=vs.100) +FORCE_INLINE uint32_t _mm_crc32_u32(uint32_t crc, uint32_t v) { - poly64_t a = vget_lane_p64(vreinterpret_p64_u64(_a), 0); - poly64_t b = vget_lane_p64(vreinterpret_p64_u64(_b), 0); - return vreinterpretq_u64_p128(vmull_p64(a, b)); -} -#else // ARMv7 polyfill -// ARMv7/some A64 lacks vmull_p64, but it has vmull_p8. -// -// vmull_p8 calculates 8 8-bit->16-bit polynomial multiplies, but we need a -// 64-bit->128-bit polynomial multiply. -// -// It needs some work and is somewhat slow, but it is still faster than all -// known scalar methods. -// -// Algorithm adapted to C from -// https://www.workofard.com/2017/07/ghash-for-low-end-cores/, which is adapted -// from "Fast Software Polynomial Multiplication on ARM Processors Using the -// NEON Engine" by Danilo Camara, Conrado Gouvea, Julio Lopez and Ricardo Dahab -// (https://hal.inria.fr/hal-01506572) -static uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b) -{ - poly8x8_t a = vreinterpret_p8_u64(_a); - poly8x8_t b = vreinterpret_p8_u64(_b); - - // Masks - uint8x16_t k48_32 = vcombine_u8(vcreate_u8(0x0000ffffffffffff), - vcreate_u8(0x00000000ffffffff)); - uint8x16_t k16_00 = vcombine_u8(vcreate_u8(0x000000000000ffff), - vcreate_u8(0x0000000000000000)); - - // Do the multiplies, rotating with vext to get all combinations - uint8x16_t d = vreinterpretq_u8_p16(vmull_p8(a, b)); // D = A0 * B0 - uint8x16_t e = - vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 1))); // E = A0 * B1 - uint8x16_t f = - vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 1), b)); // F = A1 * B0 - uint8x16_t g = - vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 2))); // G = A0 * B2 - uint8x16_t h = - vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 2), b)); // H = A2 * B0 - uint8x16_t i = - vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 3))); // I = A0 * B3 - uint8x16_t j = - vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 3), b)); // J = A3 * B0 - uint8x16_t k = - vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 4))); // L = A0 * B4 - - // Add cross products - uint8x16_t l = veorq_u8(e, f); // L = E + F - uint8x16_t m = veorq_u8(g, h); // M = G + H - uint8x16_t n = veorq_u8(i, j); // N = I + J - - // Interleave. Using vzip1 and vzip2 prevents Clang from emitting TBL - // instructions. -#if defined(__aarch64__) - uint8x16_t lm_p0 = vreinterpretq_u8_u64( - vzip1q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m))); - uint8x16_t lm_p1 = vreinterpretq_u8_u64( - vzip2q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m))); - uint8x16_t nk_p0 = vreinterpretq_u8_u64( - vzip1q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k))); - uint8x16_t nk_p1 = vreinterpretq_u8_u64( - vzip2q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k))); +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + __asm__ __volatile__("crc32cw %w[c], %w[c], %w[v]\n\t" + : [c] "+r"(crc) + : [v] "r"(v)); +#elif (__ARM_ARCH == 8) && defined(__ARM_FEATURE_CRC32) + crc = __crc32cw(crc, v); #else - uint8x16_t lm_p0 = vcombine_u8(vget_low_u8(l), vget_low_u8(m)); - uint8x16_t lm_p1 = vcombine_u8(vget_high_u8(l), vget_high_u8(m)); - uint8x16_t nk_p0 = vcombine_u8(vget_low_u8(n), vget_low_u8(k)); - uint8x16_t nk_p1 = vcombine_u8(vget_high_u8(n), vget_high_u8(k)); + crc = _mm_crc32_u16(crc, v & 0xffff); + crc = _mm_crc32_u16(crc, (v >> 16) & 0xffff); #endif - // t0 = (L) (P0 + P1) << 8 - // t1 = (M) (P2 + P3) << 16 - uint8x16_t t0t1_tmp = veorq_u8(lm_p0, lm_p1); - uint8x16_t t0t1_h = vandq_u8(lm_p1, k48_32); - uint8x16_t t0t1_l = veorq_u8(t0t1_tmp, t0t1_h); - - // t2 = (N) (P4 + P5) << 24 - // t3 = (K) (P6 + P7) << 32 - uint8x16_t t2t3_tmp = veorq_u8(nk_p0, nk_p1); - uint8x16_t t2t3_h = vandq_u8(nk_p1, k16_00); - uint8x16_t t2t3_l = veorq_u8(t2t3_tmp, t2t3_h); - - // De-interleave -#if defined(__aarch64__) - uint8x16_t t0 = vreinterpretq_u8_u64( - vuzp1q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h))); - uint8x16_t t1 = vreinterpretq_u8_u64( - vuzp2q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h))); - uint8x16_t t2 = vreinterpretq_u8_u64( - vuzp1q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h))); - uint8x16_t t3 = vreinterpretq_u8_u64( - vuzp2q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h))); -#else - uint8x16_t t1 = vcombine_u8(vget_high_u8(t0t1_l), vget_high_u8(t0t1_h)); - uint8x16_t t0 = vcombine_u8(vget_low_u8(t0t1_l), vget_low_u8(t0t1_h)); - uint8x16_t t3 = vcombine_u8(vget_high_u8(t2t3_l), vget_high_u8(t2t3_h)); - uint8x16_t t2 = vcombine_u8(vget_low_u8(t2t3_l), vget_low_u8(t2t3_h)); -#endif - // Shift the cross products - uint8x16_t t0_shift = vextq_u8(t0, t0, 15); // t0 << 8 - uint8x16_t t1_shift = vextq_u8(t1, t1, 14); // t1 << 16 - uint8x16_t t2_shift = vextq_u8(t2, t2, 13); // t2 << 24 - uint8x16_t t3_shift = vextq_u8(t3, t3, 12); // t3 << 32 - - // Accumulate the products - uint8x16_t cross1 = veorq_u8(t0_shift, t1_shift); - uint8x16_t cross2 = veorq_u8(t2_shift, t3_shift); - uint8x16_t mix = veorq_u8(d, cross1); - uint8x16_t r = veorq_u8(mix, cross2); - return vreinterpretq_u64_u8(r); + return crc; } -#endif // ARMv7 polyfill -// Perform a carry-less multiplication of two 64-bit integers, selected from a -// and b according to imm8, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_clmulepi64_si128 -FORCE_INLINE __m128i _mm_clmulepi64_si128(__m128i _a, __m128i _b, const int imm) +// Starting with the initial value in crc, accumulates a CRC32 value for +// unsigned 64-bit integer v. +// https://msdn.microsoft.com/en-us/library/bb514033(v=vs.100) +FORCE_INLINE uint64_t _mm_crc32_u64(uint64_t crc, uint64_t v) { - uint64x2_t a = vreinterpretq_u64_m128i(_a); - uint64x2_t b = vreinterpretq_u64_m128i(_b); - switch (imm & 0x11) { - case 0x00: - return vreinterpretq_m128i_u64( - _sse2neon_vmull_p64(vget_low_u64(a), vget_low_u64(b))); - case 0x01: - return vreinterpretq_m128i_u64( - _sse2neon_vmull_p64(vget_high_u64(a), vget_low_u64(b))); - case 0x10: - return vreinterpretq_m128i_u64( - _sse2neon_vmull_p64(vget_low_u64(a), vget_high_u64(b))); - case 0x11: - return vreinterpretq_m128i_u64( - _sse2neon_vmull_p64(vget_high_u64(a), vget_high_u64(b))); - default: - abort(); +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + __asm__ __volatile__("crc32cx %w[c], %w[c], %x[v]\n\t" + : [c] "+r"(crc) + : [v] "r"(v)); +#else + crc = _mm_crc32_u32((uint32_t) (crc), v & 0xffffffff); + crc = _mm_crc32_u32((uint32_t) (crc), (v >> 32) & 0xffffffff); +#endif + return crc; +} + +// Starting with the initial value in crc, accumulates a CRC32 value for +// unsigned 8-bit integer v. +// https://msdn.microsoft.com/en-us/library/bb514036(v=vs.100) +FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t crc, uint8_t v) +{ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + __asm__ __volatile__("crc32cb %w[c], %w[c], %w[v]\n\t" + : [c] "+r"(crc) + : [v] "r"(v)); +#elif (__ARM_ARCH == 8) && defined(__ARM_FEATURE_CRC32) + crc = __crc32cb(crc, v); +#else + crc ^= v; + for (int bit = 0; bit < 8; bit++) { + if (crc & 1) + crc = (crc >> 1) ^ UINT32_C(0x82f63b78); + else + crc = (crc >> 1); } +#endif + return crc; } +/* AES */ + #if !defined(__ARM_FEATURE_CRYPTO) /* clang-format off */ #define SSE2NEON_AES_DATA(w) \ @@ -7238,7 +8517,7 @@ FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey) v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0xc0), w - 0xc0); // mix columns - w = (v << 1) ^ (uint8x16_t)(((int8x16_t) v >> 7) & 0x1b); + w = (v << 1) ^ (uint8x16_t) (((int8x16_t) v >> 7) & 0x1b); w ^= (uint8x16_t) vrev32q_u16((uint16x8_t) v); w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8)); @@ -7246,9 +8525,9 @@ FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey) return vreinterpretq_m128i_u8(w) ^ RoundKey; #else /* ARMv7-A NEON implementation */ -#define SSE2NEON_AES_B2W(b0, b1, b2, b3) \ - (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | \ - (b0)) +#define SSE2NEON_AES_B2W(b0, b1, b2, b3) \ + (((uint32_t) (b3) << 24) | ((uint32_t) (b2) << 16) | \ + ((uint32_t) (b1) << 8) | (uint32_t) (b0)) #define SSE2NEON_AES_F2(x) ((x << 1) ^ (((x >> 7) & 1) * 0x011b /* WPOLY */)) #define SSE2NEON_AES_F3(x) (SSE2NEON_AES_F2(x) ^ x) #define SSE2NEON_AES_U0(p) \ @@ -7299,22 +8578,22 @@ FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) { /* FIXME: optimized for NEON */ uint8_t v[4][4] = { - [0] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 0)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 5)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 10)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 15)]}, - [1] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 4)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 9)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 14)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 3)]}, - [2] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 8)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 13)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 2)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 7)]}, - [3] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 12)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 1)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 6)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 11)]}, + {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 0)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 5)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 10)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 15)]}, + {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 4)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 9)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 14)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 3)]}, + {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 8)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 13)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 2)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 7)]}, + {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 12)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 1)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 6)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 11)]}, }; for (int i = 0; i < 16; i++) vreinterpretq_nth_u8_m128i(a, i) = @@ -7380,211 +8659,135 @@ FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon) } #endif -/* Streaming Extensions */ +/* Others */ -// Guarantees that every preceding store is globally visible before any -// subsequent store. -// https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx -FORCE_INLINE void _mm_sfence(void) +// Perform a carry-less multiplication of two 64-bit integers, selected from a +// and b according to imm8, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_clmulepi64_si128 +FORCE_INLINE __m128i _mm_clmulepi64_si128(__m128i _a, __m128i _b, const int imm) { - __sync_synchronize(); -} - -// Store 64-bits of integer data from a into memory using a non-temporal memory -// hint. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_pi -FORCE_INLINE void _mm_stream_pi(__m64 *p, __m64 a) -{ - vst1_s64((int64_t *) p, vreinterpret_s64_m64(a)); -} - -// Store 128-bits (composed of 4 packed single-precision (32-bit) floating- -// point elements) from a into memory using a non-temporal memory hint. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_ps -FORCE_INLINE void _mm_stream_ps(float *p, __m128 a) -{ -#if __has_builtin(__builtin_nontemporal_store) - __builtin_nontemporal_store(a, (float32x4_t *) p); -#else - vst1q_f32(p, vreinterpretq_f32_m128(a)); -#endif -} - -// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point -// elements) from a into memory using a non-temporal memory hint. mem_addr must -// be aligned on a 16-byte boundary or a general-protection exception may be -// generated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_pd -FORCE_INLINE void _mm_stream_pd(double *p, __m128d a) -{ -#if __has_builtin(__builtin_nontemporal_store) - __builtin_nontemporal_store(a, (float32x4_t *) p); -#elif defined(__aarch64__) - vst1q_f64(p, vreinterpretq_f64_m128d(a)); -#else - vst1q_s64((int64_t *) p, vreinterpretq_s64_m128d(a)); -#endif -} - -// Stores the data in a to the address p without polluting the caches. If the -// cache line containing address p is already in the cache, the cache will be -// updated. -// https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx -FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a) -{ -#if __has_builtin(__builtin_nontemporal_store) - __builtin_nontemporal_store(a, p); -#else - vst1q_s64((int64_t *) p, vreinterpretq_s64_m128i(a)); -#endif -} - -// Store 32-bit integer a into memory using a non-temporal hint to minimize -// cache pollution. If the cache line containing address mem_addr is already in -// the cache, the cache will be updated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_si32 -FORCE_INLINE void _mm_stream_si32(int *p, int a) -{ - vst1q_lane_s32((int32_t *) p, vdupq_n_s32(a), 0); -} - -// Load 128-bits of integer data from memory into dst using a non-temporal -// memory hint. mem_addr must be aligned on a 16-byte boundary or a -// general-protection exception may be generated. -// -// dst[127:0] := MEM[mem_addr+127:mem_addr] -// -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_load_si128 -FORCE_INLINE __m128i _mm_stream_load_si128(__m128i *p) -{ -#if __has_builtin(__builtin_nontemporal_store) - return __builtin_nontemporal_load(p); -#else - return vreinterpretq_m128i_s64(vld1q_s64((int64_t *) p)); -#endif -} - -// Cache line containing p is flushed and invalidated from all caches in the -// coherency domain. : -// https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx -FORCE_INLINE void _mm_clflush(void const *p) -{ - (void) p; - // no corollary for Neon? -} - -// Allocate aligned blocks of memory. -// https://software.intel.com/en-us/ -// cpp-compiler-developer-guide-and-reference-allocating-and-freeing-aligned-memory-blocks -FORCE_INLINE void *_mm_malloc(size_t size, size_t align) -{ - void *ptr; - if (align == 1) - return malloc(size); - if (align == 2 || (sizeof(void *) == 8 && align == 4)) - align = sizeof(void *); - if (!posix_memalign(&ptr, align, size)) - return ptr; - return NULL; -} - -// Conditionally store 8-bit integer elements from a into memory using mask -// (elements are not stored when the highest bit is not set in the corresponding -// element) and a non-temporal memory hint. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskmove_si64 -FORCE_INLINE void _mm_maskmove_si64(__m64 a, __m64 mask, char *mem_addr) -{ - int8x8_t shr_mask = vshr_n_s8(vreinterpret_s8_m64(mask), 7); - __m128 b = _mm_load_ps((const float *) mem_addr); - int8x8_t masked = - vbsl_s8(vreinterpret_u8_s8(shr_mask), vreinterpret_s8_m64(a), - vreinterpret_s8_u64(vget_low_u64(vreinterpretq_u64_m128(b)))); - vst1_s8((int8_t *) mem_addr, masked); -} - -// Conditionally store 8-bit integer elements from a into memory using mask -// (elements are not stored when the highest bit is not set in the corresponding -// element) and a non-temporal memory hint. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_maskmovq -#define _m_maskmovq(a, mask, mem_addr) _mm_maskmove_si64(a, mask, mem_addr) - -// Free aligned memory that was allocated with _mm_malloc. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_free -FORCE_INLINE void _mm_free(void *addr) -{ - free(addr); -} - -// Starting with the initial value in crc, accumulates a CRC32 value for -// unsigned 8-bit integer v. -// https://msdn.microsoft.com/en-us/library/bb514036(v=vs.100) -FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t crc, uint8_t v) -{ -#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) - __asm__ __volatile__("crc32cb %w[c], %w[c], %w[v]\n\t" - : [c] "+r"(crc) - : [v] "r"(v)); -#else - crc ^= v; - for (int bit = 0; bit < 8; bit++) { - if (crc & 1) - crc = (crc >> 1) ^ UINT32_C(0x82f63b78); - else - crc = (crc >> 1); + uint64x2_t a = vreinterpretq_u64_m128i(_a); + uint64x2_t b = vreinterpretq_u64_m128i(_b); + switch (imm & 0x11) { + case 0x00: + return vreinterpretq_m128i_u64( + _sse2neon_vmull_p64(vget_low_u64(a), vget_low_u64(b))); + case 0x01: + return vreinterpretq_m128i_u64( + _sse2neon_vmull_p64(vget_high_u64(a), vget_low_u64(b))); + case 0x10: + return vreinterpretq_m128i_u64( + _sse2neon_vmull_p64(vget_low_u64(a), vget_high_u64(b))); + case 0x11: + return vreinterpretq_m128i_u64( + _sse2neon_vmull_p64(vget_high_u64(a), vget_high_u64(b))); + default: + abort(); } -#endif - return crc; } -// Starting with the initial value in crc, accumulates a CRC32 value for -// unsigned 16-bit integer v. -// https://msdn.microsoft.com/en-us/library/bb531411(v=vs.100) -FORCE_INLINE uint32_t _mm_crc32_u16(uint32_t crc, uint16_t v) +FORCE_INLINE unsigned int _sse2neon_mm_get_denormals_zero_mode() { -#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) - __asm__ __volatile__("crc32ch %w[c], %w[c], %w[v]\n\t" - : [c] "+r"(crc) - : [v] "r"(v)); + union { + fpcr_bitfield field; +#if defined(__aarch64__) + uint64_t value; #else - crc = _mm_crc32_u8(crc, v & 0xff); - crc = _mm_crc32_u8(crc, (v >> 8) & 0xff); + uint32_t value; #endif - return crc; + } r; + +#if defined(__aarch64__) + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ +#else + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ +#endif + + return r.field.bit24 ? _MM_DENORMALS_ZERO_ON : _MM_DENORMALS_ZERO_OFF; } -// Starting with the initial value in crc, accumulates a CRC32 value for -// unsigned 32-bit integer v. -// https://msdn.microsoft.com/en-us/library/bb531394(v=vs.100) -FORCE_INLINE uint32_t _mm_crc32_u32(uint32_t crc, uint32_t v) +// Count the number of bits set to 1 in unsigned 32-bit integer a, and +// return that count in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u32 +FORCE_INLINE int _mm_popcnt_u32(unsigned int a) { -#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) - __asm__ __volatile__("crc32cw %w[c], %w[c], %w[v]\n\t" - : [c] "+r"(crc) - : [v] "r"(v)); +#if defined(__aarch64__) +#if __has_builtin(__builtin_popcount) + return __builtin_popcount(a); #else - crc = _mm_crc32_u16(crc, v & 0xffff); - crc = _mm_crc32_u16(crc, (v >> 16) & 0xffff); + return (int) vaddlv_u8(vcnt_u8(vcreate_u8((uint64_t) a))); +#endif +#else + uint32_t count = 0; + uint8x8_t input_val, count8x8_val; + uint16x4_t count16x4_val; + uint32x2_t count32x2_val; + + input_val = vld1_u8((uint8_t *) &a); + count8x8_val = vcnt_u8(input_val); + count16x4_val = vpaddl_u8(count8x8_val); + count32x2_val = vpaddl_u16(count16x4_val); + + vst1_u32(&count, count32x2_val); + return count; #endif - return crc; } -// Starting with the initial value in crc, accumulates a CRC32 value for -// unsigned 64-bit integer v. -// https://msdn.microsoft.com/en-us/library/bb514033(v=vs.100) -FORCE_INLINE uint64_t _mm_crc32_u64(uint64_t crc, uint64_t v) +// Count the number of bits set to 1 in unsigned 64-bit integer a, and +// return that count in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u64 +FORCE_INLINE int64_t _mm_popcnt_u64(uint64_t a) { -#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) - __asm__ __volatile__("crc32cx %w[c], %w[c], %x[v]\n\t" - : [c] "+r"(crc) - : [v] "r"(v)); +#if defined(__aarch64__) +#if __has_builtin(__builtin_popcountll) + return __builtin_popcountll(a); #else - crc = _mm_crc32_u32((uint32_t)(crc), v & 0xffffffff); - crc = _mm_crc32_u32((uint32_t)(crc), (v >> 32) & 0xffffffff); + return (int64_t) vaddlv_u8(vcnt_u8(vcreate_u8(a))); +#endif +#else + uint64_t count = 0; + uint8x8_t input_val, count8x8_val; + uint16x4_t count16x4_val; + uint32x2_t count32x2_val; + uint64x1_t count64x1_val; + + input_val = vld1_u8((uint8_t *) &a); + count8x8_val = vcnt_u8(input_val); + count16x4_val = vpaddl_u8(count8x8_val); + count32x2_val = vpaddl_u16(count16x4_val); + count64x1_val = vpaddl_u32(count32x2_val); + vst1_u64(&count, count64x1_val); + return count; #endif - return crc; } -FORCE_INLINE void _mm_empty (void) { } +FORCE_INLINE void _sse2neon_mm_set_denormals_zero_mode(unsigned int flag) +{ + // AArch32 Advanced SIMD arithmetic always uses the Flush-to-zero setting, + // regardless of the value of the FZ bit. + union { + fpcr_bitfield field; +#if defined(__aarch64__) + uint64_t value; +#else + uint32_t value; +#endif + } r; + +#if defined(__aarch64__) + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ +#else + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ +#endif + + r.field.bit24 = (flag & _MM_DENORMALS_ZERO_MASK) == _MM_DENORMALS_ZERO_ON; + +#if defined(__aarch64__) + __asm__ __volatile__("msr FPCR, %0" ::"r"(r)); /* write */ +#else + __asm__ __volatile__("vmsr FPSCR, %0" ::"r"(r)); /* write */ +#endif +} #if defined(__GNUC__) || defined(__clang__) #pragma pop_macro("ALIGN_STRUCT") diff --git a/engine/OcclusionSystem.cpp b/engine/OcclusionSystem.cpp index 86491631..1c3fad1c 100644 --- a/engine/OcclusionSystem.cpp +++ b/engine/OcclusionSystem.cpp @@ -1268,7 +1268,9 @@ void CEdgeList::CullSmallOccluders() // Sort the surfaces by screen area, in descending order int nSurfCount = m_Surfaces.Count(); s_pSortSurfaces = m_Surfaces.Base(); - qsort( m_SurfaceSort.Base(), nSurfCount, sizeof(int), SurfCompare ); + + if( m_SurfaceSort.Base() ) + qsort( m_SurfaceSort.Base(), nSurfCount, sizeof(int), SurfCompare ); // We're going to keep the greater of r_occludermin + All surfaces with a screen area >= r_occluderarea int nMinSurfaces = r_occludermincount.GetInt(); @@ -1282,7 +1284,7 @@ void CEdgeList::CullSmallOccluders() bool *bUseSurface = (bool*)stackalloc( nSurfCount * sizeof(bool) ); memset( bUseSurface, 0, nSurfCount * sizeof(bool) ); - + int i; for ( i = 0; i < nSurfCount; ++i ) { diff --git a/engine/gl_rsurf.cpp b/engine/gl_rsurf.cpp index 82ed85ac..836a3443 100644 --- a/engine/gl_rsurf.cpp +++ b/engine/gl_rsurf.cpp @@ -4099,7 +4099,9 @@ CBrushBatchRender::brushrender_t *CBrushBatchRender::FindOrCreateRenderBatch( mo surfaceList.Sort( SurfaceCmp ); renderT.pPlanes = new cplane_t *[planeList.Count()]; renderT.planeCount = planeList.Count(); - memcpy( renderT.pPlanes, planeList.Base(), sizeof(cplane_t *)*planeList.Count() ); + + if( planeList.Base() ) + memcpy( renderT.pPlanes, planeList.Base(), sizeof(cplane_t *)*planeList.Count() ); renderT.pSurfaces = new brushrendersurface_t[surfaceList.Count()]; renderT.surfaceCount = surfaceList.Count(); diff --git a/game/client/c_rumble.cpp b/game/client/c_rumble.cpp index a22ef884..478cb853 100644 --- a/game/client/c_rumble.cpp +++ b/game/client/c_rumble.cpp @@ -166,7 +166,7 @@ void GenerateSquareWaveEffect( RumbleWaveform_t *pWaveform, const WaveGenParams_ while( i < NUM_WAVE_SAMPLES ) { - for( j = 0 ; j < steps ; j++ ) + for( j = 0 ; j < steps && i < NUM_WAVE_SAMPLES; j++ ) { if( params.leftChannel ) { @@ -177,7 +177,7 @@ void GenerateSquareWaveEffect( RumbleWaveform_t *pWaveform, const WaveGenParams_ pWaveform->amplitude_right[i++] = params.minAmplitude; } } - for( j = 0 ; j < steps ; j++ ) + for( j = 0 ; j < steps && i < NUM_WAVE_SAMPLES; j++ ) { if( params.leftChannel ) { diff --git a/game/client/c_vote_controller.cpp b/game/client/c_vote_controller.cpp index c900c27e..52184061 100644 --- a/game/client/c_vote_controller.cpp +++ b/game/client/c_vote_controller.cpp @@ -33,7 +33,7 @@ void C_VoteController::RecvProxy_VoteType( const CRecvProxyData *pData, void *pS if( pMe->m_iActiveIssueIndex == pData->m_Value.m_Int ) return; - pMe->m_iActiveIssueIndex = pData->m_Value.m_Int; + memcpy( &pMe->m_iActiveIssueIndex, &pData->m_Value.m_Int, sizeof(pData->m_Value.m_Int) ); pMe->m_bTypeDirty = true; // Since the contents of a new vote are in three parts, we can't directly send an event to the Hud @@ -186,4 +186,4 @@ void C_VoteController::FireGameEvent( IGameEvent *event ) } } } -} \ No newline at end of file +} diff --git a/game/client/client_hl1mp.vpc b/game/client/client_hl1mp.vpc new file mode 100644 index 00000000..ef5eddf4 --- /dev/null +++ b/game/client/client_hl1mp.vpc @@ -0,0 +1,109 @@ +//----------------------------------------------------------------------------- +// CLIENT_HL1MP.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro GAMENAME "hl1mp" + +$Include "$SRCDIR\game\client\client_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE;.\hl1,.\hl2,.\hl2\elements,$SRCDIR\game\shared\hl1,$SRCDIR\game\shared\hl2" + $PreprocessorDefinitions "$BASE;HL1_CLIENT_DLL;HL1MP_CLIENT_DLL" + } +} + +$Project "Client (HL1MP)" +{ + $Folder "Source Files" + { + -$File "geiger.cpp" + -$File "history_resource.cpp" + -$File "train.cpp" + + $File "c_team_objectiveresource.cpp" + $File "c_team_objectiveresource.h" + $File "hud_chat.cpp" + $File "$SRCDIR\game\shared\predicted_viewmodel.cpp" + $File "$SRCDIR\game\shared\predicted_viewmodel.h" + + $Folder "HL2 DLL" + { + $File "hl2\c_antlion_dust.cpp" + $File "hl2\c_basehelicopter.cpp" + $File "hl2\c_basehelicopter.h" + $File "hl2\c_basehlcombatweapon.h" + $File "hl2\c_corpse.cpp" + $File "hl2\c_corpse.h" + $File "hl2\c_hl2_playerlocaldata.h" + $File "hl2\c_rotorwash.cpp" + $File "$SRCDIR\game\shared\hl2\citadel_effects_shared.h" + $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.h" + $File "hl2\fx_bugbait.cpp" + $File "$SRCDIR\game\shared\hl2\hl2_shareddefs.h" + $File "hl2\hl_in_main.cpp" + $File "hl2\hl_prediction.cpp" + $File "hl2\vgui_rootpanel_hl2.cpp" + } + + $Folder "HL1 DLL" + { + $File "hl1\hl1_c_legacytempents.cpp" + $File "hl1\hl1_c_player.cpp" + $File "hl1\hl1_c_player.h" + $File "hl1\hl1_c_rpg_rocket.cpp" + $File "hl1\hl1_c_weapon__stubs.cpp" + $File "hl1\hl1_clientmode.cpp" + $File "hl1\hl1_clientmode.h" + $File "hl1\hl1_clientscoreboard.cpp" + $File "hl1\hl1_hud_deathnotice.cpp" + $File "hl1\hl1_fx_gauss.cpp" + $File "hl1\hl1_fx_gibs.cpp" + $File "hl1\hl1_fx_impacts.cpp" + $File "hl1\hl1_fx_shelleject.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_gamemovement.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_gamemovement.h" + $File "hl1\hl1_hud_ammo.cpp" + $File "hl1\hl1_hud_battery.cpp" + $File "hl1\hl1_hud_damageindicator.cpp" + $File "hl1\hl1_hud_damagetiles.cpp" + $File "hl1\hl1_hud_flashlight.cpp" + $File "hl1\hl1_hud_geiger.cpp" + $File "hl1\hl1_hud_health.cpp" + $File "hl1\hl1_hud_history_resource.cpp" + $File "hl1\hl1_hud_numbers.cpp" + $File "hl1\hl1_hud_numbers.h" + $File "hl1\hl1_hud_train.cpp" + $File "hl1\hl1_hud_weaponselection.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_basecombatweapon_shared.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_gamerules.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_player_shared.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_player_shared.h" + $File "$SRCDIR\game\shared\hl1\hl1_usermessages.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_357.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_crossbow.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_egon.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_gauss.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_glock.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_handgrenade.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_hornetgun.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_mp5.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_rpg.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_sachel.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_shotgun.cpp" + $File "$SRCDIR\game\server\hl1\hl1_weapon_crowbar.cpp" + } + + $Folder "HL1MP DLL" + { + $File "hl1\c_hl1mp_player.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_basecombatweapon_shared.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_gamerules.cpp" + } + } +} diff --git a/game/client/hud_vote.h b/game/client/hud_vote.h index 91ba1e9b..33df877d 100644 --- a/game/client/hud_vote.h +++ b/game/client/hud_vote.h @@ -119,6 +119,9 @@ class CHudVote : public vgui::EditablePanel, public CHudElement { DECLARE_CLASS_SIMPLE( CHudVote, vgui::EditablePanel ); +public: + DECLARE_MULTIPLY_INHERITED(); + CHudVote( const char *pElementName ); virtual void LevelInit( void ); diff --git a/game/client/viewrender.cpp b/game/client/viewrender.cpp index 0240c238..f6193ef4 100644 --- a/game/client/viewrender.cpp +++ b/game/client/viewrender.cpp @@ -4010,7 +4010,7 @@ void CRendering3dView::DrawOpaqueRenderables( ERenderDepthMode DepthMode ) } } - if ( 0 && r_threaded_renderables.GetBool() ) + if ( r_threaded_renderables.GetBool() ) { ParallelProcess( "BoneSetupNpcsLast", arrBoneSetupNpcsLast.Base() + numOpaqueEnts - numNpcs, numNpcs, &SetupBonesOnBaseAnimating ); ParallelProcess( "BoneSetupNpcsLast NonNPCs", arrBoneSetupNpcsLast.Base(), numNonNpcsAnimating, &SetupBonesOnBaseAnimating ); diff --git a/game/client/wscript b/game/client/wscript index 56373a8a..3732c8b4 100755 --- a/game/client/wscript +++ b/game/client/wscript @@ -17,7 +17,7 @@ games = { 'hl1': ['client_base.vpc', 'client_hl1.vpc'], 'episodic': ['client_base.vpc', 'client_episodic.vpc'], 'portal': ['client_base.vpc', 'client_portal.vpc'], - 'hl1mp': ['client_base.vpc', 'client_hl1.vpc'], + 'hl1mp': ['client_base.vpc', 'client_hl1mp.vpc'], 'cstrike': ['client_base.vpc', 'client_cstrike.vpc'], 'dod': ['client_base.vpc', 'client_dod.vpc'] } diff --git a/game/server/AI_Criteria.h b/game/server/AI_Criteria.h index 72c54080..e9a2c13f 100644 --- a/game/server/AI_Criteria.h +++ b/game/server/AI_Criteria.h @@ -93,7 +93,7 @@ private: CUtlRBTree< CritEntry_t, short > m_Lookup; }; -#pragma pack(1) +//#pragma pack(1) template struct response_interval_t { @@ -150,7 +150,7 @@ struct AI_ResponseParams responseparams_interval_t predelay; //21 }; -#pragma pack() +//#pragma pack() //----------------------------------------------------------------------------- // Purpose: Generic container for a response to a match to a criteria set diff --git a/game/server/AI_ResponseSystem.cpp b/game/server/AI_ResponseSystem.cpp index 510a1d4e..7b739679 100644 --- a/game/server/AI_ResponseSystem.cpp +++ b/game/server/AI_ResponseSystem.cpp @@ -44,7 +44,6 @@ inline static char *CopyString( const char *in ) return out; } -#pragma pack(1) class Matcher { public: @@ -542,7 +541,6 @@ struct Rule bool m_bMatchOnce : 1; bool m_bEnabled : 1; }; -#pragma pack() //----------------------------------------------------------------------------- // Purpose: diff --git a/game/server/server_hl1mp.vpc b/game/server/server_hl1mp.vpc new file mode 100644 index 00000000..5692cbda --- /dev/null +++ b/game/server/server_hl1mp.vpc @@ -0,0 +1,179 @@ +//----------------------------------------------------------------------------- +// SERVER_HL1MP.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro GAMENAME "hl1mp" + +$Include "$SRCDIR\game\server\server_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE;$SRCDIR\game\shared\hl1,$SRCDIR\game\shared\hl2,.\hl1,.\hl2" + $PreprocessorDefinitions "$BASE;HL1_DLL;HL1MP_DLL" + } +} + +$Project "Server (HL1MP)" +{ + $Folder "Source Files" + { + $File "hl1\hl1mp_gameinterface.cpp" + $File "basegrenade_concussion.cpp" + $File "basegrenade_contact.cpp" + $File "basegrenade_timed.cpp" + $File "hl2\Func_Monitor.cpp" + $File "GrenadeThrown.cpp" + $File "GrenadeThrown.h" + $File "h_cycler.cpp" + $File "$SRCDIR\game\shared\predicted_viewmodel.cpp" + $File "$SRCDIR\game\shared\predicted_viewmodel.h" + $File "$SRCDIR\game\shared\hl2\survival_gamerules.cpp" + $File "team_spawnpoint.cpp" + $File "team_spawnpoint.h" + $File "$SRCDIR\game\shared\weapon_parse_default.cpp" + + $Folder "HL2 DLL" + { + $File "hl2\ai_behavior_police.h" + $File "hl2\ai_goal_police.h" + $File "hl2\ai_interactions.h" + $File "hl2\antlion_maker.h" + $File "hl2\CBaseSpriteProjectile.cpp" + $File "hl2\CBaseSpriteProjectile.h" + $File "$SRCDIR\game\shared\hl2\citadel_effects_shared.h" + $File "hl2\energy_wave.h" + $File "$SRCDIR\game\shared\hl2\env_alyxemp_shared.h" + $File "$SRCDIR\game\shared\hl2\hl2_shareddefs.h" + $File "$SRCDIR\game\shared\hl2\hl_movedata.h" + $File "hl2\look_door.cpp" + $File "hl2\monster_dummy.cpp" + $File "hl2\npc_metropolice.h" + $File "hl2\npc_playercompanion.h" + $File "npc_Talker.cpp" + $File "npc_Talker.h" + $File "hl2\prop_combine_ball.h" + $File "hl2\script_intro.h" + $File "hl2\vehicle_crane.h" + $File "hl2\weapon_crowbar.h" + $File "hl2\weapon_physcannon.h" + $File "hl2\weapon_stunstick.h" + + $Folder "unused" + { + $File "hl2\grenade_beam.cpp" + $File "hl2\grenade_beam.h" + $File "hl2\grenade_homer.cpp" + $File "hl2\grenade_homer.h" + } + } + + $Folder "HL1 DLL" + { + $File "actanimating.cpp" + $File "actanimating.h" + $File "hl1\hl1_ai_basenpc.cpp" + $File "hl1\hl1_ai_basenpc.h" + $File "hl1\hl1_basecombatweapon.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_basecombatweapon_shared.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_basecombatweapon_shared.h" + $File "hl1\hl1_basegrenade.cpp" + $File "hl1\hl1_basegrenade.h" + $File "hl1_CBaseHelicopter.h" + $File "hl1\hl1_client.cpp" + $File "hl1\hl1_ents.cpp" + $File "hl1\hl1_env_speaker.cpp" + $File "hl1\hl1_eventlog.cpp" + $File "hl1\hl1_func_recharge.cpp" + $File "hl1\hl1_func_tank.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_gamemovement.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_gamemovement.h" + $File "$SRCDIR\game\shared\hl1\hl1_gamerules.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_gamerules.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_gamerules.h" + $File "hl1\hl1_grenade_mp5.cpp" + $File "hl1\hl1_grenade_mp5.h" + $File "hl1\hl1_grenade_spit.cpp" + $File "hl1\hl1_grenade_spit.h" + $File "hl1\hl1_item_ammo.cpp" + $File "hl1\hl1_item_battery.cpp" + $File "hl1\hl1_item_healthkit.cpp" + $File "hl1\hl1_item_longjump.cpp" + $File "hl1\hl1_item_suit.cpp" + $File "hl1\hl1_items.cpp" + $File "hl1\hl1_items.h" + $File "hl1\hl1_monstermaker.cpp" + $File "hl1\hl1_monstermaker.h" + $File "hl1\hl1_npc_aflock.cpp" + $File "hl1\hl1_npc_agrunt.cpp" + $File "hl1\hl1_npc_apache.cpp" + $File "hl1\hl1_npc_barnacle.cpp" + $File "hl1\hl1_npc_barnacle.h" + $File "hl1\hl1_npc_barney.cpp" + $File "hl1\hl1_npc_barney.h" + $File "hl1\hl1_npc_bigmomma.cpp" + $File "hl1\hl1_npc_bloater.cpp" + $File "hl1\hl1_npc_bullsquid.cpp" + $File "hl1\hl1_npc_bullsquid.h" + $File "hl1\hl1_npc_controller.cpp" + $File "hl1\hl1_npc_gargantua.cpp" + $File "hl1\hl1_npc_gargantua.h" + $File "hl1\hl1_npc_gman.cpp" + $File "hl1\hl1_npc_hassassin.cpp" + $File "hl1\hl1_npc_headcrab.cpp" + $File "hl1\hl1_npc_headcrab.h" + $File "hl1\hl1_npc_hgrunt.cpp" + $File "hl1\hl1_npc_hgrunt.h" + $File "hl1\hl1_npc_hornet.cpp" + $File "hl1\hl1_npc_hornet.h" + $File "hl1\hl1_npc_houndeye.cpp" + $File "hl1\hl1_npc_houndeye.h" + $File "hl1\hl1_npc_ichthyosaur.cpp" + $File "hl1\hl1_npc_ichthyosaur.h" + $File "hl1\hl1_npc_leech.cpp" + $File "hl1\hl1_npc_nihilanth.cpp" + $File "hl1\hl1_npc_osprey.cpp" + $File "hl1\hl1_npc_roach.cpp" + $File "hl1\hl1_npc_scientist.cpp" + $File "hl1\hl1_npc_scientist.h" + $File "hl1\hl1_npc_snark.cpp" + $File "hl1\hl1_npc_snark.h" + $File "hl1\hl1_npc_talker.cpp" + $File "hl1\hl1_npc_talker.h" + $File "hl1\hl1_npc_tentacle.cpp" + $File "hl1\hl1_npc_turret.cpp" + $File "hl1\hl1_npc_vortigaunt.cpp" + $File "hl1\hl1_npc_vortigaunt.h" + $File "hl1\hl1_npc_zombie.cpp" + $File "hl1\hl1_npc_zombie.h" + $File "hl1\hl1_player.cpp" + $File "hl1\hl1_player.h" + $File "$SRCDIR\game\shared\hl1\hl1_player_shared.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_player_shared.h" + $File "hl1\hl1_playermove.cpp" + $File "$SRCDIR\game\shared\hl1\hl1_usermessages.cpp" + $File "hl1\hl1_weapon_snark.cpp" + $File "hl1\hl1_weapon_tripmine.cpp" + $File "hl1\hl1_weaponbox.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_basecombatweapon_shared.cpp" + $File "hl1\hl1mp_bot_temp.cpp" + $File "hl1\hl1mp_player.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_357.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_crossbow.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_egon.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_gauss.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_glock.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_handgrenade.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_hornetgun.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_mp5.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_rpg.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_sachel.cpp" + $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_shotgun.cpp" + $File "$SRCDIR\game\server\hl1\hl1_weapon_crowbar.cpp" + } + } +} diff --git a/game/server/wscript b/game/server/wscript index 848f9c40..21e4e4ee 100755 --- a/game/server/wscript +++ b/game/server/wscript @@ -14,7 +14,7 @@ games = { 'hl2mp': ['server_base.vpc', 'server_hl2mp.vpc'], 'portal': ['server_base.vpc', 'server_portal.vpc'], 'hl1': ['server_base.vpc', 'server_hl1.vpc'], - 'hl1mp': ['server_base.vpc', 'server_hl1.vpc'], + 'hl1mp': ['server_base.vpc', 'server_hl1mp.vpc'], 'cstrike': ['server_base.vpc', 'server_cstrike.vpc', 'nav_mesh.vpc'], 'dod': ['server_base.vpc', 'server_dod.vpc'], 'tf': [ diff --git a/game/shared/saverestore.cpp b/game/shared/saverestore.cpp index bd1a7bef..387aefc2 100644 --- a/game/shared/saverestore.cpp +++ b/game/shared/saverestore.cpp @@ -203,6 +203,7 @@ CSave::CSave( CSaveRestoreData *pdata ) inline int CSave::DataEmpty( const char *pdata, int size ) { + static int void_data = 0; if ( size != 4 ) { const char *pLimit = pdata + size; @@ -214,7 +215,7 @@ inline int CSave::DataEmpty( const char *pdata, int size ) return 1; } - return ( *((int *)pdata) == 0 ); + return memcmp(pdata, &void_data, sizeof(int)) == 0; } //----------------------------------------------------------------------------- diff --git a/gameui/BaseSaveGameDialog.cpp b/gameui/BaseSaveGameDialog.cpp index 99f7fc1c..c59d18ce 100644 --- a/gameui/BaseSaveGameDialog.cpp +++ b/gameui/BaseSaveGameDialog.cpp @@ -560,7 +560,7 @@ int SaveReadNameAndComment( FileHandle_t f, OUT_Z_CAP(nameSize) char *name, int int nNumberOfFields; char *pData; - int nFieldSize; + short nFieldSize; pData = pSaveData; @@ -580,9 +580,12 @@ int SaveReadNameAndComment( FileHandle_t f, OUT_Z_CAP(nameSize) char *name, int pTokenList = NULL; // short, short (size, index of field name) - nFieldSize = *(short *)pData; + memcpy( &nFieldSize, pData, sizeof(short) ); + pData += sizeof(short); - pFieldName = pTokenList[ *(short *)pData ]; + short index; + memcpy( &index, pData, sizeof(short) ); + pFieldName = pTokenList[index]; if (stricmp(pFieldName, "GameHeader")) { @@ -592,7 +595,7 @@ int SaveReadNameAndComment( FileHandle_t f, OUT_Z_CAP(nameSize) char *name, int // int (fieldcount) pData += sizeof(short); - nNumberOfFields = *(int*)pData; + memcpy( &nNumberOfFields, pData, sizeof(int) ); pData += nFieldSize; // Each field is a short (size), short (index of name), binary string of "size" bytes (data) @@ -603,10 +606,12 @@ int SaveReadNameAndComment( FileHandle_t f, OUT_Z_CAP(nameSize) char *name, int // szName // Actual Data - nFieldSize = *(short *)pData; + memcpy( &nFieldSize, pData, sizeof(short) ); pData += sizeof(short); - pFieldName = pTokenList[ *(short *)pData ]; + short index; + memcpy( &index, pData, sizeof(short)); + pFieldName = pTokenList[index]; pData += sizeof(short); if (!stricmp(pFieldName, "comment")) diff --git a/public/bone_setup.cpp b/public/bone_setup.cpp index 35d72d5e..564f9ea6 100644 --- a/public/bone_setup.cpp +++ b/public/bone_setup.cpp @@ -21,6 +21,8 @@ #include "convar.h" #include "tier0/tslist.h" #include "vphysics_interface.h" +#include "mathlib/compressed_vector.h" + #ifdef CLIENT_DLL #include "posedebugger.h" #endif @@ -378,14 +380,18 @@ void CalcBoneQuaternion( int frame, float s, { if ( panim->flags & STUDIO_ANIM_RAWROT ) { - q = *(panim->pQuat48()); + Quaternion48 tmp; + memcpy( &tmp, panim->pQuat48(), sizeof(Quaternion48) ); + q = tmp; Assert( q.IsValid() ); return; - } - + } + if ( panim->flags & STUDIO_ANIM_RAWROT2 ) { - q = *(panim->pQuat64()); + Quaternion64 tmp; + memcpy( &tmp, panim->pQuat64(), sizeof(Quaternion64) ); + q = tmp; Assert( q.IsValid() ); return; } diff --git a/public/dt_send.cpp b/public/dt_send.cpp index caad4191..27580f8f 100644 --- a/public/dt_send.cpp +++ b/public/dt_send.cpp @@ -265,7 +265,7 @@ void SendProxy_UInt16ToInt32( const SendProp *pProp, const void *pStruct, const void SendProxy_UInt32ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) { - *((unsigned long*)&pOut->m_Int) = *((unsigned long*)pData); + memcpy( &pOut->m_Int, pData, sizeof(unsigned long) ); } #ifdef SUPPORTS_INT64 void SendProxy_UInt64ToInt64( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) diff --git a/public/mathlib/compressed_vector.h b/public/mathlib/compressed_vector.h index 6a495229..796a50bc 100644 --- a/public/mathlib/compressed_vector.h +++ b/public/mathlib/compressed_vector.h @@ -149,7 +149,7 @@ class Quaternion64 { public: // Construction/destruction: - Quaternion64(void); + Quaternion64(void) {}; Quaternion64(vec_t X, vec_t Y, vec_t Z); // assignment @@ -197,7 +197,7 @@ class Quaternion48 { public: // Construction/destruction: - Quaternion48(void); + Quaternion48(void) {}; Quaternion48(vec_t X, vec_t Y, vec_t Z); // assignment diff --git a/public/mathlib/lightdesc.h b/public/mathlib/lightdesc.h index 1096d623..3f0e1656 100644 --- a/public/mathlib/lightdesc.h +++ b/public/mathlib/lightdesc.h @@ -34,7 +34,7 @@ enum LightType_OptimizationFlags_t struct LightDesc_t { LightType_t m_Type; //< MATERIAL_LIGHT_xxx - Vector m_Color; //< color+intensity + Vector m_Color; //< color+intensity Vector m_Position; //< light source center position Vector m_Direction; //< for SPOT, direction it is pointing float m_Range; //< distance range for light.0=infinite @@ -60,6 +60,7 @@ public: LightDesc_t(void) { + m_Type = MATERIAL_LIGHT_DISABLE; } // constructors for various useful subtypes diff --git a/public/mathlib/vector4d.h b/public/mathlib/vector4d.h index d63cf52b..89fcce01 100644 --- a/public/mathlib/vector4d.h +++ b/public/mathlib/vector4d.h @@ -23,6 +23,10 @@ #include "tier0/dbg.h" #include "mathlib/math_pfns.h" +#ifdef __arm__ +#include "sse2neon.h" +#endif + // forward declarations class Vector; class Vector2D; @@ -141,10 +145,8 @@ public: inline void Set( vec_t X, vec_t Y, vec_t Z, vec_t W ); inline void InitZero( void ); -#ifndef __arm__ inline __m128 &AsM128() { return *(__m128*)&x; } inline const __m128 &AsM128() const { return *(const __m128*)&x; } -#endif private: // No copy constructors allowed if we're in optimal mode @@ -616,9 +618,7 @@ inline void Vector4DAligned::Set( vec_t X, vec_t Y, vec_t Z, vec_t W ) inline void Vector4DAligned::InitZero( void ) { -#if defined (__arm__) - x = y = z = w = 0; -#elif !defined( _X360 ) +#if !defined( _X360 ) this->AsM128() = _mm_set1_ps( 0.0f ); #else this->AsM128() = __vspltisw( 0 ); @@ -629,7 +629,7 @@ inline void Vector4DAligned::InitZero( void ) inline void Vector4DMultiplyAligned( Vector4DAligned const& a, Vector4DAligned const& b, Vector4DAligned& c ) { Assert( a.IsValid() && b.IsValid() ); -#if !defined( _X360 ) || defined (__arm__) +#if !defined( _X360 ) c.x = a.x * b.x; c.y = a.y * b.y; c.z = a.z * b.z; @@ -643,7 +643,7 @@ inline void Vector4DWeightMAD( vec_t w, Vector4DAligned const& vInA, Vector4DAli { Assert( vInA.IsValid() && vInB.IsValid() && IsFinite(w) ); -#if !defined( _X360 ) || defined (__arm__) +#if !defined( _X360 ) vOutA.x += vInA.x * w; vOutA.y += vInA.y * w; vOutA.z += vInA.z * w; @@ -664,7 +664,6 @@ inline void Vector4DWeightMAD( vec_t w, Vector4DAligned const& vInA, Vector4DAli #endif } -#ifndef __arm__ inline void Vector4DWeightMADSSE( vec_t w, Vector4DAligned const& vInA, Vector4DAligned& vOutA, Vector4DAligned const& vInB, Vector4DAligned& vOutB ) { Assert( vInA.IsValid() && vInB.IsValid() && IsFinite(w) ); @@ -686,7 +685,6 @@ inline void Vector4DWeightMADSSE( vec_t w, Vector4DAligned const& vInA, Vector4D vOutB.AsM128() = __vmaddfp( vInB.AsM128(), temp, vOutB.AsM128() ); #endif } -#endif #endif // VECTOR4D_H diff --git a/public/mathlib/vmatrix.h b/public/mathlib/vmatrix.h index e49a888d..48738df0 100644 --- a/public/mathlib/vmatrix.h +++ b/public/mathlib/vmatrix.h @@ -423,6 +423,12 @@ void MatrixInverseTranspose( const VMatrix& src, VMatrix& dst ); //----------------------------------------------------------------------------- inline VMatrix::VMatrix() { + Init( + 0.f, 0.f, 0.f, 0.f, + 0.f, 0.f, 0.f, 0.f, + 0.f, 0.f, 0.f, 0.f, + 0.f, 0.f, 0.f, 0.f + ); } inline VMatrix::VMatrix( diff --git a/public/studio.h b/public/studio.h index ae20a045..a30875be 100644 --- a/public/studio.h +++ b/public/studio.h @@ -639,6 +639,7 @@ struct mstudioanim_t byte bone; byte flags; // weighing options + // valid for animating data only inline byte *pData( void ) const { return (((byte *)this) + sizeof( struct mstudioanim_t )); }; inline mstudioanim_valueptr_t *pRotV( void ) const { return (mstudioanim_valueptr_t *)(pData()); }; @@ -650,8 +651,9 @@ struct mstudioanim_t inline Vector48 *pPos( void ) const { return (Vector48 *)(pData() + ((flags & STUDIO_ANIM_RAWROT) != 0) * sizeof( *pQuat48() ) + ((flags & STUDIO_ANIM_RAWROT2) != 0) * sizeof( *pQuat64() ) ); }; short nextoffset; + inline mstudioanim_t *pNext( void ) const { if (nextoffset != 0) return (mstudioanim_t *)(((byte *)this) + nextoffset); else return NULL; }; -}; +} ALIGN16; struct mstudiomovement_t { diff --git a/public/togles/linuxwin/dxabstract_types.h b/public/togles/linuxwin/dxabstract_types.h index 37818c2d..49861e86 100644 --- a/public/togles/linuxwin/dxabstract_types.h +++ b/public/togles/linuxwin/dxabstract_types.h @@ -1195,7 +1195,7 @@ typedef enum _D3DVERTEXBLENDFLAGS D3DVBF_3WEIGHTS = 3, // 4 matrix blending D3DVBF_TWEENING = 255, // blending using D3DRS_TWEENFACTOR D3DVBF_0WEIGHTS = 256, // one matrix is used with weight 1.0 - D3DVBF_FORCE_DWORD = 0x7fffffff, // force 32-bit size enum + D3DVBF_FORCE_DWORD = 0xffffffff, // force 32-bit size enum } D3DVERTEXBLENDFLAGS; typedef struct _D3DINDEXBUFFER_DESC @@ -1533,7 +1533,7 @@ typedef enum _D3DTRANSFORMSTATETYPE D3DTS_VIEW = 2, D3DTS_PROJECTION = 3, D3DTS_TEXTURE0 = 16, - D3DTS_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ + D3DTS_FORCE_DWORD = 0xffffffff, /* force 32-bit size enum */ } D3DTRANSFORMSTATETYPE; // **** FIXED FUNCTION STUFF - None of this stuff needs support in GL. diff --git a/public/togles/linuxwin/glentrypoints.h b/public/togles/linuxwin/glentrypoints.h index fa5a4cf8..310932bc 100644 --- a/public/togles/linuxwin/glentrypoints.h +++ b/public/togles/linuxwin/glentrypoints.h @@ -38,18 +38,8 @@ #include "interface.h" #include "togles/rendermechanism.h" -#ifdef LINUX -#include -#endif - void *VoidFnPtrLookup_GlMgr(const char *fn, bool &okay, const bool bRequired, void *fallback=NULL); -/* -#define GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS 1 -#define GL_TRACK_API_TIME 1 -#define GL_DUMP_ALL_API_CALLS 1 -*/ - #if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS class CGLExecuteHelperBase { @@ -57,7 +47,7 @@ public: inline void StartCall(const char *pName); inline void StopCall(const char *pName); #if GL_TRACK_API_TIME - uint64 m_nStartTime; + TmU64 m_nStartTime; #endif }; @@ -313,32 +303,30 @@ public: int m_nOpenGLVersionMinor; // if GL_VERSION is 2.1.0, this will be set to 1. int m_nOpenGLVersionPatch; // if GL_VERSION is 2.1.0, this will be set to 0. bool m_bHave_OpenGL; - + char *m_pGLDriverStrings[cGLTotalDriverStrings]; - GLDriverProvider_t m_nDriverProvider; + GLDriverProvider_t m_nDriverProvider; + +#ifdef LOAD_HARDFP +#define _APIENTRY __attribute__((pcs("aapcs"))) APIENTRY +#else +#define _APIENTRY APIENTRY +#endif #ifdef OSX #define GL_EXT(x,glmajor,glminor) bool m_bHave_##x; #define GL_FUNC(ext,req,ret,fn,arg,call) CDynamicFunctionOpenGL< req, ret (*) arg, ret > fn; #define GL_FUNC_VOID(ext,req,fn,arg,call) CDynamicFunctionOpenGL< req, void (*) arg, void > fn; #else - -#ifdef LOAD_HARDFP -#define _APIENTRY __attribute__((pcs("aapcs"))) APIENTRY #define GL_EXT(x,glmajor,glminor) bool m_bHave_##x; #define GL_FUNC(ext,req,ret,fn,arg,call) CDynamicFunctionOpenGL< req, ret (_APIENTRY *) arg, ret > fn; #define GL_FUNC_VOID(ext,req,fn,arg,call) CDynamicFunctionOpenGL< req, void (_APIENTRY *) arg, void > fn; -#else -#define GL_EXT(x,glmajor,glminor) bool m_bHave_##x; -#define GL_FUNC(ext,req,ret,fn,arg,call) CDynamicFunctionOpenGL< req, ret (APIENTRY *) arg, ret > fn; -#define GL_FUNC_VOID(ext,req,fn,arg,call) CDynamicFunctionOpenGL< req, void (APIENTRY *) arg, void > fn; #endif -#endif - #include "togles/glfuncs.inl" - #undef GL_FUNC_VOID - #undef GL_FUNC - #undef GL_EXT +#include "togles/glfuncs.inl" +#undef GL_FUNC_VOID +#undef GL_FUNC +#undef GL_EXT bool HasSwapTearExtension() const { @@ -366,30 +354,54 @@ typedef void * (*GL_GetProcAddressCallbackFunc_t)(const char *, bool &, const bo DLL_IMPORT void ClearOpenGLEntryPoints(); #endif -inline uint64 get_nsecs() -{ - struct timespec time={0,0}; - clock_gettime(CLOCK_MONOTONIC, &time); - return time.tv_nsec; -} - #if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS inline void CGLExecuteHelperBase::StartCall(const char *pName) { (void)pName; - m_nStartTime = get_nsecs(); + +#if GL_TELEMETRY_ZONES + tmEnter( TELEMETRY_LEVEL3, TMZF_NONE, pName ); +#endif + +#if GL_TRACK_API_TIME + m_nStartTime = tmFastTime(); +#endif + +#if GL_DUMP_ALL_API_CALLS + static bool s_bDumpCalls; + if ( s_bDumpCalls ) + { + char buf[128]; + buf[0] = 'G'; + buf[1] = 'L'; + buf[2] = ':'; + size_t l = strlen( pName ); + memcpy( buf + 3, pName, l ); + buf[3 + l] = '\n'; + buf[4 + l] = '\0'; + Plat_DebugString( buf ); + } +#endif } inline void CGLExecuteHelperBase::StopCall(const char *pName) -{ - if( gGL ) - { - uint64 time = get_nsecs() - m_nStartTime; - printf("Function %s finished in %llu\n", pName, time); - - if( strcmp(pName, "glBufferSubData") == 0 && time > 1000000 ) - DebuggerBreak(); - } +{ +#if GL_TRACK_API_TIME + uint64 nTotalCycles = tmFastTime() - m_nStartTime; +#endif + +#if GL_TELEMETRY_ZONES + tmLeave( TELEMETRY_LEVEL3 ); +#endif + +#if GL_TRACK_API_TIME + //double flMilliseconds = g_Telemetry.flRDTSCToMilliSeconds * nTotalCycles; + if (gGL) + { + gGL->m_nTotalGLCycles += nTotalCycles; + gGL->m_nTotalGLCalls++; + } +#endif } #endif diff --git a/serverbrowser/ServerBrowserDialog.cpp b/serverbrowser/ServerBrowserDialog.cpp index 0e2f3f43..3faf2d14 100644 --- a/serverbrowser/ServerBrowserDialog.cpp +++ b/serverbrowser/ServerBrowserDialog.cpp @@ -154,9 +154,10 @@ CServerBrowserDialog::~CServerBrowserDialog() SaveUserData(); if (m_pSavedData) - { m_pSavedData->deleteThis(); - } + + if( m_pFilterData ) + m_pFilterData->deleteThis(); } @@ -813,4 +814,4 @@ void CServerBrowserDialog::OnKeyCodePressed( vgui::KeyCode code ) } BaseClass::OnKeyCodePressed( code ); -} \ No newline at end of file +} diff --git a/studiorender/studiorendercontext.cpp b/studiorender/studiorendercontext.cpp index c29a27b6..62a7c8d3 100644 --- a/studiorender/studiorendercontext.cpp +++ b/studiorender/studiorendercontext.cpp @@ -763,7 +763,9 @@ void CStudioRenderContext::R_StudioBuildMeshGroup( const char *pModelName, bool for (i = 0; i < pStripGroup->numIndices; ++i) { - meshBuilder.Index( *pStripGroup->pIndex(i) ); + unsigned short index; + memcpy( &index, pStripGroup->pIndex(i), sizeof(index) ); + meshBuilder.Index( index ); meshBuilder.AdvanceIndex(); } diff --git a/tier0/cpu.cpp b/tier0/cpu.cpp index d5bf6c9b..90ca43ac 100644 --- a/tier0/cpu.cpp +++ b/tier0/cpu.cpp @@ -142,9 +142,9 @@ static bool IsWin98OrOlder() static bool CheckSSETechnology(void) { -#if defined(__SANITIZE_ADDRESS__) +#if defined(__SANITIZE_ADDRESS__) || defined (__arm__) return false; -#elif defined( _X360 ) || defined( _PS3 ) || defined (__arm__) +#elif defined( _X360 ) || defined( _PS3 ) return true; #else if ( IsWin98OrOlder() ) { @@ -162,10 +162,8 @@ static bool CheckSSETechnology(void) static bool CheckSSE2Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) || defined (__arm__) return false; -#elif defined (__arm__) - return true; #else unsigned long eax,ebx,edx,unused; if ( !cpuid(1,eax,ebx,unused,edx) ) @@ -177,10 +175,8 @@ static bool CheckSSE2Technology(void) bool CheckSSE3Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) || defined (__arm__) return false; -#elif defined (__arm__) - return true; #else unsigned long eax,ebx,edx,ecx; if( !cpuid(1,eax,ebx,ecx,edx) ) @@ -192,10 +188,8 @@ bool CheckSSE3Technology(void) bool CheckSSSE3Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) || defined (__arm__) return false; -#elif defined (__arm__) - return true; #else // SSSE 3 is implemented by both Intel and AMD // detection is done the same way for both vendors @@ -209,10 +203,8 @@ bool CheckSSSE3Technology(void) bool CheckSSE41Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) || defined (__arm__) return false; -#elif defined (__arm__) - return true; #else // SSE 4.1 is implemented by both Intel and AMD // detection is done the same way for both vendors @@ -227,10 +219,8 @@ bool CheckSSE41Technology(void) bool CheckSSE42Technology(void) { -#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) || defined (__arm__) return false; -#elif defined (__arm__) - return true; #else // SSE4.2 is an Intel-only feature @@ -249,10 +239,8 @@ bool CheckSSE42Technology(void) bool CheckSSE4aTechnology( void ) { -#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) +#if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) || defined (__arm__) return false; -#elif defined (__arm__) - return true; #else // SSE 4a is an AMD-only feature diff --git a/tier1/checksum_crc.cpp b/tier1/checksum_crc.cpp index b9dacbb6..29093d1e 100644 --- a/tier1/checksum_crc.cpp +++ b/tier1/checksum_crc.cpp @@ -105,6 +105,8 @@ void CRC32_ProcessBuffer(CRC32_t *pulCRC, const void *pBuffer, int nBuffer) unsigned int nFront; int nMain; + CRC32_t tmp; + JustAfew: switch (nBuffer) @@ -119,7 +121,8 @@ JustAfew: ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8); case 4: - ulCrc ^= LittleLong( *(CRC32_t *)pb ); + memcpy( &tmp, pb, sizeof(CRC32_t) ); + ulCrc ^= LittleLong( tmp ); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); @@ -162,12 +165,15 @@ JustAfew: nMain = nBuffer >> 3; while (nMain--) { - ulCrc ^= LittleLong( *(CRC32_t *)pb ); + memcpy( &tmp, pb, sizeof(CRC32_t) ); + ulCrc ^= LittleLong( tmp ); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); - ulCrc ^= LittleLong( *(CRC32_t *)(pb + 4) ); + + memcpy( &tmp, pb+4, sizeof(CRC32_t) ); + ulCrc ^= LittleLong( tmp ); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8); diff --git a/tier1/processor_detect_linux.cpp b/tier1/processor_detect_linux.cpp index 11248ab2..9e2490bd 100644 --- a/tier1/processor_detect_linux.cpp +++ b/tier1/processor_detect_linux.cpp @@ -12,9 +12,9 @@ bool CheckSSETechnology(void) { return false; } bool CheckSSE2Technology(void) { return false; } bool Check3DNowTechnology(void) { return false; } #elif defined (__arm__) -bool CheckMMXTechnology(void) { return true; } -bool CheckSSETechnology(void) { return true; } -bool CheckSSE2Technology(void) { return true; } +bool CheckMMXTechnology(void) { return false; } +bool CheckSSETechnology(void) { return false; } +bool CheckSSE2Technology(void) { return false; } bool Check3DNowTechnology(void) { return false; } #else diff --git a/tier1/snappy-stubs-internal.h b/tier1/snappy-stubs-internal.h index 1413825a..ab6a5a5f 100644 --- a/tier1/snappy-stubs-internal.h +++ b/tier1/snappy-stubs-internal.h @@ -100,7 +100,8 @@ static const int64 kint64max = static_cast(0x7FFFFFFFFFFFFFFFLL); // x86 and PowerPC can simply do these loads and stores native. -#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) +// fuck this shit +#if 0 // defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) #define UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) #define UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) diff --git a/togles/linuxwin/cglmbuffer.cpp b/togles/linuxwin/cglmbuffer.cpp index 1fb77b62..6d01e001 100644 --- a/togles/linuxwin/cglmbuffer.cpp +++ b/togles/linuxwin/cglmbuffer.cpp @@ -472,10 +472,7 @@ CGLMBuffer::CGLMBuffer( GLMContext *pCtx, EGLMBufferType type, uint size, uint o m_bPseudo = true; #endif - const char *szRenderer = (const char*)gGL->glGetString(GL_VENDOR); -// Msg("GL_VENDOR: %s\n", szRenderer); - - if( strcmp(szRenderer, "ARM") == 0 ) + if( strcmp(gGL->m_pGLDriverStrings[cGLVendorString], "ARM") == 0 ) g_bUsePseudoBufs = true; // works faster with Mali gpu #if GL_ENABLE_INDEX_VERIFICATION diff --git a/togles/linuxwin/cglmprogram.cpp b/togles/linuxwin/cglmprogram.cpp index 05a9cf7f..28d24f91 100644 --- a/togles/linuxwin/cglmprogram.cpp +++ b/togles/linuxwin/cglmprogram.cpp @@ -350,11 +350,10 @@ void CGLMProgram::Compile( EGLMProgramLang lang ) // compile gGL->glCompileShader( glslDesc->m_object.glsl ); - - + GLint isCompiled = 0; gGL->glGetShaderiv(glslDesc->m_object.glsl, GL_COMPILE_STATUS, &isCompiled); - + if(isCompiled == GL_FALSE) { GLint maxLength = 0; diff --git a/togles/linuxwin/cglmtex.cpp b/togles/linuxwin/cglmtex.cpp index 5230ad11..962fce7c 100644 --- a/togles/linuxwin/cglmtex.cpp +++ b/togles/linuxwin/cglmtex.cpp @@ -3649,9 +3649,9 @@ void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDa Assert( writeWholeSlice ); //subimage not implemented in this path yet // compressed path // http://www.opengl.org/sdk/docs/man/xhtml/glCompressedTexImage2D.xml - if( gGL->m_bHave_GL_EXT_texture_compression_dxt1 ) +/* if( gGL->m_bHave_GL_EXT_texture_compression_dxt1 ) gGL->glCompressedTexImage2D( target, desc->m_req.m_mip, intformat, slice->m_xSize, slice->m_ySize, 0, slice->m_storageSize, sliceAddress ); - else + else*/ CompressedTexImage2D( target, desc->m_req.m_mip, intformat, slice->m_xSize, slice->m_ySize, 0, slice->m_storageSize, sliceAddress ); } else diff --git a/togles/linuxwin/decompress.o b/togles/linuxwin/decompress.o deleted file mode 100644 index 3e88c1046fa3c29e782b4c3fc597b8552ee8b93d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35548 zcmb@t2{={V_W*n^*E}2{bH-cT$P{HNG88funM0<8LWaykS90T)At?$)L`5XCxaN6` z%wvXY%9J_2eR$vB|M&lf=X;*-`EH%F_g-tSwbx#I?X}k4r-Ib9E+dgh#J@izf)w#T zEd(O+(Gf=Kun(uroYR;RbGnFiweC!4ep7ZGckt!S#XyJFWO1EH8{DN4DX% zL3dEYY~wu8v@lgW;Wrs>A7D0dbue4dgxUI|nIp{6%>QBVFMGHf;0=2H%bqaFfLWoM z#}fWC1_3+H1I7R&uz_KxDKTx>ItIXrNQPXA0Kzb1&tk_&v0EfiXb9kn-6HjH#%>{TeI7RmV{A04XjJH+ zheGh~fd@61vr;`NyeK$SJhlpnC6HiuP@aX@S`?{2P*@!b`0k19R;aD4zX9~*U8f?*lvALBhvA))}D`TNJL ztSmh9C0xhmG_D)Z?1Jm)oZp-ViUC;K&N-^?2m>@5o>>|0026f15hf_9Ku>jC2R!f1 z>CQP^C*B|c5#fwh#dQEJ9d?9iJ7L;-pex5MYY>gQJ z*dzw=vLCkF;kW z6})rcQ31Lr9kH7K`j1}!DWYx|;eNt9CS;)uj06=hLIn?yU=|`!feVSng`z)! zLZT8XxPk)4O^c}lH8QZfP!e63I#4Ia)Z$gq&OiZ_xcZ}Yg$lG{kx&6D7Rmv$gL2xC z4KRoV%4tP5{9_+G44!@P+$6g2zy<(19;S%@Ulj5GQpCa*1;|;D}m{&0^1P* z!tx@w@yry!q!oa8XkhC*om-CvJ>7vouzD!*uhAdi87$7TNmRA+5y4Auzr2up%Mgw(()!_6L9 z^O3@%2;(Ti1d1?*0%9>pGy)}o=>a*wUPNo*Xc@3oDC`dJ{XY_m|Jszqfy4&R87+i2 zK%3*XVUcmm|1Odjy!MoME_kwR5mLH%R4}p+w?>#mA^T*3xj|1AfPsJ-1N1Zx)Ic|0 zV8SApI#5I5)(+i>c*K25(4@pGc;TgnfyfBVNQA073b`NQi^3~ZAop?gq>_Xg002`5 zJY`^>9xzWGm?v->-%&6X>_Jdee}J%DxGRT>jquQ=jPRw!iv-~nY7aTrBY#IYQsSLI zBapvwe@J~%geesAw=7s?=xHVB0cwCR3(VIU&0E0$KwuG3m?gZ(AD98oof5RUFn_3a z;i-e&$rWKr8{w}@i|0xNzIL9}l#(!wLaxc0qiF+8z#FiG{T=XgyroK@g4v{jiNGRu zPhts_ROV=>#(NIE_=$fCm)Hp&IEc++XB5Lp zp@PthN&tv2fZyRNU^_A&3x_um3LUObf~yZV01*Z-uTvpKK!rbX^>7C`o&joo6jUH} z5h~chEr+X+0ScS~8au`V70@Davvn#Iz`4u<-&_GZ>+q}Oz>m)0mZ1Xh7YuOdN>SnZ zlz8ULFs5@ZT%QUm0KVtHXKIgEu<0~BtFFhz-*$E@M?8F1Z% zc`_vY!j0gX?FsWVpa)2J264l1r#Z|3w(8$bxM2|S=gA0*WY|eX+yDq$06Wfut>T5b zkR!WsO#lXJm?n7ArSMw8)SYnt(HWsf3l+lAj!1?BQ4Q$Ho-hkRg_X!I>;ySg6<8_| zW!-@4C&7C5!toTu(rJdxNuVAE5KDUj4eBU{f*x?tgdq$-URpTWVE_=^GQ4xCW~n-G ztH2k+jthiZ2C6N%cL#u=00r040>h(p!X^cKr=zG1K!*{V0ncoRYl9^L3>=^Wcqu@v zAWX6W8nBdyW5f2v3I=BYLmJ>Zf%xKhsc*|*OA*G|09**b^`IPpB=rE!TMI3Pm-=$3 z0U!r2-f|C5YlhvXg`RD~h6Iw$?j7s|#iK4Lv<(2@SRVQpR6t-uv&v|pS)j0e&@83| zFH9$t1A;7e4hiLeVUe9Bv1pALT*KxZvWc+GL)ak!E6_ujV1vz_ma}^ncbK(d$4RL= zg13*-2L`zMZ~D+d1FScA8>A0aIAUm{=Xqe*R`rL8H4c>o@&?&m=#dtf8kmX@-VcS{ zWq=;Zf;P5B=D+tx@b-a68=$p4qMfh$$8*72hYFn0EJVluaycMAfi=hOl0l(l01O&v zED_{7Kn=w8BmZT9mV)V6iISj$eH3jCO<$(18u@gYy{V1^kcBBGuw6n#(TY_+fHmfEJPH0iM;l0-idV#)3BCZE2XaqqJfhgpF&c&*@EQRJU2#FG+R zqj0!(M`7SFpT1#qpxyqO|~!1d6M~Rw5%Hypa-M7zr5Sub^Zp zp-1EZi>*Y-c6hD;d0l~4oq;3C0?rZkj8K6q2>{dLqm;nL#TO|7QK146Q;_@Vf}LuL zBuvo|#>l8<0q{Oyl7^}lga}v zaAiaW!YmtZ4k`dSYa>_|N^s1vhjTI90Ep;R4gY|kf-cw*02uJ>hc()*em(U{7z+W6E^#K&d zIIa)aS|s)_sb>yY8a==p&cVRw5(hvycvt{dg2AAKa}ih!1AuyY1cH+`7z9t{^-4AB1z0ZbeTwhNTg1m$!f4bVzZ zP9+iuf^3xs(bh8`$VfW~B(R6>wS#9EJU|WL?Ti+;hpd}ndjc9m^aq0%0zhi*A!owS zHe^-_SscP3p#~rud}tB?p7Z>Xui2^Jeb!~q28Z3M=`b$_%t z@Hrl(zyyQ81GgCj6)1x(Ne#y%1}LW%KBsAdLsvVpLAEZC9Bdj}U{KWoaLo#2kyR*p z5a~P{!QQX}j>{G*Uva@eRM>`)>* z2wRl6DsYzH0vQ(#@~|8uL&D?$3utwapn_LmfC^aPBq{L!hP}@JXZD8@*aQ9e+skfw zoW{RKw*WDr!Ui~{?VBxL2azli4ND8O?ur|j{Rwgc(A^nc1YmsL0E55>!`=&Q;c&Pg z2rPJ1ISiNB0(T_P<8ZKUVE=gl3~wnM@r&SB3H&-dM?eJjIZ66$I z+C66@J{>Y7?4ZB_1NKT=D8c~>pLpaXJ#GL`Nvi_9pbC;OO+y$bgT3MkRNxVSpjwH@ zKcvOAg2cuU2^34!0cwFrkT+G^gRSN7Nn(=6BF%r#e|7ff?}Gz*Fn=f%3kbpGgEtb)%Uize(CI^=_kkwtfy?x_2WP`TSX0C~ z5R8ZWi7Mda0&5LS#rQwY1cW^Nb2NN-#uo_zJH!XWY5~g(2Weh>8G7ibY5tGS&B4iD z9Gs=W?gG3Fu(L{FbmMvy1iB%B7Qwmh{vtTbMw|v+7yu9WxD5AUz)LAX1rTWQ;{Cyi zbf2&f4!o4$oN^vu^)M^AWgHEzHA0gzoC59+cLetzppOQgb`j=|AtJZ`IVEqCQsWiG zK^Hy3HpuX4A>1amk^$2muD*`*Lq%xP9u5q+01m)(HNfgC5ynY@S5$&|08j-e!30S) zQGf$-6XpSr3Kay=V%oyhx4_vK@X!OS@Ct{AVaz7jVZ1=!3=DW$+#$6dsU{^%y$`7A z;lcNCe&Bd~=%o&|BU=xJz6Qnz^4S4gGjSEH13=RPX`I0VSizG5r8!)Jxp?4{VQ-GF zfZG6W{7@xt*vH~Itl+%oXZ|~qs zIdR~s#rxo75dln89Lkx;5pf_U&0>fEYf#Js5d9BfbYEj%9$dnNfXJY)=?FeV0RG(^ zZLkK30Q;3~f^<728bO+*-U+6xhwB0TL2zpZxeFK?(+P8h$qzaAHTMzzA88q=U|J9Z z8-NlpO~r~}aNuhXsr#D#p9rCx{X^EkwNmxqcEA#VNo`?v0OiqKkA@UK6j%Je#XTg$ z{eZXdg1!(?B?m%7#vO6O0#*s%RuKodjrtjzvuwMpY;7=;<0~MBE1)G3)Z2Qpv zxPrWs6t72ttyBSQ#c>Vu^s@bsR`XFb6NmFB4iMw!ad18b;+weVQbgHdk_YpI%^@7Z z5U}+mxYqD12O!t<2QEwj4;5eJiB zNmaPs%>lk0!ZgVt1a?*c_7mB)IVu3gq*}#n$<~6)O|T1)9h-f)DsT+@Kn^{J0TLbE zV^m-+_)DaKD+6|m0(#~F!at4xMu!LWjKChHwUk5_5CCzz_zL)b$R2WmZ_MEGD_r8X z@J76#QTh)s6)qtR*!=*Q_z&=q0>S{_^)DGHe?k~rIHz;5J?vWrYE8g_+C%#jFa~6H z00Rj2C+wkHHTKY*762Iobpoi5!@U8n7d)*;cozV>1z>~K01s$fIzjmZzyRGLyxAVQ z4QO2&?4i9%d&sSmKRAFZ+aRiV;0K+B*gL|P}N@V|G%CQY1BrOyk$pLeNyO3iD_>f@04K%hX zkqsbi1BW&8@K6qT2yihUvcmwndL|s+YBL}}9qb!k7zxan7Z@C^#2{2qCIbrzAmC6H zNeb7Cj=tRJZccR0VZfEq<_M&|3cjy3Z1w?%foE1K;(0WGZF7P!M}}Ml`;s95T;PN4 zLkrv-LwMg4*kEv>_ux$I@Y4vd=Ud=AcwtY%i{0Y&3<2kykiW1z&?9T0u>UvtV7>h- zA6)@?FZq=IFY>`-*9XITgMY+8kaq$T0se?s18#Z&7EXygh#f0nDwPtA z@TUXf@xumD0tEWQqyN!&(IXD<8)SIkF9{NbAVI-jSC4)`B3La5pp^ghgRw9i#>0JK z=l9p@s7xavcgSQpNAlQbCWTt1SFbo6Q|8Z=d{M zeNjV_>X%fdTg)BaNrpST=<^441?B`- ze9LfQTGl8HWE>M_3)E?kS1PfQe8o`C`ir+xJ}PZfX+M;UwR?fGp}vDVwf{CR`HQA! z=nNB1b;@@aZbfn`y?=axn`H1QC3IH#w7S5LSciCuJW{K(8te@aBBO?A{v~5vo_H`?1F?3mDJg#d>!Qen%e>9BfLa}27}n= zb+Qgx3eLI7$QU-^W7T@1*@f5M=g3H0t{zhstg}Nfv11JxZIFH67*o&N44smYye8-P zvPev&pRxY0eQ@Gz60yhyReE*k2IN&`SzEzXdq&Pe&Wcm>{PqI9H_uo~`%-W+;`>@Z zJ|i{r^!t^NIPTJwXf|hpgx8`P!iT}-z5cG%mk^1YCtS5o=X{eJ6Vr)|7XRRBZB8Qo zRKoEMn>)eOrbKQmt>(kQ6^i^+=jh4r)K({l=TB_PSDvfs%PCDeW4v-!&!gtq#3HZR zH4h%N2SeJKhD#PtR&zY|76X^QeOMHKGHOS5D*WMwUyRGGWGcpxqKn9tE?uMQbn2|{ zpRAbG1uBoDnJyWUe&Q`={3RMZ8rwqd!)!&-_=oomqLjD)ql}&GFTp*p#NQ}l#BdR$ z`XHE=oK1aIyg@zKH0BNOB%&^6fxMVx?0yU>?@xr5pe%JBWeWb6d( z^u_gNGsK%*^LE|}m8|9fP_B3{qDVlQiD*RI@sc5AktXezoS-4y49zI_l#7X8)k@^Z z*H1;ak*RW_C?enJeuG#;4oobtoFO$PS>bjw&1e6lV)~<+itXb?72;Zn z>BI6zRTXlCrzBin58oiRo)a#*KYTy2n84+7rZ$hGOfoD@=nrke@zna|Z``T%zSEck zUB&mcvk?mJsLZc|RjvWXku9^mUeG6z$%vNOHm?PK*=KKW1kGgM*V<*RU+tlNG%u@A zW{^=4=UlOV5mCfI$41?084TP&;xCG*UE~sa<*kVyLQX@O_X?6;W%cYOt?#jUh<*Cj z3@Hp5d)Qfh%kU-AJo>R0_q>uW3AeZADmJf~3bwzTWm#8K7*&o$&M#cA68Y(b;xkct3WsbT|8+G-*K!aZJ zntJa;E#ynBRf?!$#2IwrrFV#C4Q?_bYRp7av3;vgHjvkc4oz8gLF(Xcl(_uTiKH8E zH70vEkm@Iukd3Uokl-!Km_8R-lN2(A(sOJUieKVYDS5OP6q-?8KIv9dQQyQJ+6v2?Lt+ose$nvbT|{2}9(que>S z04aHpH@F2?qicCb43=`$^UgO|hniNet@rbib=Y58rFbZnw{Z!f@|ImWIhxl9p~b%~ z7WEBLs3iH0*9k&!`?K!58J+~QHGji z)n7!9pu8{i=u9wIQVHT-N1lzLtdeEOjeR+VzJ}Cp4}Vi56g&Xl*S#ESbgT`?W5?E7 z(Dzi_q^t#V*;522hCG{n`sv2xKJk~Os%5RPye)Co9oN{%2gkD~MdL3u( z)P%R;w?-$7iyBqg{r7AE-jk=tw1sOwoYWcne7d&8mQSFH`2^2b zi83PI53P#PrGKrH1-!GzlyNdP=}ljh6V6VP)|uXYoz<3`(y#FK+MjPL<|+5Qnr#@$ z^xXqAo8`adE8I$q@K!Zymj6?fEoa${OZ_Bb@zapyS?ZLZ^BzC9-`&^Pd;J+IWs{{9 zKWpwhJg;0~NilVatxymdb$RZ6-Zcy$gD|`7*JaXE)WolYZRKxbnh1 zu3kMW+W*)6*4PB|hSE&;1n~sndhg?1UHE z*hFLJmN0h5Z_@d%6!5or@6B_B4|;TPhYx<@yVkgbnawEuEHnM>xMM1vSkdm?cJ~&6LSoP$?CG&mmnfI8r%dKcr|3;1A`6{pZ6Db^4q3RH>g!qX$Y9#GIsI}y zi^;if=dz3hL_**9%Q$6c{oFW*;bD38GP1->gVgAN$?~_W%8j*;k)6@1y%ARoxS7rm z1!Il*uk_D;n3z>~`qz&F?G`&*r}u!;pT~3PRpe6*+SgD1UZh=d4d6_)d$)E%U-PDf zC)D8VNL~?HBJOFX`hWrS9RA>^=i%usZ>UnG;K^$3LwTl@3x_I3(r z?q>vF&YJGFkAJ;7Pmn7rolp#8A7skBS}!boY(loF*QGt>p2C*8`uJnsQa8kEt`pwK z_Qvqjhh|#=IZ?^ttnVh?8Wj|rwh3Ce&=vlBFu=%qoNZS{zA_m*CBQK2s}ip^tUETU z_p|R^9dc1axFUiJVgFB`%HW^!|qAKGlVzeHJuj>ASG`IZ{EsWu)NIXzb88Mat1}*PNIs)6lg%)9P4vQOlc7 zO|q-Sui2flsQz|QToaqzI(gtwc!K5fNT(Eyz$*uwlE}$PLlaG{ZSZOg6ggpYGq1*G z^ph~Z$Ufz_J)L}+ALrd=;!{mdSBb@PUR+4PH&1DQCCL;Evz1?6XqlhHqqFXPuK^_-ml^JmS-X zcPr7JsAf-^;r zJET~lyZ4QEDbMlbaYzg`w)=T=zWs7>iPAk~JYML4|EJd$a!g*X!OiuV2PV1fGY6g9 z#8|6JfKP!6zfz$>f}MEu=KI901+`~A>F5}Gta{QLbv~s)@Fr7gS11keINNi=kiVJV zYqw3sEhwXeBY50LM>zxicK36rmkhnlwTpFbMa)*$lVYQ$GZ=l6UUf)4KQBlB6=|=b zoaJzC^IUqIS!8CvIp4=A_tW!R)(v-SeD5alcJs*h_TL61rw4+^^!sM}OxC_kq_0~o=9OyN*EY;S}OH+TiZLvvOL>o*}P${Ws%85ETY90 zA!176n*s;)MK4oj`o%3%J`fk+(0OA^{rlF+j~}o0ewe=}J;VNsy*eR|+sdaR*tK10 zb;~A#`@`S0nzZcY(?#nj?(f0hRXiMI8_d4=W6x$T@Jc2G-?VoO^AB^qLYm}n8Ofc< zAbsIlvY>F5f=@ZkfPqEi_Xe^@rxj1QX5Y|VCG3&x4L@~Tq*Giyz5lwD6+hbZkgELh z$hy&O8?5TH#TfcsmTy6HjmkNTF*@#3)zmRU7YeV+iE=9-sPZ-~V!oe!7otimh(Gz8 zQd8f7knPt`EaH`4vdb8JxKLp9T4&9_UT1jmb|TH#D~c7iJ-S;DqDqp+rhcq=rOUtX zLXO4#IPrd|$GG4w*Ou|zmV0#InHP#TbdbPfY5!O}HmtS$@q?eb2j5(8aL&UmQ$I|( zQ9>SBJ~r!A)DceZ&sR{B{qqqU+7Gwt#A$*Z*;)@+t-el%_@r)U-M z5Oi7HG*t?F`Z;YMy8P`&jqZG<`ri6#Y&psnCEr(LQrL1T zd3S67Pw~6VJeWbejYME&WU-6?w66R59HEIH5vo_!T;UlSHvfTb`4(Eh1fq!{BDv9guX`yUP^KP7m=&8LR z)~}Zj%wk_5K7X#TzkW6LVERKl&EHkcm3xLdqE}DGkERAxEH>F?{#upY8qYR=p&>fy zXLa||gh}nFOxYZjp@)+Yk{TO#Mrq~Sg|<&Wtll@Ln0Bf3XB$P#bC--TmsGk1KvTc> zKhC>-cuy7?y|D)h99 z&t_iG9W~1jJI@;*ikRrGoqpBlzcS&P_HngeQHG0{^|inxgXLzAZihk2Emg;w%L+ns z2gqcPLGYmxzJK!smx6HV{n{>e@cN)QL)d|*p1QC&s!--M9Zu$beMhigFiKgUe&x*B zS1;nnkT37ZcgH*OO?-hT&*%R$AFQCA*+npirRio@>joO){r~+fPmRO zcM?fVXGP?jOI)k_D6L*zlg&yo*8U={-`m3Qcw+uFF;nC~jLc?%@$*ly{g*rjUsNi% zMwU4DNi5j9)0UE*{UTV!zO?2qQ+p}7iP`sCM#+HkdY<@-FsI#H-_yG0Kb&su`c8&_ z%yMBpPBx-V6#QGj6rf1P6B1}*zEum|OiYLrANao2k&%1VeM zI=MoQZx!((Bn=?`MbW7zayxB3?qvlQK@2SmZS8~pp@oA^v0n1*d zeR%vU#UAC}kIvWToPsbRoGjZArq{=`_|v`*kB#*8O^Jh#TaePr00LNNc&%@X{JZ8o zrha+`w_j8|%MlyaJ}>pb%3G=fFHS;b&d9xV@2;f&TK$hD1H5&lnY6}@EU*2(&rLj( z$6I^RDHEw&lc^M1KV;6GlA%6DD{)cj#ASh7*1Zyv5~?(l0``4~PTue0nth|&-~Dz+ z$XlxivNETjCD|GInFrjXyCeIXBpUbCwVv!@G(&A8^xNJG@!{TF%@n(?a#Q-#_gO0m zDtZ>4Gt&<@Bih^e3H>JLZ@Up%O>E4?&p8nlqm*LEeiT0+mpb|D)_m7|#Hy6oFbHGmZ*}L?3J$3J7;^PZDcr_nb7PT z2hBNTark}>!>4EK#NPgz*nj)JOwg&BDf4AIAI`P00Gp8wWj@g|1Im^6ReS{KxP@R~ zaH;>@>38Jx1=3DGfUH#iQhSQbK$08MmMRH0XqmkBebhb@0`EdE2h*`O8aJ zPLgk~wRFgJ znSK3M7r=blPqy&l&$JxYcQp^68s06)JU3_{dj|7jbt!n7orfof?(1;KN8~oax2(utJ%{`3=d99|(2oK6eXzyE%M z^70pRW#xHjzK(qAHdz(xpE1F%v$d97eO79sjodWM&RILIT$~dXyLA^*99aXs^pmhPk{z&Dzg$}9s=1JT$U9H!WYS-Cf?F5uJ zOm_529!k=`hce_prm0;wUB-!X>Qva@SET#uMDz^&__?iO=+{1`Wq<4dn_RYA3W8Ge-lTLZ2Hp`^? zTrIz$%BjU$p46#fkZbnj+q_P4=97#{Ue|0x$o2fl?>o*YNh{k$&J^?}^`w?Ij;}a>Dp_fFU@;%bj_1D4l_u2jI`**bp-TvPY;@t| z{a@I~$VGZpMSkH}ev;mE6kpGwc!9cBezKzwck)KqbW_S|gm|)6jDJvd+_kU{bE;z} z)eHjkJTJDrVY(e^sK_Uk-$QYyRv^(gP3s<=q}*MHbE`3I^QXK%h`sHy74DBGxUEWZ zJGVY{9Ah!(`D}UFbZWMj=6N?+eo1DJgN>x=j*mg4a`=Zo6pM}y#K-DsBRpKW??+rp zPEcJgRU4!X<^OXm^j?~dt;bde*G#5H!P)-Sg}CCq9}+7Dk_KCGy!_Z}A1*_+w8qnS5+3DG2b=d4ZhB?4!D)L78K8Og{F1w zy4wZ`CWWkO;lZ~2>KimEkG=fr=JBZ01QB7xx_-XX8DTcx(DvJUr99(r5&6ecs>P^E znARsaE>+O@mKR^bj*_22KP_P_0E4KAWDm=@|e1U#H==4m;T>%_}1N$a>>}(8Ktu>(1c61jULxiF!55L?5!qM>3wf zyIRNo{rk;pTgp$*bAMm?5-lpIW}%uu)M2=NeTycfY%7pY=8*hym$Zs_<2%Y%8skhg zzMP>CluN3977B9^o1*`&doA^8(LT?8<+S?6G`rEMq1t)K!aIv$D6{J9Bmd5b-t6Fw z5(T!;0*llR2XXZKK_?gc3qJlR%pCuImZA7mJ`4A$&RhA*vO=+`#}y@?U5at*n^d0t zywyp3<$rD{sb8tv)^9wpClh}LgaZ-P%B1dHr;g1N^&7pE~vD4D>a_-LQrY7u{ zzg%6NRSvWAA$@!Qq3cb)Pf^I3oGz5Bv--prw0P`d`^jn=F~YJcpP-N${})-#pRQ1= zIRCb`F)maf+C$GAOA(RH!k73_O!Q-Jrik~pTQrJ=S zT{qFmH}+l+t-BNgiF(Y5d)iv1 zh_R31oLei6*sCc6X44JYdWXAwMJ(moMywxh^`<`vb`3Lm{5_RTVnOIK?KGvtyL{(S zehL?&pT|hyiRVOr+X3SipL_D7UoKSzJBeof-1em)^z)Z!H+?eV>BdXzp@dAZg&L!o zg^l6d^T^Sh<~?gZN%odkO2`IU#*8#I?+bo!pU16~+1}ZAjik*(9+W@t*3^GuKVfom zDy&~8pkm~&)vZyp9GTtU@hyS0R06M97ey`ik{Y$T&c^t3Cbd8+1%hjDnyxjjcU$>A z!FQ%U{48c+*}}v5q&zO>ri;qT(}{x}MfL}y_F?k#<<&#i$_lp*#*0QH*he?4RB9=A ze@h6Z`5oL^>CcH*Q2$%=8sihiRkiRg5EnLmvfT1E&3jsoJj>Z7wZ0bGM`G(vzFqu8 zZnw~W>Ax>7{=IlDtpChk`ZFC5*4>6x2x`3bf68m2ml)4&tes;yud(HTo@VJSl{-$D z>lG#?MUmWJ>+Dxl#C{f=cbRG?>NpXLulxFGxm4bnv@QB^Q?%Ipp$gl;z|~rx4rUfA zz5>>v{7@}VQTnf5jBUrBc)s_1?_ptkA(+MJYS@XG8r#w86V!fhsdwF#)m?r!b2NX} z_I2yuk(4yGEO_^tM<`JL>2!azYO}>mYfk*lGu6d&qWx{s1%~&UhhnsPRqQ76QDlL4 zl-A~h*RQ?psZ9Wh|8Kimw@(Y@lFm85fe0;IMF+|nqC}^CUY8PN@q#qkL~0g**o{*L0ewlT@e@I43B}PpmtsDPj)N`0{sPX70rpGXQ1(+h5|hsv{~M9 z0Ln?K{W^>yJ3IIQiLv&vzF#2NbYS?@`M~hI9gCfP_n40Q##W89SllS)O2GpmWYQvT zm1!#W0vnxzS#+qEVd~eMbBtK7%huUG{hX@{v(luRSEM5Q1O}4Wc7hq#aIu!Tif&Kk z-rhWBpW5cj%Gy&Zqomd+WzK=sdO>1H_vYJ0$FVIRLnn{xe>mPG%eVz`d3u$GFM8cw z{_wWDD91P38yEic*OPNv(X>u{p9$CFX)lb}{K6a^2gDV14mKpwN&D-=$YMUtQ z`QP{P-oG=gH)S8HUo)llklW-nYvb~|tr5z5E!UNUoo1Wn0L!Q<4d+`{I6L`62<&KsX<{4(+_ zq=vI-{4Ld+@+MqW`}Cuka_Kqqsdw@9+1jEIU&ncpr+JM%+H}KQ@0*oF?ws|!`St5? zroq*P;5C`tdL-qG%c<#VO;3>x$`70zDDQ2!1|?qj%&qmru$@Y5M%TODn~=O>F|N>G zUt?S#_LJJ|SM{0Xhf~MJ>{I_l*LMt6NvkCFkulOo*PRjl)lW;Hc@eyK`A(EgsgiGp z;<;JVxyuB(;edOl{KLs5-O9gzI@s->PLJCny`i&sEhy!>uZXT@u*f=`Qvl$_d$0MA@)}mI{VBMpODS`IE8^~ zMBld=&zVeXglgl0jv+6KT@!M!n5OdSDjHH=aqyzc%6Yp|RW5CM;qiqJO@2vGWB21E zi)YW~#h#12vCtj8@ORTEOrgQIVJ%Lu=S9pbQsRo#_tl|Q|0^cZ9vjAy9XA z1erih$`-x(f!sc9`vqF^7spWikZ~OOaOygnXApC9#hD=HK~9>K5#t2+u~C%(8Mo%{ zxkuI+@uzsaCFY-U#vdG)x0FH+tsx1#kf z++ftuy#M+cr=!IO6aIYx>TIff%QV$gc7<{)_DD0%oY15=W_DZmGSk+E=Mgq4?dOEj zZ5~I}Mz>6>ea%ex&=;FHDMl@Xy_|3?lgUaVC2^8ylhH(9&+|0n*)Q@(`q5Rs6Mhp! zhg*92tGN*?d^}>T88W`18@vv5>uOa}LQT{u=OYtK!KqkNQoY zcc!?Mi@IF8={$DJ!Rp_sG!HKKluQoNt!lWxeztp=QC#5)<3(MA({F~_E_vzb-!iHi zQH`7{$EA%GFb};emLK0>j_e=QuZvwPdLwJ`dU7A<-(e&vpmgA^mBF;b^h3|@bLIA_ zTYs2MKcp`xJ)Jh&uOVbgwPtYiEm8F??OGQK?w`Cy_4m2bzTnCnvzw~)s2aUaxkB8| z^y&|znAbgfHZs+QvH6X^xMaxCi}~L?(RjftGF3dPww;eT2E)90$8AXhUaQNzVYsbh z!+ncQ)-pZ4nM#0aa zf4Fon=$gKuU9)R+itQm2Y8kK{x&5wZX=WmS>iPKn^#=+~snPU0d1tw`k1d6M>1B*D z5=B>}e<3AHa1agbadk7j$w-$Ycbcza^W4t&W%jeBoev0t_UCTvVBPY%zc*i;WFhO< z;5l`=wk)>~!6t zJa5wlR_pT$C8_6ZwjV|kgD%lymNaRc)XTF6yc2xmZJTy(8#d^dF#mXWmHqmS9~7q^ z+*p3lbC+Y~g@vQ~C3i|+`UWgD#p7RcQjcmZ!jsFgtoAChJTR{cOjYA*&0ULrbMf}2 z+e_W_Qe{Vm^nx_)nDCP*H0^T9-+@`FeACw``$mLgKHb%mil#$ zOH6(X3ghzRcu^lWa1MX5#bk%?3aioVeg7$?_<*S*Vt8iunYKFQi(wD{MOQ{9-|IA# zgAGn`KTizPk3Epz;Y#Xg&nJtK4bV8FX}z-@JhzIRQ+By{s{I+aT`0xHcOn_N-S3tR zaf=2AEy+QK&!V?p?qF^!-e_m?vp6xf5d6gXwr=Rc4RQx7dLgHtSvE5S%Ng19B>pn} zVEjFqoWRR;$ppf$Pmz`N$Dey~xyiF=-uS>-ORphFrdB(B%haHDljF^(-*U%rLds)3 zrSZ@YJmO?Jsp(bA`5#214Ic2J=N{8e9gvwKzNT`4Yc}|wVjlgY%fkwSKXG}*VKrsuDx8Lu(Re(tgEQpOiHY~5!3NZGu7?-jRC4R(#BV@ibBJmhMhCt zRP&@B8)#+!8FOdha=0x|Y3UY4)@lV-M)es8{x-DRij3^)Jv zIIuQ@_gxES%cA%r?|WzAz8k(bn6A_2ZI~%-I9^uY#C%H$%lW2Z!d@RR#utc;F{U^dMXnk3H6x#$9r^$n ze9B_gekpxi8znIJ^2z*M+LH#2yt_?T*NPL2R^okmGg=d-wY?n&VwO}}wdky+8#x}1 z3=DoN(&x-l`LI;$hiV*nD`%b=>s#<{_e1;y$%%Bfx0jwU&|TB&pnIa7@J_w^#1oM- zdJpMJG@{?#d2%A*y-#q*FOQp*wv?KT_8E>;Yza!ZCeG@yFrWIz zI7_!D)mU*T7#DV*lyLlF%gRZfnXMP?_f>r&Ctsbsd#NtZDf)MHDwo9fmgupMTuus& zR4;rU+Qj9!p||Plh4&L|%q!kba$fi(@b$@y&BRtsgz-vW>kofGPOC4*gq7+lhVBuoi zO_Yz{$Wxo$;L4LLdRA(Cr@n|Lg+I{fr_Y&XeaY}3&7{DOY)9?A0#>kt-+K^IYSY{6-MG6STl3rukYNEV4Bq>S0 zTDK&NGINoO&M~iWd_ns>a_r8kW%q&GGS{WtKSjsO@4h`3I`CqU(s00NAh&0~to+IR z)90yAj82?oe8zQ!p4KbU%V6cAZug67yyUD3S-%_2$#(PuQz zZpz~Jm#oe!59gFliTz}nCzL0BytgVw`@|&*>_d1jT66w;Cthnz=WO=Vb9%C;I8F5$ z|F*hD8hgUY0 z1)t(d?+HINBo5Rql7FiuPa}QJ+o)&NL+znBJBJz$Mw*q-kv^f@{k|rora6ElBi9NZ zDc>COYrn9WRPlRxW=G%{E??~;`2VY1_1o8sV(`_`jO0@Rvq6*xx)TTIR}Sd*uDl^Q zJXkos&aXJu6*N^&w?yHzrDi$1%- ziovRL<^^Bf^ZrWr;}?kaMWPqJFHqDn8b>8ooo+qdFyil0qv)i z?ONNCOOHN@bI+VwC)r4l)cBJov#?^6nGvlm{pN83W6|fnM|xMPr!QJk+bcwsPhZrP zv@c87ck;>8>+6CD9-NO5B~|+9=#QT&i96KN z-!g^Xn2#3{bP=QenCmoF`mxA!AzYMK)Xsfx`LgnBDa!k{ zddqB`dkpR4#SNs8=BtT?T$cZ%u{!~Wst@}Ieng7Us-lf3q=YDyWKU!X?KIif>`E)C zr;EV(3Bi=lF-J!SkdNq|ii{Oy`_ph%G(s-F(`$XTbr^~-3J{wQt zEf_m?RpPV__rh0A4Yg})vUA2ahoyI`fUw7F!N;-S$}2&VN9z{c7dIXZq$& z=%kaqw0Lmv>W)*6x2-F*l?>n6asNSsCsX%a2pY2`)u&{Y>f6RoomSrYt4_sm^Fg(6 zqpGxPYVT@G8V7x@@_o87)9~%&dmFMMFTQ9re(^bZ*lbnfL3WLCm-?h!JgV;7&*aMB zqODWygVU$UoYBY(JE2~c;^b6e-}B;}Nv+0i$=JDR%9!LT$Bt+7U1X2%GcWmTPQo|U z;x#UvWTtf5rBG{8p72P=vbgutWoP@u%as51#khKK%&U*BH=TWFr_i%-Sx}{iMV;Q9 z(Mib;^_pezmDj#bzrI;x;%2MPejoB2>X+ZVn|iG>-`3uFZHcklqtw8-*fT4<8~(gUo%5nfm9kzx+f_T%=hW-$TK%wEYUY}GwaV$vCYQ#ZS=+v>;-q@sC9fVuyNpWJ zWjDQWx|(z;qrza3V!l?+`oJ2!zH-I)Z(mRwVbdn&&8z|wHT};zeTPZ}980s4n(Tg| zvA@d1GjqyE?|ii{sq5$B^g*6`6Ytg@E2$|zmcDS_rL((N9}yzI&ex5tK0MnZ`$PP@ zk^gqq+giA3v6SoX*)~er1#x4)KC{UZ0<<=GB&Nr7sJpdxk*Px8m-7x^T{bR1dUKu6 zY?lVzqS!zg@A?Isek>Vdo8;Wzw60QcP0V<4D8I^HWA3%Jo27@2I^o(TO6u|=4U-c~ z@;|+b8?vn-q2IP?vfgqF9KXpAPyeCkvg~|X4?At!_v#X99_zJd*N?E* z_HK2zwtOCNH^Kb%aoPK#J83HxSWDlYRqEkCW_?OdsX@{5A4VRE`o%pC_o$g{;d`NE z<6=XzskZqyu03|CZ&au()%d7&HD^xmyR#SB_OY&%9{NS?O4oY#i*zEh?BKE=C$2r; z-m|w=UB~L4rrUQMUpcpO$A#L(w&l|OC1XeSd?>YU(up>O(mh{Zvwc>xRCRQgO`xe# zslnsW-g&pO-~T zZP=%~TlvBhcf;Xt3Nlhv5`4PP7Ue}gj!$gNs+c+O_S3V5`$J<78tokDwWIUIYqmCZ6zhv)8#YOWWW@^`q}8U$p8XGx|C7qsq{dg<>PnS@h& zPkB%1G^t7Fv)IRo;mGhY;#h)jeb`)-sQY*=5}cH)GThEI@)thdF9hqhIxh^*U z?@6N$*ajZlYTf&bPk3#9TkBpHaanWv&Cit=?FyPc!ne-E%Wbe<7p0G1qJ~@6n@Ab- zDZIE+yQdHs7|o#TQic4JZtYOxQT$>C}?feM*zNoD0A6e6y!> z^eW9mpWA2p$plrL@3%F5vDNAO*N3=W?U8(5bJWkviq%FQ5rIKcAA;-s&*d8Gw+#`B z?MqJi*!Icn>OCwlcb8zI@n%4`!B$h<0~S45ZMS~;fDR9*emXP1!Q*3x_xp=ob??+Q zJl8zoA6)v;e@nNKH;qe{?&!W&VXTVupxJ@XCVR`ioU))aV6x>)nXM;#JA{?`eb!lS z7n5$R($Ov5_xW2xC3(A55~3T1-sWaH#>z{ooOc=7M=1ne^$PfM(j+YH_4KvV>rXfy z)4hJsG_ZS?;b7~nZ)EzUlx~wXzSqGd#A&>Lagk!miFS!9qbALW2(R|ue`iOAoZ0+q zM>;s{{8ztyP?AGKj^km+e`~Up_RF2BTK~3Z_31*t9peIHKczUXS=w<+{`Vq>gppG; ze#EGT{=Md4<91n@PCmtDZ`LjKS?YD`s`iS>(nZ}iR%j*`YDuX@=FC~Ac+dJ$M$Y+; z<`1?_d{A)MU_+&{yn5Y$pph5_@@*FNnxte{JT#~7zH(mq(Jup!7TbS+5=SaZc@iL|MrGJzm4s`F-ZfqA{PP z4@{RAdOymUE0q^ywQJOHw~ad=NKbxIpw-tp#34{iVq)j1-?AorUXhajspg>VsXaYQ zruO`LFVta==8tZfVIQ}SoHHvX@aYP5N82w8H@`ns6P8z9u_rNYo^1B0u`~Bgo4L9% zO*$_?y7!a0dGqC7dK}OiD|L9$zOtahP62mgzDk(IUEX^))@?@0=AFyG*WWl^P^BIz zZM{&-f7SZj9{sx)wUMo`6n}@{7L41PHKjO)kL#WdpsI@Q1kWWLC$66Qa+usOv{3HWPV%cGxvGH+6h_< z-IK3g)~>It>{#dPeej^hVdoz=^kWat>(^@gz!Ih7i6*q+zMMON_*r6ctS=-@S>hZVcJRF%(Y_E7ff5%|$Bc<2h$;V7BNe#Vl-+B3hTPO8b zshpIU*D9@#s?E~(KBtvbc5T|YA+_{owsV!=@cYTbtM|4)(eYiq`Swfidxzh8^XlR4 zErO=o$O9eToiMb`wD*%-n|$cbSSE%;t`mu6F$5r)V6OA5=E=bjcaq#k!)x!~@s zv8OG2^v~RRYTK;~-_8V8zU#fl!STY4qy1maYJ6io`K6}AzWRjP85_b=H3t^G{CwK* zyz(f!u{%Ebbw9MU0G#f9>CS@9LE`_J7$b3VIQJ!*pQ4>$%FE9qT7u+1JnV z;;wzFh6&SVr-~kY&1ju^E8}cs?T`S^D($`d_iL!hH@<4S-8R0@s{THMPi`7_P~X>G z(qrRZi7daL!+q7e?MlfV{arrv$4`;$HQ~``M~lx@mvRkPo1A|4AZ^(A4?iO>d8{gX zYuWFG(ND=|*Ud}$vve|D7=n%2675~8z;dR+S_)l(g_&$$m+QX(}$Y0B!9>j}Ycvnr;W zjGSLFa?qka3N4YHvzRIQV4{TbzamfVP zM_1apRvazNDfTh*e_}LsS~t^KtJ69K9{4n^N8QmbzAj61N;jyz>(V|wdylo&{3VSO z=1wZid-LyDrHftb6NkSH>Yej^k->7?vpYVXOqJ{+IY@H-K$(qR25dWeP-&p1$D=-?;oF>-TVBH z?%DtRV{H{a!Oh;f!gpv^T=v>e>kaN|n;k4q{Ce)p)}-pvo#BScql-7kyMbSgqxonVT9nY8jqdkoqDzwaC48pI2;L|5c4CD*fl^cl*%oN!H{G zq6^>ab;QRtUnQ>T_};quj_hJxIjbKTL%Uiw42ut#cqICmf!4|Mq6rPpif0TS_NjNW z-Ha(BsRXY~=PXm5w~L)xXQqGFSYos$YFTRD>540Poevyzv$^EiCN?@Mr#9l^x%-=k?C#rzZNi2I_7%ohSd3879OE!SOGQslM^8sr{BQre({qxZngZqNnupjZ!6J5PD*Myb>a&M@kwo-RQUn}W(sZpYGtM%w@lJZ zp~F%sGledTTU#j@Np6vlRp?@tuh7Blih`WkRfV=@mldSOw3BrHQ{J|nDV2(%n=aMN z|DSa&e$};6xGf<$gbP^wr|?)_XCu0uq?(`n_)A8cw`!HVP`OKK<`C<9+gh zZYp#!1P7AGE^gJzCSO5HFs6{Nj}b;~N&j=*es8md!Z^v?R)5%Ln|9-9yc4evU0C5O z(PF*C<1Ki-EEJqtomFtPRG2(Q!Oc=(#yABhr$1CPqYX8s66st|p1xe*i#z<@&T+r? zm9;`%E6M0T?QAX~z9vK^*Pw|Xf1bG1=Rf4+n!dsK)lb~H#T|x-Gg3m`&lXK|4T|RK zO<75SF3ZtklB5Sq0Wlv>t*HM1ikpuEj!n58k15Aa6vj~*6;gs4+(}c4O%Vr@Ds%>NljN_x*OZhLuf^{Ul0wJd z0nJGYivNkb{wL;V!tY5^P!jI`4rxwSctH2RA5~f53B`O3k)}yjsH7P>)G^5lZ)lG9 zP17VRyr-Gw*B7qWK=JQ(8Q~knDs*d_=;9~zIQ*Vugw_<#_?3_mWGQxP5x1vUw?*8A zV$&8ezcz%mhE_U z+>Yly$45BEbC=^A|6@Egc>8#T&J2t2iHy|o5-fiO=E0#}L6(zU^~Q!o`9y?x1PhT- zo+6RGN0gVpMQCtnM5MS!Q`TyhM{rXTaZH#;h__+OV5r~~8WI^L@(2#|_s|(41cU@c z>F780a1>WX_oiTIQ_J{hkB}&5b5{?~7V#JkXY0|uj-C(}5$YXDe`|EcSq$epBfirU z$9j6=d42Ky5b?c%_})-_&v)WBap$2NiW|f|#T|zUB2i?NhgXou%Rflu>k$wvqP;@9 zLL`bY8mi;x6D11s5=Hq(hXm{+Vw1^$H6^qn2& z<)A$bh1=j>_z{}W8yOyF3)jO-EbX^OlJ_g^W6%55Rzr}W z*A3cqL4wB6CW!kDgLL5|acm36!^uztyC$?^D)MDW@-IY5UWESmc|&M-4b~lI37-bB9`j-BMyeqa1M-zOCi6f<@Hzx zx4?9`2WG?L@HFK2>pcD{ybmA37qAM}!g|<~jyWE$0=3{EI24Y67A$S26Jl5B4n1HX z41u%ZJopz&b&?TpfZO3txF6=g(=3g0LmQUHJFql< zI`W<{2!_HamijF~ya=vjsZKK5cObtD9)w3A|IY|q=K|u(@HR_zO3?ls`Iqn?_%Hm# zQXT&6!}~)Dc48^t2eBID_YGWMAMNJITSG_a0^Q&Y7|2rHNW`;Y99#ld!L=|IZiBnw zK6n(Kgje7VSPV*Dl8(|yz1I_!V9qaOg%s5{`!azKZLOgA-WV zFP?~fVJM7*^I;rZ!P2;mh|^#u{2LyE$KW}55f;E(@F7c&^HY}U*CJmJzeB!mByWc- zOZ}8t8mEF-7wrac6f}dj&;h!zRL2eR3>d^x-Eg!oLjEtf8YaUuxE*G)R5u&(A$XRh zx);%Y7x@zS6js0*mg@XqX`G~NQ{0)Q{m>1nKy^3>>cOEb)ftW00y?l%*A?wEkoSf& zVK|%%7sACX)m@2r4cyG~cEVRI_4^4s(kTI6e?{0E_J!JTFf@Y3&Srv`By{0bXk8#)2V+uaU!VX2-n9DuwI90o^18$40T;p)cmWo{hwvq=gFoPKS{ARz3U~?Lf{$P|tcO2gJ37z7c*u+;Ac;+wD(K7y6-6|84zIbT>BFGHvJ zc|GM}SEvm8u+&cz@jz$@heLB{4ac**KUf;?hkOu>f-!Ir{0pvTX?zMx`z) z?Vt}#h9_VZ)TDLg@sr?mmewl)@n)FC(wIH)0P^SHP51Ns zs}F}EZ;sd++95v?@l+^6J`iyTj6{AR;&`|W`DDZ!U>fqf5buSjU@k0#x8YM*0sn;! zur-|n=k1e$-C<8S0O~+vXbP=Zs^x^(6;46k8?ir}$;vUyFD>OhrBm z@g8^p`BR8<;YH+&5Z{4iEG=K4?@HMIa2yO~X?wz1em=0Ye^$XXxE*G))c+vjBk&~h z`G~K=LgdTfE7$;~RGR8_Wa+(3SC-bp81ZDZPe*iM~zS+ZrmcR8J4O!r5>=Ol4_# zSuE|xJ@5eXrx54Di^vxtz5~nHR)X-1rRBay{sU~I)>OY8RAi}t50?6CBR?3LLu=^7 zQvZo8_4h?S5Jtk;Fb*z(tKeFg#!|fucnJAp@ERX&;pFc~tTo&YP)Fz7@qW@GSfc`S%pu z?g}#@f3Mey-m`ya={+<5mZBBC=M;1z=gf?v9|-6~MnyE~-#i!L6RZ>E6B8xqczZ;7 z2s)mTk%A8Wen1>FspAzHrANO7_#M$N0eFngAHMVVjQPLY==T8s=Q#RWUWeDk+s8B7 zPZSX18%k>=p7-$djPRM&vX#Et4-SZo;uZZh!Xv^X#LtIPO@ksr{Qg&$-~jrmC)#QA zn`b#qKWU(ten2qOCxmuINNALg4*fcBkocDli2XvMb?BEBVLlO2bDEay<1g}!@R&(O z{USo6!)QnU|4sb+75b?BYcilYI%Uj%)&xDe(V-~5{kI<C=O-H`6{t&cJvwZ~6Zhj>^VD3=h!Wh7{=|x>HPmkn<{91&zKNfQ zWOF|idM?vT!LO-#TU;o^^`x<2BkI?@Ebh#0JcZJ&Wj}sD^{0M`|LMo?xBk>`ANq-R z4$WIqzlC%zqj_o`vzrnvACF33`fUh3Nc?!vDJ^kr-oGd4CSF$#Xu3oPQ(g1QQ`}td zI?cE2cX9}QR{X8H&D;B(5-peOM$6^bR$eZ> zO#WJ~92Mhwy4Zi+>4o}f^TCLI+}`a!{XVX^LB#?wYrE66!Ut`UC3MvpJxy&HY@cU(5Y+kM@fb zwex=Ig?_v%c=;`c3m-&+FoPZs70M5y8`tCK8`o;_FbS?+^qz(XV``q|W2a?5^(A!f LxVe$qnrHtX@qk%C diff --git a/togles/linuxwin/dx9asmtogl2.cpp b/togles/linuxwin/dx9asmtogl2.cpp index 969b6a91..41d08a94 100644 --- a/togles/linuxwin/dx9asmtogl2.cpp +++ b/togles/linuxwin/dx9asmtogl2.cpp @@ -2148,23 +2148,32 @@ static uint PrintDoubleInt( char *pBuf, uint nBufSize, double f, uint nMinChars if ( bAnyDigitsLeft ) { - uint n = remainder % 100U; remainder /= 100U; *reinterpret_cast(pDst - 1) = reinterpret_cast(pDigits)[n]; - n = remainder % 100U; remainder /= 100U; *reinterpret_cast(pDst - 1 - 2) = reinterpret_cast(pDigits)[n]; + uint n = remainder % 100U; remainder /= 100U; + memcpy( reinterpret_cast(pDst - 1), &(reinterpret_cast(pDigits)[n]), sizeof(uint16) ); + n = remainder % 100U; remainder /= 100U; + memcpy( reinterpret_cast(pDst - 3), &(reinterpret_cast(pDigits)[n]), sizeof(uint16) ); Assert( remainder < 100U ); - *reinterpret_cast(pDst - 1 - 4) = reinterpret_cast(pDigits)[remainder]; + memcpy( reinterpret_cast(pDst - 5), &(reinterpret_cast(pDigits)[remainder]), sizeof(uint16) ); pDst -= 6; } else { - uint n = remainder % 100U; remainder /= 100U; *reinterpret_cast(pDst - 1) = reinterpret_cast(pDigits)[n]; --pDst; if ( ( n >= 10 ) || ( remainder ) ) --pDst; + uint n = remainder % 100U; remainder /= 100U; + memcpy( reinterpret_cast(pDst - 1), &(reinterpret_cast(pDigits)[n]), sizeof(uint16) ); + --pDst; if ( ( n >= 10 ) || ( remainder ) ) --pDst; + if ( remainder ) { - n = remainder % 100U; remainder /= 100U; *reinterpret_cast(pDst - 1) = reinterpret_cast(pDigits)[n]; --pDst; if ( ( n >= 10 ) || ( remainder ) ) --pDst; + n = remainder % 100U; remainder /= 100U; + memcpy( reinterpret_cast(pDst - 1), &(reinterpret_cast(pDigits)[n]), sizeof(uint16) ); + + --pDst; if ( ( n >= 10 ) || ( remainder ) ) --pDst; if ( remainder ) { Assert( remainder < 100U ); - *reinterpret_cast(pDst - 1) = reinterpret_cast(pDigits)[remainder]; --pDst; if ( remainder >= 10 ) --pDst; + memcpy( reinterpret_cast(pDst - 1), &(reinterpret_cast(pDigits)[remainder]), sizeof(uint16) ); + --pDst; if ( remainder >= 10 ) --pDst; } } } diff --git a/togles/linuxwin/glentrypoints.cpp b/togles/linuxwin/glentrypoints.cpp index e4f78713..2d48c251 100644 --- a/togles/linuxwin/glentrypoints.cpp +++ b/togles/linuxwin/glentrypoints.cpp @@ -206,7 +206,7 @@ void ToGLDisconnectLibraries() static void GetOpenGLVersion(int *major, int *minor, int *patch) { *major = *minor = *patch = 0; - static CDynamicFunctionOpenGL< true, const GLubyte *( APIENTRY *)(GLenum name), const GLubyte * > glGetString("glGetString"); + static CDynamicFunctionOpenGL< true, const GLubyte *( _APIENTRY *)(GLenum name), const GLubyte * > glGetString("glGetString"); if (glGetString) { const char *version = (const char *) glGetString(GL_VERSION); @@ -271,7 +271,7 @@ static bool CheckOpenGLExtension_internal(const char *ext, const int coremajor, } // okay, see if the GL_EXTENSIONS string reports it. - static CDynamicFunctionOpenGL< true, const GLubyte *( APIENTRY *)(GLenum name), const GLubyte * > glGetString("glGetString"); + static CDynamicFunctionOpenGL< true, const GLubyte *( _APIENTRY *)(GLenum name), const GLubyte * > glGetString("glGetString"); if (!glGetString) return false; @@ -284,7 +284,7 @@ static bool CheckOpenGLExtension_internal(const char *ext, const int coremajor, #if _WIN32 if (!ptr) { - static CDynamicFunctionOpenGL< true, const char *( APIENTRY *)( ), const char * > wglGetExtensionsStringEXT("wglGetExtensionsStringEXT"); + static CDynamicFunctionOpenGL< true, const char *( _APIENTRY *)( ), const char * > wglGetExtensionsStringEXT("wglGetExtensionsStringEXT"); if (wglGetExtensionsStringEXT) { extensions = wglGetExtensionsStringEXT(); diff --git a/togles/linuxwin/glmgr.cpp b/togles/linuxwin/glmgr.cpp index 7fb01e38..01a2bf72 100644 --- a/togles/linuxwin/glmgr.cpp +++ b/togles/linuxwin/glmgr.cpp @@ -221,7 +221,7 @@ void APIENTRY GL_Debug_Output_Callback(GLenum source, GLenum type, GLuint id, GL return; } - if ( gl_debug_output.GetBool() || type == GL_DEBUG_TYPE_ERROR_ARB ) + if ( gl_debug_output.GetBool() || type == GL_DEBUG_TYPE_ERROR_ARB || type == GL_DEBUG_SEVERITY_MEDIUM_ARB ) { Msg( "GL: [%s][%s][%s][%d]: %s\n", sSource, sType, sSeverity, id, message ); } diff --git a/vphysics/physics_collide.cpp b/vphysics/physics_collide.cpp index 6a6d185b..1c2609f6 100644 --- a/vphysics/physics_collide.cpp +++ b/vphysics/physics_collide.cpp @@ -1641,8 +1641,13 @@ void CPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, const memcpy( &size, pBuffer + position, sizeof(int) ); position += sizeof(int); - pOutput->solids[i] = CPhysCollide::UnserializeFromBuffer( pBuffer + position, size, i, swap ); + char *tmpbuf = new char[size]; + memcpy(tmpbuf, pBuffer + position, size); + + pOutput->solids[i] = CPhysCollide::UnserializeFromBuffer( tmpbuf, size, i, swap ); position += size; + + delete[] tmpbuf; } END_IVP_ALLOCATION(); From ae8b73626e9089a920f9befb667b5cc6542a04c6 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 15 May 2022 21:19:04 +0300 Subject: [PATCH 07/34] materialsystem: fix(hack) flashlight. normalizedcubemap broken? --- materialsystem/stdshaders/flashlight_ps2x.fxc | 12 +- .../vertexlit_and_unlit_generic_ps20b.inc | 1113 +++++++---------- .../vertexlit_and_unlit_generic_vs20.fxc | 2 - materialsystem/texturemanager.cpp | 4 + scripts/waifulib/compiler_optimizations.py | 21 +- 5 files changed, 442 insertions(+), 710 deletions(-) diff --git a/materialsystem/stdshaders/flashlight_ps2x.fxc b/materialsystem/stdshaders/flashlight_ps2x.fxc index 8ac860cb..000405d0 100644 --- a/materialsystem/stdshaders/flashlight_ps2x.fxc +++ b/materialsystem/stdshaders/flashlight_ps2x.fxc @@ -201,22 +201,16 @@ float4 main( PS_INPUT i ) : COLOR #if NORMALMAP == 0 float3 worldPosToLightVector = texCUBE( NormalizingCubemapSampler, i.worldPosToLightVector ) * 2.0f - 1.0f; - float nDotL = dot( worldPosToLightVector, vNormal.xyz ); + float nDotL = 0.577350f; #endif #if NORMALMAP == 1 // flashlightfixme: wrap this! - float3 tangentPosToLightVector = texCUBE( NormalizingCubemapSampler, i.tangentPosToLightVector ) * 2.0f - 1.0f; - float nDotL = dot( tangentPosToLightVector, vNormal.xyz ); + float nDotL = 0.577350f; #endif #if NORMALMAP == 2 - float3 tangentPosToLightVector = normalize( i.tangentPosToLightVector ); - - float nDotL = - vNormal.x*dot( tangentPosToLightVector, bumpBasis[0]) + - vNormal.y*dot( tangentPosToLightVector, bumpBasis[1]) + - vNormal.z*dot( tangentPosToLightVector, bumpBasis[2]); + float nDotL = 0.577350f; #endif float3 outColor; diff --git a/materialsystem/stdshaders/fxctmp9/vertexlit_and_unlit_generic_ps20b.inc b/materialsystem/stdshaders/fxctmp9/vertexlit_and_unlit_generic_ps20b.inc index ee4f7148..8f52fcd1 100644 --- a/materialsystem/stdshaders/fxctmp9/vertexlit_and_unlit_generic_ps20b.inc +++ b/materialsystem/stdshaders/fxctmp9/vertexlit_and_unlit_generic_ps20b.inc @@ -1,687 +1,426 @@ -#include "shaderlib/cshader.h" -class vertexlit_and_unlit_generic_ps20b_Static_Index -{ -private: - int m_nDETAILTEXTURE; -#ifdef _DEBUG - bool m_bDETAILTEXTURE; -#endif -public: - void SetDETAILTEXTURE( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nDETAILTEXTURE = i; -#ifdef _DEBUG - m_bDETAILTEXTURE = true; -#endif - } - void SetDETAILTEXTURE( bool i ) - { - m_nDETAILTEXTURE = i ? 1 : 0; -#ifdef _DEBUG - m_bDETAILTEXTURE = true; -#endif - } -private: - int m_nCUBEMAP; -#ifdef _DEBUG - bool m_bCUBEMAP; -#endif -public: - void SetCUBEMAP( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nCUBEMAP = i; -#ifdef _DEBUG - m_bCUBEMAP = true; -#endif - } - void SetCUBEMAP( bool i ) - { - m_nCUBEMAP = i ? 1 : 0; -#ifdef _DEBUG - m_bCUBEMAP = true; -#endif - } -private: - int m_nDIFFUSELIGHTING; -#ifdef _DEBUG - bool m_bDIFFUSELIGHTING; -#endif -public: - void SetDIFFUSELIGHTING( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nDIFFUSELIGHTING = i; -#ifdef _DEBUG - m_bDIFFUSELIGHTING = true; -#endif - } - void SetDIFFUSELIGHTING( bool i ) - { - m_nDIFFUSELIGHTING = i ? 1 : 0; -#ifdef _DEBUG - m_bDIFFUSELIGHTING = true; -#endif - } -private: - int m_nENVMAPMASK; -#ifdef _DEBUG - bool m_bENVMAPMASK; -#endif -public: - void SetENVMAPMASK( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nENVMAPMASK = i; -#ifdef _DEBUG - m_bENVMAPMASK = true; -#endif - } - void SetENVMAPMASK( bool i ) - { - m_nENVMAPMASK = i ? 1 : 0; -#ifdef _DEBUG - m_bENVMAPMASK = true; -#endif - } -private: - int m_nBASEALPHAENVMAPMASK; -#ifdef _DEBUG - bool m_bBASEALPHAENVMAPMASK; -#endif -public: - void SetBASEALPHAENVMAPMASK( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nBASEALPHAENVMAPMASK = i; -#ifdef _DEBUG - m_bBASEALPHAENVMAPMASK = true; -#endif - } - void SetBASEALPHAENVMAPMASK( bool i ) - { - m_nBASEALPHAENVMAPMASK = i ? 1 : 0; -#ifdef _DEBUG - m_bBASEALPHAENVMAPMASK = true; -#endif - } -private: - int m_nSELFILLUM; -#ifdef _DEBUG - bool m_bSELFILLUM; -#endif -public: - void SetSELFILLUM( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nSELFILLUM = i; -#ifdef _DEBUG - m_bSELFILLUM = true; -#endif - } - void SetSELFILLUM( bool i ) - { - m_nSELFILLUM = i ? 1 : 0; -#ifdef _DEBUG - m_bSELFILLUM = true; -#endif - } -private: - int m_nVERTEXCOLOR; -#ifdef _DEBUG - bool m_bVERTEXCOLOR; -#endif -public: - void SetVERTEXCOLOR( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nVERTEXCOLOR = i; -#ifdef _DEBUG - m_bVERTEXCOLOR = true; -#endif - } - void SetVERTEXCOLOR( bool i ) - { - m_nVERTEXCOLOR = i ? 1 : 0; -#ifdef _DEBUG - m_bVERTEXCOLOR = true; -#endif - } -private: - int m_nFLASHLIGHT; -#ifdef _DEBUG - bool m_bFLASHLIGHT; -#endif -public: - void SetFLASHLIGHT( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nFLASHLIGHT = i; -#ifdef _DEBUG - m_bFLASHLIGHT = true; -#endif - } - void SetFLASHLIGHT( bool i ) - { - m_nFLASHLIGHT = i ? 1 : 0; -#ifdef _DEBUG - m_bFLASHLIGHT = true; -#endif - } -private: - int m_nSELFILLUM_ENVMAPMASK_ALPHA; -#ifdef _DEBUG - bool m_bSELFILLUM_ENVMAPMASK_ALPHA; -#endif -public: - void SetSELFILLUM_ENVMAPMASK_ALPHA( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nSELFILLUM_ENVMAPMASK_ALPHA = i; -#ifdef _DEBUG - m_bSELFILLUM_ENVMAPMASK_ALPHA = true; -#endif - } - void SetSELFILLUM_ENVMAPMASK_ALPHA( bool i ) - { - m_nSELFILLUM_ENVMAPMASK_ALPHA = i ? 1 : 0; -#ifdef _DEBUG - m_bSELFILLUM_ENVMAPMASK_ALPHA = true; -#endif - } -private: - int m_nDETAIL_BLEND_MODE; -#ifdef _DEBUG - bool m_bDETAIL_BLEND_MODE; -#endif -public: - void SetDETAIL_BLEND_MODE( int i ) - { - Assert( i >= 0 && i <= 9 ); - m_nDETAIL_BLEND_MODE = i; -#ifdef _DEBUG - m_bDETAIL_BLEND_MODE = true; -#endif - } - void SetDETAIL_BLEND_MODE( bool i ) - { - m_nDETAIL_BLEND_MODE = i ? 1 : 0; -#ifdef _DEBUG - m_bDETAIL_BLEND_MODE = true; -#endif - } -private: - int m_nSEAMLESS_BASE; -#ifdef _DEBUG - bool m_bSEAMLESS_BASE; -#endif -public: - void SetSEAMLESS_BASE( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nSEAMLESS_BASE = i; -#ifdef _DEBUG - m_bSEAMLESS_BASE = true; -#endif - } - void SetSEAMLESS_BASE( bool i ) - { - m_nSEAMLESS_BASE = i ? 1 : 0; -#ifdef _DEBUG - m_bSEAMLESS_BASE = true; -#endif - } -private: - int m_nSEAMLESS_DETAIL; -#ifdef _DEBUG - bool m_bSEAMLESS_DETAIL; -#endif -public: - void SetSEAMLESS_DETAIL( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nSEAMLESS_DETAIL = i; -#ifdef _DEBUG - m_bSEAMLESS_DETAIL = true; -#endif - } - void SetSEAMLESS_DETAIL( bool i ) - { - m_nSEAMLESS_DETAIL = i ? 1 : 0; -#ifdef _DEBUG - m_bSEAMLESS_DETAIL = true; -#endif - } -private: - int m_nDISTANCEALPHA; -#ifdef _DEBUG - bool m_bDISTANCEALPHA; -#endif -public: - void SetDISTANCEALPHA( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nDISTANCEALPHA = i; -#ifdef _DEBUG - m_bDISTANCEALPHA = true; -#endif - } - void SetDISTANCEALPHA( bool i ) - { - m_nDISTANCEALPHA = i ? 1 : 0; -#ifdef _DEBUG - m_bDISTANCEALPHA = true; -#endif - } -private: - int m_nDISTANCEALPHAFROMDETAIL; -#ifdef _DEBUG - bool m_bDISTANCEALPHAFROMDETAIL; -#endif -public: - void SetDISTANCEALPHAFROMDETAIL( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nDISTANCEALPHAFROMDETAIL = i; -#ifdef _DEBUG - m_bDISTANCEALPHAFROMDETAIL = true; -#endif - } - void SetDISTANCEALPHAFROMDETAIL( bool i ) - { - m_nDISTANCEALPHAFROMDETAIL = i ? 1 : 0; -#ifdef _DEBUG - m_bDISTANCEALPHAFROMDETAIL = true; -#endif - } -private: - int m_nSOFT_MASK; -#ifdef _DEBUG - bool m_bSOFT_MASK; -#endif -public: - void SetSOFT_MASK( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nSOFT_MASK = i; -#ifdef _DEBUG - m_bSOFT_MASK = true; -#endif - } - void SetSOFT_MASK( bool i ) - { - m_nSOFT_MASK = i ? 1 : 0; -#ifdef _DEBUG - m_bSOFT_MASK = true; -#endif - } -private: - int m_nOUTLINE; -#ifdef _DEBUG - bool m_bOUTLINE; -#endif -public: - void SetOUTLINE( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nOUTLINE = i; -#ifdef _DEBUG - m_bOUTLINE = true; -#endif - } - void SetOUTLINE( bool i ) - { - m_nOUTLINE = i ? 1 : 0; -#ifdef _DEBUG - m_bOUTLINE = true; -#endif - } -private: - int m_nOUTER_GLOW; -#ifdef _DEBUG - bool m_bOUTER_GLOW; -#endif -public: - void SetOUTER_GLOW( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nOUTER_GLOW = i; -#ifdef _DEBUG - m_bOUTER_GLOW = true; -#endif - } - void SetOUTER_GLOW( bool i ) - { - m_nOUTER_GLOW = i ? 1 : 0; -#ifdef _DEBUG - m_bOUTER_GLOW = true; -#endif - } -private: - int m_nFLASHLIGHTDEPTHFILTERMODE; -#ifdef _DEBUG - bool m_bFLASHLIGHTDEPTHFILTERMODE; -#endif -public: - void SetFLASHLIGHTDEPTHFILTERMODE( int i ) - { - Assert( i >= 0 && i <= 2 ); - m_nFLASHLIGHTDEPTHFILTERMODE = i; -#ifdef _DEBUG - m_bFLASHLIGHTDEPTHFILTERMODE = true; -#endif - } - void SetFLASHLIGHTDEPTHFILTERMODE( bool i ) - { - m_nFLASHLIGHTDEPTHFILTERMODE = i ? 1 : 0; -#ifdef _DEBUG - m_bFLASHLIGHTDEPTHFILTERMODE = true; -#endif - } -private: - int m_nDEPTHBLEND; -#ifdef _DEBUG - bool m_bDEPTHBLEND; -#endif -public: - void SetDEPTHBLEND( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nDEPTHBLEND = i; -#ifdef _DEBUG - m_bDEPTHBLEND = true; -#endif - } - void SetDEPTHBLEND( bool i ) - { - m_nDEPTHBLEND = i ? 1 : 0; -#ifdef _DEBUG - m_bDEPTHBLEND = true; -#endif - } -private: - int m_nBLENDTINTBYBASEALPHA; -#ifdef _DEBUG - bool m_bBLENDTINTBYBASEALPHA; -#endif -public: - void SetBLENDTINTBYBASEALPHA( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nBLENDTINTBYBASEALPHA = i; -#ifdef _DEBUG - m_bBLENDTINTBYBASEALPHA = true; -#endif - } - void SetBLENDTINTBYBASEALPHA( bool i ) - { - m_nBLENDTINTBYBASEALPHA = i ? 1 : 0; -#ifdef _DEBUG - m_bBLENDTINTBYBASEALPHA = true; -#endif - } -private: - int m_nSRGB_INPUT_ADAPTER; -#ifdef _DEBUG - bool m_bSRGB_INPUT_ADAPTER; -#endif -public: - void SetSRGB_INPUT_ADAPTER( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nSRGB_INPUT_ADAPTER = i; -#ifdef _DEBUG - m_bSRGB_INPUT_ADAPTER = true; -#endif - } - void SetSRGB_INPUT_ADAPTER( bool i ) - { - m_nSRGB_INPUT_ADAPTER = i ? 1 : 0; -#ifdef _DEBUG - m_bSRGB_INPUT_ADAPTER = true; -#endif - } -private: - int m_nCUBEMAP_SPHERE_LEGACY; -#ifdef _DEBUG - bool m_bCUBEMAP_SPHERE_LEGACY; -#endif -public: - void SetCUBEMAP_SPHERE_LEGACY( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nCUBEMAP_SPHERE_LEGACY = i; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } - void SetCUBEMAP_SPHERE_LEGACY( bool i ) - { - m_nCUBEMAP_SPHERE_LEGACY = i ? 1 : 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } -public: - vertexlit_and_unlit_generic_ps20b_Static_Index( ) - { -#ifdef _DEBUG - m_bDETAILTEXTURE = false; -#endif // _DEBUG - m_nDETAILTEXTURE = 0; -#ifdef _DEBUG - m_bCUBEMAP = false; -#endif // _DEBUG - m_nCUBEMAP = 0; -#ifdef _DEBUG - m_bDIFFUSELIGHTING = false; -#endif // _DEBUG - m_nDIFFUSELIGHTING = 0; -#ifdef _DEBUG - m_bENVMAPMASK = false; -#endif // _DEBUG - m_nENVMAPMASK = 0; -#ifdef _DEBUG - m_bBASEALPHAENVMAPMASK = false; -#endif // _DEBUG - m_nBASEALPHAENVMAPMASK = 0; -#ifdef _DEBUG - m_bSELFILLUM = false; -#endif // _DEBUG - m_nSELFILLUM = 0; -#ifdef _DEBUG - m_bVERTEXCOLOR = false; -#endif // _DEBUG - m_nVERTEXCOLOR = 0; -#ifdef _DEBUG - m_bFLASHLIGHT = false; -#endif // _DEBUG - m_nFLASHLIGHT = 0; -#ifdef _DEBUG - m_bSELFILLUM_ENVMAPMASK_ALPHA = false; -#endif // _DEBUG - m_nSELFILLUM_ENVMAPMASK_ALPHA = 0; -#ifdef _DEBUG - m_bDETAIL_BLEND_MODE = false; -#endif // _DEBUG - m_nDETAIL_BLEND_MODE = 0; -#ifdef _DEBUG - m_bSEAMLESS_BASE = false; -#endif // _DEBUG - m_nSEAMLESS_BASE = 0; -#ifdef _DEBUG - m_bSEAMLESS_DETAIL = false; -#endif // _DEBUG - m_nSEAMLESS_DETAIL = 0; -#ifdef _DEBUG - m_bDISTANCEALPHA = false; -#endif // _DEBUG - m_nDISTANCEALPHA = 0; -#ifdef _DEBUG - m_bDISTANCEALPHAFROMDETAIL = false; -#endif // _DEBUG - m_nDISTANCEALPHAFROMDETAIL = 0; -#ifdef _DEBUG - m_bSOFT_MASK = false; -#endif // _DEBUG - m_nSOFT_MASK = 0; -#ifdef _DEBUG - m_bOUTLINE = false; -#endif // _DEBUG - m_nOUTLINE = 0; -#ifdef _DEBUG - m_bOUTER_GLOW = false; -#endif // _DEBUG - m_nOUTER_GLOW = 0; -#ifdef _DEBUG - m_bFLASHLIGHTDEPTHFILTERMODE = false; -#endif // _DEBUG - m_nFLASHLIGHTDEPTHFILTERMODE = 0; -#ifdef _DEBUG - m_bDEPTHBLEND = false; -#endif // _DEBUG - m_nDEPTHBLEND = 0; -#ifdef _DEBUG - m_bBLENDTINTBYBASEALPHA = false; -#endif // _DEBUG - m_nBLENDTINTBYBASEALPHA = 0; -#ifdef _DEBUG - m_bSRGB_INPUT_ADAPTER = false; -#endif // _DEBUG - m_nSRGB_INPUT_ADAPTER = 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = false; -#endif // _DEBUG - m_nCUBEMAP_SPHERE_LEGACY = 0; - } - int GetIndex() - { - // Asserts to make sure that we aren't using any skipped combinations. - // Asserts to make sure that we are setting all of the combination vars. -#ifdef _DEBUG - bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bSRGB_INPUT_ADAPTER && m_bCUBEMAP_SPHERE_LEGACY; - Assert( bAllStaticVarsDefined ); -#endif // _DEBUG - return ( 24 * m_nDETAILTEXTURE ) + ( 48 * m_nCUBEMAP ) + ( 96 * m_nDIFFUSELIGHTING ) + ( 192 * m_nENVMAPMASK ) + ( 384 * m_nBASEALPHAENVMAPMASK ) + ( 768 * m_nSELFILLUM ) + ( 1536 * m_nVERTEXCOLOR ) + ( 3072 * m_nFLASHLIGHT ) + ( 6144 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 12288 * m_nDETAIL_BLEND_MODE ) + ( 122880 * m_nSEAMLESS_BASE ) + ( 245760 * m_nSEAMLESS_DETAIL ) + ( 491520 * m_nDISTANCEALPHA ) + ( 983040 * m_nDISTANCEALPHAFROMDETAIL ) + ( 1966080 * m_nSOFT_MASK ) + ( 3932160 * m_nOUTLINE ) + ( 7864320 * m_nOUTER_GLOW ) + ( 15728640 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 47185920 * m_nDEPTHBLEND ) + ( 94371840 * m_nBLENDTINTBYBASEALPHA ) + ( 188743680 * m_nSRGB_INPUT_ADAPTER ) + ( 377487360 * m_nCUBEMAP_SPHERE_LEGACY ) + 0; - } -}; -#define shaderStaticTest_vertexlit_and_unlit_generic_ps20b psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_SRGB_INPUT_ADAPTER + psh_forgot_to_set_static_CUBEMAP_SPHERE_LEGACY + 0 -class vertexlit_and_unlit_generic_ps20b_Dynamic_Index -{ -private: - int m_nLIGHTING_PREVIEW; -#ifdef _DEBUG - bool m_bLIGHTING_PREVIEW; -#endif -public: - void SetLIGHTING_PREVIEW( int i ) - { - Assert( i >= 0 && i <= 2 ); - m_nLIGHTING_PREVIEW = i; -#ifdef _DEBUG - m_bLIGHTING_PREVIEW = true; -#endif - } - void SetLIGHTING_PREVIEW( bool i ) - { - m_nLIGHTING_PREVIEW = i ? 1 : 0; -#ifdef _DEBUG - m_bLIGHTING_PREVIEW = true; -#endif - } -private: - int m_nFLASHLIGHTSHADOWS; -#ifdef _DEBUG - bool m_bFLASHLIGHTSHADOWS; -#endif -public: - void SetFLASHLIGHTSHADOWS( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nFLASHLIGHTSHADOWS = i; -#ifdef _DEBUG - m_bFLASHLIGHTSHADOWS = true; -#endif - } - void SetFLASHLIGHTSHADOWS( bool i ) - { - m_nFLASHLIGHTSHADOWS = i ? 1 : 0; -#ifdef _DEBUG - m_bFLASHLIGHTSHADOWS = true; -#endif - } -private: - int m_nSTATIC_LIGHT_LIGHTMAP; -#ifdef _DEBUG - bool m_bSTATIC_LIGHT_LIGHTMAP; -#endif -public: - void SetSTATIC_LIGHT_LIGHTMAP( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nSTATIC_LIGHT_LIGHTMAP = i; -#ifdef _DEBUG - m_bSTATIC_LIGHT_LIGHTMAP = true; -#endif - } - void SetSTATIC_LIGHT_LIGHTMAP( bool i ) - { - m_nSTATIC_LIGHT_LIGHTMAP = i ? 1 : 0; -#ifdef _DEBUG - m_bSTATIC_LIGHT_LIGHTMAP = true; -#endif - } -private: - int m_nDEBUG_LUXELS; -#ifdef _DEBUG - bool m_bDEBUG_LUXELS; -#endif -public: - void SetDEBUG_LUXELS( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nDEBUG_LUXELS = i; -#ifdef _DEBUG - m_bDEBUG_LUXELS = true; -#endif - } - void SetDEBUG_LUXELS( bool i ) - { - m_nDEBUG_LUXELS = i ? 1 : 0; -#ifdef _DEBUG - m_bDEBUG_LUXELS = true; -#endif - } -public: - vertexlit_and_unlit_generic_ps20b_Dynamic_Index() - { -#ifdef _DEBUG - m_bLIGHTING_PREVIEW = false; -#endif // _DEBUG - m_nLIGHTING_PREVIEW = 0; -#ifdef _DEBUG - m_bFLASHLIGHTSHADOWS = false; -#endif // _DEBUG - m_nFLASHLIGHTSHADOWS = 0; -#ifdef _DEBUG - m_bSTATIC_LIGHT_LIGHTMAP = false; -#endif // _DEBUG - m_nSTATIC_LIGHT_LIGHTMAP = 0; -#ifdef _DEBUG - m_bDEBUG_LUXELS = false; -#endif // _DEBUG - m_nDEBUG_LUXELS = 0; - } - int GetIndex() - { - // Asserts to make sure that we aren't using any skipped combinations. - // Asserts to make sure that we are setting all of the combination vars. -#ifdef _DEBUG - bool bAllDynamicVarsDefined = m_bLIGHTING_PREVIEW && m_bFLASHLIGHTSHADOWS && m_bSTATIC_LIGHT_LIGHTMAP && m_bDEBUG_LUXELS; - Assert( bAllDynamicVarsDefined ); -#endif // _DEBUG - return ( 1 * m_nLIGHTING_PREVIEW ) + ( 3 * m_nFLASHLIGHTSHADOWS ) + ( 6 * m_nSTATIC_LIGHT_LIGHTMAP ) + ( 12 * m_nDEBUG_LUXELS ) + 0; - } -}; -#define shaderDynamicTest_vertexlit_and_unlit_generic_ps20b psh_forgot_to_set_dynamic_LIGHTING_PREVIEW + psh_forgot_to_set_dynamic_FLASHLIGHTSHADOWS + psh_forgot_to_set_dynamic_STATIC_LIGHT_LIGHTMAP + psh_forgot_to_set_dynamic_DEBUG_LUXELS + 0 +// ALL SKIP STATEMENTS THAT AFFECT THIS SHADER!!! +// ($DETAILTEXTURE == 0 ) && ( $DETAIL_BLEND_MODE != 0 ) +// ($DETAILTEXTURE == 0 ) && ( $SEAMLESS_DETAIL ) +// ($ENVMAPMASK || $SELFILLUM_ENVMAPMASK_ALPHA) && ($SEAMLESS_BASE || $SEAMLESS_DETAIL) +// $BASEALPHAENVMAPMASK && $ENVMAPMASK +// $BASEALPHAENVMAPMASK && $SELFILLUM +// $SELFILLUM && $SELFILLUM_ENVMAPMASK_ALPHA +// $SELFILLUM_ENVMAPMASK_ALPHA && (! $ENVMAPMASK) +// $ENVMAPMASK && ($FLASHLIGHT || $FLASHLIGHTSHADOWS) +// $BASEALPHAENVMAPMASK && ($SEAMLESS_BASE || $SEAMLESS_DETAIL) +// ($DISTANCEALPHA == 0) && ($DISTANCEALPHAFROMDETAIL || $SOFT_MASK || $OUTLINE || $OUTER_GLOW) +// ($DETAILTEXTURE == 0) && ($DISTANCEALPHAFROMDETAIL) +// ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 ) +// ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTDEPTHFILTERMODE != 0 ) +// ($DISTANCEALPHA) && ($ENVMAPMASK || $BASEALPHAENVMAPMASK || $SELFILLUM || $SELFILLUM_ENVMAPMASK_ALPHA ) +// ($DISTANCEALPHA) && ($SEAMLESS_BASE || $SEAMLESS_DETAIL || $CUBEMAP || $LIGHTING_PREVIEW ) +// ($DISTANCEALPHA) && ($WRITEWATERFOGTODESTALPHA || $PIXELFOGTYPE || $FLASHLIGHT || $FLASHLIGHTSHADOWS || $SRGB_INPUT_ADAPTER ) +// $SEAMLESS_BASE && $SRGB_INPUT_ADAPTER +// $SEAMLESS_BASE && ($BLENDTINTBYBASEALPHA ) +// ($BLENDTINTBYBASEALPHA) && ($SELFILLUM || (($DISTANCEALPHA) && ($DISTANCEALPHAFROMDETAIL == 0)) || $BASEALPHAENVMAPMASK) +// $FLASHLIGHT && $CUBEMAP +// $CUBEMAP_SPHERE_LEGACY && ($CUBEMAP == 0) +// ($STATIC_LIGHT_LIGHTMAP == 0) && ($DEBUG_LUXELS == 1) +// defined $HDRTYPE && defined $HDRENABLED && !$HDRTYPE && $HDRENABLED +// defined $PIXELFOGTYPE && defined $WRITEWATERFOGTODESTALPHA && ( $PIXELFOGTYPE != 1 ) && $WRITEWATERFOGTODESTALPHA +// defined $LIGHTING_PREVIEW && defined $HDRTYPE && $LIGHTING_PREVIEW && $HDRTYPE != 0 +// defined $LIGHTING_PREVIEW && defined $FASTPATHENVMAPTINT && $LIGHTING_PREVIEW && $FASTPATHENVMAPTINT +// defined $LIGHTING_PREVIEW && defined $FASTPATHENVMAPCONTRAST && $LIGHTING_PREVIEW && $FASTPATHENVMAPCONTRAST +// defined $LIGHTING_PREVIEW && defined $FASTPATH && $LIGHTING_PREVIEW && $FASTPATH +// ($FLASHLIGHT || $FLASHLIGHTSHADOWS) && $LIGHTING_PREVIEW +// defined $HDRTYPE && defined $HDRENABLED && !$HDRTYPE && $HDRENABLED +// defined $PIXELFOGTYPE && defined $WRITEWATERFOGTODESTALPHA && ( $PIXELFOGTYPE != 1 ) && $WRITEWATERFOGTODESTALPHA +// defined $LIGHTING_PREVIEW && defined $HDRTYPE && $LIGHTING_PREVIEW && $HDRTYPE != 0 +// defined $LIGHTING_PREVIEW && defined $FASTPATHENVMAPTINT && $LIGHTING_PREVIEW && $FASTPATHENVMAPTINT +// defined $LIGHTING_PREVIEW && defined $FASTPATHENVMAPCONTRAST && $LIGHTING_PREVIEW && $FASTPATHENVMAPCONTRAST +// defined $LIGHTING_PREVIEW && defined $FASTPATH && $LIGHTING_PREVIEW && $FASTPATH +// ($FLASHLIGHT || $FLASHLIGHTSHADOWS) && $LIGHTING_PREVIEW + +#ifndef VERTEXLIT_AND_UNLIT_GENERIC_PS20B_H +#define VERTEXLIT_AND_UNLIT_GENERIC_PS20B_H + +#include "shaderapi/ishaderapi.h" +#include "shaderapi/ishadershadow.h" +#include "materialsystem/imaterialvar.h" + +class vertexlit_and_unlit_generic_ps20b_Static_Index +{ + unsigned int m_nDETAILTEXTURE : 2; + unsigned int m_nCUBEMAP : 2; + unsigned int m_nDIFFUSELIGHTING : 2; + unsigned int m_nENVMAPMASK : 2; + unsigned int m_nBASEALPHAENVMAPMASK : 2; + unsigned int m_nSELFILLUM : 2; + unsigned int m_nVERTEXCOLOR : 2; + unsigned int m_nFLASHLIGHT : 2; + unsigned int m_nSELFILLUM_ENVMAPMASK_ALPHA : 2; + unsigned int m_nDETAIL_BLEND_MODE : 4; + unsigned int m_nSEAMLESS_BASE : 2; + unsigned int m_nSEAMLESS_DETAIL : 2; + unsigned int m_nDISTANCEALPHA : 2; + unsigned int m_nDISTANCEALPHAFROMDETAIL : 2; + unsigned int m_nSOFT_MASK : 2; + unsigned int m_nOUTLINE : 2; + unsigned int m_nOUTER_GLOW : 2; + unsigned int m_nFLASHLIGHTDEPTHFILTERMODE : 2; + unsigned int m_nDEPTHBLEND : 2; + unsigned int m_nBLENDTINTBYBASEALPHA : 2; + unsigned int m_nSRGB_INPUT_ADAPTER : 2; + unsigned int m_nCUBEMAP_SPHERE_LEGACY : 2; +#ifdef _DEBUG + bool m_bDETAILTEXTURE : 1; + bool m_bCUBEMAP : 1; + bool m_bDIFFUSELIGHTING : 1; + bool m_bENVMAPMASK : 1; + bool m_bBASEALPHAENVMAPMASK : 1; + bool m_bSELFILLUM : 1; + bool m_bVERTEXCOLOR : 1; + bool m_bFLASHLIGHT : 1; + bool m_bSELFILLUM_ENVMAPMASK_ALPHA : 1; + bool m_bDETAIL_BLEND_MODE : 1; + bool m_bSEAMLESS_BASE : 1; + bool m_bSEAMLESS_DETAIL : 1; + bool m_bDISTANCEALPHA : 1; + bool m_bDISTANCEALPHAFROMDETAIL : 1; + bool m_bSOFT_MASK : 1; + bool m_bOUTLINE : 1; + bool m_bOUTER_GLOW : 1; + bool m_bFLASHLIGHTDEPTHFILTERMODE : 1; + bool m_bDEPTHBLEND : 1; + bool m_bBLENDTINTBYBASEALPHA : 1; + bool m_bSRGB_INPUT_ADAPTER : 1; + bool m_bCUBEMAP_SPHERE_LEGACY : 1; +#endif // _DEBUG +public: + void SetDETAILTEXTURE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nDETAILTEXTURE = i; +#ifdef _DEBUG + m_bDETAILTEXTURE = true; +#endif // _DEBUG + } + + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif // _DEBUG + } + + void SetDIFFUSELIGHTING( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nDIFFUSELIGHTING = i; +#ifdef _DEBUG + m_bDIFFUSELIGHTING = true; +#endif // _DEBUG + } + + void SetENVMAPMASK( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nENVMAPMASK = i; +#ifdef _DEBUG + m_bENVMAPMASK = true; +#endif // _DEBUG + } + + void SetBASEALPHAENVMAPMASK( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nBASEALPHAENVMAPMASK = i; +#ifdef _DEBUG + m_bBASEALPHAENVMAPMASK = true; +#endif // _DEBUG + } + + void SetSELFILLUM( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSELFILLUM = i; +#ifdef _DEBUG + m_bSELFILLUM = true; +#endif // _DEBUG + } + + void SetVERTEXCOLOR( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nVERTEXCOLOR = i; +#ifdef _DEBUG + m_bVERTEXCOLOR = true; +#endif // _DEBUG + } + + void SetFLASHLIGHT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLASHLIGHT = i; +#ifdef _DEBUG + m_bFLASHLIGHT = true; +#endif // _DEBUG + } + + void SetSELFILLUM_ENVMAPMASK_ALPHA( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSELFILLUM_ENVMAPMASK_ALPHA = i; +#ifdef _DEBUG + m_bSELFILLUM_ENVMAPMASK_ALPHA = true; +#endif // _DEBUG + } + + void SetDETAIL_BLEND_MODE( int i ) + { + Assert( i >= 0 && i <= 9 ); + m_nDETAIL_BLEND_MODE = i; +#ifdef _DEBUG + m_bDETAIL_BLEND_MODE = true; +#endif // _DEBUG + } + + void SetSEAMLESS_BASE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSEAMLESS_BASE = i; +#ifdef _DEBUG + m_bSEAMLESS_BASE = true; +#endif // _DEBUG + } + + void SetSEAMLESS_DETAIL( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSEAMLESS_DETAIL = i; +#ifdef _DEBUG + m_bSEAMLESS_DETAIL = true; +#endif // _DEBUG + } + + void SetDISTANCEALPHA( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nDISTANCEALPHA = i; +#ifdef _DEBUG + m_bDISTANCEALPHA = true; +#endif // _DEBUG + } + + void SetDISTANCEALPHAFROMDETAIL( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nDISTANCEALPHAFROMDETAIL = i; +#ifdef _DEBUG + m_bDISTANCEALPHAFROMDETAIL = true; +#endif // _DEBUG + } + + void SetSOFT_MASK( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSOFT_MASK = i; +#ifdef _DEBUG + m_bSOFT_MASK = true; +#endif // _DEBUG + } + + void SetOUTLINE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nOUTLINE = i; +#ifdef _DEBUG + m_bOUTLINE = true; +#endif // _DEBUG + } + + void SetOUTER_GLOW( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nOUTER_GLOW = i; +#ifdef _DEBUG + m_bOUTER_GLOW = true; +#endif // _DEBUG + } + + void SetFLASHLIGHTDEPTHFILTERMODE( int i ) + { + Assert( i >= 0 && i <= 2 ); + m_nFLASHLIGHTDEPTHFILTERMODE = i; +#ifdef _DEBUG + m_bFLASHLIGHTDEPTHFILTERMODE = true; +#endif // _DEBUG + } + + void SetDEPTHBLEND( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nDEPTHBLEND = i; +#ifdef _DEBUG + m_bDEPTHBLEND = true; +#endif // _DEBUG + } + + void SetBLENDTINTBYBASEALPHA( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nBLENDTINTBYBASEALPHA = i; +#ifdef _DEBUG + m_bBLENDTINTBYBASEALPHA = true; +#endif // _DEBUG + } + + void SetSRGB_INPUT_ADAPTER( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSRGB_INPUT_ADAPTER = i; +#ifdef _DEBUG + m_bSRGB_INPUT_ADAPTER = true; +#endif // _DEBUG + } + + void SetCUBEMAP_SPHERE_LEGACY( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP_SPHERE_LEGACY = i; +#ifdef _DEBUG + m_bCUBEMAP_SPHERE_LEGACY = true; +#endif // _DEBUG + } + + vertexlit_and_unlit_generic_ps20b_Static_Index( ) + { + m_nDETAILTEXTURE = 0; + m_nCUBEMAP = 0; + m_nDIFFUSELIGHTING = 0; + m_nENVMAPMASK = 0; + m_nBASEALPHAENVMAPMASK = 0; + m_nSELFILLUM = 0; + m_nVERTEXCOLOR = 0; + m_nFLASHLIGHT = 0; + m_nSELFILLUM_ENVMAPMASK_ALPHA = 0; + m_nDETAIL_BLEND_MODE = 0; + m_nSEAMLESS_BASE = 0; + m_nSEAMLESS_DETAIL = 0; + m_nDISTANCEALPHA = 0; + m_nDISTANCEALPHAFROMDETAIL = 0; + m_nSOFT_MASK = 0; + m_nOUTLINE = 0; + m_nOUTER_GLOW = 0; + m_nFLASHLIGHTDEPTHFILTERMODE = 0; + m_nDEPTHBLEND = 0; + m_nBLENDTINTBYBASEALPHA = 0; + m_nSRGB_INPUT_ADAPTER = 0; + m_nCUBEMAP_SPHERE_LEGACY = 0; +#ifdef _DEBUG + m_bDETAILTEXTURE = false; + m_bCUBEMAP = false; + m_bDIFFUSELIGHTING = false; + m_bENVMAPMASK = false; + m_bBASEALPHAENVMAPMASK = false; + m_bSELFILLUM = false; + m_bVERTEXCOLOR = false; + m_bFLASHLIGHT = false; + m_bSELFILLUM_ENVMAPMASK_ALPHA = false; + m_bDETAIL_BLEND_MODE = false; + m_bSEAMLESS_BASE = false; + m_bSEAMLESS_DETAIL = false; + m_bDISTANCEALPHA = false; + m_bDISTANCEALPHAFROMDETAIL = false; + m_bSOFT_MASK = false; + m_bOUTLINE = false; + m_bOUTER_GLOW = false; + m_bFLASHLIGHTDEPTHFILTERMODE = false; + m_bDEPTHBLEND = false; + m_bBLENDTINTBYBASEALPHA = false; + m_bSRGB_INPUT_ADAPTER = false; + m_bCUBEMAP_SPHERE_LEGACY = false; +#endif // _DEBUG + } + + int GetIndex() const + { + Assert( m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bSRGB_INPUT_ADAPTER && m_bCUBEMAP_SPHERE_LEGACY ); + return ( 24 * m_nDETAILTEXTURE ) + ( 48 * m_nCUBEMAP ) + ( 96 * m_nDIFFUSELIGHTING ) + ( 192 * m_nENVMAPMASK ) + ( 384 * m_nBASEALPHAENVMAPMASK ) + ( 768 * m_nSELFILLUM ) + ( 1536 * m_nVERTEXCOLOR ) + ( 3072 * m_nFLASHLIGHT ) + ( 6144 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 12288 * m_nDETAIL_BLEND_MODE ) + ( 122880 * m_nSEAMLESS_BASE ) + ( 245760 * m_nSEAMLESS_DETAIL ) + ( 491520 * m_nDISTANCEALPHA ) + ( 983040 * m_nDISTANCEALPHAFROMDETAIL ) + ( 1966080 * m_nSOFT_MASK ) + ( 3932160 * m_nOUTLINE ) + ( 7864320 * m_nOUTER_GLOW ) + ( 15728640 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 47185920 * m_nDEPTHBLEND ) + ( 94371840 * m_nBLENDTINTBYBASEALPHA ) + ( 188743680 * m_nSRGB_INPUT_ADAPTER ) + ( 377487360 * m_nCUBEMAP_SPHERE_LEGACY ) + 0; + } +}; + +#define shaderStaticTest_vertexlit_and_unlit_generic_ps20b psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_SRGB_INPUT_ADAPTER + psh_forgot_to_set_static_CUBEMAP_SPHERE_LEGACY + + +class vertexlit_and_unlit_generic_ps20b_Dynamic_Index +{ + unsigned int m_nLIGHTING_PREVIEW : 2; + unsigned int m_nFLASHLIGHTSHADOWS : 2; + unsigned int m_nSTATIC_LIGHT_LIGHTMAP : 2; + unsigned int m_nDEBUG_LUXELS : 2; +#ifdef _DEBUG + bool m_bLIGHTING_PREVIEW : 1; + bool m_bFLASHLIGHTSHADOWS : 1; + bool m_bSTATIC_LIGHT_LIGHTMAP : 1; + bool m_bDEBUG_LUXELS : 1; +#endif // _DEBUG +public: + void SetLIGHTING_PREVIEW( int i ) + { + Assert( i >= 0 && i <= 2 ); + m_nLIGHTING_PREVIEW = i; +#ifdef _DEBUG + m_bLIGHTING_PREVIEW = true; +#endif // _DEBUG + } + + void SetFLASHLIGHTSHADOWS( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLASHLIGHTSHADOWS = i; +#ifdef _DEBUG + m_bFLASHLIGHTSHADOWS = true; +#endif // _DEBUG + } + + void SetSTATIC_LIGHT_LIGHTMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSTATIC_LIGHT_LIGHTMAP = i; +#ifdef _DEBUG + m_bSTATIC_LIGHT_LIGHTMAP = true; +#endif // _DEBUG + } + + void SetDEBUG_LUXELS( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nDEBUG_LUXELS = i; +#ifdef _DEBUG + m_bDEBUG_LUXELS = true; +#endif // _DEBUG + } + + vertexlit_and_unlit_generic_ps20b_Dynamic_Index( ) + { + m_nLIGHTING_PREVIEW = 0; + m_nFLASHLIGHTSHADOWS = 0; + m_nSTATIC_LIGHT_LIGHTMAP = 0; + m_nDEBUG_LUXELS = 0; +#ifdef _DEBUG + m_bLIGHTING_PREVIEW = false; + m_bFLASHLIGHTSHADOWS = false; + m_bSTATIC_LIGHT_LIGHTMAP = false; + m_bDEBUG_LUXELS = false; +#endif // _DEBUG + } + + int GetIndex() const + { + Assert( m_bLIGHTING_PREVIEW && m_bFLASHLIGHTSHADOWS && m_bSTATIC_LIGHT_LIGHTMAP && m_bDEBUG_LUXELS ); + return ( 1 * m_nLIGHTING_PREVIEW ) + ( 3 * m_nFLASHLIGHTSHADOWS ) + ( 6 * m_nSTATIC_LIGHT_LIGHTMAP ) + ( 12 * m_nDEBUG_LUXELS ) + 0; + } +}; + +#define shaderDynamicTest_vertexlit_and_unlit_generic_ps20b psh_forgot_to_set_dynamic_LIGHTING_PREVIEW + psh_forgot_to_set_dynamic_FLASHLIGHTSHADOWS + psh_forgot_to_set_dynamic_STATIC_LIGHT_LIGHTMAP + psh_forgot_to_set_dynamic_DEBUG_LUXELS + + +#endif // VERTEXLIT_AND_UNLIT_GENERIC_PS20B_H diff --git a/materialsystem/stdshaders/vertexlit_and_unlit_generic_vs20.fxc b/materialsystem/stdshaders/vertexlit_and_unlit_generic_vs20.fxc index 43dae3a0..0a85a979 100644 --- a/materialsystem/stdshaders/vertexlit_and_unlit_generic_vs20.fxc +++ b/materialsystem/stdshaders/vertexlit_and_unlit_generic_vs20.fxc @@ -102,9 +102,7 @@ struct VS_OUTPUT #endif float4 color : TEXCOORD2; // Vertex color (from lighting or unlit) -#if CUBEMAP || _X360 float3 worldVertToEyeVector : TEXCOORD3; // Necessary for cubemaps -#endif float3 worldSpaceNormal : TEXCOORD4; // Necessary for cubemaps and flashlight diff --git a/materialsystem/texturemanager.cpp b/materialsystem/texturemanager.cpp index eb5be140..1c5c226b 100644 --- a/materialsystem/texturemanager.cpp +++ b/materialsystem/texturemanager.cpp @@ -246,9 +246,13 @@ static void CreateSolidTexture( ITextureInternal *pTexture, color32 color ) //----------------------------------------------------------------------------- // Creates a normalization cubemap texture //----------------------------------------------------------------------------- + class CNormalizationCubemap : public ITextureRegenerator { public: + + // TODO(nillerusr): broken here with togl /= (maybe here) + virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect ) { // Normalization cubemap doesn't make sense on low-end hardware diff --git a/scripts/waifulib/compiler_optimizations.py b/scripts/waifulib/compiler_optimizations.py index f5fb4744..ec203e07 100644 --- a/scripts/waifulib/compiler_optimizations.py +++ b/scripts/waifulib/compiler_optimizations.py @@ -48,16 +48,13 @@ CFLAGS = { 'common': { # disable thread-safe local static initialization for C++11 code, as it cause crashes on Windows XP 'msvc': ['/D_USING_V110_SDK71_', '/Zi', '/FS', '/Zc:threadSafeInit-', '/MT'], - 'clang': ['-g', '-gdwarf-2', '-fvisibility=hidden'], - 'gcc': ['-g0', '-fvisibility=hidden'], - 'owcc': ['-fno-short-enum', '-ffloat-store', '-g3'] + 'clang': ['-g0', '-fno-strict-aliasing', '-gdwarf-2', '-fvisibility=hidden'], + 'gcc': ['-g0', '-fno-strict-aliasing', '-fvisibility=hidden'], + 'owcc': ['-fno-short-enum', '-ffloat-store', '-g0'] }, 'fast': { - 'msvc': ['/O2', '/Oy'], - 'gcc': { - '3': ['-O3', '-fomit-frame-pointer'], - 'default': ['-Ofast', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer'] - }, + 'msvc': ['/O2', '/Oy'], + 'gcc': ['-Ofast'], 'clang': ['-Ofast'], 'default': ['-O3'] }, @@ -69,13 +66,13 @@ CFLAGS = { }, 'release': { 'msvc': ['/O2'], - 'owcc': ['-O3', '-foptimize-sibling-calls', '-fomit-leaf-frame-pointer', '-fomit-frame-pointer', '-fschedule-insns', '-funsafe-math-optimizations', '-funroll-loops', '-frerun-optimizer', '-finline-functions', '-finline-limit=512', '-fguess-branch-probability', '-fno-strict-aliasing', '-floop-optimize'], - 'default': ['-O3'] + 'owcc': ['-O3', '-fomit-leaf-frame-pointer', '-fomit-frame-pointer', '-finline-functions', '-finline-limit=512'], + 'default': ['-O2', '-funsafe-math-optimizations', '-ftree-vectorize'] }, 'debug': { 'msvc': ['/Od'], - 'owcc': ['-O0', '-fno-omit-frame-pointer', '-funwind-tables', '-fno-omit-leaf-frame-pointer'], - 'default': ['-O3'] #, '-ftree-vectorize'] + 'owcc': ['-g', '-O0', '-fno-omit-frame-pointer', '-funwind-tables', '-fno-omit-leaf-frame-pointer'], + 'default': ['-g', '-O0'] #, '-ftree-vectorize', '-ffast-math', '-fno-tree-partial-pre'] }, 'sanitize': { 'msvc': ['/Od', '/RTC1'], From 816cc2383362305d14852c8feedd9c34e695b6ec Mon Sep 17 00:00:00 2001 From: nillerusr Date: Mon, 16 May 2022 00:00:37 +0300 Subject: [PATCH 08/34] wscript: add --disable-warns option --- wscript | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/wscript b/wscript index 6624260e..b3b87b0d 100644 --- a/wscript +++ b/wscript @@ -211,6 +211,9 @@ def options(opt): grp.add_option('--use-ccache', action = 'store_true', dest = 'CCACHE', default = False, help = 'build using ccache [default: %default]') + grp.add_option('--disable-warns', action = 'store_true', dest = 'DISABLE_WARNS', default = False, + help = 'build using ccache [default: %default]') + grp.add_option('--togles', action = 'store_true', dest = 'TOGLES', default = False, help = 'build engine with ToGLES [default: %default]') @@ -252,17 +255,18 @@ def configure(conf): conf.load('force_32bit') - compiler_optional_flags = [ - '-pipe', - '-Wall', - '-fdiagnostics-color=always', - '-Wcast-align', - '-Wuninitialized', - '-Winit-self', - '-Wstrict-aliasing', - '-faligned-new' - # '-Werror=strict-aliasing' - ] + if conf.options.DISABLE_WARNS: + compiler_optional_flags = ['-w'] + else: + compiler_optional_flags = [ + '-Wall', + '-fdiagnostics-color=always', + '-Wcast-align', + '-Wuninitialized', + '-Winit-self', + '-Wstrict-aliasing', + '-faligned-new', + ] c_compiler_optional_flags = [ '-fnonconst-initializers' # owcc @@ -270,7 +274,9 @@ def configure(conf): cflags, linkflags = conf.get_optimization_flags() - flags = ['-fPIC'] #, '-fsanitize=undefined'] + flags = ['-fPIC', '-pipe'] #, '-fsanitize=undefined', '-fno-sanitize=vptr'] #, '-fno-sanitize=vptr,shift,shift-exponent,shift-base,signed-integer-overflow'] + if conf.env.COMPILER_CC != 'msvc': + flags += ['-pthread'] if conf.env.DEST_OS == 'android': flags += [ @@ -290,7 +296,7 @@ def configure(conf): if conf.env.DEST_OS != 'android': flags += ['-march=native', '-mtune=native'] else: - flags += ['-march=native','-mtune=native','-mfpmath=sse', '-msse', '-msse2'] + flags += ['-march=native','-mtune=native','-mfpmath=sse'] cflags += flags @@ -307,7 +313,6 @@ def configure(conf): # for func in wrapfunctions: # linkflags += ['-Wl,--wrap='+func] - conf.define('COMPILER_GCC', 1) @@ -315,7 +320,6 @@ def configure(conf): conf.check_cc(cflags=cflags, linkflags=linkflags, msg='Checking for required C flags') conf.check_cxx(cxxflags=cxxflags, linkflags=linkflags, msg='Checking for required C++ flags') - linkflags += ['-pthread'] conf.env.append_unique('CFLAGS', cflags) conf.env.append_unique('CXXFLAGS', cxxflags) conf.env.append_unique('LINKFLAGS', linkflags) @@ -358,6 +362,19 @@ def configure(conf): conf.check(lib='opus', uselib_store='OPUS') # conf.check(lib='speex', uselib_store='SPEEX') + +# 'ivp/havana', +# 'ivp/havana/havok/hk_base', +# 'ivp/havana/havok/hk_math', +# 'ivp/ivp_compact_builder', +# 'ivp/ivp_physics', +# conf.check(lib='ivp_physics', uselib_store='ivp_physics') +# conf.check(lib='ivp_compactbuilder', uselib_store='ivp_compactbuilder') +# conf.check(lib='havana_constraints', uselib_store='havana_constraints') +# conf.check(lib='hk_math', uselib_store='hk_math') +# conf.check(lib='hk_base', uselib_store='hk_base') +# conf.check(lib='', uselib_store='') + if conf.env.DEST_OS != 'win32': conf.check_cc(lib='dl', mandatory=False) conf.check_cc(lib='bz2', mandatory=False) From dbb6acff3789acd5770a8f1565d12851a47afe8b Mon Sep 17 00:00:00 2001 From: nillerusr Date: Mon, 16 May 2022 00:06:26 +0300 Subject: [PATCH 09/34] ivp: update submodule --- ivp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivp b/ivp index e83263d0..4568e0ea 160000 --- a/ivp +++ b/ivp @@ -1 +1 @@ -Subproject commit e83263d03e0f46f69c94d1881d76f65bbdc03487 +Subproject commit 4568e0ea73573823d89feebe1d541b06fd4eab8e From e1206f5c46f8bf465628ecc3ae7d42e2bf77f89f Mon Sep 17 00:00:00 2001 From: nillerusr Date: Mon, 16 May 2022 12:37:38 +0300 Subject: [PATCH 10/34] tier0: enable vprof --- public/tier0/vprof.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/public/tier0/vprof.h b/public/tier0/vprof.h index 7a183eac..5c6ab143 100644 --- a/public/tier0/vprof.h +++ b/public/tier0/vprof.h @@ -15,9 +15,10 @@ #include "tier0/vprof_telemetry.h" // VProf is enabled by default in all configurations -except- X360 Retail. -//#if !( defined( _X360 ) && defined( _CERT ) ) -//#define VPROF_ENABLED -//#endif +#if !( defined( _X360 ) && defined( _CERT ) ) +#define VPROF_ENABLED +#endif +// TODO(nillerusr): make stubbed vprofile #if defined(_X360) && defined(VPROF_ENABLED) #include "tier0/pmc360.h" From 432a6b22972d06217d28bae8f1e6dc06ba51f152 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Tue, 17 May 2022 14:38:34 +0300 Subject: [PATCH 11/34] materialsystem: fix s_NormalizationCubemap generation for ToGL --- engine/vprof_engine.cpp | 3 -- materialsystem/stdshaders/flashlight_ps2x.fxc | 12 +++-- materialsystem/texturemanager.cpp | 48 +++++++++++++++---- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/engine/vprof_engine.cpp b/engine/vprof_engine.cpp index 31df9668..a57db191 100644 --- a/engine/vprof_engine.cpp +++ b/engine/vprof_engine.cpp @@ -1117,8 +1117,6 @@ void WriteRemoteVProfGroupData( VProfListenInfo_t &info ) const char *pName = g_pVProfileForDisplay->GetBudgetGroupName( nIndex ); buf.PutString( pName ); } - - g_ServerRemoteAccess.SendVProfData( info.m_nListenerId, true, buf.Base(), buf.TellMaxPut() ); } static ConVar rpt_vprof_time( "rpt_vprof_time","0.25", FCVAR_HIDDEN | FCVAR_DONTRECORD, "" ); @@ -1167,7 +1165,6 @@ void WriteRemoteVProfData() Assert( nIndex >= 0 ); pSentTimes[ nIndex ] = pTimes[j]; } - g_ServerRemoteAccess.SendVProfData( s_VProfListeners[i].m_nListenerId, false, pSentTimes, nSentSize ); } } diff --git a/materialsystem/stdshaders/flashlight_ps2x.fxc b/materialsystem/stdshaders/flashlight_ps2x.fxc index 000405d0..8ac860cb 100644 --- a/materialsystem/stdshaders/flashlight_ps2x.fxc +++ b/materialsystem/stdshaders/flashlight_ps2x.fxc @@ -201,16 +201,22 @@ float4 main( PS_INPUT i ) : COLOR #if NORMALMAP == 0 float3 worldPosToLightVector = texCUBE( NormalizingCubemapSampler, i.worldPosToLightVector ) * 2.0f - 1.0f; - float nDotL = 0.577350f; + float nDotL = dot( worldPosToLightVector, vNormal.xyz ); #endif #if NORMALMAP == 1 // flashlightfixme: wrap this! - float nDotL = 0.577350f; + float3 tangentPosToLightVector = texCUBE( NormalizingCubemapSampler, i.tangentPosToLightVector ) * 2.0f - 1.0f; + float nDotL = dot( tangentPosToLightVector, vNormal.xyz ); #endif #if NORMALMAP == 2 - float nDotL = 0.577350f; + float3 tangentPosToLightVector = normalize( i.tangentPosToLightVector ); + + float nDotL = + vNormal.x*dot( tangentPosToLightVector, bumpBasis[0]) + + vNormal.y*dot( tangentPosToLightVector, bumpBasis[1]) + + vNormal.z*dot( tangentPosToLightVector, bumpBasis[2]); #endif float3 outColor; diff --git a/materialsystem/texturemanager.cpp b/materialsystem/texturemanager.cpp index 1c5c226b..db503695 100644 --- a/materialsystem/texturemanager.cpp +++ b/materialsystem/texturemanager.cpp @@ -250,9 +250,6 @@ static void CreateSolidTexture( ITextureInternal *pTexture, color32 color ) class CNormalizationCubemap : public ITextureRegenerator { public: - - // TODO(nillerusr): broken here with togl /= (maybe here) - virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect ) { // Normalization cubemap doesn't make sense on low-end hardware @@ -280,7 +277,39 @@ public: { float u = x * flInvWidth - 1.0f; float oow = 1.0f / sqrt( 1.0f + u*u + v*v ); +#ifdef DX_TO_GL_ABSTRACTION + float flX = (255.0f * 0.5 * (u*oow + 1.0f) + 0.5f); + float flY = (255.0f * 0.5 * (v*oow + 1.0f) + 0.5f); + float flZ = (255.0f * 0.5 * (oow + 1.0f) + 0.5f); + flX /= 256.0f; + flY /= 256.0f; + flZ /= 256.0f; + + switch (iFace) + { + case CUBEMAP_FACE_RIGHT: + pixelWriter.WritePixelF( flZ, 1.f - flY, 1.f - flX, 1.f ); + break; + case CUBEMAP_FACE_LEFT: + pixelWriter.WritePixelF( 1.f - flZ, 1.f - flY, flX, 1.f ); + break; + case CUBEMAP_FACE_BACK: + pixelWriter.WritePixelF( flX, flZ, flY, 1.f ); + break; + case CUBEMAP_FACE_FRONT: + pixelWriter.WritePixelF( flX, 1.f - flZ, 1.f - flY, 1.f ); + break; + case CUBEMAP_FACE_UP: + pixelWriter.WritePixelF( flX, 1.f - flY, flZ, 1.f ); + break; + case CUBEMAP_FACE_DOWN: + pixelWriter.WritePixelF( 1.f - flX, 1.f - flY, 1.f - flZ, 1.f ); + break; + default: + break; + } +#else int ix = (int)(255.0f * 0.5f * (u*oow + 1.0f) + 0.5f); ix = clamp( ix, 0, 255 ); int iy = (int)(255.0f * 0.5f * (v*oow + 1.0f) + 0.5f); @@ -311,6 +340,7 @@ public: default: break; } +#endif } } } @@ -1501,13 +1531,16 @@ void CTextureManager::Init( int nFlags ) color.a = 0; CreateSolidTexture( m_pGreyAlphaZeroTexture, color ); + int nTextureFlags = TEXTUREFLAGS_ENVMAP | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_CLAMPU; + if ( HardwareConfig()->GetMaxDXSupportLevel() >= 80 ) { + ImageFormat fmt = IsOpenGL() ? IMAGE_FORMAT_RGBA16161616F : IMAGE_FORMAT_BGRX8888; + // Create a normalization cubemap m_pNormalizationCubemap = CreateProceduralTexture( "normalize", TEXTURE_GROUP_CUBE_MAP, - NORMALIZATION_CUBEMAP_SIZE, NORMALIZATION_CUBEMAP_SIZE, 1, IMAGE_FORMAT_BGRX8888, - TEXTUREFLAGS_ENVMAP | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY | - TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_CLAMPU ); + NORMALIZATION_CUBEMAP_SIZE, NORMALIZATION_CUBEMAP_SIZE, 1, fmt, + nTextureFlags ); CreateNormalizationCubemap( m_pNormalizationCubemap ); } @@ -1516,7 +1549,6 @@ void CTextureManager::Init( int nFlags ) // In GL, we have poor format support, so we ask for signed float ImageFormat fmt = IsOpenGL() ? IMAGE_FORMAT_RGBA16161616F : IMAGE_FORMAT_UVWQ8888; - int nTextureFlags = TEXTUREFLAGS_ENVMAP | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_CLAMPU; #ifdef OSX // JasonM - ridiculous hack around R500 lameness...we never use this texture on OSX anyways (right?) @@ -1528,7 +1560,7 @@ void CTextureManager::Init( int nFlags ) m_pSignedNormalizationCubemap = CreateProceduralTexture( "normalizesigned", TEXTURE_GROUP_CUBE_MAP, NORMALIZATION_CUBEMAP_SIZE, NORMALIZATION_CUBEMAP_SIZE, 1, fmt, nTextureFlags ); CreateSignedNormalizationCubemap( m_pSignedNormalizationCubemap ); - + m_pIdentityLightWarp = FindOrLoadTexture( "dev/IdentityLightWarp", TEXTURE_GROUP_OTHER ); m_pIdentityLightWarp->IncrementReferenceCount(); } From ac956a9b4f1683ebacdd14e9d1ad9f2c464020f0 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sat, 4 Jun 2022 23:08:40 +0300 Subject: [PATCH 12/34] game: small fixes --- game/client/c_vote_controller.cpp | 2 +- game/server/triggers.cpp | 4 +++- launcher/android.cpp | 19 ++++++++++++++----- launcher_main/main.cpp | 3 +++ togles/linuxwin/dxabstract.cpp | 6 +++++- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/game/client/c_vote_controller.cpp b/game/client/c_vote_controller.cpp index 52184061..b750c2a9 100644 --- a/game/client/c_vote_controller.cpp +++ b/game/client/c_vote_controller.cpp @@ -30,7 +30,7 @@ END_RECV_TABLE() void C_VoteController::RecvProxy_VoteType( const CRecvProxyData *pData, void *pStruct, void *pOut ) { C_VoteController *pMe = (C_VoteController *)pStruct; - if( pMe->m_iActiveIssueIndex == pData->m_Value.m_Int ) + if( memcmp( &pMe->m_iActiveIssueIndex, &pData->m_Value.m_Int, sizeof(pData->m_Value.m_Int)) == 0 ) return; memcpy( &pMe->m_iActiveIssueIndex, &pData->m_Value.m_Int, sizeof(pData->m_Value.m_Int) ); diff --git a/game/server/triggers.cpp b/game/server/triggers.cpp index 295e826a..94b0323a 100644 --- a/game/server/triggers.cpp +++ b/game/server/triggers.cpp @@ -2517,6 +2517,8 @@ LINK_ENTITY_TO_CLASS( trigger_autosave, CTriggerSave ); //----------------------------------------------------------------------------- void CTriggerSave::Spawn( void ) { + m_minHitPoints = 1; + if ( g_pGameRules->IsDeathmatch() ) { UTIL_Remove( this ); @@ -2534,7 +2536,7 @@ void CTriggerSave::Spawn( void ) void CTriggerSave::Touch( CBaseEntity *pOther ) { // Only save on clients - if ( !pOther->IsPlayer() ) + if ( !pOther->IsPlayer() || !pOther->IsAlive() ) return; if ( m_fDangerousTimer != 0.0f ) diff --git a/launcher/android.cpp b/launcher/android.cpp index ceb7cb3f..7e5b4aa6 100644 --- a/launcher/android.cpp +++ b/launcher/android.cpp @@ -2,6 +2,17 @@ #include #include +#ifdef ANDROID +#include + +#define TAG "SRCENG" +#define PRIO ANDROID_LOG_DEBUG +#define LogPrintf(...) do { __android_log_print(PRIO, TAG, __VA_ARGS__); printf( __VA_ARGS__); } while( 0 ); + +#else +#define LogPrintf(...) printf(__VA_ARGS__) +#endif + typedef void (*t_set_getprocaddress)(void *(*new_proc_address)(const char *)); t_set_getprocaddress gl4es_set_getprocaddress; @@ -18,13 +29,13 @@ void InitGL4ES() void *lgl4es = dlopen("libgl4es.so", RTLD_LAZY); if( !lgl4es ) { - printf("Failed to dlopen library libgl4es.so: %s\n", dlerror()); + LogPrintf("Failed to dlopen library libgl4es.so: %s\n", dlerror()); } void *lEGL = dlopen("libEGL.so", RTLD_LAZY); if( !lEGL ) { - printf("Failed to dlopen library libEGL.so: %s\n", dlerror()); + LogPrintf("Failed to dlopen library libEGL.so: %s\n", dlerror()); } gl4es_set_getprocaddress = (t_set_getprocaddress)dlsym(lgl4es, "set_getprocaddress"); @@ -36,13 +47,11 @@ void InitGL4ES() } else { - printf("Failed to call set_getprocaddress\n"); + LogPrintf("Failed to call set_getprocaddress\n"); } } #ifdef ANDROID - -#include #include #include #include diff --git a/launcher_main/main.cpp b/launcher_main/main.cpp index 90aafcc3..4740ac88 100644 --- a/launcher_main/main.cpp +++ b/launcher_main/main.cpp @@ -217,6 +217,9 @@ static void WaitForDebuggerConnect( int argc, char *argv[], int time ) int main( int argc, char *argv[] ) { void *launcher = dlopen( "bin/liblauncher" DLL_EXT_STRING, RTLD_NOW ); + if ( !launcher ) + fprintf( stderr, "%s\nFailed to load the launcher\n", dlerror() ); + if( !launcher ) launcher = dlopen( "bin/launcher" DLL_EXT_STRING, RTLD_NOW ); diff --git a/togles/linuxwin/dxabstract.cpp b/togles/linuxwin/dxabstract.cpp index 796ac60e..a1b17a69 100644 --- a/togles/linuxwin/dxabstract.cpp +++ b/togles/linuxwin/dxabstract.cpp @@ -3769,6 +3769,10 @@ static int ShadowDepthSamplerMaskFromName( const char *pName ) { return (1<<7); } + else if ( V_stristr( pName, "skin_ps" ) ) + { + return (1<<4) | (1<<6); + } else if ( V_stristr( pName, "infected_ps" ) ) { return (1<<1); @@ -3795,7 +3799,7 @@ static int ShadowDepthSamplerMaskFromName( const char *pName ) } else if ( V_stristr( pName, "worldtwotextureblend_ps" ) ) { - return (1<<7); + return (1<<2); } else if ( V_stristr( pName, "teeth_flashlight_ps" ) ) { From 2690e6c85a5bfcc71096039e74a8a7e668cbc1ae Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sat, 4 Jun 2022 23:21:08 +0300 Subject: [PATCH 13/34] update ivp submodule --- ivp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivp b/ivp index 4568e0ea..65ec2e7f 160000 --- a/ivp +++ b/ivp @@ -1 +1 @@ -Subproject commit 4568e0ea73573823d89feebe1d541b06fd4eab8e +Subproject commit 65ec2e7f5bf944892ed3f7e59a519bbbbde2ac86 From 4e4039d7569830b947ecf2ba317c1b9f35055828 Mon Sep 17 00:00:00 2001 From: hymei Date: Wed, 23 Feb 2022 19:50:30 +0800 Subject: [PATCH 14/34] arm64 : fix intptr_t size --- bitmap/float_bm4.cpp | 2 +- bitmap/float_bm_bilateral_filter.cpp | 2 +- common/GameUI/IGameConsole.h | 2 +- common/engine/idownloadsystem.h | 2 +- common/studiobyteswap.cpp | 33 ++- datacache/datacache.h | 2 +- datacache/mdlcache.cpp | 128 ++++++---- datamodel/datamodel.cpp | 6 +- datamodel/dependencygraph.cpp | 2 +- engine/LoadScreenUpdate.cpp | 4 +- engine/ModelInfo.cpp | 20 +- engine/audio/private/snd_mix.cpp | 6 +- engine/audio/private/snd_mp3_source.cpp | 4 +- engine/audio/private/snd_wave_source.cpp | 2 +- .../private/voice_mixer_controls_openal.cpp | 2 +- engine/cmd.cpp | 2 +- engine/cmodel_disp.cpp | 6 +- engine/colorcorrectionpanel.cpp | 2 +- engine/disp.cpp | 4 +- engine/disp_interface.cpp | 10 +- engine/download.cpp | 10 +- engine/dt_localtransfer.cpp | 4 +- engine/gl_rsurf.cpp | 24 +- engine/l_studio.cpp | 4 +- engine/modelloader.cpp | 13 +- engine/pure_server.h | 2 +- engine/r_decal.cpp | 16 +- engine/r_decal.h | 8 +- engine/saverestore_filesystem.cpp | 6 +- engine/shadowmgr.cpp | 10 +- engine/snd_io.cpp | 26 +-- engine/sv_uploadgamestats.cpp | 2 +- engine/sys_dll2.cpp | 2 +- engine/tmessage.cpp | 2 +- engine/view.cpp | 4 +- filesystem/QueuedLoader.cpp | 2 +- filesystem/filesystem_async.cpp | 8 +- filesystem/filetracker.cpp | 2 +- game/client/c_pixel_visibility.cpp | 6 +- game/client/c_rope.cpp | 2 +- game/client/c_te_effect_dispatch.cpp | 2 +- game/client/clientleafsystem.cpp | 6 +- game/client/clientshadowmgr.cpp | 6 +- game/client/detailobjectsystem.cpp | 12 +- game/client/proxyplayer.cpp | 2 +- game/server/ai_component.h | 2 +- game/server/ai_hint.cpp | 4 +- game/server/ai_memory.cpp | 2 +- game/server/ai_navigator.cpp | 2 +- game/server/ai_navigator.h | 2 +- game/server/ai_senses.cpp | 7 +- game/server/ai_task.h | 6 +- game/server/baseanimating.cpp | 4 +- game/server/baseentity.cpp | 8 +- game/server/baseentity.h | 15 ++ game/server/cbase.cpp | 2 +- game/server/nav_mesh.h | 6 + game/server/player_lagcompensation.cpp | 4 +- game/server/triggers.cpp | 2 +- game/shared/baseentity_shared.cpp | 8 + game/shared/entitydatainstantiator.h | 2 +- game/shared/querycache.cpp | 2 +- game/shared/saverestore.cpp | 1 + gameui/GameConsole.cpp | 2 +- gameui/GameConsole.h | 2 +- hammer/texturesystem.cpp | 4 +- hammer/texturesystem.h | 4 +- materialsystem/cmatqueuedrendercontext.cpp | 2 +- materialsystem/cmatrendercontext.cpp | 2 +- materialsystem/cmatrendercontext.h | 2 +- materialsystem/ctexture.cpp | 7 +- materialsystem/ctexturecompositor.cpp | 4 +- materialsystem/occlusionquerymgr.cpp | 18 +- .../shaderapidx9/cvballoctracker.cpp | 4 +- materialsystem/shaderapidx9/locald3dtypes.h | 8 +- .../shaderapidx9/shaderdevicebase.h | 2 +- .../shaderapidx9/vertexshaderdx8.cpp | 14 +- materialsystem/stdshaders/commandbuilder.h | 7 +- materialsystem/texturemanager.cpp | 9 +- particles/particles.cpp | 2 +- public/XUnzip.cpp | 18 +- public/bspfile.h | 2 +- public/bsptreedata.cpp | 24 +- public/bsptreedata.h | 22 +- public/datacache/idatacache.h | 4 +- public/datacache/imdlcache.h | 11 + public/datamap.h | 3 +- public/materialsystem/IColorCorrection.h | 2 +- public/materialsystem/imesh.h | 24 +- public/networkvar.h | 2 +- public/shaderapi/ishaderapi.h | 2 +- public/shaderapi/ishaderdynamic.h | 2 +- public/studio.h | 72 +++++- public/tier0/platform.h | 31 ++- public/tier0/threadtools.h | 218 ++++++++++++------ public/tier0/vcrmode.h | 2 +- public/tier1/CommandBuffer.h | 8 +- public/tier1/KeyValues.h | 22 +- public/tier1/bitbuf.h | 30 +-- public/tier1/datamanager.h | 2 +- public/tier1/refcount.h | 4 +- public/tier1/utlbuffer.h | 27 +++ public/tier1/utlhandletable.h | 28 ++- public/tier1/utlhash.h | 14 +- public/tier1/utllinkedlist.h | 15 +- public/tier2/riff.h | 16 +- public/togl/linuxwin/dxabstract.h | 6 +- public/togl/linuxwin/glmgr.h | 4 +- public/togles/linuxwin/dxabstract.h | 2 +- public/togles/linuxwin/glmgr.h | 4 +- public/vgui/VGUI.h | 12 +- public/vgui_controls/ListPanel.h | 10 +- public/vstdlib/IKeyValuesSystem.h | 4 +- public/vstdlib/jobthread.h | 2 +- soundsystem/snd_wave_source.cpp | 10 +- studiorender/r_studiodecal.cpp | 14 +- tier0/threadtools.cpp | 114 ++++----- tier0/tslist.cpp | 6 +- tier0/vcrmode.cpp | 2 +- tier0/vcrmode_posix.cpp | 2 +- tier1/KeyValues.cpp | 38 +-- tier1/bitbuf.cpp | 74 +++--- tier1/checksum_crc.cpp | 2 +- tier1/commandbuffer.cpp | 16 +- tier1/kvpacker.cpp | 4 +- tier1/lzss.cpp | 2 +- tier2/riff.cpp | 14 +- tier2/soundutils.cpp | 28 +-- tier3/studiohdrstub.cpp | 8 +- togl/linuxwin/dxabstract.cpp | 2 +- utils/common/bsplib.cpp | 26 +-- utils/common/bsplib.h | 6 +- utils/studiomdl/perfstats.cpp | 2 +- utils/vrad/leaf_ambient_lighting.cpp | 2 +- utils/vrad/vraddetailprops.cpp | 4 +- utils/vrad/vraddisps.cpp | 34 +-- vgui2/matsys_controls/baseassetpicker.cpp | 12 +- vgui2/vgui_controls/ListPanel.cpp | 10 +- vgui2/vgui_controls/RichText.cpp | 4 +- vphysics/main.cpp | 2 +- vphysics/physics_environment.cpp | 2 +- vphysics/physics_virtualmesh.cpp | 2 +- vstdlib/KeyValuesSystem.cpp | 4 +- 143 files changed, 1015 insertions(+), 674 deletions(-) diff --git a/bitmap/float_bm4.cpp b/bitmap/float_bm4.cpp index 7130b27e..79f9073e 100644 --- a/bitmap/float_bm4.cpp +++ b/bitmap/float_bm4.cpp @@ -40,7 +40,7 @@ struct SSBumpCalculationContext // what each thread needs to see }; -static unsigned SSBumpCalculationThreadFN( void * ctx1 ) +static uintp SSBumpCalculationThreadFN( void * ctx1 ) { SSBumpCalculationContext *ctx = ( SSBumpCalculationContext * ) ctx1; diff --git a/bitmap/float_bm_bilateral_filter.cpp b/bitmap/float_bm_bilateral_filter.cpp index 4d45eb9e..919b07e7 100644 --- a/bitmap/float_bm_bilateral_filter.cpp +++ b/bitmap/float_bm_bilateral_filter.cpp @@ -24,7 +24,7 @@ struct TBFCalculationContext FloatBitMap_t *dest_bm; }; -static unsigned TBFCalculationThreadFN( void *ctx1 ) +static uintp TBFCalculationThreadFN( void *ctx1 ) { TBFCalculationContext *ctx = (TBFCalculationContext *) ctx1; for(int y=ctx->min_y; y <= ctx->max_y; y++) diff --git a/common/GameUI/IGameConsole.h b/common/GameUI/IGameConsole.h index a18f3310..15b22bcd 100644 --- a/common/GameUI/IGameConsole.h +++ b/common/GameUI/IGameConsole.h @@ -33,7 +33,7 @@ public: // return true if the console has focus virtual bool IsConsoleVisible() = 0; - virtual void SetParent( int parent ) = 0; + virtual void SetParent( intp parent ) = 0; }; #define GAMECONSOLE_INTERFACE_VERSION "GameConsole004" diff --git a/common/engine/idownloadsystem.h b/common/engine/idownloadsystem.h index 3cc020fa..6eb527eb 100644 --- a/common/engine/idownloadsystem.h +++ b/common/engine/idownloadsystem.h @@ -32,7 +32,7 @@ struct RequestContext_t; class IDownloadSystem : public IBaseInterface { public: - virtual DWORD CreateDownloadThread( RequestContext_t *pContext ) = 0; + virtual uintp CreateDownloadThread( RequestContext_t *pContext ) = 0; }; //---------------------------------------------------------------------------------------- diff --git a/common/studiobyteswap.cpp b/common/studiobyteswap.cpp index e99d16ae..30b3383e 100644 --- a/common/studiobyteswap.cpp +++ b/common/studiobyteswap.cpp @@ -16,10 +16,10 @@ #undef ALIGN4 #undef ALIGN16 #undef ALIGN32 -#define ALIGN4( a ) a = (byte *)((int)((byte *)a + 3) & ~ 3) -#define ALIGN16( a ) a = (byte *)((int)((byte *)a + 15) & ~ 15) -#define ALIGN32( a ) a = (byte *)((int)((byte *)a + 31) & ~ 31) -#define ALIGN64( a ) a = (byte *)((int)((byte *)a + 63) & ~ 63) +#define ALIGN4( a ) a = (byte *)((intp)((byte *)a + 3) & ~ 3) +#define ALIGN16( a ) a = (byte *)((intp)((byte *)a + 15) & ~ 15) +#define ALIGN32( a ) a = (byte *)((intp)((byte *)a + 31) & ~ 31) +#define ALIGN64( a ) a = (byte *)((intp)((byte *)a + 63) & ~ 63) // Fixup macros create variables that may not be referenced #pragma warning( push ) @@ -1228,8 +1228,8 @@ int ByteswapANI( studiohdr_t* pHdr, void *pDestBase, const void *pSrcBase, const V_memcpy( pNewDest, pDestBase, pAnimBlock->datastart ); pNewDest += pAnimBlock->datastart; - int padding = AlignValue( (unsigned int)pNewDest - (unsigned int)pNewDestBase, 2048 ); - padding -= (unsigned int)pNewDest - (unsigned int)pNewDestBase; + int padding = AlignValue( (uintp)pNewDest - (uintp)pNewDestBase, 2048 ); + padding -= (uintp)pNewDest - (uintp)pNewDestBase; pNewDest += padding; // iterate and compress anim blocks @@ -1240,7 +1240,7 @@ int ByteswapANI( studiohdr_t* pHdr, void *pDestBase, const void *pSrcBase, const void *pInput = (byte *)pDestBase + pAnimBlock->datastart; int inputSize = pAnimBlock->dataend - pAnimBlock->datastart; - pAnimBlock->datastart = (unsigned int)pNewDest - (unsigned int)pNewDestBase; + pAnimBlock->datastart = (uintp)pNewDest - (uintp)pNewDestBase; void *pOutput; int outputSize; @@ -1257,11 +1257,11 @@ int ByteswapANI( studiohdr_t* pHdr, void *pDestBase, const void *pSrcBase, const pNewDest += inputSize; } - padding = AlignValue( (unsigned int)pNewDest - (unsigned int)pNewDestBase, 2048 ); - padding -= (unsigned int)pNewDest - (unsigned int)pNewDestBase; + padding = AlignValue( (uintp)pNewDest - (uintp)pNewDestBase, 2048 ); + padding -= (uintp)pNewDest - (uintp)pNewDestBase; pNewDest += padding; - pAnimBlock->dataend = (unsigned int)pNewDest - (unsigned int)pNewDestBase; + pAnimBlock->dataend = (uintp)pNewDest - (uintp)pNewDestBase; } fixedFileSize = pNewDest - pNewDestBase; @@ -2522,14 +2522,27 @@ BEGIN_BYTESWAP_DATADESC( studiohdr_t ) DEFINE_FIELD( contents, FIELD_INTEGER ), DEFINE_FIELD( numincludemodels, FIELD_INTEGER ), DEFINE_INDEX( includemodelindex, FIELD_INTEGER ), +#ifdef PLATFORM_64BITS + DEFINE_FIELD( index_ptr_virtualModel, FIELD_INTEGER ), // void* +#else DEFINE_FIELD( virtualModel, FIELD_INTEGER ), // void* +#endif DEFINE_INDEX( szanimblocknameindex, FIELD_INTEGER ), DEFINE_FIELD( numanimblocks, FIELD_INTEGER ), DEFINE_INDEX( animblockindex, FIELD_INTEGER ), +#ifdef PLATFORM_64BITS + DEFINE_FIELD( index_ptr_virtualModel, FIELD_INTEGER ), // void* +#else DEFINE_FIELD( animblockModel, FIELD_INTEGER ), // void* +#endif DEFINE_INDEX( bonetablebynameindex, FIELD_INTEGER ), +#ifdef PLATFORM_64BITS + DEFINE_FIELD( index_ptr_pVertexBase, FIELD_INTEGER ), // void* + DEFINE_FIELD( index_ptr_pVertexBase, FIELD_INTEGER ), // void* +#else DEFINE_FIELD( pVertexBase, FIELD_INTEGER ), // void* DEFINE_FIELD( pIndexBase, FIELD_INTEGER ), // void* +#endif DEFINE_FIELD( constdirectionallightdot, FIELD_CHARACTER ), // byte DEFINE_FIELD( rootLOD, FIELD_CHARACTER ), // byte DEFINE_FIELD( numAllowedRootLODs, FIELD_CHARACTER ), // byte diff --git a/datacache/datacache.h b/datacache/datacache.h index 56b77109..2bbc0e45 100644 --- a/datacache/datacache.h +++ b/datacache/datacache.h @@ -39,7 +39,7 @@ struct DataCacheItemData_t //------------------------------------- -#define DC_NO_NEXT_LOCKED ((DataCacheItem_t *)0xffffffff) +#define DC_NO_NEXT_LOCKED ((DataCacheItem_t *)-1) #define DC_MAX_THREADS_FRAMELOCKED 4 struct DataCacheItem_t : DataCacheItemData_t diff --git a/datacache/mdlcache.cpp b/datacache/mdlcache.cpp index 8f1ff365..2b7a4e8d 100644 --- a/datacache/mdlcache.cpp +++ b/datacache/mdlcache.cpp @@ -235,11 +235,11 @@ struct AsyncInfo_t int iAnimBlock; }; -const int NO_ASYNC = CUtlLinkedList< AsyncInfo_t >::InvalidIndex(); +const intp NO_ASYNC = CUtlFixedLinkedList< AsyncInfo_t >::InvalidIndex(); //------------------------------------- -CUtlMap g_AsyncInfoMap( DefLessFunc( int ) ); +CUtlMap g_AsyncInfoMap( DefLessFunc( int ) ); CThreadFastMutex g_AsyncInfoMapMutex; inline int MakeAsyncInfoKey( MDLHandle_t hModel, MDLCacheDataType_t type, int iAnimBlock ) @@ -248,7 +248,7 @@ inline int MakeAsyncInfoKey( MDLHandle_t hModel, MDLCacheDataType_t type, int iA return ( ( ( (int)hModel) << 16 ) | ( (int)type << 13 ) | iAnimBlock ); } -inline int GetAsyncInfoIndex( MDLHandle_t hModel, MDLCacheDataType_t type, int iAnimBlock = 0 ) +inline intp GetAsyncInfoIndex( MDLHandle_t hModel, MDLCacheDataType_t type, int iAnimBlock = 0 ) { AUTO_LOCK( g_AsyncInfoMapMutex ); int key = MakeAsyncInfoKey( hModel, type, iAnimBlock ); @@ -260,7 +260,7 @@ inline int GetAsyncInfoIndex( MDLHandle_t hModel, MDLCacheDataType_t type, int i return g_AsyncInfoMap[i]; } -inline int SetAsyncInfoIndex( MDLHandle_t hModel, MDLCacheDataType_t type, int iAnimBlock, int index ) +inline intp SetAsyncInfoIndex( MDLHandle_t hModel, MDLCacheDataType_t type, int iAnimBlock, intp index ) { AUTO_LOCK( g_AsyncInfoMapMutex ); Assert( index == NO_ASYNC || GetAsyncInfoIndex( hModel, type, iAnimBlock ) == NO_ASYNC ); @@ -277,7 +277,7 @@ inline int SetAsyncInfoIndex( MDLHandle_t hModel, MDLCacheDataType_t type, int i return index; } -inline int SetAsyncInfoIndex( MDLHandle_t hModel, MDLCacheDataType_t type, int index ) +inline intp SetAsyncInfoIndex( MDLHandle_t hModel, MDLCacheDataType_t type, intp index ) { return SetAsyncInfoIndex( hModel, type, 0, index ); } @@ -507,7 +507,7 @@ private: bool BuildHardwareData( MDLHandle_t handle, studiodata_t *pStudioData, studiohdr_t *pStudioHdr, OptimizedModel::FileHeader_t *pVtxHdr ); void ConvertFlexData( studiohdr_t *pStudioHdr ); - int ProcessPendingAsync( int iAsync ); + int ProcessPendingAsync( intp iAsync ); void ProcessPendingAsyncs( MDLCacheDataType_t type = MDLCACHE_NONE ); bool ClearAsync( MDLHandle_t handle, MDLCacheDataType_t type, int iAnimBlock, bool bAbort = false ); @@ -879,7 +879,7 @@ void CMDLCache::SetCacheNotify( IMDLCacheNotify *pNotify ) //----------------------------------------------------------------------------- const char *CMDLCache::GetModelName( MDLHandle_t handle ) { - if ( handle == MDLHANDLE_INVALID ) + if ( handle == MDLHANDLE_INVALID ) return ERROR_MODEL; return m_MDLDict.GetElementName( handle ); @@ -909,7 +909,7 @@ void CMDLCache::MakeFilename( MDLHandle_t handle, const char *pszExtension, char Q_strncpy( pszFileName, GetActualModelName( handle ), nMaxLength ); Q_SetExtension( pszFileName, pszExtension, nMaxLength ); Q_FixSlashes( pszFileName ); -#ifdef _LINUX +#ifdef POSIX Q_strlower( pszFileName ); #endif } @@ -1004,7 +1004,7 @@ void CMDLCache::UnserializeVCollide( MDLHandle_t handle, bool synchronousLoad ) // FIXME: Should the vcollde be played into cacheable memory? studiodata_t *pStudioData = m_MDLDict[handle]; - int iAsync = GetAsyncInfoIndex( handle, MDLCACHE_VCOLLIDE ); + intp iAsync = GetAsyncInfoIndex( handle, MDLCACHE_VCOLLIDE ); if ( iAsync == NO_ASYNC ) { @@ -1025,7 +1025,7 @@ void CMDLCache::UnserializeVCollide( MDLHandle_t handle, bool synchronousLoad ) { for ( int i = 1; i < pVirtualModel->m_group.Count(); i++ ) { - MDLHandle_t sharedHandle = (MDLHandle_t) (int)pVirtualModel->m_group[i].cache & 0xffff; + MDLHandle_t sharedHandle = VoidPtrToMDLHandle(pVirtualModel->m_group[i].cache); studiodata_t *pData = m_MDLDict[sharedHandle]; if ( !(pData->m_nFlags & STUDIODATA_FLAGS_VCOLLISION_LOADED) ) { @@ -1219,7 +1219,7 @@ unsigned char *CMDLCache::UnserializeAnimBlock( MDLHandle_t handle, int nBlock ) studiodata_t *pStudioData = m_MDLDict[handle]; - int iAsync = GetAsyncInfoIndex( handle, MDLCACHE_ANIMBLOCK, nBlock ); + intp iAsync = GetAsyncInfoIndex( handle, MDLCACHE_ANIMBLOCK, nBlock ); if ( iAsync == NO_ASYNC ) { @@ -1238,7 +1238,7 @@ unsigned char *CMDLCache::UnserializeAnimBlock( MDLHandle_t handle, int nBlock ) char pFileName[MAX_PATH]; Q_strncpy( pFileName, pModelName, sizeof(pFileName) ); Q_FixSlashes( pFileName ); -#ifdef _LINUX +#ifdef POSIX Q_strlower( pFileName ); #endif if ( IsX360() ) @@ -1398,12 +1398,12 @@ void CMDLCache::FreeVirtualModel( MDLHandle_t handle ) if ( pStudioData && pStudioData->m_pVirtualModel ) { int nGroupCount = pStudioData->m_pVirtualModel->m_group.Count(); - Assert( (nGroupCount >= 1) && pStudioData->m_pVirtualModel->m_group[0].cache == (void*)(uintp)handle ); + Assert( (nGroupCount >= 1) && pStudioData->m_pVirtualModel->m_group[0].cache == MDLHandleToVirtual(handle) ); // NOTE: Start at *1* here because the 0th element contains a reference to *this* handle for ( int i = 1; i < nGroupCount; ++i ) { - MDLHandle_t h = (MDLHandle_t)(int)pStudioData->m_pVirtualModel->m_group[i].cache&0xffff; + MDLHandle_t h = VoidPtrToMDLHandle( pStudioData->m_pVirtualModel->m_group[i].cache ); FreeVirtualModel( h ); Release( h ); } @@ -1450,10 +1450,13 @@ virtualmodel_t *CMDLCache::GetVirtualModelFast( const studiohdr_t *pStudioHdr, M AllocateVirtualModel( handle ); + // MoeMod : added + pStudioHdr->SetVirtualModel( MDLHandleToVirtual( handle ) ); + // Group has to be zero to ensure refcounting is correct int nGroup = pStudioData->m_pVirtualModel->m_group.AddToTail( ); Assert( nGroup == 0 ); - pStudioData->m_pVirtualModel->m_group[nGroup].cache = (void *)(uintp)handle; + pStudioData->m_pVirtualModel->m_group[nGroup].cache = MDLHandleToVirtual(handle); // Add all dependent data pStudioData->m_pVirtualModel->AppendModels( 0, pStudioHdr ); @@ -1550,7 +1553,7 @@ bool CMDLCache::LoadHardwareData( MDLHandle_t handle ) return false; } - int iAsync = GetAsyncInfoIndex( handle, MDLCACHE_STUDIOHWDATA ); + intp iAsync = GetAsyncInfoIndex( handle, MDLCACHE_STUDIOHWDATA ); if ( iAsync == NO_ASYNC ) { @@ -1970,18 +1973,39 @@ studiohdr_t *CMDLCache::UnserializeMDL( MDLHandle_t handle, void *pData, int nDa // critical! store a back link to our data // this is fetched when re-establishing dependent cached data (vtx/vvd) - pStudioHdrIn->virtualModel = (void *)(uintp)handle; +#ifndef PLATFORM_64BITS + pStudioHdrIn->SetVirtualModel( MDLHandleToVirtual( handle ) ); +#endif MdlCacheMsg( "MDLCache: Alloc studiohdr %s\n", GetModelName( handle ) ); // allocate cache space MemAlloc_PushAllocDbgInfo( "Models:StudioHdr", 0); +#ifdef PLATFORM_64BITS + studiohdr_t *pHdr = (studiohdr_t *)AllocData( MDLCACHE_STUDIOHDR, pStudioHdrIn->length + sizeof(studiohdr_shim64_index) ); +#else studiohdr_t *pHdr = (studiohdr_t *)AllocData( MDLCACHE_STUDIOHDR, pStudioHdrIn->length ); +#endif MemAlloc_PopAllocDbgInfo(); if ( !pHdr ) return NULL; +#ifdef PLATFORM_64BITS + // MoeMod : fix shim64 index + studiohdr_shim64_index *pHdrIndex = (studiohdr_shim64_index *)(((byte *)pHdr)+ pStudioHdrIn->length); + pHdrIndex->virtualModel = nullptr; + pHdrIndex->animblockModel = nullptr; + pHdrIndex->pVertexBase = nullptr; + pHdrIndex->pIndexBase = nullptr; + pStudioHdrIn->index_ptr_virtualModel = (byte *)&pHdrIndex->virtualModel - (byte *)pHdr; + pStudioHdrIn->index_ptr_animblockModel = (byte *)&pHdrIndex->animblockModel - (byte *)pHdr; + pStudioHdrIn->index_ptr_pVertexBase = (byte *)&pHdrIndex->pVertexBase - (byte *)pHdr; + pStudioHdrIn->index_ptr_pIndexBase = (byte *)&pHdrIndex->pIndexBase - (byte *)pHdr; + pStudioHdrIn->SetVirtualModel( MDLHandleToVirtual( handle ) ); + CacheData( &m_MDLDict[handle]->m_MDLCache, pHdr, pStudioHdrIn->length + sizeof(studiohdr_shim64_index), GetModelName( handle ), MDLCACHE_STUDIOHDR, MakeCacheID( handle, MDLCACHE_STUDIOHDR) ); +#else CacheData( &m_MDLDict[handle]->m_MDLCache, pHdr, pStudioHdrIn->length, GetModelName( handle ), MDLCACHE_STUDIOHDR, MakeCacheID( handle, MDLCACHE_STUDIOHDR) ); +#endif if ( mod_lock_mdls_on_load.GetBool() ) { @@ -2022,7 +2046,7 @@ bool CMDLCache::ReadMDLFile( MDLHandle_t handle, const char *pMDLFileName, CUtlB char pFileName[ MAX_PATH ]; Q_strncpy( pFileName, pMDLFileName, sizeof( pFileName ) ); Q_FixSlashes( pFileName ); -#ifdef _LINUX +#ifdef POSIX Q_strlower( pFileName ); #endif @@ -2059,6 +2083,12 @@ bool CMDLCache::ReadMDLFile( MDLHandle_t handle, const char *pMDLFileName, CUtlB } } + if ( buf.Size() < sizeof(studiohdr_t) ) + { + DevWarning( "Empty model %s\n", pMDLFileName ); + return false; + } + studiohdr_t *pStudioHdr = (studiohdr_t*)buf.PeekGet(); if ( !pStudioHdr ) { @@ -2073,7 +2103,27 @@ bool CMDLCache::ReadMDLFile( MDLHandle_t handle, const char *pMDLFileName, CUtlB // critical! store a back link to our data // this is fetched when re-establishing dependent cached data (vtx/vvd) - pStudioHdr->virtualModel = (void*)(uintp)handle; +#if PLATFORM_64BITS + int length = buf.Size(); + { + studiohdr_shim64_index shim; + buf.Put( &shim, sizeof(shim) ); + } + studiohdr_shim64_index *pHdrIndex = (studiohdr_shim64_index *)(((byte *)buf.PeekGet())+ length); + pStudioHdr = (studiohdr_t*)buf.PeekGet(); + + pHdrIndex->virtualModel = nullptr; + pHdrIndex->animblockModel = nullptr; + pHdrIndex->pVertexBase = nullptr; + pHdrIndex->pIndexBase = nullptr; + pStudioHdr->index_ptr_virtualModel = (byte *)&pHdrIndex->virtualModel - (byte *)pStudioHdr; + pStudioHdr->index_ptr_animblockModel = (byte *)&pHdrIndex->animblockModel - (byte *)pStudioHdr; + pStudioHdr->index_ptr_pVertexBase = (byte *)&pHdrIndex->pVertexBase - (byte *)pStudioHdr; + pStudioHdr->index_ptr_pIndexBase = (byte *)&pHdrIndex->pIndexBase - (byte *)pStudioHdr; + pStudioHdr->SetVirtualModel( MDLHandleToVirtual( handle ) ); +#else + pStudioHdr->SetVirtualModel( MDLHandleToVirtual( handle ) ); +#endif // Make sure all dependent files are valid if ( !VerifyHeaders( pStudioHdr ) ) @@ -2236,7 +2286,7 @@ void CMDLCache::TouchAllData( MDLHandle_t handle ) // ensure all sub models are cached for ( int i=1; im_group.Count(); ++i ) { - MDLHandle_t childHandle = (MDLHandle_t)(int)pVModel->m_group[i].cache&0xffff; + MDLHandle_t childHandle = VoidPtrToMDLHandle( pVModel->m_group[i].cache ); if ( childHandle != MDLHANDLE_INVALID ) { // FIXME: Should this be calling TouchAllData on the child? @@ -2301,7 +2351,7 @@ bool CMDLCache::HandleCacheNotification( const DataCacheNotification_t ¬ifica { MdlCacheMsg( "MDLCache: Data cache discard %s %s\n", g_ppszTypes[TypeFromCacheID( notification.clientId )], GetModelName( HandleFromCacheID( notification.clientId ) ) ); - if ( (DataCacheClientID_t)notification.pItemData == notification.clientId || + if ( (DataCacheClientID_t)(intp)notification.pItemData == notification.clientId || TypeFromCacheID(notification.clientId) != MDLCACHE_STUDIOHWDATA ) { Assert( notification.pItemData ); @@ -2320,7 +2370,7 @@ bool CMDLCache::HandleCacheNotification( const DataCacheNotification_t ¬ifica bool CMDLCache::GetItemName( DataCacheClientID_t clientId, const void *pItem, char *pDest, unsigned nMaxLen ) { - if ( (DataCacheClientID_t)pItem == clientId ) + if ( (DataCacheClientID_t)(uintp)pItem == clientId ) { return false; } @@ -2426,7 +2476,7 @@ void CMDLCache::FinishPendingLoads() AUTO_LOCK( m_AsyncMutex ); // finish just our known jobs - int iAsync = m_PendingAsyncs.Head(); + intp iAsync = m_PendingAsyncs.Head(); while ( iAsync != m_PendingAsyncs.InvalidIndex() ) { AsyncInfo_t &info = m_PendingAsyncs[iAsync]; @@ -2581,7 +2631,7 @@ bool CMDLCache::VerifyHeaders( studiohdr_t *pStudioHdr ) } char pFileName[ MAX_PATH ]; - MDLHandle_t handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff; + MDLHandle_t handle = VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ); MakeFilename( handle, ".vvd", pFileName, sizeof(pFileName) ); @@ -2642,7 +2692,7 @@ vertexFileHeader_t *CMDLCache::CacheVertexData( studiohdr_t *pStudioHdr ) Assert( pStudioHdr ); - handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff; + handle = VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ); Assert( handle != MDLHANDLE_INVALID ); pVvdHdr = (vertexFileHeader_t *)CheckData( m_MDLDict[handle]->m_VertexCache, MDLCACHE_VERTEXES ); @@ -3037,7 +3087,7 @@ bool CMDLCache::ProcessDataIntoCache( MDLHandle_t handle, MDLCacheDataType_t typ // =0: pending // >0: completed //----------------------------------------------------------------------------- -int CMDLCache::ProcessPendingAsync( int iAsync ) +int CMDLCache::ProcessPendingAsync( intp iAsync ) { if ( !ThreadInMainThread() ) { @@ -3122,10 +3172,10 @@ void CMDLCache::ProcessPendingAsyncs( MDLCacheDataType_t type ) // things -- the LRU is in correct order, and it catches precached items lurking // in the async queue that have only been requested once (thus aren't being cached // and might lurk forever, e.g., wood gibs in the citadel) - int current = m_PendingAsyncs.Head(); + intp current = m_PendingAsyncs.Head(); while ( current != m_PendingAsyncs.InvalidIndex() ) { - int next = m_PendingAsyncs.Next( current ); + intp next = m_PendingAsyncs.Next( current ); if ( type == MDLCACHE_NONE || m_PendingAsyncs[current].type == type ) { @@ -3148,7 +3198,7 @@ void CMDLCache::ProcessPendingAsyncs( MDLCacheDataType_t type ) //----------------------------------------------------------------------------- bool CMDLCache::ClearAsync( MDLHandle_t handle, MDLCacheDataType_t type, int iAnimBlock, bool bAbort ) { - int iAsyncInfo = GetAsyncInfoIndex( handle, type, iAnimBlock ); + intp iAsyncInfo = GetAsyncInfoIndex( handle, type, iAnimBlock ); if ( iAsyncInfo != NO_ASYNC ) { AsyncInfo_t *pInfo; @@ -3242,7 +3292,7 @@ bool CMDLCache::SetAsyncLoad( MDLCacheDataType_t type, bool bAsync ) //----------------------------------------------------------------------------- vertexFileHeader_t *CMDLCache::BuildAndCacheVertexData( studiohdr_t *pStudioHdr, vertexFileHeader_t *pRawVvdHdr ) { - MDLHandle_t handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff; + MDLHandle_t handle = VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ); vertexFileHeader_t *pVvdHdr; MdlCacheMsg( "MDLCache: Load VVD for %s\n", pStudioHdr->pszName() ); @@ -3330,7 +3380,7 @@ vertexFileHeader_t *CMDLCache::LoadVertexData( studiohdr_t *pStudioHdr ) MDLHandle_t handle; Assert( pStudioHdr ); - handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff; + handle = VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ); Assert( !m_MDLDict[handle]->m_VertexCache ); studiodata_t *pStudioData = m_MDLDict[handle]; @@ -3340,7 +3390,7 @@ vertexFileHeader_t *CMDLCache::LoadVertexData( studiohdr_t *pStudioHdr ) return NULL; } - int iAsync = GetAsyncInfoIndex( handle, MDLCACHE_VERTEXES ); + intp iAsync = GetAsyncInfoIndex( handle, MDLCACHE_VERTEXES ); if ( iAsync == NO_ASYNC ) { @@ -3420,7 +3470,7 @@ void CMDLCache::CacheData( DataCacheHandle_t *c, void *pData, int size, const ch } if ( id == (DataCacheClientID_t)-1 ) - id = (DataCacheClientID_t)pData; + id = (DataCacheClientID_t)(intp)pData; GetCacheSection( type )->Add(id, pData, size, c ); } @@ -3584,7 +3634,7 @@ void CMDLCache::QueuedLoaderCallback_MDL( void *pContext, void *pContext2, const // journal each incoming buffer ModelParts_t *pModelParts = (ModelParts_t *)pContext; - ModelParts_t::BufferType_t bufferType = static_cast< ModelParts_t::BufferType_t >((int)pContext2); + ModelParts_t::BufferType_t bufferType = static_cast< ModelParts_t::BufferType_t >((intp)pContext2); pModelParts->Buffers[bufferType].SetExternalBuffer( (void *)pData, nSize, nSize, CUtlBuffer::READ_ONLY ); pModelParts->nLoadedParts += (1 << bufferType); @@ -3895,7 +3945,7 @@ void CMDLCache::MarkFrame() const studiohdr_t *studiohdr_t::FindModel( void **cache, char const *pModelName ) const { MDLHandle_t handle = g_MDLCache.FindMDL( pModelName ); - *cache = (void*)(uintp)handle; + *cache = MDLHandleToVirtual(handle); return g_MDLCache.GetStudioHdr( handle ); } @@ -3904,21 +3954,21 @@ virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const if (numincludemodels == 0) return NULL; - return g_MDLCache.GetVirtualModelFast( this, (MDLHandle_t)(int)virtualModel&0xffff ); + return g_MDLCache.GetVirtualModelFast( this, VoidPtrToMDLHandle( VirtualModel() ) ); } byte *studiohdr_t::GetAnimBlock( int i ) const { - return g_MDLCache.GetAnimBlock( (MDLHandle_t)(int)virtualModel&0xffff, i ); + return g_MDLCache.GetAnimBlock( VoidPtrToMDLHandle( VirtualModel() ), i ); } int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const { - return g_MDLCache.GetAutoplayList( (MDLHandle_t)(int)virtualModel&0xffff, pOut ); + return g_MDLCache.GetAutoplayList( VoidPtrToMDLHandle( VirtualModel() ), pOut ); } const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const { - return g_MDLCache.GetStudioHdr( (MDLHandle_t)(int)cache&0xffff ); + return g_MDLCache.GetStudioHdr( VoidPtrToMDLHandle( cache ) ); } diff --git a/datamodel/datamodel.cpp b/datamodel/datamodel.cpp index a569e65c..7e7589dc 100644 --- a/datamodel/datamodel.cpp +++ b/datamodel/datamodel.cpp @@ -901,7 +901,9 @@ bool CDataModel::Unserialize( CUtlBuffer &inBuf, const char *pEncodingName, cons return false; } +#if !defined(NO_MALLOC_OVERRIDE) g_pMemAlloc->heapchk(); +#endif DmxHeader_t header; bool bStoresVersionInFile = pSerializer->StoresVersionInFile(); @@ -1656,7 +1658,7 @@ DmAttributeReferenceIterator_t CDataModel::FirstAttributeReferencingElement( DmE if ( !pRef || pRef->m_attributes.m_hAttribute == DMATTRIBUTE_HANDLE_INVALID ) return DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; - return ( DmAttributeReferenceIterator_t )( int )&pRef->m_attributes; + return ( DmAttributeReferenceIterator_t )( intp )&pRef->m_attributes; } DmAttributeReferenceIterator_t CDataModel::NextAttributeReferencingElement( DmAttributeReferenceIterator_t hAttrIter ) @@ -1665,7 +1667,7 @@ DmAttributeReferenceIterator_t CDataModel::NextAttributeReferencingElement( DmAt if ( !pList ) return DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; - return ( DmAttributeReferenceIterator_t )( int )pList->m_pNext; + return ( DmAttributeReferenceIterator_t )( intp )pList->m_pNext; } CDmAttribute *CDataModel::GetAttribute( DmAttributeReferenceIterator_t hAttrIter ) diff --git a/datamodel/dependencygraph.cpp b/datamodel/dependencygraph.cpp index 2040b34d..527a38a4 100644 --- a/datamodel/dependencygraph.cpp +++ b/datamodel/dependencygraph.cpp @@ -67,7 +67,7 @@ bool HashEntryCompareFunc( CAttributeNode *const& lhs, CAttributeNode *const& rh uint HashEntryKeyFunc( CAttributeNode *const& keyinfo ) { - uint i = (uint)keyinfo->m_attribute; + uintp i = (uintp)keyinfo->m_attribute; return i >> 2; // since memory is allocated on a 4-byte (at least!) boundary } diff --git a/engine/LoadScreenUpdate.cpp b/engine/LoadScreenUpdate.cpp index 6bfcd1b7..2ea25063 100644 --- a/engine/LoadScreenUpdate.cpp +++ b/engine/LoadScreenUpdate.cpp @@ -53,8 +53,8 @@ public: DELEGATE_TO_OBJECT_0( int, heapchk, m_pMemAlloc ); DELEGATE_TO_OBJECT_0( bool, IsDebugHeap, m_pMemAlloc ); DELEGATE_TO_OBJECT_2V( GetActualDbgInfo, const char *&, int &, m_pMemAlloc ); - DELEGATE_TO_OBJECT_5V( RegisterAllocation, const char *, int, int, int, unsigned, m_pMemAlloc ); - DELEGATE_TO_OBJECT_5V( RegisterDeallocation, const char *, int, int, int, unsigned, m_pMemAlloc ); + DELEGATE_TO_OBJECT_5V( RegisterAllocation, const char *, int, size_t, size_t, unsigned, m_pMemAlloc ); + DELEGATE_TO_OBJECT_5V( RegisterDeallocation, const char *, int, size_t, size_t, unsigned, m_pMemAlloc ); DELEGATE_TO_OBJECT_0( int, GetVersion, m_pMemAlloc ); DELEGATE_TO_OBJECT_0V( CompactHeap, m_pMemAlloc ); DELEGATE_TO_OBJECT_1( MemAllocFailHandler_t, SetAllocFailHandler, MemAllocFailHandler_t, m_pMemAlloc ); diff --git a/engine/ModelInfo.cpp b/engine/ModelInfo.cpp index d5d1f371..b72a0bc5 100644 --- a/engine/ModelInfo.cpp +++ b/engine/ModelInfo.cpp @@ -208,8 +208,8 @@ protected: public: struct ModelFileHandleHash { - uint operator()( model_t *p ) const { return Mix32HashFunctor()( (uint32)( p->fnHandle ) ); } - uint operator()( FileNameHandle_t fn ) const { return Mix32HashFunctor()( (uint32) fn ); } + uint operator()( model_t *p ) const { return PointerHashFunctor()( p->fnHandle ); } + uint operator()( FileNameHandle_t fn ) const { return PointerHashFunctor()( fn ); } }; struct ModelFileHandleEq { @@ -532,7 +532,7 @@ const studiohdr_t *CModelInfo::FindModel( const studiohdr_t *pStudioHdr, void ** //----------------------------------------------------------------------------- const studiohdr_t *CModelInfo::FindModel( void *cache ) const { - return g_pMDLCache->GetStudioHdr( (MDLHandle_t)(int)cache&0xffff ); + return g_pMDLCache->GetStudioHdr( VoidPtrToMDLHandle( cache ) ); } @@ -541,7 +541,7 @@ const studiohdr_t *CModelInfo::FindModel( void *cache ) const //----------------------------------------------------------------------------- virtualmodel_t *CModelInfo::GetVirtualModel( const studiohdr_t *pStudioHdr ) const { - MDLHandle_t handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff; + MDLHandle_t handle = VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ); return g_pMDLCache->GetVirtualModelFast( pStudioHdr, handle ); } @@ -550,13 +550,13 @@ virtualmodel_t *CModelInfo::GetVirtualModel( const studiohdr_t *pStudioHdr ) con //----------------------------------------------------------------------------- byte *CModelInfo::GetAnimBlock( const studiohdr_t *pStudioHdr, int nBlock ) const { - MDLHandle_t handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff; + MDLHandle_t handle = VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ); return g_pMDLCache->GetAnimBlock( handle, nBlock ); } int CModelInfo::GetAutoplayList( const studiohdr_t *pStudioHdr, unsigned short **pAutoplayList ) const { - MDLHandle_t handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff; + MDLHandle_t handle = VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ); return g_pMDLCache->GetAutoplayList( handle, pAutoplayList ); } @@ -576,22 +576,22 @@ virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const { if ( numincludemodels == 0 ) return NULL; - return g_pMDLCache->GetVirtualModelFast( this, (MDLHandle_t)(int)virtualModel&0xffff ); + return g_pMDLCache->GetVirtualModelFast( this, VoidPtrToMDLHandle( VirtualModel() ) ); } byte *studiohdr_t::GetAnimBlock( int i ) const { - return g_pMDLCache->GetAnimBlock( (MDLHandle_t)(int)virtualModel&0xffff, i ); + return g_pMDLCache->GetAnimBlock( VoidPtrToMDLHandle( VirtualModel() ), i ); } int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const { - return g_pMDLCache->GetAutoplayList( (MDLHandle_t)(int)virtualModel&0xffff, pOut ); + return g_pMDLCache->GetAutoplayList( VoidPtrToMDLHandle( VirtualModel() ), pOut ); } const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const { - return g_pMDLCache->GetStudioHdr( (MDLHandle_t)(int)cache&0xffff ); + return g_pMDLCache->GetStudioHdr( VoidPtrToMDLHandle( cache ) ); } diff --git a/engine/audio/private/snd_mix.cpp b/engine/audio/private/snd_mix.cpp index ca44cbf6..94d9e794 100644 --- a/engine/audio/private/snd_mix.cpp +++ b/engine/audio/private/snd_mix.cpp @@ -1962,7 +1962,7 @@ public: { int m_channelNum; int m_vol; // max volume of sound. -1 means "do not cull, ever, do not even do the math" - unsigned int m_nameHash; // a unique id for a sound file + uintp m_nameHash; // a unique id for a sound file }; protected: sChannelVolData m_channelInfo[MAX_CHANNELS]; @@ -1994,7 +1994,7 @@ void CChannelCullList::Initialize( CChannelList &list ) { m_channelInfo[i].m_vol = ChannelLoudestCurVolume(ch); AssertMsg(m_channelInfo[i].m_vol >= 0, "Sound channel has a negative volume?"); - m_channelInfo[i].m_nameHash = (unsigned int) ch->sfx; + m_channelInfo[i].m_nameHash = (uintp) ch->sfx; } else { @@ -2029,7 +2029,7 @@ void CChannelCullList::Initialize( CChannelList &list ) ++j ) { // j steps through the sorted list until we find ourselves: - if (m_channelInfo[j].m_nameHash == (unsigned int)(ch->sfx)) + if (m_channelInfo[j].m_nameHash == (uintp)(ch->sfx)) { // that's another channel playing this sound but louder than me ++howManyLouder; diff --git a/engine/audio/private/snd_mp3_source.cpp b/engine/audio/private/snd_mp3_source.cpp index d4b012e4..82c9662e 100644 --- a/engine/audio/private/snd_mp3_source.cpp +++ b/engine/audio/private/snd_mp3_source.cpp @@ -93,7 +93,7 @@ CAudioSourceMP3::CAudioSourceMP3( CSfxTable *pSfx ) m_dataStart = 0; - int file = g_pSndIO->open( pSfx->GetFileName() ); + intp file = g_pSndIO->open( pSfx->GetFileName() ); if ( file != -1 ) { m_dataSize = g_pSndIO->size( file ); @@ -239,7 +239,7 @@ void CAudioSourceMP3::GetCacheData( CAudioSourceCachedInfo *info ) info->SetSampleRate( m_sampleRate ); info->SetDataStart( 0 ); - int file = g_pSndIO->open( m_pSfx->GetFileName() ); + intp file = g_pSndIO->open( m_pSfx->GetFileName() ); if ( !file ) { Warning( "Failed to find file for building soundcache [ %s ]\n", m_pSfx->GetFileName() ); diff --git a/engine/audio/private/snd_wave_source.cpp b/engine/audio/private/snd_wave_source.cpp index e51d22dc..3954dfdf 100644 --- a/engine/audio/private/snd_wave_source.cpp +++ b/engine/audio/private/snd_wave_source.cpp @@ -723,7 +723,7 @@ bool CAudioSourceWave::GetStartupData( void *dest, int destsize, int& bytesCopie // requesting precache snippet as leader for streaming startup latency if ( destsize ) { - int file = g_pSndIO->open( m_pSfx->GetFileName() ); + intp file = g_pSndIO->open( m_pSfx->GetFileName() ); if ( !file ) { return false; diff --git a/engine/audio/private/voice_mixer_controls_openal.cpp b/engine/audio/private/voice_mixer_controls_openal.cpp index 832815c8..6286889e 100644 --- a/engine/audio/private/voice_mixer_controls_openal.cpp +++ b/engine/audio/private/voice_mixer_controls_openal.cpp @@ -141,7 +141,7 @@ bool CMixerControls::GetValue_Float(Control iControl, float &value) case MicVolume: { OSStatus theError = noErr; - for ( int iChannel = 0; iChannel < 3; iChannel++ ) + for ( uint iChannel = 0; iChannel < 3; iChannel++ ) { // scan the channel list until you find a channel set to non-zero, then use that Float32 theVolume = 0; diff --git a/engine/cmd.cpp b/engine/cmd.cpp index 783ded93..689832b1 100644 --- a/engine/cmd.cpp +++ b/engine/cmd.cpp @@ -645,7 +645,7 @@ void Cmd_Exec_f( const CCommand &args ) ConDMsg( "execing %s\n", szFile ); // check to make sure we're not going to overflow the cmd_text buffer - int hCommand = s_CommandBuffer.GetNextCommandHandle(); + CommandHandle_t hCommand = s_CommandBuffer.GetNextCommandHandle(); // Execute each command immediately const char *pszDataPtr = f; diff --git a/engine/cmodel_disp.cpp b/engine/cmodel_disp.cpp index f805c4ac..3b71a765 100644 --- a/engine/cmodel_disp.cpp +++ b/engine/cmodel_disp.cpp @@ -228,7 +228,7 @@ public: // Fill out the meshlist for this terrain patch virtual void GetVirtualMesh( void *userData, virtualmeshlist_t *pList ) { - int index = (int)userData; + intp index = (intp)userData; Assert(index >= 0 && index < g_DispCollTreeCount ); g_pDispCollTrees[index].GetVirtualMeshList( pList ); pList->pHull = NULL; @@ -243,14 +243,14 @@ public: // returns the bounds for the terrain patch virtual void GetWorldspaceBounds( void *userData, Vector *pMins, Vector *pMaxs ) { - int index = (int)userData; + intp index = (intp)userData; *pMins = g_pDispBounds[index].mins; *pMaxs = g_pDispBounds[index].maxs; } // Query against the AABB tree to find the list of triangles for this patch in a sphere virtual void GetTrianglesInSphere( void *userData, const Vector ¢er, float radius, virtualmeshtrianglelist_t *pList ) { - int index = (int)userData; + intp index = (intp)userData; pList->triangleCount = g_pDispCollTrees[index].AABBTree_GetTrisInSphere( center, radius, pList->triangleIndices, ARRAYSIZE(pList->triangleIndices) ); } void LevelInit( dphysdisp_t *pLump, int lumpSize ) diff --git a/engine/colorcorrectionpanel.cpp b/engine/colorcorrectionpanel.cpp index b211aecf..b198be00 100644 --- a/engine/colorcorrectionpanel.cpp +++ b/engine/colorcorrectionpanel.cpp @@ -4895,7 +4895,7 @@ void CColorOperationListPanel::PopulateList( ) KeyValues *kv = new KeyValues( "operation", "layer", op->GetName() ); kv->SetInt( "image", (op->IsEnabled())?1:0 ); - m_pOperationListPanel->AddItem( kv, (unsigned int)op, false, false ); + m_pOperationListPanel->AddItem( kv, (uintp)op, false, false ); } } } diff --git a/engine/disp.cpp b/engine/disp.cpp index 6c9781c1..b0cdb86c 100644 --- a/engine/disp.cpp +++ b/engine/disp.cpp @@ -547,9 +547,9 @@ bool CDispInfo::Render( CGroupMesh *pGroup, bool bAllowDebugModes ) VectorAdd( bbMin, bbMax, vecCenter ); vecCenter *= 0.5f; - int nInt = ( mat_surfaceid.GetInt() != 2 ) ? (int)m_ParentSurfID : (msurface2_t*)m_ParentSurfID - host_state.worldbrush->surfaces2; + intp nInt = ( mat_surfaceid.GetInt() != 2 ) ? (intp)m_ParentSurfID : (msurface2_t*)m_ParentSurfID - host_state.worldbrush->surfaces2; char buf[32]; - Q_snprintf( buf, sizeof( buf ), "%d", nInt ); + Q_snprintf( buf, sizeof( buf ), "%d", (int)nInt ); CDebugOverlay::AddTextOverlay( vecCenter, 0, buf ); } diff --git a/engine/disp_interface.cpp b/engine/disp_interface.cpp index da6ea461..6bf015ca 100644 --- a/engine/disp_interface.cpp +++ b/engine/disp_interface.cpp @@ -764,7 +764,7 @@ void DispInfo_BatchDecals( CDispInfo **pVisibleDisps, int nVisibleDisps ) // There is only one group at a time. int iGroup = 0; - int iPool = g_aDispDecalSortPool.Alloc( true ); + intp iPool = g_aDispDecalSortPool.Alloc( true ); g_aDispDecalSortPool[iPool] = decal.m_pDecal; int iSortTree = decal.m_pDecal->m_iSortTree; @@ -773,7 +773,7 @@ void DispInfo_BatchDecals( CDispInfo **pVisibleDisps, int nVisibleDisps ) DecalMaterialBucket_t &materialBucket = g_aDispDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iSortMaterial ); if ( materialBucket.m_nCheckCount == g_nDispDecalSortCheckCount ) { - int iHead = materialBucket.m_iHead; + intp iHead = materialBucket.m_iHead; g_aDispDecalSortPool.LinkBefore( iHead, iPool ); } @@ -844,7 +844,7 @@ void DispInfo_DrawDecalsGroup( int iGroup, int iTreeType ) if ( materialBucketList.Element( iBucket ).m_nCheckCount != g_nDispDecalSortCheckCount ) continue; - int iHead = materialBucketList.Element( iBucket ).m_iHead; + intp iHead = materialBucketList.Element( iBucket ).m_iHead; if ( !g_aDispDecalSortPool.IsValidIndex( iHead ) ) continue; @@ -863,7 +863,7 @@ void DispInfo_DrawDecalsGroup( int iGroup, int iTreeType ) bool bBatchInit = true; int nCount; - int iElement = iHead; + intp iElement = iHead; while ( iElement != g_aDispDecalSortPool.InvalidIndex() ) { decal_t *pDecal = g_aDispDecalSortPool.Element( iElement ); @@ -1300,7 +1300,7 @@ int DispInfo_ComputeIndex( HDISPINFOARRAY hArray, IDispInfo* pInfo ) if( !pArray ) return NULL; - int iElement = ((int)pInfo - (int)(pArray->m_pDispInfos)) / sizeof(CDispInfo); + intp iElement = ((intp)pInfo - (intp)(pArray->m_pDispInfos)) / sizeof(CDispInfo); Assert( iElement >= 0 && iElement < pArray->m_nDispInfos ); return iElement; diff --git a/engine/download.cpp b/engine/download.cpp index 8714b06d..eb58261c 100644 --- a/engine/download.cpp +++ b/engine/download.cpp @@ -924,12 +924,12 @@ void CDownloadManager::StartNewDownload() m_lastPercent = 0; // Start the thread - DWORD threadID; + uintp threadID; VCRHook_CreateThread(NULL, 0, #ifdef POSIX (void *) #endif - DownloadThread, m_activeRequest, 0, (unsigned long int *)&threadID ); + DownloadThread, m_activeRequest, 0, &threadID ); ThreadDetach( ( ThreadHandle_t )threadID ); } @@ -1070,14 +1070,14 @@ bool CL_IsGamePathValidAndSafeForDownload( const char *pGamePath ) class CDownloadSystem : public IDownloadSystem { public: - virtual DWORD CreateDownloadThread( RequestContext_t *pContext ) + virtual uintp CreateDownloadThread( RequestContext_t *pContext ) { - DWORD nThreadID; + uintp nThreadID; VCRHook_CreateThread(NULL, 0, #ifdef POSIX (void*) #endif - DownloadThread, pContext, 0, (unsigned long int *)&nThreadID ); + DownloadThread, pContext, 0, (uintp *)&nThreadID ); ThreadDetach( ( ThreadHandle_t )nThreadID ); return nThreadID; diff --git a/engine/dt_localtransfer.cpp b/engine/dt_localtransfer.cpp index 61c78edf..9cc101dc 100644 --- a/engine/dt_localtransfer.cpp +++ b/engine/dt_localtransfer.cpp @@ -175,12 +175,12 @@ void BuildPropOffsetToIndexMap( CSendTablePrecalc *pPrecalc, const CStandardSend { const SendProp *pProp = pPrecalc->m_Props[i]; - int offset = pProp->GetOffset() + (int)pmStack.GetCurStructBase() - 1; + intp offset = pProp->GetOffset() + (intp)pmStack.GetCurStructBase() - 1; int elementCount = 1; int elementStride = 0; if ( pProp->GetType() == DPT_Array ) { - offset = pProp->GetArrayProp()->GetOffset() + (int)pmStack.GetCurStructBase() - 1; + offset = pProp->GetArrayProp()->GetOffset() + (intp)pmStack.GetCurStructBase() - 1; elementCount = pProp->m_nElements; elementStride = pProp->m_ElementStride; } diff --git a/engine/gl_rsurf.cpp b/engine/gl_rsurf.cpp index 836a3443..5731704c 100644 --- a/engine/gl_rsurf.cpp +++ b/engine/gl_rsurf.cpp @@ -4747,7 +4747,7 @@ struct EnumLeafBoxInfo_t VectorAligned m_vecBoxCenter; VectorAligned m_vecBoxHalfDiagonal; ISpatialLeafEnumerator *m_pIterator; - int m_nContext; + intp m_nContext; }; struct EnumLeafSphereInfo_t @@ -4757,7 +4757,7 @@ struct EnumLeafSphereInfo_t Vector m_vecBoxCenter; Vector m_vecBoxHalfDiagonal; ISpatialLeafEnumerator *m_pIterator; - int m_nContext; + intp m_nContext; }; //----------------------------------------------------------------------------- @@ -5094,7 +5094,7 @@ bool EnumerateLeafInSphere_R( mnode_t *node, EnumLeafSphereInfo_t& info, int nTe //----------------------------------------------------------------------------- static bool EnumerateLeavesAlongRay_R( mnode_t *node, Ray_t const& ray, - float start, float end, ISpatialLeafEnumerator* pEnum, int context ) + float start, float end, ISpatialLeafEnumerator* pEnum, intp context ) { // no polygons in solid nodes (don't report these leaves either) if (node->contents == CONTENTS_SOLID) @@ -5153,7 +5153,7 @@ static bool EnumerateLeavesAlongRay_R( mnode_t *node, Ray_t const& ray, //----------------------------------------------------------------------------- static bool EnumerateLeavesAlongExtrudedRay_R( mnode_t *node, Ray_t const& ray, - float start, float end, ISpatialLeafEnumerator* pEnum, int context ) + float start, float end, ISpatialLeafEnumerator* pEnum, intp context ) { // no polygons in solid nodes (don't report these leaves either) if (node->contents == CONTENTS_SOLID) @@ -5276,10 +5276,10 @@ public: int LeafCount() const; // Enumerates the leaves along a ray, box, etc. - bool EnumerateLeavesAtPoint( const Vector& pt, ISpatialLeafEnumerator* pEnum, int context ); - bool EnumerateLeavesInBox( const Vector& mins, const Vector& maxs, ISpatialLeafEnumerator* pEnum, int context ); - bool EnumerateLeavesInSphere( const Vector& center, float radius, ISpatialLeafEnumerator* pEnum, int context ); - bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ); + bool EnumerateLeavesAtPoint( const Vector& pt, ISpatialLeafEnumerator* pEnum, intp context ); + bool EnumerateLeavesInBox( const Vector& mins, const Vector& maxs, ISpatialLeafEnumerator* pEnum, intp context ); + bool EnumerateLeavesInSphere( const Vector& center, float radius, ISpatialLeafEnumerator* pEnum, intp context ); + bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context ); }; //----------------------------------------------------------------------------- @@ -5304,7 +5304,7 @@ int CEngineBSPTree::LeafCount() const //----------------------------------------------------------------------------- bool CEngineBSPTree::EnumerateLeavesAtPoint( const Vector& pt, - ISpatialLeafEnumerator* pEnum, int context ) + ISpatialLeafEnumerator* pEnum, intp context ) { int leaf = CM_PointLeafnum( pt ); return pEnum->EnumerateLeaf( leaf, context ); @@ -5315,7 +5315,7 @@ static ConVar opt_EnumerateLeavesFastAlgorithm( "opt_EnumerateLeavesFastAlgorith bool CEngineBSPTree::EnumerateLeavesInBox( const Vector& mins, const Vector& maxs, - ISpatialLeafEnumerator* pEnum, int context ) + ISpatialLeafEnumerator* pEnum, intp context ) { if ( !host_state.worldmodel ) return false; @@ -5340,7 +5340,7 @@ bool CEngineBSPTree::EnumerateLeavesInBox( const Vector& mins, const Vector& max bool CEngineBSPTree::EnumerateLeavesInSphere( const Vector& center, float radius, - ISpatialLeafEnumerator* pEnum, int context ) + ISpatialLeafEnumerator* pEnum, intp context ) { EnumLeafSphereInfo_t info; info.m_vecCenter = center; @@ -5354,7 +5354,7 @@ bool CEngineBSPTree::EnumerateLeavesInSphere( const Vector& center, float radius } -bool CEngineBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ) +bool CEngineBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context ) { if (!ray.m_IsSwept) { diff --git a/engine/l_studio.cpp b/engine/l_studio.cpp index f1bb594c..aca389f2 100644 --- a/engine/l_studio.cpp +++ b/engine/l_studio.cpp @@ -872,7 +872,7 @@ public: virtual void SetupLighting( const Vector &vecCenter ); virtual void SuppressEngineLighting( bool bSuppress ); - inline vertexFileHeader_t *CacheVertexData() { return g_pMDLCache->GetVertexData( (MDLHandle_t)(int)m_pStudioHdr->virtualModel&0xffff ); } + inline vertexFileHeader_t *CacheVertexData() { return g_pMDLCache->GetVertexData( VoidPtrToMDLHandle( m_pStudioHdr->VirtualModel() ) ); } bool Init(); void Shutdown(); @@ -4121,7 +4121,7 @@ bool CModelRender::UpdateStaticPropColorData( IHandleEntity *pProp, ModelInstanc if ( !bDebugColor ) { // vertexes must be available for lighting calculation - vertexFileHeader_t *pVertexHdr = g_pMDLCache->GetVertexData( (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff ); + vertexFileHeader_t *pVertexHdr = g_pMDLCache->GetVertexData( VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ) ); if ( !pVertexHdr ) { // data not available yet diff --git a/engine/modelloader.cpp b/engine/modelloader.cpp index 58ffea68..b3a851ad 100644 --- a/engine/modelloader.cpp +++ b/engine/modelloader.cpp @@ -1869,6 +1869,12 @@ void Mod_LoadFaces( void ) // align these allocations // If you trip one of these, you need to rethink the alignment of the struct +#ifdef PLATFORM_64BITS + msurface1_t *out1 = Hunk_AllocNameAlignedClear< msurface1_t >( count, alignof(msurface1_t), va( "%s [%s]", lh.GetLoadName(), "surface1" ) ); + msurface2_t *out2 = Hunk_AllocNameAlignedClear< msurface2_t >( count, alignof(msurface2_t), va( "%s [%s]", lh.GetLoadName(), "surface2" ) ); + + msurfacelighting_t *pLighting = Hunk_AllocNameAlignedClear< msurfacelighting_t >( count, alignof(msurfacelighting_t), va( "%s [%s]", lh.GetLoadName(), "surfacelighting" ) ); +#else Assert( sizeof(msurface1_t) == 16 ); Assert( sizeof(msurface2_t) == 32 ); Assert( sizeof(msurfacelighting_t) == 32 ); @@ -1877,6 +1883,7 @@ void Mod_LoadFaces( void ) msurface2_t *out2 = Hunk_AllocNameAlignedClear< msurface2_t >( count, 32, va( "%s [%s]", lh.GetLoadName(), "surface2" ) ); msurfacelighting_t *pLighting = Hunk_AllocNameAlignedClear< msurfacelighting_t >( count, 32, va( "%s [%s]", lh.GetLoadName(), "surfacelighting" ) ); +#endif lh.GetMap()->surfaces1 = out1; lh.GetMap()->surfaces2 = out2; @@ -2860,7 +2867,7 @@ void Mod_TouchAllData( model_t *pModel, int nServerCount ) // skip self, start at children for ( int i=1; im_group.Count(); ++i ) { - MDLHandle_t childHandle = (MDLHandle_t)(int)pVirtualModel->m_group[i].cache&0xffff; + MDLHandle_t childHandle = (MDLHandle_t)(intp)pVirtualModel->m_group[i].cache&0xffff; model_t *pChildModel = (model_t *)g_pMDLCache->GetUserData( childHandle ); if ( pChildModel ) { @@ -4325,7 +4332,7 @@ public: m_pShared = pBrush->brush.pShared; m_count = 0; } - bool EnumerateLeaf( int leaf, int ) + bool EnumerateLeaf( int leaf, intp ) { // garymcthack - need to test identity brush models int flags = ( m_pShared->leafs[leaf].leafWaterDataID == -1 ) ? SURFDRAW_ABOVEWATER : SURFDRAW_UNDERWATER; @@ -4372,7 +4379,7 @@ static void MarkBrushModelWaterSurfaces( model_t* world, model_t* pTemp = host_state.worldmodel; CBrushBSPIterator brushIterator( world, brush ); host_state.SetWorldModel( world ); - g_pToolBSPTree->EnumerateLeavesInBox( mins, maxs, &brushIterator, (int)brush ); + g_pToolBSPTree->EnumerateLeavesInBox( mins, maxs, &brushIterator, (intp)brush ); brushIterator.CheckSurfaces(); host_state.SetWorldModel( pTemp ); } diff --git a/engine/pure_server.h b/engine/pure_server.h index 5fb33ef3..a5bb0ab1 100644 --- a/engine/pure_server.h +++ b/engine/pure_server.h @@ -96,7 +96,7 @@ private: CPureServerWhitelist::CCommand *pBestEntry ); unsigned short m_LoadCounter; // Incremented as we load things so their m_LoadOrder increases. - volatile long int m_RefCount; + volatile int32 m_RefCount; // Commands are applied to files in order. CUtlDict m_FileCommands; // file commands diff --git a/engine/r_decal.cpp b/engine/r_decal.cpp index 95f8c8ea..69b11d68 100644 --- a/engine/r_decal.cpp +++ b/engine/r_decal.cpp @@ -2001,9 +2001,9 @@ void R_DrawDecalsAllImmediate_GatherDecals( IMatRenderContext *pRenderContext, i if ( g_aDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iBucket ).m_nCheckCount != nCheckCount ) continue; - int iHead = g_aDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iBucket ).m_iHead; + intp iHead = g_aDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iBucket ).m_iHead; - int iElement = iHead; + intp iElement = iHead; while ( iElement != g_aDecalSortPool.InvalidIndex() ) { decal_t *pDecal = g_aDecalSortPool.Element( iElement ); @@ -2155,10 +2155,10 @@ void R_DrawDecalsAllImmediate( IMatRenderContext *pRenderContext, int iGroup, in if ( g_aDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iBucket ).m_nCheckCount != nCheckCount ) continue; - int iHead = g_aDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iBucket ).m_iHead; + intp iHead = g_aDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iBucket ).m_iHead; int nCount; - int iElement = iHead; + intp iElement = iHead; while ( iElement != g_aDecalSortPool.InvalidIndex() ) { decal_t *pDecal = g_aDecalSortPool.Element( iElement ); @@ -2330,7 +2330,7 @@ void R_DrawDecalsAll_GatherDecals( IMatRenderContext *pRenderContext, int iGroup if ( bucket.m_nCheckCount != nCheckCount ) continue; - int iHead = bucket.m_iHead; + intp iHead = bucket.m_iHead; if ( !g_aDecalSortPool.IsValidIndex( iHead ) ) continue; @@ -2346,7 +2346,7 @@ void R_DrawDecalsAll_GatherDecals( IMatRenderContext *pRenderContext, int iGroup DrawDecals.AddToTail( DECALMARKERS_SWITCHBUCKET ); - int iElement = iHead; + intp iElement = iHead; while ( iElement != g_aDecalSortPool.InvalidIndex() ) { decal_t *pDecal = g_aDecalSortPool.Element( iElement ); @@ -3015,7 +3015,7 @@ void DecalSurfaceAdd( SurfaceHandle_t surfID, int iGroup ) } pDecal->flags &= ~FDECAL_HASUPDATED; - int iPool = g_aDecalSortPool.Alloc( true ); + intp iPool = g_aDecalSortPool.Alloc( true ); if ( iPool != g_aDecalSortPool.InvalidIndex() ) { g_aDecalSortPool[iPool] = pDecal; @@ -3024,7 +3024,7 @@ void DecalSurfaceAdd( SurfaceHandle_t surfID, int iGroup ) DecalMaterialBucket_t &bucket = sortTree.m_aDecalSortBuckets[iGroup][iTreeType].Element( pDecal->m_iSortMaterial ); if ( bucket.m_nCheckCount == nCheckCount ) { - int iHead = bucket.m_iHead; + intp iHead = bucket.m_iHead; g_aDecalSortPool.LinkBefore( iHead, iPool ); } diff --git a/engine/r_decal.h b/engine/r_decal.h index 8883c3a9..63fdb57e 100644 --- a/engine/r_decal.h +++ b/engine/r_decal.h @@ -74,7 +74,7 @@ struct DecalMaterialSortData_t struct DecalMaterialBucket_t { - int m_iHead; + intp m_iHead; int m_nCheckCount; }; @@ -82,16 +82,16 @@ inline bool DecalSortTreeSortLessFunc( const DecalMaterialSortData_t &decal1, co { if ( ( decal1.m_iLightmapPage == -1 ) || ( decal2.m_iLightmapPage == -1 ) ) { - return ( ( int )decal1.m_pMaterial < ( int )decal2.m_pMaterial ); + return ( ( intp )decal1.m_pMaterial < ( intp )decal2.m_pMaterial ); } - if ( ( int )decal1.m_pMaterial == ( int )decal2.m_pMaterial ) + if ( ( intp )decal1.m_pMaterial == ( intp )decal2.m_pMaterial ) { return ( decal1.m_iLightmapPage < decal2.m_iLightmapPage ); } else { - return ( ( int )decal1.m_pMaterial < ( int )decal2.m_pMaterial ); + return ( ( intp )decal1.m_pMaterial < ( intp )decal2.m_pMaterial ); } } diff --git a/engine/saverestore_filesystem.cpp b/engine/saverestore_filesystem.cpp index f0d40ec2..0fde4082 100644 --- a/engine/saverestore_filesystem.cpp +++ b/engine/saverestore_filesystem.cpp @@ -154,7 +154,7 @@ private: CSaveDirectory *m_pSaveDirectory; CUtlMap &GetDirectory( void ) { return m_pSaveDirectory->m_Files; } SaveFile_t &GetFile( const int idx ) { return m_pSaveDirectory->m_Files[idx]; } - SaveFile_t &GetFile( const FileHandle_t hFile ) { return GetFile( (unsigned int)hFile ); } + SaveFile_t &GetFile( const FileHandle_t hFile ) { return GetFile( (uintp)hFile ); } FileHandle_t GetFileHandle( const char *pFileName ); int GetFileIndex( const char *pFileName ); @@ -331,7 +331,7 @@ bool CSaveRestoreFileSystem::FileExists( const char *pFileName, const char *pPat //----------------------------------------------------------------------------- bool CSaveRestoreFileSystem::HandleIsValid( FileHandle_t hFile ) { - return hFile && GetDirectory().IsValidIndex( (unsigned int)hFile ); + return hFile && GetDirectory().IsValidIndex( (uintp)hFile ); } //----------------------------------------------------------------------------- @@ -588,7 +588,7 @@ FSAsyncStatus_t CSaveRestoreFileSystem::AsyncWrite( const char *pFileName, const FileHandle_t hFile = Open( pFileName, "wb" ); if ( hFile ) { - SaveFile_t &file = GetFile( (unsigned int)hFile ); + SaveFile_t &file = GetFile( (uintp)hFile ); if( file.eType == WRITE_ONLY ) { diff --git a/engine/shadowmgr.cpp b/engine/shadowmgr.cpp index 49abd6e8..7ed88684 100644 --- a/engine/shadowmgr.cpp +++ b/engine/shadowmgr.cpp @@ -166,7 +166,7 @@ public: virtual unsigned short InvalidShadowIndex( ); // Methods of ISpatialLeafEnumerator - virtual bool EnumerateLeaf( int leaf, int context ); + virtual bool EnumerateLeaf( int leaf, intp context ); // Sets the texture coordinate range for a shadow... virtual void SetShadowTexCoord( ShadowHandle_t handle, float x, float y, float w, float h ); @@ -605,7 +605,7 @@ void CShadowMgr::SetMaterial( Shadow_t& shadow, IMaterial* pMaterial, IMaterial* } // Search the sort order handles for an enumeration id match - int materialEnum = (int)pMaterial; + int materialEnum = (intp)pMaterial; for (unsigned short i = m_SortOrderIds.Head(); i != m_SortOrderIds.InvalidIndex(); i = m_SortOrderIds.Next(i) ) { @@ -1536,7 +1536,7 @@ void CShadowMgr::ProjectShadow( ShadowHandle_t handle, const Vector &origin, for ( int i = 0; i < nLeafCount; ++i ) { // NOTE: Scope specifier eliminates virtual function call - CShadowMgr::EnumerateLeaf( pLeafList[i], (int)&build ); + CShadowMgr::EnumerateLeaf( pLeafList[i], (intp)&build ); } } @@ -1650,7 +1650,7 @@ void CShadowMgr::ProjectFlashlight( ShadowHandle_t handle, const VMatrix& worldT for ( int i = 0; i < nLeafCount; ++i ) { // NOTE: Scope specifier eliminates virtual function call - CShadowMgr::EnumerateLeaf( pLeafList[i], (int)&build ); + CShadowMgr::EnumerateLeaf( pLeafList[i], (intp)&build ); } } @@ -1809,7 +1809,7 @@ void CShadowMgr::ApplyShadowToLeaf( const Shadow_t &shadow, mleaf_t* RESTRICT pL //----------------------------------------------------------------------------- // Applies a projected texture to all surfaces in the leaf //----------------------------------------------------------------------------- -bool CShadowMgr::EnumerateLeaf( int leaf, int context ) +bool CShadowMgr::EnumerateLeaf( int leaf, intp context ) { VPROF( "CShadowMgr::EnumerateLeaf" ); ShadowBuildInfo_t* pBuild = (ShadowBuildInfo_t*)context; diff --git a/engine/snd_io.cpp b/engine/snd_io.cpp index 594e7c4d..6d986647 100644 --- a/engine/snd_io.cpp +++ b/engine/snd_io.cpp @@ -20,17 +20,17 @@ class COM_IOReadBinary : public IFileReadBinary { public: - int open( const char *pFileName ); - int read( void *pOutput, int size, int file ); - void seek( int file, int pos ); - unsigned int tell( int file ); - unsigned int size( int file ); - void close( int file ); + intp open( const char *pFileName ); + int read( void *pOutput, int size, intp file ); + void seek( intp file, int pos ); + unsigned int tell( intp file ); + unsigned int size( intp file ); + void close( intp file ); }; // prepend sound/ to the filename -- all sounds are loaded from the sound/ directory -int COM_IOReadBinary::open( const char *pFileName ) +intp COM_IOReadBinary::open( const char *pFileName ) { char namebuffer[512]; FileHandle_t hFile; @@ -46,10 +46,10 @@ int COM_IOReadBinary::open( const char *pFileName ) hFile = g_pFileSystem->Open( namebuffer, "rb", "GAME" ); - return (int)hFile; + return (intp)hFile; } -int COM_IOReadBinary::read( void *pOutput, int size, int file ) +int COM_IOReadBinary::read( void *pOutput, int size, intp file ) { if ( !file ) return 0; @@ -57,7 +57,7 @@ int COM_IOReadBinary::read( void *pOutput, int size, int file ) return g_pFileSystem->Read( pOutput, size, (FileHandle_t)file ); } -void COM_IOReadBinary::seek( int file, int pos ) +void COM_IOReadBinary::seek( intp file, int pos ) { if ( !file ) return; @@ -65,7 +65,7 @@ void COM_IOReadBinary::seek( int file, int pos ) g_pFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); } -unsigned int COM_IOReadBinary::tell( int file ) +unsigned int COM_IOReadBinary::tell( intp file ) { if ( !file ) return 0; @@ -73,7 +73,7 @@ unsigned int COM_IOReadBinary::tell( int file ) return g_pFileSystem->Tell( (FileHandle_t)file ); } -unsigned int COM_IOReadBinary::size( int file ) +unsigned int COM_IOReadBinary::size( intp file ) { if (!file) return 0; @@ -81,7 +81,7 @@ unsigned int COM_IOReadBinary::size( int file ) return g_pFileSystem->Size( (FileHandle_t)file ); } -void COM_IOReadBinary::close( int file ) +void COM_IOReadBinary::close( intp file ) { if (!file) return; diff --git a/engine/sv_uploadgamestats.cpp b/engine/sv_uploadgamestats.cpp index 8665b061..f4836600 100644 --- a/engine/sv_uploadgamestats.cpp +++ b/engine/sv_uploadgamestats.cpp @@ -1099,7 +1099,7 @@ protected: }; public: - static unsigned CallbackThreadProc( void *pvParam ) { ((CAsyncUploaderThread*) pvParam)->ThreadProc(); return 0; } + static uintp CallbackThreadProc( void *pvParam ) { ((CAsyncUploaderThread*) pvParam)->ThreadProc(); return 0; } void QueueData( char const *szMapName, uint uiBlobVersion, uint uiBlobSize, const void *pvBlob ); void TerminateAndSelfDelete(); }; diff --git a/engine/sys_dll2.cpp b/engine/sys_dll2.cpp index e6742211..59b66b8c 100644 --- a/engine/sys_dll2.cpp +++ b/engine/sys_dll2.cpp @@ -2260,7 +2260,7 @@ bool EnableLongTickWatcher() #ifdef POSIX (void*) #endif - LongTickWatcherThread, NULL, 0, (unsigned long int *)&nThreadID ); + LongTickWatcherThread, NULL, 0, (uintp *)&nThreadID ); bRet = true; } diff --git a/engine/tmessage.cpp b/engine/tmessage.cpp index a31ce050..3188f166 100644 --- a/engine/tmessage.cpp +++ b/engine/tmessage.cpp @@ -192,7 +192,7 @@ int ParseString( char const *pText, char *buf, size_t bufsize ) char const *pStart = pTemp; pTemp = SkipText( pTemp ); - int len = min( pTemp - pStart + 1, (int)bufsize - 1 ); + intp len = min( pTemp - pStart + 1, (ptrdiff_t)bufsize - 1 ); Q_strncpy( buf, pStart, len ); buf[ len ] = 0; return 1; diff --git a/engine/view.cpp b/engine/view.cpp index 7e7cf61b..04772894 100644 --- a/engine/view.cpp +++ b/engine/view.cpp @@ -523,7 +523,7 @@ public: int m_nLeafWaterDataID; }; - bool EnumerateLeaf( int leaf, int context ) + bool EnumerateLeaf( int leaf, intp context ) { BoxIntersectWaterContext_t *pSearchContext = ( BoxIntersectWaterContext_t * )context; mleaf_t *pLeaf = &host_state.worldmodel->brush.pShared->leafs[leaf]; @@ -541,7 +541,7 @@ public: BoxIntersectWaterContext_t context; context.m_bFoundWaterLeaf = false; context.m_nLeafWaterDataID = leafWaterDataID; - g_pToolBSPTree->EnumerateLeavesInBox( mins, maxs, this, ( int )&context ); + g_pToolBSPTree->EnumerateLeavesInBox( mins, maxs, this, ( intp )&context ); return context.m_bFoundWaterLeaf; } diff --git a/filesystem/QueuedLoader.cpp b/filesystem/QueuedLoader.cpp index 15ab20f1..0fe235a6 100644 --- a/filesystem/QueuedLoader.cpp +++ b/filesystem/QueuedLoader.cpp @@ -643,7 +643,7 @@ FileNameHandle_t CQueuedLoader::FindFilename( const char *pFilename ) //----------------------------------------------------------------------------- bool CQueuedLoader::CResourceNameLessFunc::Less( const FileNameHandle_t &hFilenameLHS, const FileNameHandle_t &hFilenameRHS, void *pCtx ) { - switch ( (int)pCtx ) + switch ( (intp)pCtx ) { case RESOURCEPRELOAD_MATERIAL: { diff --git a/filesystem/filesystem_async.cpp b/filesystem/filesystem_async.cpp index ad9bb7dd..e8ad047e 100644 --- a/filesystem/filesystem_async.cpp +++ b/filesystem/filesystem_async.cpp @@ -122,7 +122,7 @@ public: Q_strncpy( szFixedName, pszFilename, sizeof( szFixedName ) ); Q_FixSlashes( szFixedName ); - Assert( (int)FS_INVALID_ASYNC_FILE == m_map.InvalidIndex() ); + Assert( (intp)FS_INVALID_ASYNC_FILE == m_map.InvalidIndex() ); AUTO_LOCK( m_mutex ); @@ -164,7 +164,7 @@ public: AUTO_LOCK( m_mutex ); - int iEntry = (CUtlMap::IndexType_t)(int)item; + int iEntry = (CUtlMap::IndexType_t)(intp)item; Assert( m_map.IsValidIndex( iEntry ) ); m_map[iEntry]->AddRef(); return m_map[iEntry]; @@ -179,7 +179,7 @@ public: AUTO_LOCK( m_mutex ); - int iEntry = (CUtlMap::IndexType_t)(int)item; + int iEntry = (CUtlMap::IndexType_t)(intp)item; Assert( m_map.IsValidIndex( iEntry ) ); m_map[iEntry]->AddRef(); } @@ -193,7 +193,7 @@ public: AUTO_LOCK( m_mutex ); - int iEntry = (CUtlMap::IndexType_t)(int)item; + int iEntry = (CUtlMap::IndexType_t)(intp)item; Assert( m_map.IsValidIndex( iEntry ) ); if ( m_map[iEntry]->Release() == 0 ) { diff --git a/filesystem/filetracker.cpp b/filesystem/filetracker.cpp index 056af151..2956d4c6 100644 --- a/filesystem/filetracker.cpp +++ b/filesystem/filetracker.cpp @@ -14,7 +14,7 @@ #ifdef SUPPORT_PACKED_STORE -unsigned ThreadStubProcessMD5Requests( void *pParam ) +uintp ThreadStubProcessMD5Requests( void *pParam ) { return ((CFileTracker2 *)pParam)->ThreadedProcessMD5Requests(); } diff --git a/game/client/c_pixel_visibility.cpp b/game/client/c_pixel_visibility.cpp index 8ff507b1..d95bb540 100644 --- a/game/client/c_pixel_visibility.cpp +++ b/game/client/c_pixel_visibility.cpp @@ -345,7 +345,7 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) if ( r_pixelvisibility_spew.GetBool() && CurrentViewID() == 0 ) { - DevMsg( 1, "Pixels visible: %d (qh:%d) Pixels possible: %d (qh:%d) (frame:%d)\n", pixels, (int)m_queryHandle, pixelsPossible, (int)m_queryHandleCount, gpGlobals->framecount ); + DevMsg( 1, "Pixels visible: %d (qh:%d) Pixels possible: %d (qh:%d) (frame:%d)\n", pixels, (int)(intp)m_queryHandle, pixelsPossible, (int)(intp)m_queryHandleCount, gpGlobals->framecount ); } if ( pixels < 0 || pixelsPossible < 0 ) @@ -376,7 +376,7 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) if ( r_pixelvisibility_spew.GetBool() && CurrentViewID() == 0 ) { - DevMsg( 1, "Pixels visible: %d (qh:%d) (frame:%d)\n", pixels, (int)m_queryHandle, gpGlobals->framecount ); + DevMsg( 1, "Pixels visible: %d (qh:%d) (frame:%d)\n", pixels, (int)(intp)m_queryHandle, gpGlobals->framecount ); } if ( pixels < 0 ) @@ -415,7 +415,7 @@ void CPixelVisibilityQuery::IssueQuery( IMatRenderContext *pRenderContext, float if ( r_pixelvisibility_spew.GetBool() && CurrentViewID() == 0 ) { - DevMsg( 1, "Draw Proxy: qh:%d org:<%d,%d,%d> (frame:%d)\n", (int)m_queryHandle, (int)m_origin[0], (int)m_origin[1], (int)m_origin[2], gpGlobals->framecount ); + DevMsg( 1, "Draw Proxy: qh:%d org:<%d,%d,%d> (frame:%d)\n", (int)(intp)m_queryHandle, (int)m_origin[0], (int)m_origin[1], (int)m_origin[2], gpGlobals->framecount ); } m_clipFraction = PixelVisibility_DrawProxy( pRenderContext, m_queryHandle, m_origin, proxySize, proxyAspect, pMaterial, sizeIsScreenSpace ); diff --git a/game/client/c_rope.cpp b/game/client/c_rope.cpp index 605f4750..9b6e0880 100644 --- a/game/client/c_rope.cpp +++ b/game/client/c_rope.cpp @@ -1691,7 +1691,7 @@ void C_RopeKeyframe::BuildRope( RopeSegData_t *pSegmentData, const Vector &vCurr if ( !bQueued && RopeManager()->IsHolidayLightMode() && r_rope_holiday_light_scale.GetFloat() > 0.0f ) { - data.m_nMaterial = reinterpret_cast< int >( this ); + data.m_nMaterial = (intp)this; data.m_nHitBox = ( iNode << 8 ); data.m_flScale = r_rope_holiday_light_scale.GetFloat(); data.m_vOrigin = pSegmentData->m_Segments[nSegmentCount].m_vPos; diff --git a/game/client/c_te_effect_dispatch.cpp b/game/client/c_te_effect_dispatch.cpp index 160e11b7..b586df97 100644 --- a/game/client/c_te_effect_dispatch.cpp +++ b/game/client/c_te_effect_dispatch.cpp @@ -213,7 +213,7 @@ void TE_DispatchEffect( IRecipientFilter& filter, float delay, KeyValues *pKeyVa // NOTE: Ptrs are our way of indicating it's an entindex ClientEntityHandle_t hWorld = ClientEntityList().EntIndexToHandle( 0 ); - data.m_hEntity = (int)pKeyValues->GetPtr( "entindex", (void*)hWorld.ToInt() ); + data.m_hEntity = (intp)pKeyValues->GetPtr( "entindex", (void*)hWorld.ToInt() ); const char *pEffectName = pKeyValues->GetString( "effectname" ); diff --git a/game/client/clientleafsystem.cpp b/game/client/clientleafsystem.cpp index 0a4018f1..f8e46d88 100644 --- a/game/client/clientleafsystem.cpp +++ b/game/client/clientleafsystem.cpp @@ -132,7 +132,7 @@ public: // methods of ISpatialLeafEnumerator public: - bool EnumerateLeaf( int leaf, int context ); + bool EnumerateLeaf( int leaf, intp context ); // Adds a shadow to a leaf void AddShadowToLeaf( int leaf, ClientLeafShadowHandle_t handle ); @@ -1132,7 +1132,7 @@ void CClientLeafSystem::AddRenderableToLeaves( ClientRenderHandle_t handle, int //----------------------------------------------------------------------------- // Inserts an element into the tree //----------------------------------------------------------------------------- -bool CClientLeafSystem::EnumerateLeaf( int leaf, int context ) +bool CClientLeafSystem::EnumerateLeaf( int leaf, intp context ) { EnumResultList_t *pList = (EnumResultList_t *)context; if ( ThreadInMainThread() ) @@ -1168,7 +1168,7 @@ void CClientLeafSystem::InsertIntoTree( ClientRenderHandle_t &handle ) Assert( absMins.IsValid() && absMaxs.IsValid() ); ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); - pQuery->EnumerateLeavesInBox( absMins, absMaxs, this, (int)&list ); + pQuery->EnumerateLeavesInBox( absMins, absMaxs, this, (intp)&list ); if ( list.pHead ) { diff --git a/game/client/clientshadowmgr.cpp b/game/client/clientshadowmgr.cpp index c37e7650..5b4dc6c8 100644 --- a/game/client/clientshadowmgr.cpp +++ b/game/client/clientshadowmgr.cpp @@ -2244,7 +2244,7 @@ inline ShadowType_t CClientShadowMgr::GetActualShadowCastType( IClientRenderable class CShadowLeafEnum : public ISpatialLeafEnumerator { public: - bool EnumerateLeaf( int leaf, int context ) + bool EnumerateLeaf( int leaf, intp context ) { m_LeafList.AddToTail( leaf ); return true; @@ -4217,7 +4217,7 @@ bool CShadowProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) void CShadowProxy::OnBind( void *pProxyData ) { - unsigned short clientShadowHandle = ( unsigned short )(int)pProxyData&0xffff; + unsigned short clientShadowHandle = ( unsigned short )(intp)pProxyData&0xffff; ITexture* pTex = s_ClientShadowMgr.GetShadowTexture( clientShadowHandle ); m_BaseTextureVar->SetTextureValue( pTex ); if ( ToolsEnabled() ) @@ -4301,7 +4301,7 @@ bool CShadowModelProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) void CShadowModelProxy::OnBind( void *pProxyData ) { - unsigned short clientShadowHandle = ( unsigned short )((int)pProxyData&0xffff); + unsigned short clientShadowHandle = ( unsigned short )((intp)pProxyData&0xffff); ITexture* pTex = s_ClientShadowMgr.GetShadowTexture( clientShadowHandle ); m_BaseTextureVar->SetTextureValue( pTex ); diff --git a/game/client/detailobjectsystem.cpp b/game/client/detailobjectsystem.cpp index 8acac352..3c033714 100644 --- a/game/client/detailobjectsystem.cpp +++ b/game/client/detailobjectsystem.cpp @@ -405,7 +405,7 @@ public: void BeginTranslucentDetailRendering( ); // Method of ISpatialLeafEnumerator - bool EnumerateLeaf( int leaf, int context ); + bool EnumerateLeaf( int leaf, intp context ); DetailPropLightstylesLump_t& DetailLighting( int i ) { return m_DetailLighting[i]; } DetailPropSpriteDict_t& DetailSpriteDict( int i ) { return m_DetailSpriteDict[i]; } @@ -464,7 +464,7 @@ private: int SortSpritesBackToFront( int nLeaf, const Vector &viewOrigin, const Vector &viewForward, SortInfo_t *pSortInfo ); // For fast detail object insertion - IterationRetval_t EnumElement( int userId, int context ); + IterationRetval_t EnumElement( int userId, intp context ); CUtlVector m_DetailObjectDict; CUtlVector m_DetailObjects; @@ -2322,7 +2322,7 @@ void CDetailObjectSystem::RenderFastSprites( const Vector &viewOrigin, const Vec FastSpriteQuadBuildoutBufferNonSIMDView_t const *pquad = pQuadBuffer+nSIMDIdx; // voodoo - since everything is in 4s, offset structure pointer by a couple of floats to handle sub-index - pquad = (FastSpriteQuadBuildoutBufferNonSIMDView_t const *) ( ( (int) ( pquad ) )+ ( nSubIdx << 2 ) ); + pquad = (FastSpriteQuadBuildoutBufferNonSIMDView_t const *) ( ( (intp) ( pquad ) )+ ( nSubIdx << 2 ) ); uint8 const *pColorsCasted = reinterpret_cast ( pquad->m_Alpha ); uint8 color[4]; @@ -2554,7 +2554,7 @@ void CDetailObjectSystem::RenderFastTranslucentDetailObjectsInLeaf( const Vector FastSpriteQuadBuildoutBufferNonSIMDView_t const *pquad = pQuadBuffer+nSIMDIdx; // voodoo - since everything is in 4s, offset structure pointer by a couple of floats to handle sub-index - pquad = (FastSpriteQuadBuildoutBufferNonSIMDView_t const *) ( ( (int) ( pquad ) )+ ( nSubIdx << 2 ) ); + pquad = (FastSpriteQuadBuildoutBufferNonSIMDView_t const *) ( ( (intp) ( pquad ) )+ ( nSubIdx << 2 ) ); uint8 const *pColorsCasted = reinterpret_cast ( pquad->m_Alpha ); uint8 color[4]; @@ -2707,7 +2707,7 @@ void CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf( const Vector &vi //----------------------------------------------------------------------------- // Gets called each view //----------------------------------------------------------------------------- -bool CDetailObjectSystem::EnumerateLeaf( int leaf, int context ) +bool CDetailObjectSystem::EnumerateLeaf( int leaf, intp context ) { VPROF_BUDGET( "CDetailObjectSystem::EnumerateLeaf", VPROF_BUDGETGROUP_DETAILPROP_RENDERING ); Vector v; @@ -2806,6 +2806,6 @@ void CDetailObjectSystem::BuildDetailObjectRenderLists( const Vector &vViewOrigi ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); pQuery->EnumerateLeavesInSphere( CurrentViewOrigin(), - cl_detaildist.GetFloat(), this, (int)&ctx ); + cl_detaildist.GetFloat(), this, (intp)&ctx ); } diff --git a/game/client/proxyplayer.cpp b/game/client/proxyplayer.cpp index d6521cc9..09dbf2e8 100644 --- a/game/client/proxyplayer.cpp +++ b/game/client/proxyplayer.cpp @@ -410,7 +410,7 @@ bool CPlayerLogoProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) void CPlayerLogoProxy::OnBind( void *pC_BaseEntity ) { // Decal's are bound with the player index as the passed in paramter - int playerindex = (int)pC_BaseEntity; + int playerindex = (intp)pC_BaseEntity; if ( playerindex <= 0 ) return; diff --git a/game/server/ai_component.h b/game/server/ai_component.h index 7722f66a..62a7ab09 100644 --- a/game/server/ai_component.h +++ b/game/server/ai_component.h @@ -14,7 +14,7 @@ class CAI_BaseNPC; class CAI_Enemies; -typedef int AI_TaskFailureCode_t; +typedef intp AI_TaskFailureCode_t; struct Task_t; //----------------------------------------------------------------------------- diff --git a/game/server/ai_hint.cpp b/game/server/ai_hint.cpp index c0014220..5d541887 100644 --- a/game/server/ai_hint.cpp +++ b/game/server/ai_hint.cpp @@ -741,9 +741,9 @@ CAI_Hint *CAI_HintManager::GetFirstHint( AIHintIter_t *pIter ) //----------------------------------------------------------------------------- CAI_Hint *CAI_HintManager::GetNextHint( AIHintIter_t *pIter ) { - if ( (int)*pIter != gm_AllHints.InvalidIndex() ) + if ( (intp)*pIter != gm_AllHints.InvalidIndex() ) { - int i = ( (int)*pIter ) + 1; + int i = ( (intp)*pIter ) + 1; if ( gm_AllHints.Count() <= i ) { *pIter = (AIHintIter_t)gm_AllHints.InvalidIndex(); diff --git a/game/server/ai_memory.cpp b/game/server/ai_memory.cpp index 7ac69311..ca4fe573 100644 --- a/game/server/ai_memory.cpp +++ b/game/server/ai_memory.cpp @@ -191,7 +191,7 @@ AI_EnemyInfo_t *CAI_Enemies::GetFirst( AIEnemiesIter_t *pIter ) AI_EnemyInfo_t *CAI_Enemies::GetNext( AIEnemiesIter_t *pIter ) { - CMemMap::IndexType_t i = (CMemMap::IndexType_t)((unsigned)(*pIter)); + CMemMap::IndexType_t i = (CMemMap::IndexType_t)((uintp)(*pIter)); if ( i == m_Map.InvalidIndex() ) return NULL; diff --git a/game/server/ai_navigator.cpp b/game/server/ai_navigator.cpp index d136c923..005ecec7 100644 --- a/game/server/ai_navigator.cpp +++ b/game/server/ai_navigator.cpp @@ -1231,7 +1231,7 @@ AI_PathNode_t CAI_Navigator::GetNearestNode() Vector CAI_Navigator::GetNodePos( AI_PathNode_t node ) { - return GetNetwork()->GetNode((int)node)->GetPosition(GetHullType()); + return GetNetwork()->GetNode((intp)node)->GetPosition(GetHullType()); } //----------------------------------------------------------------------------- diff --git a/game/server/ai_navigator.h b/game/server/ai_navigator.h index a2100943..67b0a83d 100644 --- a/game/server/ai_navigator.h +++ b/game/server/ai_navigator.h @@ -29,7 +29,7 @@ class CAI_WaypointList; class CAI_Network; struct AIMoveTrace_t; struct AILocalMoveGoal_t; -typedef int AI_TaskFailureCode_t; +typedef intp AI_TaskFailureCode_t; //----------------------------------------------------------------------------- // Debugging tools diff --git a/game/server/ai_senses.cpp b/game/server/ai_senses.cpp index 45e23e09..3c056f0e 100644 --- a/game/server/ai_senses.cpp +++ b/game/server/ai_senses.cpp @@ -49,6 +49,9 @@ struct AISightIterVal_t char array; short iNext; char SeenArray; +#ifdef PLATFORM_64BITS + uint32 unused; +#endif }; #pragma pack(pop) @@ -272,7 +275,7 @@ CBaseEntity *CAI_Senses::GetFirstSeenEntity( AISightIter_t *pIter, seentype_t iS CBaseEntity *CAI_Senses::GetNextSeenEntity( AISightIter_t *pIter ) const { - if ( ((int)*pIter) != -1 ) + if ( ((intp)*pIter) != -1 ) { AISightIterVal_t *pIterVal = (AISightIterVal_t *)pIter; @@ -581,7 +584,7 @@ CSound* CAI_Senses::GetNextHeardSound( AISoundIter_t *pIter ) if ( !*pIter ) return NULL; - int iCurrent = (int)*pIter; + int iCurrent = (intp)*pIter; Assert( iCurrent != SOUNDLIST_EMPTY ); if ( iCurrent == SOUNDLIST_EMPTY ) diff --git a/game/server/ai_task.h b/game/server/ai_task.h index 43170a39..a49c9797 100644 --- a/game/server/ai_task.h +++ b/game/server/ai_task.h @@ -21,9 +21,9 @@ class CStringRegistry; // ---------------------------------------------------------------------- // Codes are either one of the enumerated types below, or a string (similar to Windows resource IDs) -typedef int AI_TaskFailureCode_t; +typedef intp AI_TaskFailureCode_t; -enum AI_BaseTaskFailureCodes_t +enum AI_BaseTaskFailureCodes_t : AI_TaskFailureCode_t { NO_TASK_FAILURE, FAIL_NO_TARGET, @@ -63,7 +63,7 @@ inline bool IsPathTaskFailure( AI_TaskFailureCode_t code ) } const char *TaskFailureToString( AI_TaskFailureCode_t code ); -inline int MakeFailCode( const char *pszGeneralError ) { return (int)pszGeneralError; } +inline intp MakeFailCode( const char *pszGeneralError ) { return (intp)pszGeneralError; } enum TaskStatus_e diff --git a/game/server/baseanimating.cpp b/game/server/baseanimating.cpp index 34bf6378..58fd656d 100644 --- a/game/server/baseanimating.cpp +++ b/game/server/baseanimating.cpp @@ -2553,7 +2553,7 @@ void CBaseAnimating::LockStudioHdr() if ( pStudioHdrContainer && pStudioHdrContainer->GetVirtualModel() ) { - MDLHandle_t hVirtualModel = (MDLHandle_t)(int)(pStudioHdrContainer->GetRenderHdr()->virtualModel)&0xffff; + MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( pStudioHdrContainer->GetRenderHdr()->VirtualModel() ); mdlcache->LockStudioHdr( hVirtualModel ); } m_pStudioHdr = pStudioHdrContainer; // must be last to ensure virtual model correctly set up @@ -2571,7 +2571,7 @@ void CBaseAnimating::UnlockStudioHdr() mdlcache->UnlockStudioHdr( modelinfo->GetCacheHandle( mdl ) ); if ( m_pStudioHdr->GetVirtualModel() ) { - MDLHandle_t hVirtualModel = (MDLHandle_t)(int)(m_pStudioHdr->GetRenderHdr()->virtualModel)&0xffff; + MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( m_pStudioHdr->GetRenderHdr()->VirtualModel() ); mdlcache->UnlockStudioHdr( hVirtualModel ); } } diff --git a/game/server/baseentity.cpp b/game/server/baseentity.cpp index 3ba3e2ef..f187479c 100644 --- a/game/server/baseentity.cpp +++ b/game/server/baseentity.cpp @@ -1259,7 +1259,7 @@ void CBaseEntity::ValidateEntityConnections() typedescription_t *dataDesc = &dmap->dataDesc[i]; if ( ( dataDesc->fieldType == FIELD_CUSTOM ) && ( dataDesc->flags & FTYPEDESC_OUTPUT ) ) { - CBaseEntityOutput *pOutput = (CBaseEntityOutput *)((int)this + (int)dataDesc->fieldOffset[0]); + CBaseEntityOutput *pOutput = (CBaseEntityOutput *)((intp)this + (intp)dataDesc->fieldOffset[0]); if ( pOutput->NumberOfElements() ) return; } @@ -1292,7 +1292,7 @@ void CBaseEntity::FireNamedOutput( const char *pszOutput, variant_t variant, CBa typedescription_t *dataDesc = &dmap->dataDesc[i]; if ( ( dataDesc->fieldType == FIELD_CUSTOM ) && ( dataDesc->flags & FTYPEDESC_OUTPUT ) ) { - CBaseEntityOutput *pOutput = ( CBaseEntityOutput * )( ( int )this + ( int )dataDesc->fieldOffset[0] ); + CBaseEntityOutput *pOutput = ( CBaseEntityOutput * )( ( intp )this + ( intp )dataDesc->fieldOffset[0] ); if ( !Q_stricmp( dataDesc->externalName, pszOutput ) ) { pOutput->FireOutput( variant, pActivator, pCaller, flDelay ); @@ -3799,7 +3799,7 @@ void CBaseEntity::OnEntityEvent( EntityEvent_t event, void *pEventData ) { case ENTITY_EVENT_WATER_TOUCH: { - int nContents = (int)pEventData; + intp nContents = (intp)pEventData; if ( !nContents || (nContents & CONTENTS_WATER) ) { ++m_nWaterTouch; @@ -3813,7 +3813,7 @@ void CBaseEntity::OnEntityEvent( EntityEvent_t event, void *pEventData ) case ENTITY_EVENT_WATER_UNTOUCH: { - int nContents = (int)pEventData; + intp nContents = (intp)pEventData; if ( !nContents || (nContents & CONTENTS_WATER) ) { --m_nWaterTouch; diff --git a/game/server/baseentity.h b/game/server/baseentity.h index c5843015..3b70c7e6 100644 --- a/game/server/baseentity.h +++ b/game/server/baseentity.h @@ -1089,6 +1089,21 @@ public: // Ugly code to lookup all functions to make sure they are in the table when set. #ifdef _DEBUG + +#ifdef PLATFORM_64BITS +#ifdef GNUC +#define ENTITYFUNCPTR_SIZE 16 +#else +#define ENTITYFUNCPTR_SIZE 8 +#endif +#else +#ifdef GNUC +#define ENTITYFUNCPTR_SIZE 8 +#else +#define ENTITYFUNCPTR_SIZE 4 +#endif +#endif + void FunctionCheck( void *pFunction, const char *name ); ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) diff --git a/game/server/cbase.cpp b/game/server/cbase.cpp index 19dd3ac2..55d59076 100644 --- a/game/server/cbase.cpp +++ b/game/server/cbase.cpp @@ -1486,7 +1486,7 @@ bool variant_t::Convert( fieldtype_t newType ) //----------------------------------------------------------------------------- const char *variant_t::ToString( void ) const { - COMPILE_TIME_ASSERT( sizeof(string_t) == sizeof(int) ); + COMPILE_TIME_ASSERT( sizeof(string_t) == sizeof(intp) ); static char szBuf[512]; diff --git a/game/server/nav_mesh.h b/game/server/nav_mesh.h index fe5c98d9..cb757709 100644 --- a/game/server/nav_mesh.h +++ b/game/server/nav_mesh.h @@ -198,9 +198,15 @@ public: unsigned int operator()( const NavVisPair_t &item ) const { +#if PLATFORM_64BITS + COMPILE_TIME_ASSERT( sizeof(CNavArea *) == 8 ); + int64 key[2] = { (int64)item.pAreas[0] + (int64)item.pAreas[1]->GetID(), (int64)item.pAreas[1] + (int64)item.pAreas[0]->GetID() }; + return Hash16( key ); +#else COMPILE_TIME_ASSERT( sizeof(CNavArea *) == 4 ); int key[2] = { (int)(item.pAreas[0] + item.pAreas[1]->GetID()), (int)(item.pAreas[1] + item.pAreas[0]->GetID()) }; return Hash8( key ); +#endif } }; diff --git a/game/server/player_lagcompensation.cpp b/game/server/player_lagcompensation.cpp index 08503652..1bec034d 100644 --- a/game/server/player_lagcompensation.cpp +++ b/game/server/player_lagcompensation.cpp @@ -260,7 +260,7 @@ void CLagCompensationManager::FrameUpdatePostEntityThink() Assert( track->Count() < 1000 ); // insanity check // remove tail records that are too old - int tailIndex = track->Tail(); + intp tailIndex = track->Tail(); while ( track->IsValidIndex( tailIndex ) ) { LagRecord &tail = track->Element( tailIndex ); @@ -428,7 +428,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar if ( track->Count() <= 0 ) return; - int curr = track->Head(); + intp curr = track->Head(); LagRecord *prevRecord = NULL; LagRecord *record = NULL; diff --git a/game/server/triggers.cpp b/game/server/triggers.cpp index 94b0323a..5bdda3d7 100644 --- a/game/server/triggers.cpp +++ b/game/server/triggers.cpp @@ -3688,7 +3688,7 @@ public: return IMotionEvent::SIM_NOTHING; // Get a cosine modulated noise between 5 and 20 that is object specific - int nNoiseMod = 5+(int)pObject%15; // + int nNoiseMod = 5+(intp)pObject%15; // // Turn wind yaw direction into a vector and add noise QAngle vWindAngle = vec3_angle; diff --git a/game/shared/baseentity_shared.cpp b/game/shared/baseentity_shared.cpp index 43348cb1..a702ba94 100644 --- a/game/shared/baseentity_shared.cpp +++ b/game/shared/baseentity_shared.cpp @@ -754,12 +754,20 @@ BASEPTR CBaseEntity::ThinkSet( BASEPTR func, float thinkTime, const char *szCont { #if !defined( CLIENT_DLL ) #ifdef _DEBUG +#ifdef PLATFORM_64BITS +#ifdef GNUC + COMPILE_TIME_ASSERT( sizeof(func) == 16 ); +#else + COMPILE_TIME_ASSERT( sizeof(func) == 8 ); +#endif +#else #ifdef GNUC COMPILE_TIME_ASSERT( sizeof(func) == 8 ); #else COMPILE_TIME_ASSERT( sizeof(func) == 4 ); #endif #endif +#endif #endif // Old system? diff --git a/game/shared/entitydatainstantiator.h b/game/shared/entitydatainstantiator.h index 2882c585..8c3eaa90 100644 --- a/game/shared/entitydatainstantiator.h +++ b/game/shared/entitydatainstantiator.h @@ -115,7 +115,7 @@ private: static unsigned int KeyFunc( const HashEntry &src ) { // Shift right to get rid of alignment bits and border the struct on a 16 byte boundary - return (unsigned int)src.key; + return (unsigned int)(uintp)src.key; } CUtlHash< HashEntry > m_HashTable; diff --git a/game/shared/querycache.cpp b/game/shared/querycache.cpp index 4450d0e3..a6383c48 100644 --- a/game/shared/querycache.cpp +++ b/game/shared/querycache.cpp @@ -45,7 +45,7 @@ void QueryCacheKey_t::ComputeHashIndex( void ) for( int i = 0 ; i < m_nNumValidPoints; i++ ) { ret += ( unsigned int ) m_pEntities[i].ToInt(); - ret += ( unsigned int ) m_nOffsetMode; + ret += ( uintp ) m_nOffsetMode; } ret += *( ( uint32 *) &m_flMinimumUpdateInterval ); ret += m_nTraceMask; diff --git a/game/shared/saverestore.cpp b/game/shared/saverestore.cpp index 387aefc2..e1eb4f66 100644 --- a/game/shared/saverestore.cpp +++ b/game/shared/saverestore.cpp @@ -91,6 +91,7 @@ static int gSizes[FIELD_TYPECOUNT] = FIELD_SIZE( FIELD_MATERIALINDEX ), FIELD_SIZE( FIELD_VECTOR2D ), + FIELD_SIZE( FIELD_INTEGER64 ), }; diff --git a/gameui/GameConsole.cpp b/gameui/GameConsole.cpp index 8bd55b72..307d091e 100644 --- a/gameui/GameConsole.cpp +++ b/gameui/GameConsole.cpp @@ -141,7 +141,7 @@ void CGameConsole::ActivateDelayed(float time) #endif } -void CGameConsole::SetParent( int parent ) +void CGameConsole::SetParent( intp parent ) { #ifndef _XBOX if (!m_bInitialized) diff --git a/gameui/GameConsole.h b/gameui/GameConsole.h index f3ed1cec..cc61f891 100644 --- a/gameui/GameConsole.h +++ b/gameui/GameConsole.h @@ -40,7 +40,7 @@ public: // activates the console after a delay void ActivateDelayed(float time); - void SetParent( int parent ); + void SetParent( intp parent ); static void OnCmdCondump(); private: diff --git a/hammer/texturesystem.cpp b/hammer/texturesystem.cpp index 4c849e1b..c507b413 100644 --- a/hammer/texturesystem.cpp +++ b/hammer/texturesystem.cpp @@ -64,7 +64,7 @@ CTextureSystem g_Textures; //----------------------------------------------------------------------------- // CMaterialFileChangeWatcher implementation. //----------------------------------------------------------------------------- -void CMaterialFileChangeWatcher::Init( CTextureSystem *pSystem, int context ) +void CMaterialFileChangeWatcher::Init( CTextureSystem *pSystem, intp context ) { m_pTextureSystem = pSystem; m_Context = context; @@ -662,7 +662,7 @@ void CTextureSystem::UpdateFileChangeWatchers() } -void CTextureSystem::OnFileChange( const char *pFilename, int context, CTextureSystem::EFileType eFileType ) +void CTextureSystem::OnFileChange( const char *pFilename, intp context, CTextureSystem::EFileType eFileType ) { // It requires the forward slashes later... char fixedSlashes[MAX_PATH]; diff --git a/hammer/texturesystem.h b/hammer/texturesystem.h index 4baf2f3f..e39dd181 100644 --- a/hammer/texturesystem.h +++ b/hammer/texturesystem.h @@ -106,7 +106,7 @@ struct TextureContext_t class CMaterialFileChangeWatcher : private CFileChangeWatcher::ICallbacks { public: - void Init( CTextureSystem *pSystem, int context ); + void Init( CTextureSystem *pSystem, intp context ); void Update(); // Call this periodically to update. private: @@ -214,7 +214,7 @@ protected: k_eFileTypeVMT, k_eFileTypeVTF }; - void OnFileChange( const char *pFilename, int context, EFileType eFileType ); + void OnFileChange( const char *pFilename, intp context, EFileType eFileType ); void ReloadMaterialsUsingTexture( ITexture *pTestTexture ); static bool GetFileTypeFromFilename( const char *pFilename, CTextureSystem::EFileType *pFileType ); diff --git a/materialsystem/cmatqueuedrendercontext.cpp b/materialsystem/cmatqueuedrendercontext.cpp index 47b10d56..157e34df 100644 --- a/materialsystem/cmatqueuedrendercontext.cpp +++ b/materialsystem/cmatqueuedrendercontext.cpp @@ -338,7 +338,7 @@ public: Assert( m_VertexSize ); Assert( !m_pVertexData ); m_pVertexData = (byte *)m_pOwner->AllocVertices( numVerts, m_VertexSize ); - Assert( (unsigned)m_pVertexData % 16 == 0 ); + Assert( (uintp)m_pVertexData % 16 == 0 ); // Compute the vertex index.. desc.m_nFirstVertex = 0; diff --git a/materialsystem/cmatrendercontext.cpp b/materialsystem/cmatrendercontext.cpp index c8f217f4..9aa65144 100644 --- a/materialsystem/cmatrendercontext.cpp +++ b/materialsystem/cmatrendercontext.cpp @@ -2200,7 +2200,7 @@ int CMatRenderContext::CompareMaterialCombos( IMaterial *pMaterial1, IMaterial * if ( dLightmap ) return dLightmap; - return (int)pMat1 - (int)pMat2; + return (intp)pMat1 - (intp)pMat2; } diff --git a/materialsystem/cmatrendercontext.h b/materialsystem/cmatrendercontext.h index 0f024ebb..74d0c1ad 100644 --- a/materialsystem/cmatrendercontext.h +++ b/materialsystem/cmatrendercontext.h @@ -34,7 +34,7 @@ class ITextureInternal; class CMaterialSystem; class CMatLightmaps; -typedef int ShaderAPITextureHandle_t; +typedef intp ShaderAPITextureHandle_t; class IMorphMgrRenderContext; class CMatCallQueue; diff --git a/materialsystem/ctexture.cpp b/materialsystem/ctexture.cpp index dbfac959..e4353a0b 100644 --- a/materialsystem/ctexture.cpp +++ b/materialsystem/ctexture.cpp @@ -32,7 +32,6 @@ #endif #include "colorspace.h" #include "string.h" -#include #include #include "utlmemory.h" #include "IHardwareConfigInternal.h" @@ -2577,7 +2576,7 @@ bool CTexture::SetRenderTarget( int nRenderTargetID, ITexture *pDepthTexture ) ShaderAPITextureHandle_t textureHandle = m_pTextureHandles[0]; - ShaderAPITextureHandle_t depthTextureHandle = (unsigned int)SHADER_RENDERTARGET_DEPTHBUFFER; + ShaderAPITextureHandle_t depthTextureHandle = (uintp)SHADER_RENDERTARGET_DEPTHBUFFER; if ( m_nFlags & TEXTUREFLAGS_DEPTHRENDERTARGET ) { @@ -2587,7 +2586,7 @@ bool CTexture::SetRenderTarget( int nRenderTargetID, ITexture *pDepthTexture ) else if ( m_nFlags & TEXTUREFLAGS_NODEPTHBUFFER ) { // GR - render target without depth buffer - depthTextureHandle = (unsigned int)SHADER_RENDERTARGET_NONE; + depthTextureHandle = (uintp)SHADER_RENDERTARGET_NONE; } if ( pDepthTexture) @@ -4140,7 +4139,7 @@ bool CTexture::UpdateExcludedState( void ) void CTextureStreamingJob::OnAsyncFindComplete( ITexture* pTex, void* pExtraArgs ) { - const int cArgsAsInt = ( int ) pExtraArgs; + const intp cArgsAsInt = ( intp ) pExtraArgs; Assert( m_pOwner == NULL || m_pOwner == pTex ); if ( m_pOwner ) diff --git a/materialsystem/ctexturecompositor.cpp b/materialsystem/ctexturecompositor.cpp index 88683b18..a8d79eff 100644 --- a/materialsystem/ctexturecompositor.cpp +++ b/materialsystem/ctexturecompositor.cpp @@ -453,7 +453,7 @@ public: virtual void OnAsyncFindComplete( ITexture* pTex, void* pExtraArgs ) { - switch ( ( int ) pExtraArgs ) + switch ( ( intp ) pExtraArgs ) { case Neutral: SafeAssign( &m_pTex, pTex ); @@ -1202,7 +1202,7 @@ protected: virtual void OnAsyncFindComplete( ITexture* pTex, void* pExtraArgs ) { - switch ( ( int ) pExtraArgs ) + switch ( ( intp ) pExtraArgs ) { case Albedo: SafeAssign( &m_pTex, pTex ); diff --git a/materialsystem/occlusionquerymgr.cpp b/materialsystem/occlusionquerymgr.cpp index 5ee497e1..ba027027 100644 --- a/materialsystem/occlusionquerymgr.cpp +++ b/materialsystem/occlusionquerymgr.cpp @@ -38,7 +38,7 @@ COcclusionQueryMgr::COcclusionQueryMgr() OcclusionQueryObjectHandle_t COcclusionQueryMgr::CreateOcclusionQueryObject( ) { m_Mutex.Lock(); - int h = m_OcclusionQueryObjects.AddToTail(); + intp h = m_OcclusionQueryObjects.AddToTail(); m_Mutex.Unlock(); return (OcclusionQueryObjectHandle_t)h; } @@ -47,7 +47,7 @@ void COcclusionQueryMgr::OnCreateOcclusionQueryObject( OcclusionQueryObjectHandl { for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++) { - m_OcclusionQueryObjects[(int)h].m_QueryHandle[i] = g_pShaderAPI->CreateOcclusionQueryObject( ); + m_OcclusionQueryObjects[(intp)h].m_QueryHandle[i] = g_pShaderAPI->CreateOcclusionQueryObject( ); } } @@ -56,7 +56,7 @@ void COcclusionQueryMgr::OnCreateOcclusionQueryObject( OcclusionQueryObjectHandl void COcclusionQueryMgr::FlushQuery( OcclusionQueryObjectHandle_t hOcclusionQuery, int nIndex ) { // Flush out any previous queries - int h = (int)hOcclusionQuery; + intp h = (intp)hOcclusionQuery; if ( m_OcclusionQueryObjects[h].m_bHasBeenIssued[nIndex] ) { ShaderAPIOcclusionQuery_t hQuery = m_OcclusionQueryObjects[h].m_QueryHandle[nIndex]; @@ -68,7 +68,7 @@ void COcclusionQueryMgr::FlushQuery( OcclusionQueryObjectHandle_t hOcclusionQuer void COcclusionQueryMgr::DestroyOcclusionQueryObject( OcclusionQueryObjectHandle_t hOcclusionQuery ) { - int h = (int)hOcclusionQuery; + intp h = (intp)hOcclusionQuery; Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) { @@ -133,7 +133,7 @@ void COcclusionQueryMgr::FreeOcclusionQueryObjects( void ) //----------------------------------------------------------------------------- void COcclusionQueryMgr::ResetOcclusionQueryObject( OcclusionQueryObjectHandle_t hOcclusionQuery ) { - int h = (int)hOcclusionQuery; + intp h = (intp)hOcclusionQuery; Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) { @@ -154,7 +154,7 @@ void COcclusionQueryMgr::ResetOcclusionQueryObject( OcclusionQueryObjectHandle_t //----------------------------------------------------------------------------- void COcclusionQueryMgr::BeginOcclusionQueryDrawing( OcclusionQueryObjectHandle_t hOcclusionQuery ) { - int h = (int)hOcclusionQuery; + intp h = (intp)hOcclusionQuery; Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) { @@ -194,7 +194,7 @@ void COcclusionQueryMgr::BeginOcclusionQueryDrawing( OcclusionQueryObjectHandle_ void COcclusionQueryMgr::EndOcclusionQueryDrawing( OcclusionQueryObjectHandle_t hOcclusionQuery ) { - int h = (int)hOcclusionQuery; + intp h = (intp)hOcclusionQuery; Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) { @@ -220,7 +220,7 @@ void COcclusionQueryMgr::EndOcclusionQueryDrawing( OcclusionQueryObjectHandle_t //----------------------------------------------------------------------------- void COcclusionQueryMgr::OcclusionQuery_IssueNumPixelsRenderedQuery( OcclusionQueryObjectHandle_t hOcclusionQuery ) { - int h = (int)hOcclusionQuery; + intp h = (intp)hOcclusionQuery; Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) { @@ -253,6 +253,6 @@ int COcclusionQueryMgr::OcclusionQuery_GetNumPixelsRendered( OcclusionQueryObjec OcclusionQuery_IssueNumPixelsRenderedQuery( h ); } - int nPixels = m_OcclusionQueryObjects[(int)h].m_LastResult; + int nPixels = m_OcclusionQueryObjects[(intp)h].m_LastResult; return nPixels; } diff --git a/materialsystem/shaderapidx9/cvballoctracker.cpp b/materialsystem/shaderapidx9/cvballoctracker.cpp index 8c3cdd0c..168d9ff8 100644 --- a/materialsystem/shaderapidx9/cvballoctracker.cpp +++ b/materialsystem/shaderapidx9/cvballoctracker.cpp @@ -237,7 +237,7 @@ EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CVBAllocTracker, IVBAllocTracker, UtlHashFixedHandle_t CVBAllocTracker::TrackAlloc( void * buffer, int bufferSize, VertexFormat_t fmt, int numVerts, short allocatorHash ) { AllocData newData( buffer, bufferSize, fmt, numVerts, allocatorHash ); - UtlHashFixedHandle_t handle = m_VBAllocTable.Insert( (int)buffer, newData ); + UtlHashFixedHandle_t handle = m_VBAllocTable.Insert( (intp)buffer, newData ); if ( handle == m_VBAllocTable.InvalidHandle() ) { Warning( "[VBMEM] VBMemAllocTable hash collision (grow table).\n" ); @@ -247,7 +247,7 @@ UtlHashFixedHandle_t CVBAllocTracker::TrackAlloc( void * buffer, int bufferSize, bool CVBAllocTracker::KillAlloc( void * buffer, int & bufferSize, VertexFormat_t & fmt, int & numVerts, short & allocatorHash ) { - UtlHashFixedHandle_t handle = m_VBAllocTable.Find( (int)buffer ); + UtlHashFixedHandle_t handle = m_VBAllocTable.Find( (intp)buffer ); if ( handle != m_VBAllocTable.InvalidHandle() ) { AllocData & data = m_VBAllocTable.Element( handle ); diff --git a/materialsystem/shaderapidx9/locald3dtypes.h b/materialsystem/shaderapidx9/locald3dtypes.h index ad453558..acbb19ff 100644 --- a/materialsystem/shaderapidx9/locald3dtypes.h +++ b/materialsystem/shaderapidx9/locald3dtypes.h @@ -12,6 +12,8 @@ #pragma once #endif +#include "tier0/platform.h" + #if defined( DX10 ) && !defined( DX_TO_GL_ABSTRACTION ) #include @@ -113,13 +115,13 @@ typedef void *HardwareShader_t; //----------------------------------------------------------------------------- // The vertex and pixel shader type //----------------------------------------------------------------------------- -typedef int VertexShader_t; -typedef int PixelShader_t; +typedef intp VertexShader_t; +typedef intp PixelShader_t; //----------------------------------------------------------------------------- // Bitpattern for an invalid shader //----------------------------------------------------------------------------- -#define INVALID_SHADER ( 0xFFFFFFFF ) +#define INVALID_SHADER (-1) // ( 0xFFFFFFFF ) #define INVALID_HARDWARE_SHADER ( NULL ) #define D3DSAMP_NOTSUPPORTED D3DSAMP_FORCE_DWORD diff --git a/materialsystem/shaderapidx9/shaderdevicebase.h b/materialsystem/shaderapidx9/shaderdevicebase.h index 37d7cc02..9852c587 100644 --- a/materialsystem/shaderapidx9/shaderdevicebase.h +++ b/materialsystem/shaderapidx9/shaderdevicebase.h @@ -184,7 +184,7 @@ protected: int m_nWindowWidth; int m_nWindowHeight; - uint32 m_dwThreadId; + uintp m_dwThreadId; }; diff --git a/materialsystem/shaderapidx9/vertexshaderdx8.cpp b/materialsystem/shaderapidx9/vertexshaderdx8.cpp index 614d88f0..7444c8f2 100644 --- a/materialsystem/shaderapidx9/vertexshaderdx8.cpp +++ b/materialsystem/shaderapidx9/vertexshaderdx8.cpp @@ -615,7 +615,7 @@ private: ShaderStaticCombos_t m_ShaderStaticCombos; DWORD m_Flags; int m_nRefCount; - unsigned int m_hShaderFileCache; + uintp m_hShaderFileCache; // for queued loading, bias an aligned optimal buffer forward to correct location int m_nDataOffset; @@ -1017,7 +1017,7 @@ void CShaderManager::DestroyVertexShader( VertexShaderHandle_t hShader ) if ( hShader == VERTEX_SHADER_HANDLE_INVALID ) return; - VertexShaderIndex_t i = (VertexShaderIndex_t)hShader; + VertexShaderIndex_t i = (VertexShaderIndex_t)(uintp)hShader; IDirect3DVertexShader9 *pVertexShader = m_RawVertexShaderDict[ i ]; UnregisterVS( pVertexShader ); @@ -1053,7 +1053,7 @@ void CShaderManager::DestroyPixelShader( PixelShaderHandle_t hShader ) if ( hShader == PIXEL_SHADER_HANDLE_INVALID ) return; - PixelShaderIndex_t i = (PixelShaderIndex_t)hShader; + PixelShaderIndex_t i = (PixelShaderIndex_t)(uintp)hShader; IDirect3DPixelShader9 *pPixelShader = m_RawPixelShaderDict[ i ]; UnregisterPS( pPixelShader ); @@ -2522,7 +2522,7 @@ bool CShaderManager::LoadAndCreateShaders( ShaderLookup_t &lookup, bool bVertexS ShaderFileCache_t fileCacheLookup; fileCacheLookup.m_Name = lookup.m_Name; fileCacheLookup.m_bVertexShader = bVertexShader; - int fileCacheIndex = m_ShaderFileCache.Find( fileCacheLookup ); + intp fileCacheIndex = m_ShaderFileCache.Find( fileCacheLookup ); if ( fileCacheIndex == m_ShaderFileCache.InvalidIndex() ) { // not found, create a new entry @@ -3286,7 +3286,7 @@ void CShaderManager::SetVertexShaderState( HardwareShader_t shader, DataCacheHan void CShaderManager::BindVertexShader( VertexShaderHandle_t hVertexShader ) { - HardwareShader_t hHardwareShader = m_RawVertexShaderDict[ (VertexShaderIndex_t)hVertexShader] ; + HardwareShader_t hHardwareShader = m_RawVertexShaderDict[ (VertexShaderIndex_t)(uintp)hVertexShader] ; SetVertexShaderState( hHardwareShader ); } @@ -3395,7 +3395,7 @@ void CShaderManager::SetPixelShaderState( HardwareShader_t shader, DataCacheHand void CShaderManager::BindPixelShader( PixelShaderHandle_t hPixelShader ) { - HardwareShader_t hHardwareShader = m_RawPixelShaderDict[ (PixelShaderIndex_t)hPixelShader ]; + HardwareShader_t hHardwareShader = m_RawPixelShaderDict[ (PixelShaderIndex_t)(uintp)hPixelShader ]; SetPixelShaderState( hHardwareShader ); } @@ -3594,7 +3594,7 @@ void CShaderManager::SpewVertexAndPixelShaders( void ) { // only spew a populated shader file cache Msg( "\nShader File Cache:\n" ); - for ( int cacheIndex = m_ShaderFileCache.Head(); + for ( intp cacheIndex = m_ShaderFileCache.Head(); cacheIndex != m_ShaderFileCache.InvalidIndex(); cacheIndex = m_ShaderFileCache.Next( cacheIndex ) ) { diff --git a/materialsystem/stdshaders/commandbuilder.h b/materialsystem/stdshaders/commandbuilder.h index 278f2dce..e40ee0a5 100644 --- a/materialsystem/stdshaders/commandbuilder.h +++ b/materialsystem/stdshaders/commandbuilder.h @@ -61,6 +61,11 @@ public: Put( nValue ); } + FORCEINLINE void PutIntPtr( intp nValue ) + { + Put( nValue ); + } + FORCEINLINE void PutFloat( float nValue ) { Put( nValue ); @@ -335,7 +340,7 @@ public: { m_Storage.PutInt( CBCMD_BIND_SHADERAPI_TEXTURE_HANDLE ); m_Storage.PutInt( nSampler ); - m_Storage.PutInt( hTexture ); + m_Storage.PutIntPtr( hTexture ); } } diff --git a/materialsystem/texturemanager.cpp b/materialsystem/texturemanager.cpp index db503695..9719db4f 100644 --- a/materialsystem/texturemanager.cpp +++ b/materialsystem/texturemanager.cpp @@ -5,7 +5,6 @@ //===========================================================================// #include -#include #include "materialsystem_global.h" #include "string.h" #include "shaderapi/ishaderapi.h" @@ -787,8 +786,8 @@ protected: friend class AsyncReader; AsyncReader* m_pAsyncReader; - uint m_nAsyncLoadThread; - uint m_nAsyncReadThread; + ThreadId_t m_nAsyncLoadThread; + ThreadId_t m_nAsyncReadThread; int m_iSuspendTextureStreaming; }; @@ -1131,7 +1130,7 @@ private: m_completedJobs.PushItem( pJob ); } - static unsigned LoaderMain( void* _this ) + static uintp LoaderMain( void* _this ) { ThreadSetDebugName( "Loader" ); @@ -1432,7 +1431,7 @@ private: mip_h = Max( 1, mip_h >> 1 ); } } - static unsigned ReaderMain( void* _this ) + static uintp ReaderMain( void* _this ) { ThreadSetDebugName( "Helper" ); diff --git a/particles/particles.cpp b/particles/particles.cpp index a78417a6..73acbeb0 100644 --- a/particles/particles.cpp +++ b/particles/particles.cpp @@ -1006,7 +1006,7 @@ void CParticleCollection::Init( CParticleSystemDefinition *pDef, float flDelay, } else { - m_nRandomSeed = (int)this; + m_nRandomSeed = (intp)this; #ifndef _DEBUG m_nRandomSeed += Plat_MSTime(); #endif diff --git a/public/XUnzip.cpp b/public/XUnzip.cpp index 85641a29..650a932a 100644 --- a/public/XUnzip.cpp +++ b/public/XUnzip.cpp @@ -119,21 +119,21 @@ #define _T( arg ) arg #endif #define INVALID_HANDLE_VALUE (void*)-1 -#define CloseHandle( arg ) close( (int) arg ) +#define CloseHandle( arg ) close( (intptr_t) arg ) #define ZeroMemory( ptr, size ) memset( ptr, 0, size ) #define FILE_CURRENT SEEK_CUR #define FILE_BEGIN SEEK_SET #define FILE_END SEEK_END #define CreateDirectory( dir, ign ) mkdir( dir, S_IRWXU | S_IRWXG | S_IRWXO ) -#define SetFilePointer( handle, pos, ign, dir ) lseek( (int) handle, pos, dir ) +#define SetFilePointer( handle, pos, ign, dir ) lseek( (intptr_t) handle, pos, dir ) bool ReadFile( void *handle, void *outbuf, unsigned int toread, unsigned int *nread, void *ignored ) { - *nread = read( (int) handle, outbuf, toread ); + *nread = read( (intptr_t) handle, outbuf, toread ); return *nread == toread; } bool WriteFile( void *handle, void *buf, unsigned int towrite, unsigned int *written, void *ignored ) { - *written = write( (int) handle, buf, towrite ); + *written = write( (intptr_t) handle, buf, towrite ); return *written == towrite; } @@ -2778,8 +2778,8 @@ LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err) #ifdef _WIN32 res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&h,0,FALSE,DUPLICATE_SAME_ACCESS) == TRUE; #else - h = (void*) dup( (int)hf ); - res = (int) dup >= 0; + h = (void*) dup( (intptr_t)hf ); + res = (intptr_t) dup >= 0; #endif if (!res) { @@ -2806,7 +2806,7 @@ LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err) canseek = (type==FILE_TYPE_DISK); #else struct stat buf; - fstat( (int)h, &buf ); + fstat( (intptr_t)h, &buf ); canseek = buf.st_mode & S_IFREG; #endif } @@ -4235,7 +4235,7 @@ ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) settime=true; #else struct stat sbuf; - fstat( (int)h, &sbuf ); + fstat( (intptr_t)h, &sbuf ); settime = ( sbuf.st_mode & S_IFREG ); #endif @@ -4256,7 +4256,7 @@ ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) tv[0].tv_usec = 0; tv[1].tv_sec = ze.mtime; tv[1].tv_usec = 0; - futimes( (int)h, tv ); + futimes( (intptr_t)h, tv ); #endif } if (flags!=ZIP_HANDLE) diff --git a/public/bspfile.h b/public/bspfile.h index 680137c3..7d5365da 100644 --- a/public/bspfile.h +++ b/public/bspfile.h @@ -663,7 +663,7 @@ public: CDispCornerNeighbors m_CornerNeighbors[4]; // Indexed by CORNER_ defines. enum unnamed { ALLOWEDVERTS_SIZE = PAD_NUMBER( MAX_DISPVERTS, 32 ) / 32 }; - unsigned long m_AllowedVerts[ALLOWEDVERTS_SIZE]; // This is built based on the layout and sizes of our neighbors + unsigned int m_AllowedVerts[ALLOWEDVERTS_SIZE]; // This is built based on the layout and sizes of our neighbors // and tells us which vertices are allowed to be active. }; diff --git a/public/bsptreedata.cpp b/public/bsptreedata.cpp index e03dd2c5..f6ef748a 100644 --- a/public/bsptreedata.cpp +++ b/public/bsptreedata.cpp @@ -35,16 +35,16 @@ public: void ElementMoved( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs ); // Enumerate elements in a particular leaf - bool EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, int context ); + bool EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, intp context ); // For convenience, enumerates the leaves along a ray, box, etc. - bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context ); - bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context ); - bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context ); - bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ); + bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, intp context ); + bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, intp context ); + bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, intp context ); + bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context ); // methods of IBSPLeafEnumerator - bool EnumerateLeaf( int leaf, int context ); + bool EnumerateLeaf( int leaf, intp context ); // Is the element in any leaves at all? bool IsElementInTree( BSPTreeDataHandle_t handle ) const; @@ -223,7 +223,7 @@ void CBSPTreeData::AddHandleToLeaf( int leaf, BSPTreeDataHandle_t handle ) //----------------------------------------------------------------------------- // Inserts an element into the tree //----------------------------------------------------------------------------- -bool CBSPTreeData::EnumerateLeaf( int leaf, int context ) +bool CBSPTreeData::EnumerateLeaf( int leaf, intp context ) { BSPTreeDataHandle_t handle = (BSPTreeDataHandle_t)context; AddHandleToLeaf( leaf, handle ); @@ -302,7 +302,7 @@ int CBSPTreeData::CountElementsInLeaf( int leaf ) //----------------------------------------------------------------------------- // Enumerate elements in a particular leaf //----------------------------------------------------------------------------- -bool CBSPTreeData::EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, int context ) +bool CBSPTreeData::EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, intp context ) { #ifdef DBGFLAG_ASSERT // The enumeration method better damn well not change this list... @@ -330,22 +330,22 @@ bool CBSPTreeData::EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pE //----------------------------------------------------------------------------- // For convenience, enumerates the leaves along a ray, box, etc. //----------------------------------------------------------------------------- -bool CBSPTreeData::EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context ) +bool CBSPTreeData::EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, intp context ) { return m_pBSPTree->EnumerateLeavesAtPoint( pt, pEnum, context ); } -bool CBSPTreeData::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context ) +bool CBSPTreeData::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, intp context ) { return m_pBSPTree->EnumerateLeavesInBox( mins, maxs, pEnum, context ); } -bool CBSPTreeData::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context ) +bool CBSPTreeData::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, intp context ) { return m_pBSPTree->EnumerateLeavesInSphere( center, radius, pEnum, context ); } -bool CBSPTreeData::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ) +bool CBSPTreeData::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context ) { return m_pBSPTree->EnumerateLeavesAlongRay( ray, pEnum, context ); } diff --git a/public/bsptreedata.h b/public/bsptreedata.h index 2132dfbf..94f5c1b6 100644 --- a/public/bsptreedata.h +++ b/public/bsptreedata.h @@ -58,7 +58,7 @@ public: // that passes the test; return true to continue enumerating, // false to stop - virtual bool EnumerateLeaf( int leaf, int context ) = 0; + virtual bool EnumerateLeaf( int leaf, intp context ) = 0; }; abstract_class ISpatialQuery @@ -68,10 +68,10 @@ public: virtual int LeafCount() const = 0; // Enumerates the leaves along a ray, box, etc. - virtual bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context ) = 0; - virtual bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context ) = 0; - virtual bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context ) = 0; - virtual bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ) = 0; + virtual bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, intp context ) = 0; + virtual bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, intp context ) = 0; + virtual bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, intp context ) = 0; + virtual bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context ) = 0; }; @@ -87,7 +87,7 @@ abstract_class IBSPTreeDataEnumerator { public: // call back with a userId and a context - virtual bool FASTCALL EnumerateElement( int userId, int context ) = 0; + virtual bool FASTCALL EnumerateElement( int userId, intp context ) = 0; }; abstract_class IBSPTreeData @@ -109,7 +109,7 @@ public: virtual void ElementMoved( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs ) = 0; // Enumerate elements in a particular leaf - virtual bool EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, int context ) = 0; + virtual bool EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, intp context ) = 0; // Is the element in any leaves at all? virtual bool IsElementInTree( BSPTreeDataHandle_t handle ) const = 0; @@ -117,10 +117,10 @@ public: // NOTE: These methods call through to the functions in the attached // ISpatialQuery // For convenience, enumerates the leaves along a ray, box, etc. - virtual bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context ) = 0; - virtual bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context ) = 0; - virtual bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context ) = 0; - virtual bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ) = 0; + virtual bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, intp context ) = 0; + virtual bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, intp context ) = 0; + virtual bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, intp context ) = 0; + virtual bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context ) = 0; }; //----------------------------------------------------------------------------- diff --git a/public/datacache/idatacache.h b/public/datacache/idatacache.h index c21937fd..5f27a969 100644 --- a/public/datacache/idatacache.h +++ b/public/datacache/idatacache.h @@ -35,7 +35,7 @@ class IDataCache; //--------------------------------------------------------- // Unique (per section) identifier for a cache item defined by client //--------------------------------------------------------- -typedef uint32 DataCacheClientID_t; +typedef uintp DataCacheClientID_t; //--------------------------------------------------------- @@ -491,7 +491,7 @@ public: m_pCache->EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams)); STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams ); DataCacheHandle_t handle; - m_pCache->AddEx( (DataCacheClientID_t)pStore, pStore, pStore->Size(), flags, &handle); + m_pCache->AddEx( (DataCacheClientID_t)(uintp)pStore, pStore, pStore->Size(), flags, &handle); return handle; } diff --git a/public/datacache/imdlcache.h b/public/datacache/imdlcache.h index 0f7093ab..292a0ba3 100644 --- a/public/datacache/imdlcache.h +++ b/public/datacache/imdlcache.h @@ -41,6 +41,17 @@ namespace OptimizedModel //----------------------------------------------------------------------------- typedef unsigned short MDLHandle_t; +// MoeMod : integer promotion keeps sign on arm, but discards sign on x86 +inline MDLHandle_t VoidPtrToMDLHandle( void *ptr ) +{ + return ( MDLHandle_t ) ( ( uintp ) ptr & 0xffff ); +} + +inline void* MDLHandleToVirtual( MDLHandle_t hndl ) +{ + return (void*)(uintp)hndl; +} + enum { MDLHANDLE_INVALID = (MDLHandle_t)~0 diff --git a/public/datamap.h b/public/datamap.h index 11f06d0c..7c664265 100644 --- a/public/datamap.h +++ b/public/datamap.h @@ -64,6 +64,7 @@ typedef enum _fieldtypes FIELD_MATERIALINDEX, // a material index (using the material precache string table) FIELD_VECTOR2D, // 2 floats + FIELD_INTEGER64, // 64bit integer FIELD_TYPECOUNT, // MUST BE LAST } fieldtype_t; @@ -128,7 +129,7 @@ DECLARE_FIELD_SIZE( FIELD_MATERIALINDEX, sizeof(int) ) #define ARRAYSIZE2D(p) (sizeof(p)/sizeof(p[0][0])) #define SIZE_OF_ARRAY(p) _ARRAYSIZE(p) -#define _offsetof(s,m) ((int)&(((s *)0)->m)) +#define _offsetof(s,m) ((int)(intp)&(((s *)0)->m)) #define _FIELD(name,fieldtype,count,flags,mapname,tolerance) { fieldtype, #name, { _offsetof(classNameTypedef, name), 0 }, count, flags, mapname, NULL, NULL, NULL, sizeof( ((classNameTypedef *)0)->name ), NULL, 0, tolerance } #define DEFINE_FIELD_NULL { FIELD_VOID,0, {0,0},0,0,0,0,0,0} diff --git a/public/materialsystem/IColorCorrection.h b/public/materialsystem/IColorCorrection.h index 1aa0c246..6c12221e 100644 --- a/public/materialsystem/IColorCorrection.h +++ b/public/materialsystem/IColorCorrection.h @@ -14,7 +14,7 @@ #include "tier1/interface.h" #include "bitmap/imageformat.h" -typedef unsigned int ColorCorrectionHandle_t; +typedef uintp ColorCorrectionHandle_t; struct ShaderColorCorrectionInfo_t; #define COLORCORRECTION_INTERFACE_VERSION "COLORCORRECTION_VERSION_1" diff --git a/public/materialsystem/imesh.h b/public/materialsystem/imesh.h index 17533969..3995642b 100644 --- a/public/materialsystem/imesh.h +++ b/public/materialsystem/imesh.h @@ -1156,7 +1156,7 @@ inline void CVertexBuilder::FastAdvanceNVertices( int n ) //----------------------------------------------------------------------------- inline void CVertexBuilder::FastVertex( const ModelVertexDX7_t &vertex ) { -#ifdef __arm__ +#if defined(__arm__) || defined(__arm64__) FastVertexSSE( vertex ); #else Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed @@ -1244,11 +1244,11 @@ inline void CVertexBuilder::FastVertexSSE( const ModelVertexDX7_t &vertex ) const char *pRead = (char *)&vertex; char *pCurrPos = (char *)m_pCurrPosition; __m128 m1 = _mm_load_ps( (float *)pRead ); - __m128 m2 = _mm_load_ps( (float *)((int)pRead + 16) ); - __m128 m3 = _mm_load_ps( (float *)((int)pRead + 32) ); + __m128 m2 = _mm_load_ps( (float *)((intp)pRead + 16) ); + __m128 m3 = _mm_load_ps( (float *)((intp)pRead + 32) ); _mm_stream_ps( (float *)pCurrPos, m1 ); - _mm_stream_ps( (float *)((int)pCurrPos + 16), m2 ); - _mm_stream_ps( (float *)((int)pCurrPos + 32), m3 ); + _mm_stream_ps( (float *)((intp)pCurrPos + 16), m2 ); + _mm_stream_ps( (float *)((intp)pCurrPos + 32), m3 ); #else Error( "Implement CMeshBuilder::FastVertexSSE(dx7)" ); #endif @@ -1326,7 +1326,7 @@ inline void CVertexBuilder::Fast4VerticesSSE( inline void CVertexBuilder::FastVertex( const ModelVertexDX8_t &vertex ) { -#ifdef __arm__ +#if defined(__arm__) || defined(__arm64__) FastVertexSSE( vertex ); #else Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed @@ -1436,13 +1436,13 @@ inline void CVertexBuilder::FastVertexSSE( const ModelVertexDX8_t &vertex ) :: "r" (pRead), "r" (pCurrPos) : "memory"); */ __m128 m1 = _mm_load_ps( (float *)pRead ); - __m128 m2 = _mm_load_ps( (float *)((int)pRead + 16) ); - __m128 m3 = _mm_load_ps( (float *)((int)pRead + 32) ); - __m128 m4 = _mm_load_ps( (float *)((int)pRead + 48) ); + __m128 m2 = _mm_load_ps( (float *)((intp)pRead + 16) ); + __m128 m3 = _mm_load_ps( (float *)((intp)pRead + 32) ); + __m128 m4 = _mm_load_ps( (float *)((intp)pRead + 48) ); _mm_stream_ps( (float *)pCurrPos, m1 ); - _mm_stream_ps( (float *)((int)pCurrPos + 16), m2 ); - _mm_stream_ps( (float *)((int)pCurrPos + 32), m3 ); - _mm_stream_ps( (float *)((int)pCurrPos + 48), m4 ); + _mm_stream_ps( (float *)((intp)pCurrPos + 16), m2 ); + _mm_stream_ps( (float *)((intp)pCurrPos + 32), m3 ); + _mm_stream_ps( (float *)((intp)pCurrPos + 48), m4 ); #else Error( "Implement CMeshBuilder::FastVertexSSE((dx8)" ); #endif diff --git a/public/networkvar.h b/public/networkvar.h index 14c6f22a..046cb5f3 100644 --- a/public/networkvar.h +++ b/public/networkvar.h @@ -21,7 +21,7 @@ #pragma warning( disable : 4284 ) // warning C4284: return type for 'CNetworkVarT::operator ->' is 'int *' (ie; not a UDT or reference to a UDT. Will produce errors if applied using infix notation) -#define MyOffsetOf( type, var ) ( (int)&((type*)0)->var ) +#define MyOffsetOf( type, var ) ( (intp)&((type*)0)->var ) #ifdef _DEBUG extern bool g_bUseNetworkVars; diff --git a/public/shaderapi/ishaderapi.h b/public/shaderapi/ishaderapi.h index 07448b08..dc05fe2e 100644 --- a/public/shaderapi/ishaderapi.h +++ b/public/shaderapi/ishaderapi.h @@ -52,7 +52,7 @@ enum ShaderRenderTarget_t //----------------------------------------------------------------------------- // This must match the definition in playback.cpp! //----------------------------------------------------------------------------- -typedef int ShaderAPITextureHandle_t; +typedef intp ShaderAPITextureHandle_t; #define INVALID_SHADERAPI_TEXTURE_HANDLE 0 diff --git a/public/shaderapi/ishaderdynamic.h b/public/shaderapi/ishaderdynamic.h index 49237ad5..bb3d2ca8 100644 --- a/public/shaderapi/ishaderdynamic.h +++ b/public/shaderapi/ishaderdynamic.h @@ -19,7 +19,7 @@ #include "tier0/basetypes.h" -typedef int ShaderAPITextureHandle_t; +typedef intp ShaderAPITextureHandle_t; //----------------------------------------------------------------------------- // forward declarations diff --git a/public/studio.h b/public/studio.h index a30875be..9829de8d 100644 --- a/public/studio.h +++ b/public/studio.h @@ -1194,10 +1194,16 @@ struct mstudiotexture_t int flags; int used; int unused1; +#if PLATFORM_64BITS + mutable IMaterial *material; + mutable void *clientmaterial; + int unused[8]; +#else mutable IMaterial *material; // fixme: this needs to go away . .isn't used by the engine, but is used by studiomdl mutable void *clientmaterial; // gary, replace with client material pointer if used int unused[10]; +#endif }; // eyeball @@ -1290,6 +1296,11 @@ struct mstudio_modelvertexdata_t const void *pTangentData; }; +#ifdef PLATFORM_64BITS +// 64b - match 32-bit packing +#pragma pack( push, 4 ) +#endif + struct mstudio_meshvertexdata_t { DECLARE_BYTESWAP_DATADESC(); @@ -1339,9 +1350,15 @@ struct mstudiomesh_t Vector center; +#ifdef PLATFORM_64BITS + mstudio_meshvertexdata_t vertexdata; + + int unused[7]; // remove as appropriate +#else mstudio_meshvertexdata_t vertexdata; int unused[8]; // remove as appropriate +#endif mstudiomesh_t(){} private: @@ -1383,11 +1400,22 @@ struct mstudiomodel_t int eyeballindex; inline mstudioeyeball_t *pEyeball( int i ) { return (mstudioeyeball_t *)(((byte *)this) + eyeballindex) + i; }; + +#ifdef PLATFORM_64BITS + mstudio_modelvertexdata_t vertexdata; // sizeof(mstudio_modelvertexdata_t) == 16 + + int unused[6]; // remove as appropriate +#else mstudio_modelvertexdata_t vertexdata; int unused[8]; // remove as appropriate +#endif }; +#ifdef PLATFORM_64BITS +#pragma pack( pop ) +#endif + inline bool mstudio_modelvertexdata_t::HasTangentData( void ) const { return (pTangentData != NULL); @@ -1396,14 +1424,14 @@ inline bool mstudio_modelvertexdata_t::HasTangentData( void ) const inline int mstudio_modelvertexdata_t::GetGlobalVertexIndex( int i ) const { mstudiomodel_t *modelptr = (mstudiomodel_t *)((byte *)this - offsetof(mstudiomodel_t, vertexdata)); - Assert( ( modelptr->vertexindex % sizeof( mstudiovertex_t ) ) == 0 ); + //Assert( ( modelptr->vertexindex % sizeof( mstudiovertex_t ) ) == 0 ); return ( i + ( modelptr->vertexindex / sizeof( mstudiovertex_t ) ) ); } inline int mstudio_modelvertexdata_t::GetGlobalTangentIndex( int i ) const { mstudiomodel_t *modelptr = (mstudiomodel_t *)((byte *)this - offsetof(mstudiomodel_t, vertexdata)); - Assert( ( modelptr->tangentsindex % sizeof( Vector4D ) ) == 0 ); + //Assert( ( modelptr->tangentsindex % sizeof( Vector4D ) ) == 0 ); return ( i + ( modelptr->tangentsindex / sizeof( Vector4D ) ) ); } @@ -2263,7 +2291,11 @@ struct studiohdr_t const studiohdr_t *FindModel( void **cache, char const *modelname ) const; // implementation specific back pointer to virtual data +#ifdef PLATFORM_64BITS + int index_ptr_virtualModel; +#else mutable void *virtualModel; +#endif virtualmodel_t *GetVirtualModel( void ) const; // for demand loaded animation blocks @@ -2272,7 +2304,11 @@ struct studiohdr_t int numanimblocks; int animblockindex; inline mstudioanimblock_t *pAnimBlock( int i ) const { Assert( i > 0 && i < numanimblocks); return (mstudioanimblock_t *)(((byte *)this) + animblockindex) + i; }; +#ifdef PLATFORM_64BITS + int index_ptr_animblockModel; +#else mutable void *animblockModel; +#endif byte * GetAnimBlock( int i ) const; int bonetablebynameindex; @@ -2280,8 +2316,13 @@ struct studiohdr_t // used by tools only that don't cache, but persist mdl's peer data // engine uses virtualModel to back link to cache pointers +#ifdef PLATFORM_64BITS + int index_ptr_pVertexBase; + int index_ptr_pIndexBase; +#else void *pVertexBase; void *pIndexBase; +#endif // if STUDIOHDR_FLAGS_CONSTANT_DIRECTIONAL_LIGHT_DOT is set, // this value is used to calculate directional components of lighting @@ -2327,7 +2368,23 @@ struct studiohdr_t inline mstudiolinearbone_t *pLinearBones() const { return studiohdr2index ? pStudioHdr2()->pLinearBones() : NULL; } inline int BoneFlexDriverCount() const { return studiohdr2index ? pStudioHdr2()->m_nBoneFlexDriverCount : 0; } - inline const mstudioboneflexdriver_t* BoneFlexDriver( int i ) const { Assert( i >= 0 && i < BoneFlexDriverCount() ); return studiohdr2index ? pStudioHdr2()->pBoneFlexDriver( i ) : NULL; } + inline const mstudioboneflexdriver_t* BoneFlexDriver( int i ) const { Assert( i >= 0 && i < BoneFlexDriverCount() ); return studiohdr2index > 0 ? pStudioHdr2()->pBoneFlexDriver( i ) : NULL; } + +#ifdef PLATFORM_64BITS + void* VirtualModel() const { return *(void **)(((byte *)this) + index_ptr_virtualModel); } + void SetVirtualModel( void* ptr ) const { *(void **)(((byte *)this) + index_ptr_virtualModel) = ptr; } + void* VertexBase() const { return *(void **)(((byte *)this) + index_ptr_pVertexBase); } + void SetVertexBase( void* ptr ) { *(void **)(((byte *)this) + index_ptr_pVertexBase) = ptr; } + void* IndexBase() const { return *(void **)(((byte *)this) + index_ptr_pIndexBase); } + void SetIndexBase( void* ptr ) { *(void **)(((byte *)this) + index_ptr_pIndexBase) = ptr; } +#else + void* VirtualModel() const { return virtualModel; } + void SetVirtualModel( void* ptr ) const { virtualModel = ptr; } + void* VertexBase() const { return pVertexBase; } + void SetVertexBase( void* ptr ) { pVertexBase = ptr; } + void* IndexBase() const { return pIndexBase; } + void SetIndexBase( void* ptr ) { pIndexBase = ptr; } } +#endif // NOTE: No room to add stuff? Up the .mdl file format version // [and move all fields in studiohdr2_t into studiohdr_t and kill studiohdr2_t], @@ -2340,6 +2397,15 @@ private: friend struct virtualmodel_t; }; +#ifdef PLATFORM_64BITS +struct studiohdr_shim64_index +{ + mutable void *virtualModel; + mutable void *animblockModel; + void *pVertexBase; + void *pIndexBase; +}; +#endif //----------------------------------------------------------------------------- diff --git a/public/tier0/platform.h b/public/tier0/platform.h index 69970444..89b678b9 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -9,7 +9,7 @@ #ifndef PLATFORM_H #define PLATFORM_H -#if defined(__x86_64__) || defined(_WIN64) +#if defined(__x86_64__) || defined(_WIN64) || defined(__arm64__) #define PLATFORM_64BITS 1 #endif @@ -70,7 +70,11 @@ #include #endif +#ifdef OSX +#include +#else #include +#endif #include // need this for memset @@ -171,6 +175,9 @@ typedef signed char int8; typedef __int64 int64; typedef unsigned __int64 uint64; + typedef int64 lint64; + typedef uint64 ulint64; + #ifdef PLATFORM_64BITS typedef __int64 intp; // intp is an integer that can accomodate a pointer typedef unsigned __int64 uintp; // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) @@ -201,13 +208,17 @@ typedef signed char int8; typedef unsigned int uint32; typedef long long int64; typedef unsigned long long uint64; + + typedef long int lint64; + typedef unsigned long int ulint64; + #ifdef PLATFORM_64BITS typedef long long intp; typedef unsigned long long uintp; #else typedef int intp; typedef unsigned int uintp; - #endif + #endif typedef void *HWND; // Avoid redefinition warnings if a previous header defines this. @@ -429,7 +440,11 @@ typedef void * HINSTANCE; // On OSX, SIGTRAP doesn't really stop the thread cold when debugging. // So if being debugged, use INT3 which is precise. #ifdef OSX -#define DebuggerBreak() if ( Plat_IsInDebugSession() ) { __asm ( "int $3" ); } else { raise(SIGTRAP); } +#if defined(__arm__) || defined(__arm64__) +#define DebuggerBreak() do { if ( Plat_IsInDebugSession() ) { __builtin_debugtrap(); } else { raise(SIGTRAP); } } while(0) +#else +#define DebuggerBreak() do { if ( Plat_IsInDebugSession() ) { __asm ( "int $3" ); } else { raise(SIGTRAP); } } while(0) +#endif #else #define DebuggerBreak() raise(SIGTRAP) #endif @@ -752,7 +767,7 @@ typedef void * HINSTANCE; #define _wtoi(arg) wcstol(arg, NULL, 10) #define _wtoi64(arg) wcstoll(arg, NULL, 10) -typedef uint32 HMODULE; +typedef uintp HMODULE; typedef void *HANDLE; #endif @@ -830,7 +845,7 @@ static FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) #endif #endif -#elif defined (__arm__) +#elif defined (__arm__) || defined (__arm64__) inline void SetupFPUControlWord() {} #else inline void SetupFPUControlWord() @@ -1094,12 +1109,12 @@ FORCEINLINE void StoreLittleDWord( unsigned long *base, unsigned int dwordIndex, __storewordbytereverse( dword, dwordIndex<<2, base ); } #else -FORCEINLINE unsigned long LoadLittleDWord( const unsigned long *base, unsigned int dwordIndex ) +FORCEINLINE uint32 LoadLittleDWord( const uint32 *base, unsigned int dwordIndex ) { return LittleDWord( base[dwordIndex] ); } -FORCEINLINE void StoreLittleDWord( unsigned long *base, unsigned int dwordIndex, unsigned long dword ) +FORCEINLINE void StoreLittleDWord( uint32 *base, unsigned int dwordIndex, uint32 dword ) { base[dwordIndex] = LittleDWord(dword); } @@ -1167,7 +1182,7 @@ PLATFORM_INTERFACE struct tm * Plat_localtime( const time_t *timep, struct tm * inline uint64 Plat_Rdtsc() { -#if defined( __arm__ ) && defined (POSIX) +#if (defined( __arm__ ) || defined( __arm64__ )) && defined (POSIX) struct timespec t; clock_gettime( CLOCK_REALTIME, &t); return t.tv_sec * 1000000000ULL + t.tv_nsec; diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h index d7655b14..df481cc1 100644 --- a/public/tier0/threadtools.h +++ b/public/tier0/threadtools.h @@ -12,6 +12,9 @@ #include "tier0/type_traits.h" #include +#if defined( __arm__ ) || defined( __arm64__ ) +#include +#endif #include "tier0/platform.h" #include "tier0/dbg.h" @@ -100,7 +103,11 @@ const unsigned TT_INFINITE = 0xffffffff; #endif // NO_THREAD_LOCAL -typedef unsigned long ThreadId_t; +#ifdef PLATFORM_64BITS +typedef uint64 ThreadId_t; +#else +typedef uint32 ThreadId_t; +#endif //----------------------------------------------------------------------------- // @@ -109,7 +116,7 @@ typedef unsigned long ThreadId_t; // //----------------------------------------------------------------------------- FORWARD_DECLARE_HANDLE( ThreadHandle_t ); -typedef unsigned (*ThreadFunc_t)( void *pParam ); +typedef uintp (*ThreadFunc_t)( void *pParam ); PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0 ); PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0 ); @@ -119,7 +126,7 @@ PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t ); //----------------------------------------------------------------------------- PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0); -PLATFORM_INTERFACE uint ThreadGetCurrentId(); +PLATFORM_INTERFACE ThreadId_t ThreadGetCurrentId(); PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle(); PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL ); PLATFORM_INTERFACE bool ThreadSetPriority( ThreadHandle_t hThread, int priority ); @@ -142,10 +149,10 @@ inline void ThreadPause() #if defined( PLATFORM_WINDOWS_PC ) // Intrinsic for __asm pause; from _mm_pause(); -#elif POSIX && defined( __i386__ ) +#elif POSIX && ( defined( __i386__ ) || defined( __x86_64__ ) ) __asm __volatile( "pause" ); #elif defined( _X360 ) -#elif defined(__arm__) +#elif defined(__arm__) || defined(__arm64__) sched_yield(); #else #error "implement me" @@ -238,28 +245,28 @@ extern "C" #pragma intrinsic( _InterlockedExchangeAdd ) #pragma intrinsic( _InterlockedIncrement ) -inline long ThreadInterlockedIncrement( long volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( p ); } -inline long ThreadInterlockedDecrement( long volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( p ); } -inline long ThreadInterlockedExchange( long volatile *p, long value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchange( p, value ); } -inline long ThreadInterlockedExchangeAdd( long volatile *p, long value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( p, value ); } -inline long ThreadInterlockedCompareExchange( long volatile *p, long value, long comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( p, value, comperand ); } -inline bool ThreadInterlockedAssignIf( long volatile *p, long value, long comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( p, value, comperand ) == comperand ); } +inline int32 ThreadInterlockedIncrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( p ); } +inline int32 ThreadInterlockedDecrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( p ); } +inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchange( p, value ); } +inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( p, value ); } +inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( p, value, comperand ) == comperand ); } #else -PLATFORM_INTERFACE long ThreadInterlockedIncrement( long volatile * ); -PLATFORM_INTERFACE long ThreadInterlockedDecrement( long volatile * ); -PLATFORM_INTERFACE long ThreadInterlockedExchange( long volatile *, long value ); -PLATFORM_INTERFACE long ThreadInterlockedExchangeAdd( long volatile *, long value ); -PLATFORM_INTERFACE long ThreadInterlockedCompareExchange( long volatile *, long value, long comperand ); -PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( long volatile *, long value, long comperand ); +PLATFORM_INTERFACE int32 ThreadInterlockedIncrement( int32 volatile * ); +PLATFORM_INTERFACE int32 ThreadInterlockedDecrement( int32 volatile * ); +PLATFORM_INTERFACE int32 ThreadInterlockedExchange( int32 volatile *, int32 value ); +PLATFORM_INTERFACE int32 ThreadInterlockedExchangeAdd( int32 volatile *, int32 value ); +PLATFORM_INTERFACE int32 ThreadInterlockedCompareExchange( int32 volatile *, int32 value, int32 comperand ); +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( int32 volatile *, int32 value, int32 comperand ); #endif -inline unsigned ThreadInterlockedExchangeSubtract( long volatile *p, long value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, -value ); } +inline unsigned ThreadInterlockedExchangeSubtract( int32 volatile *p, int32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, -value ); } #if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( _WIN64 ) #define TIPTR() -inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)_InterlockedExchange( reinterpret_cast(p), reinterpret_cast(value) ); } -inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)_InterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ); } -inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( _InterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ) == reinterpret_cast(comperand) ); } +inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)_InterlockedExchange( reinterpret_cast(p), reinterpret_cast(value) ); } +inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)_InterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ); } +inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( _InterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ) == reinterpret_cast(comperand) ); } #else PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE; PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE; @@ -276,7 +283,7 @@ typedef __m128i int128; inline int128 int128_zero() { return _mm_setzero_si128(); } #else typedef __int128_t int128; -#define int128_zero() 0 +#define int128_zero() int128() #endif PLATFORM_INTERFACE bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand ) NOINLINE; @@ -290,21 +297,28 @@ PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 va PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE; PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE; -inline unsigned ThreadInterlockedExchangeSubtract( unsigned volatile *p, unsigned value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); } -inline unsigned ThreadInterlockedIncrement( unsigned volatile *p ) { return ThreadInterlockedIncrement( (long volatile *)p ); } -inline unsigned ThreadInterlockedDecrement( unsigned volatile *p ) { return ThreadInterlockedDecrement( (long volatile *)p ); } -inline unsigned ThreadInterlockedExchange( unsigned volatile *p, unsigned value ) { return ThreadInterlockedExchange( (long volatile *)p, value ); } -inline unsigned ThreadInterlockedExchangeAdd( unsigned volatile *p, unsigned value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); } -inline unsigned ThreadInterlockedCompareExchange( unsigned volatile *p, unsigned value, unsigned comperand ) { return ThreadInterlockedCompareExchange( (long volatile *)p, value, comperand ); } -inline bool ThreadInterlockedAssignIf( unsigned volatile *p, unsigned value, unsigned comperand ) { return ThreadInterlockedAssignIf( (long volatile *)p, value, comperand ); } +inline uint32 ThreadInterlockedExchangeSubtract( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +inline uint32 ThreadInterlockedIncrement( uint32 volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); } +inline uint32 ThreadInterlockedDecrement( uint32 volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); } +inline uint32 ThreadInterlockedExchange( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); } +inline uint32 ThreadInterlockedExchangeAdd( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +inline uint32 ThreadInterlockedCompareExchange( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); } -inline int ThreadInterlockedExchangeSubtract( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); } -inline int ThreadInterlockedIncrement( int volatile *p ) { return ThreadInterlockedIncrement( (long volatile *)p ); } -inline int ThreadInterlockedDecrement( int volatile *p ) { return ThreadInterlockedDecrement( (long volatile *)p ); } -inline int ThreadInterlockedExchange( int volatile *p, int value ) { return ThreadInterlockedExchange( (long volatile *)p, value ); } -inline int ThreadInterlockedExchangeAdd( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); } -inline int ThreadInterlockedCompareExchange( int volatile *p, int value, int comperand ) { return ThreadInterlockedCompareExchange( (long volatile *)p, value, comperand ); } -inline bool ThreadInterlockedAssignIf( int volatile *p, int value, int comperand ) { return ThreadInterlockedAssignIf( (long volatile *)p, value, comperand ); } +inline uint64 ThreadInterlockedIncrement64( uint64 volatile *p ) { return ThreadInterlockedIncrement64( (int64 volatile *)p ); } +inline uint64 ThreadInterlockedDecrement64( uint64 volatile *p ) { return ThreadInterlockedDecrement64( (int64 volatile *)p ); } +inline uint64 ThreadInterlockedCompareExchange64( uint64 volatile *p, uint64 value, uint64 comperand ) { return ThreadInterlockedCompareExchange64( (int64 volatile *)p, value, comperand ); } +inline uint64 ThreadInterlockedExchange64( uint64 volatile *p, uint64 value ) { return ThreadInterlockedExchange64( (int64 volatile *)p, value ); } +inline uint64 ThreadInterlockedExchangeAdd64( uint64 volatile *p, uint64 value ) { return ThreadInterlockedExchangeAdd64( (int64 volatile *)p, value ); } +inline bool ThreadInterlockedAssignIf64( uint64 volatile *p, uint64 value, uint64 comperand ) { return ThreadInterlockedAssignIf64( (int64 volatile *)p, value, comperand ); } + +//inline int ThreadInterlockedExchangeSubtract( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +//inline int ThreadInterlockedIncrement( int volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); } +//inline int ThreadInterlockedDecrement( int volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); } +//inline int ThreadInterlockedExchange( int volatile *p, int value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); } +//inline int ThreadInterlockedExchangeAdd( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +//inline int ThreadInterlockedCompareExchange( int volatile *p, int value, int comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); } +//inline bool ThreadInterlockedAssignIf( int volatile *p, int value, int comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); } //----------------------------------------------------------------------------- // Access to VTune thread profiling @@ -380,17 +394,44 @@ private: public: CThreadLocal() { - COMPILE_TIME_ASSERT( sizeof(T) == sizeof(void *) ); +#ifdef PLATFORM_64BITS + COMPILE_TIME_ASSERT( sizeof(T) <= sizeof(void *) ); +#else + COMPILE_TIME_ASSERT( sizeof(T) == sizeof(void *) ); +#endif } T Get() const { +#ifdef PLATFORM_64BITS + void *pData = CThreadLocalBase::Get(); + return *reinterpret_cast( &pData ); +#else + #ifdef COMPILER_MSVC + #pragma warning ( disable : 4311 ) + #endif return reinterpret_cast( CThreadLocalBase::Get() ); + #ifdef COMPILER_MSVC + #pragma warning ( default : 4311 ) + #endif +#endif } void Set(T val) { +#ifdef PLATFORM_64BITS + void* pData = 0; + *reinterpret_cast( &pData ) = val; + CThreadLocalBase::Set( pData ); +#else + #ifdef COMPILER_MSVC + #pragma warning ( disable : 4312 ) + #endif CThreadLocalBase::Set( reinterpret_cast(val) ); + #ifdef COMPILER_MSVC + #pragma warning ( default : 4312 ) + #endif +#endif } }; @@ -433,16 +474,11 @@ template operator const T *() { return (T *)Get(); } operator T *() { return (T *)Get(); } - int operator=( int i ) { AssertMsg( i == 0, "Only NULL allowed on integer assign" ); Set( NULL ); return 0; } T * operator=( T *p ) { Set( p ); return p; } bool operator !() const { return (!Get()); } - bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() != NULL); } - bool operator==( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() == NULL); } bool operator==( const void *p ) const { return (Get() == p); } bool operator!=( const void *p ) const { return (Get() != p); } - bool operator==( const T *p ) const { return operator==((void*)p); } - bool operator!=( const T *p ) const { return operator!=((void*)p); } T * operator->() { return (T *)Get(); } T & operator *() { return *((T *)Get()); } @@ -480,7 +516,7 @@ template class CInterlockedIntT { public: - CInterlockedIntT() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T) == sizeof(long) ); } + CInterlockedIntT() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T) == sizeof(int) ); } CInterlockedIntT( T value ) : m_value( value ) {} T GetRaw() const { return m_value; } @@ -491,17 +527,34 @@ public: bool operator==( T rhs ) const { return ( m_value == rhs ); } bool operator!=( T rhs ) const { return ( m_value != rhs ); } - T operator++() { return (T)ThreadInterlockedIncrement( (long *)&m_value ); } + +#if defined( __arm__ ) || defined( __arm64__ ) + CInterlockedIntT( const CInterlockedIntT &rhs ) : m_value( rhs ) {} + CInterlockedIntT &operator=( const CInterlockedIntT &rhs ) { m_value.store(rhs.m_value.load()); return *this; } + T operator++() { return m_value.fetch_add(1) + 1; } + T operator++(int) { return m_value.fetch_add(1); } + + T operator--() { return m_value.fetch_sub(1) - 1; } + T operator--(int) { return m_value.fetch_sub(1); } + + bool AssignIf( T conditionValue, T newValue ) { return m_value.compare_exchange_strong(conditionValue, newValue); } + + T operator=( T newValue ) { m_value.store(newValue); return newValue; } + + void operator+=( T add ) { m_value.fetch_add(add); } +#else + T operator++() { return (T)ThreadInterlockedIncrement( (int *)&m_value ); } T operator++(int) { return operator++() - 1; } - T operator--() { return (T)ThreadInterlockedDecrement( (long *)&m_value ); } + T operator--() { return (T)ThreadInterlockedDecrement( (int *)&m_value ); } T operator--(int) { return operator--() + 1; } - bool AssignIf( T conditionValue, T newValue ) { return ThreadInterlockedAssignIf( (long *)&m_value, (long)newValue, (long)conditionValue ); } + bool AssignIf( T conditionValue, T newValue ) { return ThreadInterlockedAssignIf( (int *)&m_value, (int)newValue, (int)conditionValue ); } - T operator=( T newValue ) { ThreadInterlockedExchange((long *)&m_value, newValue); return m_value; } + T operator=( T newValue ) { ThreadInterlockedExchange((int *)&m_value, newValue); return m_value; } - void operator+=( T add ) { ThreadInterlockedExchangeAdd( (long *)&m_value, (long)add ); } + void operator+=( T add ) { ThreadInterlockedExchangeAdd( (int *)&m_value, (int)add ); } +#endif void operator-=( T subtract ) { operator+=( -subtract ); } void operator*=( T multiplier ) { T original, result; @@ -524,7 +577,11 @@ public: T operator-( T rhs ) const { return m_value - rhs; } private: +#if defined( __arm__ ) || defined( __arm64__ ) + std::atomic m_value; +#else volatile T m_value; +#endif }; typedef CInterlockedIntT CInterlockedInt; @@ -544,7 +601,21 @@ public: bool operator!() const { return ( m_value == 0 ); } bool operator==( T *rhs ) const { return ( m_value == rhs ); } bool operator!=( T *rhs ) const { return ( m_value != rhs ); } +#if defined( __arm__ ) || defined( __arm64__ ) + CInterlockedPtr( const CInterlockedPtr &rhs ) : m_value( rhs ) {} + CInterlockedPtr &operator=( const CInterlockedPtr &rhs ) { m_value.store(rhs.m_value.load()); return *this; } + T *operator++() { return m_value.fetch_add(1) + 1; } + T *operator++(int) { return m_value.fetch_add(1); } + T *operator--() { return m_value.fetch_sub(1) - 1; } + T *operator--(int) { return m_value.fetch_sub(1); } + + bool AssignIf( T *conditionValue, T *newValue ) { return m_value.compare_exchange_strong(conditionValue, newValue); } + + T *operator=( T *newValue ) { m_value.store(newValue); return newValue; } + + void operator+=( int add ) { m_value.fetch_add(add); } +#else #if defined( PLATFORM_64BITS ) T *operator++() { return ((T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, sizeof(T) )) + 1; } T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, sizeof(T) ); } @@ -569,6 +640,7 @@ public: T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; } void operator+=( int add ) { ThreadInterlockedExchangeAdd( (long *)&m_value, add * sizeof(T) ); } +#endif #endif void operator-=( int subtract ) { operator+=( -subtract ); } @@ -581,7 +653,11 @@ public: size_t operator-( const CInterlockedPtr &p ) const { return m_value - p.m_value; } private: +#if defined( __arm__ ) || defined( __arm64__ ) + std::atomic m_value; +#else T * volatile m_value; +#endif }; //----------------------------------------------------------------------------- @@ -708,9 +784,13 @@ public: } private: - FORCEINLINE bool TryLockInline( const uint32 threadId ) volatile + FORCEINLINE bool TryLockInline( const uintp threadId ) volatile { - if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( (volatile long *)&m_ownerID, (long)threadId, 0 ) ) +#if PLATFORM_64BITS + if ( threadId != m_ownerID && !ThreadInterlockedAssignIf64( &m_ownerID, threadId, 0 ) ) +#else + if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( &m_ownerID, threadId, 0 ) ) +#endif return false; ThreadMemoryBarrier(); @@ -718,12 +798,12 @@ private: return true; } - bool TryLock( const uint32 threadId ) volatile + bool TryLock( const uintp threadId ) volatile { return TryLockInline( threadId ); } - PLATFORM_CLASS void Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile; + PLATFORM_CLASS void Lock( const uintp threadId, unsigned nSpinSleepTime ) volatile; public: bool TryLock() volatile @@ -743,7 +823,7 @@ public: #endif void Lock( unsigned int nSpinSleepTime = 0 ) volatile { - const uint32 threadId = ThreadGetCurrentId(); + const uintp threadId = ThreadGetCurrentId(); if ( !TryLockInline( threadId ) ) { @@ -779,7 +859,11 @@ public: if ( !m_depth ) { ThreadMemoryBarrier(); - ThreadInterlockedExchange( &m_ownerID, 0 ); +#if PLATFORM_64BITS + ThreadInterlockedExchange64( &m_ownerID, 0 ); +#else + ThreadInterlockedExchange( &m_ownerID, 0 ); +#endif } } @@ -792,10 +876,10 @@ public: bool AssertOwnedByCurrentThread() { return true; } void SetTrace( bool ) {} - uint32 GetOwnerId() const { return m_ownerID; } + uintp GetOwnerId() const { return m_ownerID; } int GetDepth() const { return m_depth; } private: - volatile uint32 m_ownerID; + volatile uintp m_ownerID; int m_depth; }; @@ -838,7 +922,7 @@ public: static bool AssertOwnedByCurrentThread() { return true; } static void SetTrace( bool b ) {} - static uint32 GetOwnerId() { return 0; } + static uintp GetOwnerId() { return 0; } static int GetDepth() { return 0; } }; @@ -1182,11 +1266,7 @@ private: class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock { public: - CThreadSpinRWLock() - { - COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); - Assert( (intp)this % 8 == 0 ); - } + CThreadSpinRWLock() { Assert( (intp)this % 8 == 0 ); memset( this, 0, sizeof( *this ) ); } bool TryLockForWrite(); bool TryLockForRead(); @@ -1218,8 +1298,8 @@ private: }; bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ); - bool TryLockForWrite( const uint32 threadId ); - void SpinLockForWrite( const uint32 threadId ); + bool TryLockForWrite( const uintp threadId ); + void SpinLockForWrite( const uintp threadId ); volatile LockInfo_t m_lockInfo; CInterlockedInt m_nWriters; @@ -1751,10 +1831,16 @@ inline void CThreadRWLock::UnlockRead() inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ) { +#if PLATFORM_64BITS + COMPILE_TIME_ASSERT(sizeof(LockInfo_t) == 16); + return ThreadInterlockedAssignIf128( (int128 *)&m_lockInfo, *((int128 *)&newValue), *((int128 *)&comperand) ); +#else + COMPILE_TIME_ASSERT(sizeof(LockInfo_t) == 8); return ThreadInterlockedAssignIf64( (int64 *)&m_lockInfo, *((int64 *)&newValue), *((int64 *)&comperand) ); +#endif } -inline bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId ) +inline bool CThreadSpinRWLock::TryLockForWrite( const uintp threadId ) { // In order to grab a write lock, there can be no readers and no owners of the write lock if ( m_lockInfo.m_nReaders > 0 || ( m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId ) ) @@ -1812,7 +1898,7 @@ inline bool CThreadSpinRWLock::TryLockForRead() inline void CThreadSpinRWLock::LockForWrite() { - const uint32 threadId = ThreadGetCurrentId(); + const uintp threadId = ThreadGetCurrentId(); m_nWriters++; diff --git a/public/tier0/vcrmode.h b/public/tier0/vcrmode.h index 2af8a608..52a96f09 100644 --- a/public/tier0/vcrmode.h +++ b/public/tier0/vcrmode.h @@ -190,7 +190,7 @@ typedef struct VCR_s void *lpStartAddress, void *lpParameter, unsigned long dwCreationFlags, - unsigned long *lpThreadID ); + uintp *lpThreadID ); unsigned long (*Hook_WaitForSingleObject)( void *handle, diff --git a/public/tier1/CommandBuffer.h b/public/tier1/CommandBuffer.h index d9bfd7de..d7f842f5 100644 --- a/public/tier1/CommandBuffer.h +++ b/public/tier1/CommandBuffer.h @@ -28,7 +28,7 @@ class CUtlBuffer; //----------------------------------------------------------------------------- // Invalid command handle //----------------------------------------------------------------------------- -typedef int CommandHandle_t; +typedef intp CommandHandle_t; enum { COMMAND_BUFFER_INVALID_COMMAND_HANDLE = 0 @@ -100,11 +100,11 @@ private: }; // Insert a command into the command queue at the appropriate time - void InsertCommandAtAppropriateTime( int hCommand ); + void InsertCommandAtAppropriateTime( CommandHandle_t hCommand ); // Insert a command into the command queue // Only happens if it's inserted while processing other commands - void InsertImmediateCommand( int hCommand ); + void InsertImmediateCommand( CommandHandle_t hCommand ); // Insert a command into the command queue bool InsertCommand( const char *pArgS, int nCommandSize, int nTick ); @@ -125,7 +125,7 @@ private: int m_nCurrentTick; int m_nLastTickToProcess; int m_nWaitDelayTicks; - int m_hNextCommand; + CommandHandle_t m_hNextCommand; int m_nMaxArgSBufferLength; bool m_bIsProcessingCommands; bool m_bWaitEnabled; diff --git a/public/tier1/KeyValues.h b/public/tier1/KeyValues.h index 3f0544a1..151aa281 100644 --- a/public/tier1/KeyValues.h +++ b/public/tier1/KeyValues.h @@ -115,7 +115,7 @@ public: void SetName( const char *setName); // gets the name as a unique int - int GetNameSymbol() const { return m_iKeyName; } + intp GetNameSymbol() const { return m_iKeyName; } // File access. Set UsesEscapeSequences true, if resource file/buffer uses Escape Sequences (eg \n, \t) void UsesEscapeSequences(bool state); // default false @@ -132,7 +132,7 @@ public: // Find a keyValue, create it if it is not found. // Set bCreate to true to create the key if it doesn't already exist (which ensures a valid pointer will be returned) KeyValues *FindKey(const char *keyName, bool bCreate = false); - KeyValues *FindKey(int keySymbol) const; + KeyValues *FindKey(intp keySymbol) const; KeyValues *CreateNewKey(); // creates a new key, with an autogenerated name. name is guaranteed to be an integer, of value 1 higher than the highest other integer key name void AddSubKey( KeyValues *pSubkey ); // Adds a subkey. Make sure the subkey isn't a child of some other keyvalues void RemoveSubKey(KeyValues *subKey); // removes a subkey from the list, DOES NOT DELETE IT @@ -311,7 +311,7 @@ private: void FreeAllocatedValue(); void AllocateValueBlock(int size); - int m_iKeyName; // keyname is a symbol defined in KeyValuesSystem + intp m_iKeyName; // keyname is a symbol defined in KeyValuesSystem // These are needed out of the union because the API returns string pointers char *m_sValue; @@ -338,22 +338,22 @@ private: private: // Statics to implement the optional growable string table // Function pointers that will determine which mode we are in - static int (*s_pfGetSymbolForString)( const char *name, bool bCreate ); - static const char *(*s_pfGetStringForSymbol)( int symbol ); + static intp (*s_pfGetSymbolForString)( const char *name, bool bCreate ); + static const char *(*s_pfGetStringForSymbol)( intp symbol ); static CKeyValuesGrowableStringTable *s_pGrowableStringTable; public: // Functions that invoke the default behavior - static int GetSymbolForStringClassic( const char *name, bool bCreate = true ); - static const char *GetStringForSymbolClassic( int symbol ); + static intp GetSymbolForStringClassic( const char *name, bool bCreate = true ); + static const char *GetStringForSymbolClassic( intp symbol ); // Functions that use the growable string table - static int GetSymbolForStringGrowable( const char *name, bool bCreate = true ); - static const char *GetStringForSymbolGrowable( int symbol ); + static intp GetSymbolForStringGrowable( const char *name, bool bCreate = true ); + static const char *GetStringForSymbolGrowable( intp symbol ); // Functions to get external access to whichever of the above functions we're going to call. - static int CallGetSymbolForString( const char *name, bool bCreate = true ) { return s_pfGetSymbolForString( name, bCreate ); } - static const char *CallGetStringForSymbol( int symbol ) { return s_pfGetStringForSymbol( symbol ); } + static intp CallGetSymbolForString( const char *name, bool bCreate = true ) { return s_pfGetSymbolForString( name, bCreate ); } + static const char *CallGetStringForSymbol( intp symbol ) { return s_pfGetStringForSymbol( symbol ); } }; typedef KeyValues::AutoDelete KeyValuesAD; diff --git a/public/tier1/bitbuf.h b/public/tier1/bitbuf.h index a625f5eb..979cb290 100644 --- a/public/tier1/bitbuf.h +++ b/public/tier1/bitbuf.h @@ -225,7 +225,7 @@ public: void WriteByte(int val); void WriteShort(int val); void WriteWord(int val); - void WriteLong(long val); + void WriteLong(int32 val); void WriteLongLong(int64 val); void WriteFloat(float val); bool WriteBytes( const void *pBuf, int nBytes ); @@ -255,7 +255,7 @@ public: public: // The current buffer. - unsigned long* RESTRICT m_pData; + uint32* RESTRICT m_pData; int m_nDataBytes; int m_nDataBits; @@ -342,7 +342,7 @@ BITBUF_INLINE void bf_write::WriteOneBitNoCheck(int nValue) else m_pData[m_iCurBit >> 5] &= ~(1u << (m_iCurBit & 31)); #else - extern unsigned long g_LittleBits[32]; + extern uint32 g_LittleBits[32]; if(nValue) m_pData[m_iCurBit >> 5] |= g_LittleBits[m_iCurBit & 31]; else @@ -379,7 +379,7 @@ inline void bf_write::WriteOneBitAt( int iBit, int nValue ) else m_pData[iBit >> 5] &= ~(1u << (iBit & 31)); #else - extern unsigned long g_LittleBits[32]; + extern uint32 g_LittleBits[32]; if(nValue) m_pData[iBit >> 5] |= g_LittleBits[iBit & 31]; else @@ -393,7 +393,7 @@ BITBUF_INLINE void bf_write::WriteUBitLong( unsigned int curData, int numbits, b // Make sure it doesn't overflow. if ( bCheckRange && numbits < 32 ) { - if ( curData >= (unsigned long)(1 << numbits) ) + if ( curData >= (uint32)(1 << numbits) ) { CallErrorHandler( BITBUFERROR_VALUE_OUT_OF_RANGE, GetDebugName() ); } @@ -414,8 +414,8 @@ BITBUF_INLINE void bf_write::WriteUBitLong( unsigned int curData, int numbits, b m_iCurBit += numbits; // Mask in a dword. - Assert( (iDWord*4 + sizeof(long)) <= (unsigned int)m_nDataBytes ); - unsigned long * RESTRICT pOut = &m_pData[iDWord]; + Assert( (iDWord*4 + sizeof(int32)) <= (unsigned int)m_nDataBytes ); + uint32 * RESTRICT pOut = &m_pData[iDWord]; // Rotate data into dword alignment curData = (curData << iCurBitMasked) | (curData >> (32 - iCurBitMasked)); @@ -427,8 +427,8 @@ BITBUF_INLINE void bf_write::WriteUBitLong( unsigned int curData, int numbits, b // Only look beyond current word if necessary (avoid access violation) int i = mask2 & 1; - unsigned long dword1 = LoadLittleDWord( pOut, 0 ); - unsigned long dword2 = LoadLittleDWord( pOut, i ); + uint32 dword1 = LoadLittleDWord( pOut, 0 ); + uint32 dword2 = LoadLittleDWord( pOut, i ); // Drop bits into place dword1 ^= ( mask1 & ( curData ^ dword1 ) ); @@ -467,7 +467,7 @@ BITBUF_INLINE void bf_write::WriteBitFloat(float val) { int32 intVal; - Assert(sizeof(long) == sizeof(float)); + Assert(sizeof(int32) == sizeof(float)); Assert(sizeof(float) == 4); Q_memcpy( &intVal, &val, sizeof(intVal)); @@ -603,7 +603,7 @@ public: BITBUF_INLINE int ReadByte() { return ReadUBitLong(8); } BITBUF_INLINE int ReadShort() { return (short)ReadUBitLong(16); } BITBUF_INLINE int ReadWord() { return ReadUBitLong(16); } - BITBUF_INLINE long ReadLong() { return ReadUBitLong(32); } + BITBUF_INLINE int32 ReadLong() { return ReadUBitLong(32); } int64 ReadLongLong(); float ReadFloat(); bool ReadBytes(void *pOut, int nBytes); @@ -728,7 +728,7 @@ inline bool bf_read::CheckForOverflow(int nBits) inline int bf_read::ReadOneBitNoCheck() { #if VALVE_LITTLE_ENDIAN - unsigned int value = ((unsigned long * RESTRICT)m_pData)[m_iCurBit >> 5] >> (m_iCurBit & 31); + unsigned int value = ((uint32 * RESTRICT)m_pData)[m_iCurBit >> 5] >> (m_iCurBit & 31); #else unsigned char value = m_pData[m_iCurBit >> 3] >> (m_iCurBit & 7); #endif @@ -787,12 +787,12 @@ BITBUF_INLINE unsigned int bf_read::ReadUBitLong( int numbits ) RESTRICT #if __i386__ unsigned int bitmask = (2 << (numbits-1)) - 1; #else - extern unsigned long g_ExtraMasks[33]; + extern uint32 g_ExtraMasks[33]; unsigned int bitmask = g_ExtraMasks[numbits]; #endif - unsigned int dw1 = LoadLittleDWord( (unsigned long* RESTRICT)m_pData, iWordOffset1 ) >> iStartBit; - unsigned int dw2 = LoadLittleDWord( (unsigned long* RESTRICT)m_pData, iWordOffset2 ) << (32 - iStartBit); + unsigned int dw1 = LoadLittleDWord( (uint32* RESTRICT)m_pData, iWordOffset1 ) >> iStartBit; + unsigned int dw2 = LoadLittleDWord( (uint32* RESTRICT)m_pData, iWordOffset2 ) << (32 - iStartBit); return (dw1 | dw2) & bitmask; } diff --git a/public/tier1/datamanager.h b/public/tier1/datamanager.h index 88030547..19342a39 100644 --- a/public/tier1/datamanager.h +++ b/public/tier1/datamanager.h @@ -251,7 +251,7 @@ private: inline unsigned short CDataManagerBase::FromHandle( memhandle_t handle ) { - unsigned int fullWord = (unsigned int)handle; + uintp fullWord = (uintp)handle; unsigned short serial = fullWord>>16; unsigned short index = fullWord & 0xFFFF; index--; diff --git a/public/tier1/refcount.h b/public/tier1/refcount.h index 9c756b84..8f39e418 100644 --- a/public/tier1/refcount.h +++ b/public/tier1/refcount.h @@ -193,8 +193,8 @@ public: class CRefMT { public: - static int Increment( int *p) { return ThreadInterlockedIncrement( (long *)p ); } - static int Decrement( int *p) { return ThreadInterlockedDecrement( (long *)p ); } + static int Increment( int *p) { return ThreadInterlockedIncrement( (int32 *)p ); } + static int Decrement( int *p) { return ThreadInterlockedDecrement( (int32 *)p ); } }; class CRefST diff --git a/public/tier1/utlbuffer.h b/public/tier1/utlbuffer.h index aaa95d8a..ec1b1188 100644 --- a/public/tier1/utlbuffer.h +++ b/public/tier1/utlbuffer.h @@ -189,6 +189,7 @@ public: unsigned int GetUnsignedInt( ); float GetFloat( ); double GetDouble( ); + void * GetPtr(); template void GetString( char( &pString )[maxLenInChars] ) { GetStringInternal( pString, maxLenInChars ); @@ -278,6 +279,7 @@ public: void PutUnsignedInt( unsigned int u ); void PutFloat( float f ); void PutDouble( double d ); + void PutPtr( void * ); // Writes the pointer, not the pointed to void PutString( const char* pString ); void Put( const void* pMem, int size ); @@ -757,6 +759,18 @@ inline float CUtlBuffer::GetFloat( ) return f; } +inline void *CUtlBuffer::GetPtr( ) +{ + void *p; + // LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal +#ifndef PLATFORM_64BITS + p = ( void* )GetUnsignedInt(); +#else + p = ( void* )GetInt64(); +#endif + return p; +} + inline double CUtlBuffer::GetDouble( ) { double d; @@ -986,6 +1000,19 @@ inline void CUtlBuffer::PutDouble( double d ) PutType( d, "%f" ); } +inline void CUtlBuffer::PutPtr( void *p ) +{ + // LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal + if (!IsText()) + { + PutTypeBin( p ); + } + else + { + Printf( "0x%p", p ); + } +} + //----------------------------------------------------------------------------- // Am I a text buffer? diff --git a/public/tier1/utlhandletable.h b/public/tier1/utlhandletable.h index 22f54357..f8b2b463 100644 --- a/public/tier1/utlhandletable.h +++ b/public/tier1/utlhandletable.h @@ -59,13 +59,21 @@ public: private: struct HandleType_t { + // MoeMod : use union to fix strict alias bug HandleType_t( unsigned int i, unsigned int s ) : nIndex( i ), nSerial( s ) { Assert( i < ( 1 << HandleBits ) ); Assert( s < ( 1 << ( 31 - HandleBits ) ) ); } - unsigned int nIndex : HandleBits; - unsigned int nSerial : 31 - HandleBits; + HandleType_t( UtlHandle_t handle ) : handle(handle) {} + + union { + UtlHandle_t handle; + struct { + unsigned int nIndex : HandleBits; + unsigned int nSerial : 31 - HandleBits; + }; + }; }; struct EntryType_t @@ -186,7 +194,7 @@ bool CUtlHandleTable::IsHandleValid( UtlHandle_t handle ) const return false; unsigned int nIndex = GetListIndex( handle ); - AssertOnce( nIndex < ( unsigned int )m_list.Count() ); + //AssertOnce( nIndex < ( unsigned int )m_list.Count() ); if ( nIndex >= ( unsigned int )m_list.Count() ) return false; @@ -241,20 +249,26 @@ int CUtlHandleTable::GetIndexFromHandle( UtlHandle_t h ) const template< class T, int HandleBits > unsigned int CUtlHandleTable::GetSerialNumber( UtlHandle_t handle ) { - return ( ( HandleType_t* )&handle )->nSerial; + //return ( ( HandleType_t* )&handle )->nSerial; + //return (handle >> HandleBits) & ((1 << (32 - HandleBits)) - 1); + return HandleType_t(handle).nSerial; } template< class T, int HandleBits > unsigned int CUtlHandleTable::GetListIndex( UtlHandle_t handle ) { - return ( ( HandleType_t* )&handle )->nIndex; + //return ( ( HandleType_t* )&handle )->nIndex; + //return handle & ((1 << HandleBits) - 1); + return HandleType_t(handle).nIndex; } template< class T, int HandleBits > UtlHandle_t CUtlHandleTable::CreateHandle( unsigned int nSerial, unsigned int nIndex ) { HandleType_t h( nIndex, nSerial ); - return *( UtlHandle_t* )&h; + //return *( UtlHandle_t* )&h; + //return (nIndex & ((1 << HandleBits) - 1)) | (nSerial << HandleBits); + return h.handle; } @@ -268,7 +282,7 @@ const typename CUtlHandleTable::EntryType_t *CUtlHandleTable= ( unsigned int )m_list.Count() ) return NULL; diff --git a/public/tier1/utlhash.h b/public/tier1/utlhash.h index 7207b597..19fb450b 100644 --- a/public/tier1/utlhash.h +++ b/public/tier1/utlhash.h @@ -461,7 +461,7 @@ inline void CUtlHash::Log( const char *filename ) // Number of buckets must be a power of 2. // Key must be 32-bits (unsigned int). // -typedef int UtlHashFastHandle_t; +typedef intp UtlHashFastHandle_t; #define UTLHASH_POOL_SCALAR 2 @@ -617,7 +617,7 @@ template inline UtlHashFastHandle_t CUtlHashFast inline UtlHashFastHandle_t CUtlHashFast::FastInsert( unsigned int uiKey, const Data &data ) { // Get a new element from the pool. - int iHashData = m_aDataPool.Alloc( true ); + intp iHashData = m_aDataPool.Alloc( true ); HashFastData_t *pHashData = &m_aDataPool[iHashData]; if ( !pHashData ) return InvalidHandle(); @@ -671,7 +671,7 @@ template inline UtlHashFastHandle_t CUtlHashFast inline Data const &CUtlHashFast class CUtlHashFixedGenericHash @@ -753,7 +753,7 @@ public: void Purge( void ); // Invalid handle. - static UtlHashFixedHandle_t InvalidHandle( void ) { return ( UtlHashFixedHandle_t )~0; } + static UtlHashFixedHandle_t InvalidHandle( void ) { return ( UtlHashFixedHandle_t )-1; } // Size. int Count( void ); @@ -858,7 +858,7 @@ template inline UtlHashFixedHandle pHashData->m_Data = data; m_nElements++; - return (UtlHashFixedHandle_t)pHashData; + return (UtlHashFixedHandle_t)(intp)pHashData; } //----------------------------------------------------------------------------- @@ -895,7 +895,7 @@ template inline UtlHashFixedHandle for ( UtlPtrLinkedListIndex_t iElement = bucket.Head(); iElement != bucket.InvalidIndex(); iElement = bucket.Next( iElement ) ) { if ( bucket[iElement].m_uiKey == uiKey ) - return (UtlHashFixedHandle_t)iElement; + return (UtlHashFixedHandle_t)(intp)iElement; } return InvalidHandle(); diff --git a/public/tier1/utllinkedlist.h b/public/tier1/utllinkedlist.h index dda8162d..04872008 100644 --- a/public/tier1/utllinkedlist.h +++ b/public/tier1/utllinkedlist.h @@ -389,15 +389,16 @@ private: // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +// MoeMod : CUtlFixedMemory uses intp as index type template < class T > -class CUtlFixedLinkedList : public CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > > +class CUtlFixedLinkedList : public CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > > { public: CUtlFixedLinkedList( int growSize = 0, int initSize = 0 ) - : CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > >( growSize, initSize ) {} + : CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > >( growSize, initSize ) {} - typedef CUtlLinkedList< T, int, true, int, CUtlFixedMemory< UtlLinkedListElem_t< T, int > > > BaseClass; - bool IsValidIndex( int i ) const + typedef CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > > BaseClass; + bool IsValidIndex( intp i ) const { if ( !BaseClass::Memory().IsIdxValid( i ) ) return false; @@ -414,7 +415,7 @@ public: } private: - int MaxElementIndex() const { Assert( 0 ); return BaseClass::InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1 + intp MaxElementIndex() const { Assert( 0 ); return BaseClass::InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1 void ResetDbgInfo() {} }; @@ -439,7 +440,7 @@ CUtlLinkedList::CUtlLinkedList( int growSize, int initSize ) : m_Memory( growSize, initSize ), m_LastAlloc( m_Memory.InvalidIterator() ) { // Prevent signed non-int datatypes - COMPILE_TIME_ASSERT( sizeof(S) == 4 || ( ( (S)-1 ) > 0 ) ); + COMPILE_TIME_ASSERT( sizeof(S) == sizeof(M::InvalidIndex()) || ( ( (S)-1 ) > 0 ) ); ConstructList(); ResetDbgInfo(); } @@ -797,7 +798,7 @@ inline I CUtlLinkedList::AddToHead( ) template inline I CUtlLinkedList::AddToTail( ) { - return InsertBefore( InvalidIndex() ); + return InsertBefore( InvalidIndex() ); } diff --git a/public/tier2/riff.h b/public/tier2/riff.h index e24b090a..cc8be167 100644 --- a/public/tier2/riff.h +++ b/public/tier2/riff.h @@ -25,12 +25,12 @@ class IFileReadBinary { public: - virtual int open( const char *pFileName ) = 0; - virtual int read( void *pOutput, int size, int file ) = 0; - virtual void close( int file ) = 0; - virtual void seek( int file, int pos ) = 0; - virtual unsigned int tell( int file ) = 0; - virtual unsigned int size( int file ) = 0; + virtual intp open( const char *pFileName ) = 0; + virtual int read( void *pOutput, int size, intp file ) = 0; + virtual void close( intp file ) = 0; + virtual void seek( intp file, int pos ) = 0; + virtual unsigned int tell( intp file ) = 0; + virtual unsigned int size( intp file ) = 0; }; @@ -56,7 +56,7 @@ private: const InFileRIFF & operator=( const InFileRIFF & ); IFileReadBinary &m_io; - int m_file; + intp m_file; unsigned int m_riffName; unsigned int m_riffSize; }; @@ -126,7 +126,7 @@ private: const OutFileRIFF & operator=( const OutFileRIFF & ); IFileWriteBinary &m_io; - int m_file; + intp m_file; unsigned int m_riffName; unsigned int m_riffSize; unsigned int m_nNamePos; diff --git a/public/togl/linuxwin/dxabstract.h b/public/togl/linuxwin/dxabstract.h index a4dfc073..2e2b54ae 100644 --- a/public/togl/linuxwin/dxabstract.h +++ b/public/togl/linuxwin/dxabstract.h @@ -249,7 +249,7 @@ struct TOGL_CLASS IDirect3DQuery9 : public IDirect3DResource9 //was IUnknown GLMContext *m_ctx; CGLMQuery *m_query; - uint m_nIssueStartThreadID, m_nIssueEndThreadID; + uintp m_nIssueStartThreadID, m_nIssueEndThreadID; uint m_nIssueStartDrawCallIndex, m_nIssueEndDrawCallIndex; uint m_nIssueStartFrameIndex, m_nIssueEndFrameIndex; uint m_nIssueStartQueryCreationCounter, m_nIssueEndQueryCreationCounter; @@ -373,7 +373,7 @@ struct RenderTargetState_t static inline bool LessFunc( const RenderTargetState_t &lhs, const RenderTargetState_t &rhs ) { - COMPILE_TIME_ASSERT( sizeof( lhs.m_pRenderTargets[0] ) == sizeof( uint32 ) ); + COMPILE_TIME_ASSERT( sizeof( lhs.m_pRenderTargets[0] ) == sizeof( uintp ) ); uint64 lhs0 = reinterpret_cast(lhs.m_pRenderTargets)[0]; uint64 rhs0 = reinterpret_cast(rhs.m_pRenderTargets)[0]; if ( lhs0 < rhs0 ) @@ -563,7 +563,7 @@ struct TOGL_CLASS IDirect3DDevice9 : public IUnknown void TOGLMETHODCALLTYPE AcquireThreadOwnership( ); void TOGLMETHODCALLTYPE ReleaseThreadOwnership( ); - inline DWORD TOGLMETHODCALLTYPE GetCurrentOwnerThreadId() const { return m_ctx->m_nCurOwnerThreadId; } + inline uintp TOGLMETHODCALLTYPE GetCurrentOwnerThreadId() const { return m_ctx->m_nCurOwnerThreadId; } FORCEINLINE void TOGLMETHODCALLTYPE SetMaxUsedVertexShaderConstantsHint( uint nMaxReg ); void TOGLMETHODCALLTYPE SetMaxUsedVertexShaderConstantsHintNonInline( uint nMaxReg ); diff --git a/public/togl/linuxwin/glmgr.h b/public/togl/linuxwin/glmgr.h index 7e76a682..b9e5d0d8 100644 --- a/public/togl/linuxwin/glmgr.h +++ b/public/togl/linuxwin/glmgr.h @@ -1534,7 +1534,7 @@ class GLMContext #endif FORCEINLINE void SetMaxUsedVertexShaderConstantsHint( uint nMaxConstants ); - FORCEINLINE DWORD GetCurrentOwnerThreadId() const { return m_nCurOwnerThreadId; } + FORCEINLINE uintp GetCurrentOwnerThreadId() const { return m_nCurOwnerThreadId; } protected: friend class GLMgr; // only GLMgr can make GLMContext objects @@ -1663,7 +1663,7 @@ class GLMContext // members------------------------------------------ // context - DWORD m_nCurOwnerThreadId; + uintp m_nCurOwnerThreadId; uint m_nThreadOwnershipReleaseCounter; bool m_bUseSamplerObjects; diff --git a/public/togles/linuxwin/dxabstract.h b/public/togles/linuxwin/dxabstract.h index a8e74590..93ef9267 100644 --- a/public/togles/linuxwin/dxabstract.h +++ b/public/togles/linuxwin/dxabstract.h @@ -563,7 +563,7 @@ struct TOGL_CLASS IDirect3DDevice9 : public IUnknown void TOGLMETHODCALLTYPE AcquireThreadOwnership( ); void TOGLMETHODCALLTYPE ReleaseThreadOwnership( ); - inline DWORD TOGLMETHODCALLTYPE GetCurrentOwnerThreadId() const { return m_ctx->m_nCurOwnerThreadId; } + inline uintp TOGLMETHODCALLTYPE GetCurrentOwnerThreadId() const { return m_ctx->m_nCurOwnerThreadId; } FORCEINLINE void TOGLMETHODCALLTYPE SetMaxUsedVertexShaderConstantsHint( uint nMaxReg ); void TOGLMETHODCALLTYPE SetMaxUsedVertexShaderConstantsHintNonInline( uint nMaxReg ); diff --git a/public/togles/linuxwin/glmgr.h b/public/togles/linuxwin/glmgr.h index 40ae90f2..3729911e 100644 --- a/public/togles/linuxwin/glmgr.h +++ b/public/togles/linuxwin/glmgr.h @@ -1448,7 +1448,7 @@ class GLMContext #endif FORCEINLINE void SetMaxUsedVertexShaderConstantsHint( uint nMaxConstants ); - FORCEINLINE DWORD GetCurrentOwnerThreadId() const { return m_nCurOwnerThreadId; } + FORCEINLINE uintp GetCurrentOwnerThreadId() const { return m_nCurOwnerThreadId; } protected: friend class GLMgr; // only GLMgr can make GLMContext objects @@ -1573,7 +1573,7 @@ class GLMContext // members------------------------------------------ // context - DWORD m_nCurOwnerThreadId; + uintp m_nCurOwnerThreadId; uint m_nThreadOwnershipReleaseCounter; bool m_bUseSamplerObjects; diff --git a/public/vgui/VGUI.h b/public/vgui/VGUI.h index 2faff5df..f72630c8 100644 --- a/public/vgui/VGUI.h +++ b/public/vgui/VGUI.h @@ -39,6 +39,14 @@ typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; +#ifdef PLATFORM_64BITS +typedef long long intp; +typedef unsigned long long uintp; +#else +typedef int intp; +typedef unsigned int uintp; +#endif + #ifndef _WCHAR_T_DEFINED // DAL - wchar_t is a built in define in gcc 3.2 with a size of 4 bytes #if !defined( __x86_64__ ) && !defined( __WCHAR_TYPE__ ) @@ -54,7 +62,7 @@ namespace vgui { // handle to an internal vgui panel // this is the only handle to a panel that is valid across dll boundaries -typedef unsigned int VPANEL; +typedef uintp VPANEL; // handles to vgui objects // NULL values signify an invalid value @@ -63,7 +71,7 @@ typedef unsigned long HScheme; typedef unsigned long HTexture; typedef unsigned long HCursor; typedef unsigned long HPanel; -const HPanel INVALID_PANEL = 0xffffffff; +const HPanel INVALID_PANEL = (HPanel)-1; typedef unsigned long HFont; const HFont INVALID_FONT = 0; // the value of an invalid font handle } diff --git a/public/vgui_controls/ListPanel.h b/public/vgui_controls/ListPanel.h index 9248856e..f60c5a66 100644 --- a/public/vgui_controls/ListPanel.h +++ b/public/vgui_controls/ListPanel.h @@ -49,7 +49,7 @@ public: } KeyValues *kv; - unsigned int userData; + uintp userData; KeyValues *m_pDragData; bool m_bImage; int m_nImageIndex; @@ -115,17 +115,17 @@ public: // DATA HANDLING // data->GetName() is used to uniquely identify an item // data sub items are matched against column header name to be used in the table - virtual int AddItem(const KeyValues *data, unsigned int userData, bool bScrollToItem, bool bSortOnAdd); // Takes a copy of the data for use in the table. Returns the index the item is at. + virtual int AddItem(const KeyValues *data, uintp userData, bool bScrollToItem, bool bSortOnAdd); // Takes a copy of the data for use in the table. Returns the index the item is at. void SetItemDragData( int itemID, const KeyValues *data ); // Makes a copy of the keyvalues to store in the table. Used when dragging from the table. Only used if the caller enables drag support virtual int GetItemCount( void ); // returns the number of VISIBLE items virtual int GetItem(const char *itemName); // gets the row index of an item by name (data->GetName()) virtual KeyValues *GetItem(int itemID); // returns pointer to data the row holds virtual int GetItemCurrentRow(int itemID); // returns -1 if invalid index or item not visible virtual int GetItemIDFromRow(int currentRow); // returns -1 if invalid row - virtual unsigned int GetItemUserData(int itemID); + virtual uintp GetItemUserData(int itemID); virtual ListPanelItem *GetItemData(int itemID); - virtual void SetUserData( int itemID, unsigned int userData ); - virtual int GetItemIDFromUserData( unsigned int userData ); + virtual void SetUserData( int itemID, uintp userData ); + virtual int GetItemIDFromUserData( uintp userData ); virtual void ApplyItemChanges(int itemID); // applies any changes to the data, performed by modifying the return of GetItem() above virtual void RemoveItem(int itemID); // removes an item from the table (changing the indices of all following items) virtual void RereadAllItems(); // updates the view with the new data diff --git a/public/vstdlib/IKeyValuesSystem.h b/public/vstdlib/IKeyValuesSystem.h index e999dd81..c6e41a55 100644 --- a/public/vstdlib/IKeyValuesSystem.h +++ b/public/vstdlib/IKeyValuesSystem.h @@ -13,8 +13,8 @@ #include "vstdlib/vstdlib.h" // handle to a KeyValues key name symbol -typedef int HKeySymbol; -#define INVALID_KEY_SYMBOL (-1) +typedef intp HKeySymbol; +#define INVALID_KEY_SYMBOL (HKeySymbol)(-1) class IBaseFileSystem; class KeyValues; diff --git a/public/vstdlib/jobthread.h b/public/vstdlib/jobthread.h index 559937b3..306e1308 100644 --- a/public/vstdlib/jobthread.h +++ b/public/vstdlib/jobthread.h @@ -1147,7 +1147,7 @@ private: // Raw thread launching //----------------------------------------------------------------------------- -inline unsigned FunctorExecuteThread( void *pParam ) +inline uintp FunctorExecuteThread( void *pParam ) { CFunctor *pFunctor = (CFunctor *)pParam; (*pFunctor)(); diff --git a/soundsystem/snd_wave_source.cpp b/soundsystem/snd_wave_source.cpp index 765a2b3e..1addc80e 100644 --- a/soundsystem/snd_wave_source.cpp +++ b/soundsystem/snd_wave_source.cpp @@ -31,7 +31,7 @@ public: return (int)g_pFullFileSystem->Open( pFileName, "rb", "GAME" ); } - int read( void *pOutput, int size, int file ) + int read( void *pOutput, int size, intp file ) { if ( !file ) return 0; @@ -39,7 +39,7 @@ public: return g_pFullFileSystem->Read( pOutput, size, (FileHandle_t)file ); } - void seek( int file, int pos ) + void seek( intp file, int pos ) { if ( !file ) return; @@ -47,7 +47,7 @@ public: g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); } - unsigned int tell( int file ) + unsigned int tell( intp file ) { if ( !file ) return 0; @@ -55,7 +55,7 @@ public: return g_pFullFileSystem->Tell( (FileHandle_t)file ); } - unsigned int size( int file ) + unsigned int size( intp file ) { if ( !file ) return 0; @@ -63,7 +63,7 @@ public: return g_pFullFileSystem->Size( (FileHandle_t)file ); } - void close( int file ) + void close( intp file ) { if ( !file ) return; diff --git a/studiorender/r_studiodecal.cpp b/studiorender/r_studiodecal.cpp index 52ff3506..53524cde 100644 --- a/studiorender/r_studiodecal.cpp +++ b/studiorender/r_studiodecal.cpp @@ -137,7 +137,7 @@ void CStudioRender::DestroyDecalList( StudioDecalHandle_t hDecal ) RemoveDecalListFromLRU( hDecal ); - int h = (int)hDecal; + intp h = (intp)hDecal; // Clean up for (int i = 0; i < m_DecalList[h].m_nLods; i++ ) { @@ -1130,7 +1130,7 @@ void CStudioRender::AddDecal( StudioDecalHandle_t hDecal, const StudioRenderCont return; // For each lod, build the decal list - int h = (int)hDecal; + intp h = (intp)hDecal; DecalModelList_t& list = m_DecalList[h]; if ( list.m_pHardwareData->m_NumStudioMeshes == 0 ) @@ -1215,7 +1215,7 @@ void CStudioRender::AddDecal( StudioDecalHandle_t hDecal, const StudioRenderCont { DecalId_t nRetireID = m_DecalLRU[ m_DecalLRU.Head() ].m_nDecalId; StudioDecalHandle_t hRetire = m_DecalLRU[ m_DecalLRU.Head() ].m_hDecalHandle; - DecalModelList_t &modelList = m_DecalList[(int)hRetire]; + DecalModelList_t &modelList = m_DecalList[(intp)hRetire]; RetireDecal( modelList, nRetireID, modelList.m_pHardwareData->m_RootLOD, modelList.m_pHardwareData->m_NumLODs ); } } @@ -1229,7 +1229,7 @@ void CStudioRender::AddDecal( StudioDecalHandle_t hDecal, const StudioRenderCont { DecalId_t nRetireID = m_DecalLRU[ m_DecalLRU.Head() ].m_nDecalId; StudioDecalHandle_t hRetire = m_DecalLRU[ m_DecalLRU.Head() ].m_hDecalHandle; - DecalModelList_t &modelList = m_DecalList[(int)hRetire]; + DecalModelList_t &modelList = m_DecalList[(intp)hRetire]; RetireDecal( modelList, nRetireID, modelList.m_pHardwareData->m_RootLOD, modelList.m_pHardwareData->m_NumLODs ); } @@ -1238,7 +1238,7 @@ void CStudioRender::AddDecal( StudioDecalHandle_t hDecal, const StudioRenderCont DecalHistory_t *pDecalHistory = &pHistoryList->Element( pHistoryList->Head() ); DecalId_t nRetireID = pDecalHistory->m_nId; StudioDecalHandle_t hRetire = hDecal; - RetireDecal( m_DecalList[(int)hRetire], nRetireID, nRootLOD, nFinalLOD ); + RetireDecal( m_DecalList[(intp)hRetire], nRetireID, nRootLOD, nFinalLOD ); } // Search all LODs for an overflow condition and retire those also @@ -1902,7 +1902,7 @@ void CStudioRender::DrawDecal( const DrawModelInfo_t &drawInfo, int lod, int bod // FIXME: Body stuff isn't hooked in at all for decals // Get the decal list for this lod - const DecalModelList_t& list = m_DecalList[(int)handle]; + const DecalModelList_t& list = m_DecalList[(intp)handle]; m_pStudioHdr = drawInfo.m_pStudioHdr; // Add this fix after I fix the other problem. @@ -1975,7 +1975,7 @@ void CStudioRender::DrawStaticPropDecals( const DrawModelInfo_t &drawInfo, const pRenderContext->MatrixMode( MATERIAL_MODEL ); pRenderContext->LoadMatrix( modelToWorld ); - const DecalModelList_t& list = m_DecalList[(int)handle]; + const DecalModelList_t& list = m_DecalList[(intp)handle]; // Gotta do this for all LODs // Draw each set of decals using a particular material unsigned short mat = list.m_pLod[drawInfo.m_Lod].m_FirstMaterial; diff --git a/tier0/threadtools.cpp b/tier0/threadtools.cpp index 68208e18..8f9ff285 100644 --- a/tier0/threadtools.cpp +++ b/tier0/threadtools.cpp @@ -53,6 +53,7 @@ typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; #include #include #include +#include #define GetLastError() errno typedef void *LPVOID; #endif @@ -220,12 +221,12 @@ void ThreadSleep(unsigned nMilliseconds) //----------------------------------------------------------------------------- #ifndef ThreadGetCurrentId -uint ThreadGetCurrentId() +ThreadId_t ThreadGetCurrentId() { #ifdef _WIN32 return GetCurrentThreadId(); #elif defined(POSIX) - return (uint)pthread_self(); + return (ThreadId_t)pthread_self(); #endif } #endif @@ -345,7 +346,7 @@ void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinityMask ) //----------------------------------------------------------------------------- -uint InitMainThread() +ThreadId_t InitMainThread() { #ifndef LINUX // Skip doing the setname on Linux for the main thread. Here is why... @@ -369,11 +370,11 @@ uint InitMainThread() #ifdef _WIN32 return ThreadGetCurrentId(); #elif defined(POSIX) - return (uint)pthread_self(); + return (ThreadId_t)pthread_self(); #endif } -uint g_ThreadMainThreadID = InitMainThread(); +ThreadId_t g_ThreadMainThreadID = InitMainThread(); bool ThreadInMainThread() { @@ -859,37 +860,37 @@ void CThreadLocalBase::Set( void *value ) #endif #ifndef USE_INTRINSIC_INTERLOCKED -long ThreadInterlockedIncrement( long volatile *pDest ) +int32 ThreadInterlockedIncrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedIncrement( TO_INTERLOCK_PARAM(pDest) ); } -long ThreadInterlockedDecrement( long volatile *pDest ) +int32 ThreadInterlockedDecrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedDecrement( TO_INTERLOCK_PARAM(pDest) ); } -long ThreadInterlockedExchange( long volatile *pDest, long value ) +int32 ThreadInterlockedExchange( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchange( TO_INTERLOCK_PARAM(pDest), value ); } -long ThreadInterlockedExchangeAdd( long volatile *pDest, long value ) +int32 ThreadInterlockedExchangeAdd( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchangeAdd( TO_INTERLOCK_PARAM(pDest), value ); } -long ThreadInterlockedCompareExchange( long volatile *pDest, long value, long comperand ) +int32 ThreadInterlockedCompareExchange( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ); } -bool ThreadInterlockedAssignIf( long volatile *pDest, long value, long comperand ) +bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); @@ -1070,37 +1071,52 @@ int64 ThreadInterlockedExchangeAdd64( int64 volatile *pDest, int64 value ) #elif defined(GNUC) -#ifdef OSX -#include -#endif - - -long ThreadInterlockedIncrement( long volatile *pDest ) +int32 ThreadInterlockedIncrement( int32 volatile *pDest ) { return __sync_fetch_and_add( pDest, 1 ) + 1; } -long ThreadInterlockedDecrement( long volatile *pDest ) +int64 ThreadInterlockedIncrement64( int64 volatile *pDest ) +{ + return __sync_fetch_and_add( pDest, 1 ) + 1; +} + +int32 ThreadInterlockedDecrement( int32 volatile *pDest ) { return __sync_fetch_and_sub( pDest, 1 ) - 1; } -long ThreadInterlockedExchange( long volatile *pDest, long value ) +int64 ThreadInterlockedDecrement64( int64 volatile *pDest ) +{ + return __sync_fetch_and_sub( pDest, 1 ) - 1; +} + +int32 ThreadInterlockedExchange( int32 volatile *pDest, int32 value ) { return __sync_lock_test_and_set( pDest, value ); } -long ThreadInterlockedExchangeAdd( long volatile *pDest, long value ) +int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value ) +{ + return __sync_lock_test_and_set( pDest, value ); +} + +int32 ThreadInterlockedExchangeAdd( int32 volatile *pDest, int32 value ) { return __sync_fetch_and_add( pDest, value ); } -long ThreadInterlockedCompareExchange( long volatile *pDest, long value, long comperand ) +int64 ThreadInterlockedExchangeAdd64( int64 volatile *pDest, int64 value ) +{ + return __sync_fetch_and_add( pDest, value ); +} + +int32 ThreadInterlockedCompareExchange( int32 volatile *pDest, int32 value, int32 comperand ) { return __sync_val_compare_and_swap( pDest, comperand, value ); } -bool ThreadInterlockedAssignIf( long volatile *pDest, long value, long comperand ) +bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comperand ) { return __sync_bool_compare_and_swap( pDest, comperand, value ); } @@ -1122,15 +1138,7 @@ bool ThreadInterlockedAssignPointerIf( void * volatile *pDest, void *value, void int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand ) { -#if defined(OSX) - int64 retVal = *pDest; - if ( OSAtomicCompareAndSwap64( comperand, value, pDest ) ) - retVal = *pDest; - - return retVal; -#else return __sync_val_compare_and_swap( pDest, comperand, value ); -#endif } bool ThreadInterlockedAssignIf64( int64 volatile * pDest, int64 value, int64 comperand ) @@ -1138,18 +1146,12 @@ bool ThreadInterlockedAssignIf64( int64 volatile * pDest, int64 value, int64 com return __sync_bool_compare_and_swap( pDest, comperand, value ); } -int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value ) +#ifdef PLATFORM_64BITS +bool ThreadInterlockedAssignIf128( int128 volatile *pDest, const int128 &value, const int128 &comperand ) { - Assert( (size_t)pDest % 8 == 0 ); - int64 Old; - - do - { - Old = *pDest; - } while (ThreadInterlockedCompareExchange64(pDest, value, Old) != Old); - - return Old; + return __sync_bool_compare_and_swap( pDest, comperand, value ); } +#endif #else @@ -1157,22 +1159,22 @@ int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value ) #error "Falling back to mutexed interlocked operations, you really don't have intrinsics you can use?"ß CThreadMutex g_InterlockedMutex; -long ThreadInterlockedIncrement( long volatile *pDest ) +int32 ThreadInterlockedIncrement( int32 volatile *pDest ) { AUTO_LOCK( g_InterlockedMutex ); return ++(*pDest); } -long ThreadInterlockedDecrement( long volatile *pDest ) +int32 ThreadInterlockedDecrement( int32 volatile *pDest ) { AUTO_LOCK( g_InterlockedMutex ); return --(*pDest); } -long ThreadInterlockedExchange( long volatile *pDest, long value ) +int32 ThreadInterlockedExchange( int32 volatile *pDest, int32 value ) { AUTO_LOCK( g_InterlockedMutex ); - long retVal = *pDest; + int32 retVal = *pDest; *pDest = value; return retVal; } @@ -1185,18 +1187,18 @@ void *ThreadInterlockedExchangePointer( void * volatile *pDest, void *value ) return retVal; } -long ThreadInterlockedExchangeAdd( long volatile *pDest, long value ) +int32 ThreadInterlockedExchangeAdd( int32 volatile *pDest, int32 value ) { AUTO_LOCK( g_InterlockedMutex ); - long retVal = *pDest; + int32 retVal = *pDest; *pDest += value; return retVal; } -long ThreadInterlockedCompareExchange( long volatile *pDest, long value, long comperand ) +int32 ThreadInterlockedCompareExchange( int32 volatile *pDest, int32 value, int32 comperand ) { AUTO_LOCK( g_InterlockedMutex ); - long retVal = *pDest; + int32 retVal = *pDest; if ( *pDest == comperand ) *pDest = value; return retVal; @@ -1241,7 +1243,7 @@ bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 compe return ( ThreadInterlockedCompareExchange64( pDest, value, comperand ) == comperand ); } -bool ThreadInterlockedAssignIf( long volatile *pDest, long value, long comperand ) +bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return ( ThreadInterlockedCompareExchange( pDest, value, comperand ) == comperand ); @@ -1347,7 +1349,7 @@ bool CThreadMutex::TryLock() #define THREAD_SPIN (8*1024) -void CThreadFastMutex::Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile +void CThreadFastMutex::Lock( const uintp threadId, unsigned nSpinSleepTime ) volatile { int i; if ( nSpinSleepTime != TT_INFINITE ) @@ -1482,7 +1484,7 @@ void CThreadRWLock::UnlockWrite() // //----------------------------------------------------------------------------- -void CThreadSpinRWLock::SpinLockForWrite( const uint32 threadId ) +void CThreadSpinRWLock::SpinLockForWrite( const uintp threadId ) { int i; @@ -1695,7 +1697,7 @@ const char *CThread::GetName() #ifdef _WIN32 _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/%p)", this, m_hThread ); #elif defined(POSIX) - _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(0x%x/0x%x)", (uint)this, (uint)m_threadId ); + _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(0x" PRIxPTR "/0x" PRIxPTR ")", (ThreadId_t)this, (ThreadId_t)m_threadId ); #endif m_szName[sizeof(m_szName) - 1] = 0; } @@ -1886,7 +1888,7 @@ void CThread::Stop(int exitCode) if ( !( m_flags & SUPPORT_STOP_PROTOCOL ) ) { OnExit(); - g_pCurThread = (int)NULL; + g_pCurThread = NULL; #ifdef _WIN32 CloseHandle( m_hThread ); @@ -1947,7 +1949,7 @@ void CThread::SuspendCooperative() void CThread::ResumeCooperative() { - Assert( m_nSuspendCount == 1 ); + //Assert( m_nSuspendCount == 1 ); m_SuspendEvent.Set(); } @@ -2118,7 +2120,7 @@ CThread::ThreadProc_t CThread::GetThreadProc() unsigned __stdcall CThread::ThreadProc(LPVOID pv) { - std::auto_ptr pInit((ThreadInit_t *)pv); + std::unique_ptr pInit((ThreadInit_t *)pv); #ifdef _X360 // Make sure all threads are consistent w.r.t floating-point math @@ -2170,7 +2172,7 @@ unsigned __stdcall CThread::ThreadProc(LPVOID pv) } pInit->pThread->OnExit(); - g_pCurThread = (int)NULL; + g_pCurThread = NULL; pInit->pThread->Cleanup(); return pInit->pThread->m_result; diff --git a/tier0/tslist.cpp b/tier0/tslist.cpp index 9cd81910..7bafd671 100644 --- a/tier0/tslist.cpp +++ b/tier0/tslist.cpp @@ -135,7 +135,7 @@ void ValidateBuckets() } } -unsigned PopThreadFunc( void *) +uintp PopThreadFunc( void *) { ThreadSetDebugName( "PopThread" ); g_nPopThreads++; @@ -165,7 +165,7 @@ unsigned PopThreadFunc( void *) return 0; } -unsigned PushThreadFunc( void * ) +uintp PushThreadFunc( void * ) { ThreadSetDebugName( "PushThread" ); g_nPushThreads++; @@ -306,7 +306,7 @@ void PushPopInterleavedTest() TestEnd(); } -unsigned PushPopInterleavedTestThreadFunc( void * ) +uintp PushPopInterleavedTestThreadFunc( void * ) { ThreadSetDebugName( "PushPopThread" ); g_nThreads++; diff --git a/tier0/vcrmode.cpp b/tier0/vcrmode.cpp index ed8a0f41..acf2855b 100644 --- a/tier0/vcrmode.cpp +++ b/tier0/vcrmode.cpp @@ -1543,7 +1543,7 @@ void* VCR_CreateThread( void *lpStartAddress, void *lpParameter, unsigned long dwCreationFlags, - unsigned long *lpThreadID ) + uintp *lpThreadID ) { unsigned dwThreadID = 0; diff --git a/tier0/vcrmode_posix.cpp b/tier0/vcrmode_posix.cpp index a842121f..3db6903b 100644 --- a/tier0/vcrmode_posix.cpp +++ b/tier0/vcrmode_posix.cpp @@ -859,7 +859,7 @@ void* VCR_CreateThread( void *lpStartAddress, void *lpParameter, unsigned long dwCreationFlags, - unsigned long *lpThreadID ) + uintp *lpThreadID ) { return CreateSimpleThread( (ThreadFunc_t)lpStartAddress, lpParameter, lpThreadID, 0 ); } diff --git a/tier1/KeyValues.cpp b/tier1/KeyValues.cpp index 0d9fa3a1..a86cc530 100644 --- a/tier1/KeyValues.cpp +++ b/tier1/KeyValues.cpp @@ -37,8 +37,8 @@ static const char * s_LastFileLoadingFrom = "unknown"; // just needed for error messages // Statics for the growable string table -int (*KeyValues::s_pfGetSymbolForString)( const char *name, bool bCreate ) = &KeyValues::GetSymbolForStringClassic; -const char *(*KeyValues::s_pfGetStringForSymbol)( int symbol ) = &KeyValues::GetStringForSymbolClassic; +intp (*KeyValues::s_pfGetSymbolForString)( const char *name, bool bCreate ) = &KeyValues::GetSymbolForStringClassic; +const char *(*KeyValues::s_pfGetStringForSymbol)( intp symbol ) = &KeyValues::GetStringForSymbolClassic; CKeyValuesGrowableStringTable *KeyValues::s_pGrowableStringTable = NULL; #define KEYVALUES_TOKEN_SIZE 4096 @@ -63,7 +63,7 @@ public: // entering a new keyvalues block, save state for errors // Not save symbols instead of pointers because the pointers can move! - int Push( int symName ) + int Push( intp symName ) { if ( m_errorIndex < MAX_ERROR_STACK ) { @@ -82,7 +82,7 @@ public: } // Allows you to keep the same stack level, but change the name as you parse peers - void Reset( int stackLevel, int symName ) + void Reset( int stackLevel, intp symName ) { Assert( stackLevel >= 0 ); Assert( stackLevel < m_errorIndex ); @@ -118,7 +118,7 @@ public: } private: - int m_errorStack[MAX_ERROR_STACK]; + intp m_errorStack[MAX_ERROR_STACK]; const char *m_pFilename; int m_errorIndex; int m_maxErrorIndex; @@ -138,11 +138,11 @@ public: { g_KeyValuesErrorStack.Pop(); } - CKeyErrorContext( int symName ) + CKeyErrorContext( intp symName ) { Init( symName ); } - void Reset( int symName ) + void Reset( intp symName ) { g_KeyValuesErrorStack.Reset( m_stackLevel, symName ); } @@ -151,7 +151,7 @@ public: return m_stackLevel; } private: - void Init( int symName ) + void Init( intp symName ) { m_stackLevel = g_KeyValuesErrorStack.Push( symName ); } @@ -242,7 +242,7 @@ public: } // Translates a string to an index - int GetSymbolForString( const char *name, bool bCreate = true ) + intp GetSymbolForString( const char *name, bool bCreate = true ) { AUTO_LOCK( m_mutex ); @@ -273,7 +273,7 @@ public: } // Translates an index back to a string - const char *GetStringForSymbol( int symbol ) + const char *GetStringForSymbol( intp symbol ) { return (const char *)m_vecStrings.Base() + symbol; } @@ -292,7 +292,7 @@ private: void SetCurStringBase( const char *pchCurBase ) { m_pchCurBase = pchCurBase; } // The compare function. - bool operator()( int nLhs, int nRhs ) const + bool operator()( intp nLhs, intp nRhs ) const { const char *pchLhs = nLhs > 0 ? m_pchCurBase + nLhs : m_pchCurString; const char *pchRhs = nRhs > 0 ? m_pchCurBase + nRhs : m_pchCurString; @@ -313,7 +313,7 @@ private: CThreadFastMutex m_mutex; CLookupFunctor m_Functor; - CUtlHash m_hashLookup; + CUtlHash m_hashLookup; CUtlVector m_vecStrings; }; @@ -348,22 +348,22 @@ void KeyValues::SetUseGrowableStringTable( bool bUseGrowableTable ) // Purpose: Bodys of the function pointers used for interacting with the key // name string table //----------------------------------------------------------------------------- -int KeyValues::GetSymbolForStringClassic( const char *name, bool bCreate ) +intp KeyValues::GetSymbolForStringClassic( const char *name, bool bCreate ) { return KeyValuesSystem()->GetSymbolForString( name, bCreate ); } -const char *KeyValues::GetStringForSymbolClassic( int symbol ) +const char *KeyValues::GetStringForSymbolClassic( intp symbol ) { return KeyValuesSystem()->GetStringForSymbol( symbol ); } -int KeyValues::GetSymbolForStringGrowable( const char *name, bool bCreate ) +intp KeyValues::GetSymbolForStringGrowable( const char *name, bool bCreate ) { return s_pGrowableStringTable->GetSymbolForString( name, bCreate ); } -const char *KeyValues::GetStringForSymbolGrowable( int symbol ) +const char *KeyValues::GetStringForSymbolGrowable( intp symbol ) { return s_pGrowableStringTable->GetStringForSymbol( symbol ); } @@ -970,7 +970,7 @@ void KeyValues::SaveKeyToFile( KeyValues *dat, IBaseFileSystem *filesystem, File //----------------------------------------------------------------------------- // Purpose: looks up a key by symbol name //----------------------------------------------------------------------------- -KeyValues *KeyValues::FindKey(int keySymbol) const +KeyValues *KeyValues::FindKey(intp keySymbol) const { for (KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer) { @@ -2658,7 +2658,7 @@ bool KeyValues::WriteAsBinary( CUtlBuffer &buffer ) } case TYPE_PTR: { - buffer.PutUnsignedInt( (int)dat->m_pValue ); + buffer.PutPtr( dat->m_pValue ); } default: @@ -2762,7 +2762,7 @@ bool KeyValues::ReadAsBinary( CUtlBuffer &buffer, int nStackDepth ) } case TYPE_PTR: { - dat->m_pValue = (void*)buffer.GetUnsignedInt(); + dat->m_pValue = buffer.GetPtr(); } default: diff --git a/tier1/bitbuf.cpp b/tier1/bitbuf.cpp index bb53b3be..274f8e32 100644 --- a/tier1/bitbuf.cpp +++ b/tier1/bitbuf.cpp @@ -42,14 +42,14 @@ inline unsigned int CountTrailingZeros( unsigned int elem ) inline unsigned int CountLeadingZeros(unsigned int x) { - unsigned long firstBit; + uint32 firstBit; if ( _BitScanReverse(&firstBit,x) ) return 31 - firstBit; return 32; } inline unsigned int CountTrailingZeros(unsigned int elem) { - unsigned long out; + uint32 out; if ( _BitScanForward(&out, elem) ) return out; return 32; @@ -83,14 +83,14 @@ void SetBitBufErrorHandler( BitBufErrorHandler fn ) // #define BB_PROFILING -unsigned long g_LittleBits[32]; +uint32 g_LittleBits[32]; // Precalculated bit masks for WriteUBitLong. Using these tables instead of // doing the calculations gives a 33% speedup in WriteUBitLong. -unsigned long g_BitWriteMasks[32][33]; +uint32 g_BitWriteMasks[32][33]; // (1 << i) - 1 -unsigned long g_ExtraMasks[33]; +uint32 g_ExtraMasks[33]; class CBitWriteMasksInit { @@ -110,7 +110,7 @@ public: for ( unsigned int maskBit=0; maskBit < 32; maskBit++ ) g_ExtraMasks[maskBit] = BitForBitnum(maskBit) - 1; - g_ExtraMasks[32] = ~0ul; + g_ExtraMasks[32] = ~0u; for ( unsigned int littleBit=0; littleBit < 32; littleBit++ ) StoreLittleDWord( &g_LittleBits[littleBit], 0, 1u<= 8) + while (((uintp)pOut & 3) != 0 && nBitsLeft >= 8) { WriteUBitLong( *pOut, 8, false ); @@ -485,18 +485,18 @@ bool bf_write::WriteBits(const void *pInData, int nBits) // X360TBD: Can't write dwords in WriteBits because they'll get swapped if ( IsPC() && nBitsLeft >= 32 ) { - unsigned long iBitsRight = (m_iCurBit & 31); - unsigned long iBitsLeft = 32 - iBitsRight; - unsigned long bitMaskLeft = g_BitWriteMasks[iBitsRight][32]; - unsigned long bitMaskRight = g_BitWriteMasks[0][iBitsRight]; + uint32 iBitsRight = (m_iCurBit & 31); + uint32 iBitsLeft = 32 - iBitsRight; + uint32 bitMaskLeft = g_BitWriteMasks[iBitsRight][32]; + uint32 bitMaskRight = g_BitWriteMasks[0][iBitsRight]; - unsigned long *pData = &m_pData[m_iCurBit>>5]; + uint32 *pData = &m_pData[m_iCurBit>>5]; // Read dwords. while(nBitsLeft >= 32) { - unsigned long curData = *(unsigned long*)pOut; - pOut += sizeof(unsigned long); + uint32 curData = *(uint32*)pOut; + pOut += sizeof(uint32); *pData &= bitMaskLeft; *pData |= curData << iBitsRight; @@ -736,9 +736,9 @@ void bf_write::WriteWord(int val) WriteUBitLong(val, sizeof(unsigned short) << 3); } -void bf_write::WriteLong(long val) +void bf_write::WriteLong(int32 val) { - WriteSBitLong(val, sizeof(long) << 3); + WriteSBitLong(val, sizeof(int32) << 3); } void bf_write::WriteLongLong(int64 val) @@ -748,8 +748,8 @@ void bf_write::WriteLongLong(int64 val) // Insert the two DWORDS according to network endian const short endianIndex = 0x0100; byte *idx = (byte*)&endianIndex; - WriteUBitLong(pLongs[*idx++], sizeof(long) << 3); - WriteUBitLong(pLongs[*idx], sizeof(long) << 3); + WriteUBitLong(pLongs[*idx++], sizeof(int32) << 3); + WriteUBitLong(pLongs[*idx], sizeof(int32) << 3); } void bf_write::WriteFloat(float val) @@ -898,8 +898,8 @@ void bf_read::ReadBits(void *pOutData, int nBits) // read dwords while ( nBitsLeft >= 32 ) { - *((unsigned long*)pOut) = ReadUBitLong(32); - pOut += sizeof(unsigned long); + *((uint32*)pOut) = ReadUBitLong(32); + pOut += sizeof(uint32); nBitsLeft -= 32; } } @@ -1349,8 +1349,8 @@ int64 bf_read::ReadLongLong() // Read the two DWORDs according to network endian const short endianIndex = 0x0100; byte *idx = (byte*)&endianIndex; - pLongs[*idx++] = ReadUBitLong(sizeof(long) << 3); - pLongs[*idx] = ReadUBitLong(sizeof(long) << 3); + pLongs[*idx++] = ReadUBitLong(sizeof(int32) << 3); + pLongs[*idx] = ReadUBitLong(sizeof(int32) << 3); return retval; } @@ -1448,7 +1448,7 @@ void bf_read::ExciseBits( int startbit, int bitstoremove ) int bf_read::CompareBitsAt( int offset, bf_read * RESTRICT other, int otherOffset, int numbits ) RESTRICT { - extern unsigned long g_ExtraMasks[33]; + extern uint32 g_ExtraMasks[33]; if ( numbits == 0 ) return 0; @@ -1462,17 +1462,17 @@ int bf_read::CompareBitsAt( int offset, bf_read * RESTRICT other, int otherOffse unsigned int iStartBit1 = offset & 31u; unsigned int iStartBit2 = otherOffset & 31u; - unsigned long *pData1 = (unsigned long*)m_pData + (offset >> 5); - unsigned long *pData2 = (unsigned long*)other->m_pData + (otherOffset >> 5); - unsigned long *pData1End = pData1 + ((offset + numbits - 1) >> 5); - unsigned long *pData2End = pData2 + ((otherOffset + numbits - 1) >> 5); + uint32 *pData1 = (uint32*)m_pData + (offset >> 5); + uint32 *pData2 = (uint32*)other->m_pData + (otherOffset >> 5); + uint32 *pData1End = pData1 + ((offset + numbits - 1) >> 5); + uint32 *pData2End = pData2 + ((otherOffset + numbits - 1) >> 5); while ( numbits > 32 ) { - x = LoadLittleDWord( (unsigned long*)pData1, 0 ) >> iStartBit1; - x ^= LoadLittleDWord( (unsigned long*)pData1, 1 ) << (32 - iStartBit1); - x ^= LoadLittleDWord( (unsigned long*)pData2, 0 ) >> iStartBit2; - x ^= LoadLittleDWord( (unsigned long*)pData2, 1 ) << (32 - iStartBit2); + x = LoadLittleDWord( (uint32*)pData1, 0 ) >> iStartBit1; + x ^= LoadLittleDWord( (uint32*)pData1, 1 ) << (32 - iStartBit1); + x ^= LoadLittleDWord( (uint32*)pData2, 0 ) >> iStartBit2; + x ^= LoadLittleDWord( (uint32*)pData2, 1 ) << (32 - iStartBit2); if ( x != 0 ) { return x; @@ -1482,9 +1482,9 @@ int bf_read::CompareBitsAt( int offset, bf_read * RESTRICT other, int otherOffse numbits -= 32; } - x = LoadLittleDWord( (unsigned long*)pData1, 0 ) >> iStartBit1; - x ^= LoadLittleDWord( (unsigned long*)pData1End, 0 ) << (32 - iStartBit1); - x ^= LoadLittleDWord( (unsigned long*)pData2, 0 ) >> iStartBit2; - x ^= LoadLittleDWord( (unsigned long*)pData2End, 0 ) << (32 - iStartBit2); + x = LoadLittleDWord( (uint32*)pData1, 0 ) >> iStartBit1; + x ^= LoadLittleDWord( (uint32*)pData1End, 0 ) << (32 - iStartBit1); + x ^= LoadLittleDWord( (uint32*)pData2, 0 ) >> iStartBit2; + x ^= LoadLittleDWord( (uint32*)pData2End, 0 ) << (32 - iStartBit2); return x & g_ExtraMasks[ numbits ]; } diff --git a/tier1/checksum_crc.cpp b/tier1/checksum_crc.cpp index 29093d1e..d65b919a 100644 --- a/tier1/checksum_crc.cpp +++ b/tier1/checksum_crc.cpp @@ -150,7 +150,7 @@ JustAfew: // The low-order two bits of pb and nBuffer in total control the // upfront work. // - nFront = ((unsigned int)pb) & 3; + nFront = ((uintp)pb) & 3; nBuffer -= nFront; switch (nFront) { diff --git a/tier1/commandbuffer.cpp b/tier1/commandbuffer.cpp index 2897d038..adb3ede0 100644 --- a/tier1/commandbuffer.cpp +++ b/tier1/commandbuffer.cpp @@ -92,9 +92,9 @@ bool CCommandBuffer::ParseArgV0( CUtlBuffer &buf, char *pArgV0, int nMaxLen, con //----------------------------------------------------------------------------- // Insert a command into the command queue //----------------------------------------------------------------------------- -void CCommandBuffer::InsertCommandAtAppropriateTime( int hCommand ) +void CCommandBuffer::InsertCommandAtAppropriateTime( CommandHandle_t hCommand ) { - int i; + intp i; Command_t &command = m_Commands[hCommand]; for ( i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) ) { @@ -108,7 +108,7 @@ void CCommandBuffer::InsertCommandAtAppropriateTime( int hCommand ) //----------------------------------------------------------------------------- // Insert a command into the command queue at the appropriate time //----------------------------------------------------------------------------- -void CCommandBuffer::InsertImmediateCommand( int hCommand ) +void CCommandBuffer::InsertImmediateCommand( CommandHandle_t hCommand ) { m_Commands.LinkBefore( m_hNextCommand, hCommand ); } @@ -137,7 +137,7 @@ bool CCommandBuffer::InsertCommand( const char *pArgS, int nCommandSize, int nTi m_pArgSBuffer[m_nArgSBufferSize + nCommandSize] = 0; ++nCommandSize; - int hCommand = m_Commands.Alloc(); + intp hCommand = m_Commands.Alloc(); Command_t &command = m_Commands[hCommand]; command.m_nTick = nTick; command.m_nFirstArgS = m_nArgSBufferSize; @@ -264,7 +264,7 @@ void CCommandBuffer::DelayAllQueuedCommands( int nDelay ) if ( nDelay <= 0 ) return; - for ( int i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) ) + for ( intp i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) ) { m_Commands[i].m_nTick += nDelay; } @@ -299,7 +299,7 @@ bool CCommandBuffer::DequeueNextCommand( ) if ( m_Commands.Count() == 0 ) return false; - int nHead = m_Commands.Head(); + intp nHead = m_Commands.Head(); Command_t &command = m_Commands[ nHead ]; if ( command.m_nTick > m_nLastTickToProcess ) return false; @@ -354,7 +354,7 @@ void CCommandBuffer::Compact() m_nArgSBufferSize = 0; char pTempBuffer[ ARGS_BUFFER_LENGTH ]; - for ( int i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) ) + for ( intp i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) ) { Command_t &command = m_Commands[ i ]; @@ -382,7 +382,7 @@ void CCommandBuffer::EndProcessingCommands() // Extract commands that are before the end time // NOTE: This is a bug for this to - int i = m_Commands.Head(); + intp i = m_Commands.Head(); if ( i == m_Commands.InvalidIndex() ) { m_nArgSBufferSize = 0; diff --git a/tier1/kvpacker.cpp b/tier1/kvpacker.cpp index 53f7672e..2981ebb4 100644 --- a/tier1/kvpacker.cpp +++ b/tier1/kvpacker.cpp @@ -145,7 +145,7 @@ bool KVPacker::WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer ) } case KeyValues::TYPE_PTR: { - buffer.PutUnsignedInt( (int)dat->GetPtr() ); + buffer.PutUnsignedInt( (uintptr_t)dat->GetPtr() ); break; } @@ -258,7 +258,7 @@ bool KVPacker::ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer ) } case PACKTYPE_PTR: { - dat->SetPtr( NULL, (void*)buffer.GetUnsignedInt() ); + dat->SetPtr( NULL, buffer.GetPtr() ); break; } diff --git a/tier1/lzss.cpp b/tier1/lzss.cpp index f350cf81..23bdead8 100644 --- a/tier1/lzss.cpp +++ b/tier1/lzss.cpp @@ -54,7 +54,7 @@ void CLZSS::BuildHash( const unsigned char *pData ) lzss_list_t *pList; lzss_node_t *pTarget; - int targetindex = (unsigned int)pData & ( m_nWindowSize - 1 ); + intp targetindex = (intp)pData & ( m_nWindowSize - 1 ); pTarget = &m_pHashTarget[targetindex]; if ( pTarget->pData ) { diff --git a/tier2/riff.cpp b/tier2/riff.cpp index 9e36021c..e22fdf3f 100644 --- a/tier2/riff.cpp +++ b/tier2/riff.cpp @@ -24,29 +24,29 @@ class StdIOReadBinary : public IFileReadBinary { public: - int open( const char *pFileName ) + intp open( const char *pFileName ) { - return (int)fopen( pFileName, "rb" ); + return (intp)fopen( pFileName, "rb" ); } - int read( void *pOutput, int size, int file ) + int read( void *pOutput, int size, intp file ) { FILE *fp = (FILE *)file; return fread( pOutput, size, 1, fp ); } - void seek( int file, int pos ) + void seek( intp file, int pos ) { fseek( (FILE *)file, pos, SEEK_SET ); } - unsigned int tell( int file ) + unsigned int tell( intp file ) { return ftell( (FILE *)file ); } - unsigned int size( int file ) + unsigned int size( intp file ) { FILE *fp = (FILE *)file; if ( !fp ) @@ -60,7 +60,7 @@ public: return size; } - void close( int file ) + void close( intp file ) { FILE *fp = (FILE *)file; diff --git a/tier2/soundutils.cpp b/tier2/soundutils.cpp index bebda85f..ed3e1196 100644 --- a/tier2/soundutils.cpp +++ b/tier2/soundutils.cpp @@ -29,12 +29,12 @@ class CFSIOReadBinary : public IFileReadBinary { public: // inherited from IFileReadBinary - virtual int open( const char *pFileName ); - virtual int read( void *pOutput, int size, int file ); - virtual void seek( int file, int pos ); - virtual unsigned int tell( int file ); - virtual unsigned int size( int file ); - virtual void close( int file ); + virtual intp open( const char *pFileName ); + virtual int read( void *pOutput, int size, intp file ); + virtual void seek( intp file, int pos ); + virtual unsigned int tell( intp file ); + virtual unsigned int size( intp file ); + virtual void close( intp file ); }; class CFSIOWriteBinary : public IFileWriteBinary @@ -61,12 +61,12 @@ IFileWriteBinary *g_pFSIOWriteBinary = &s_FSIoOut; //----------------------------------------------------------------------------- // RIFF reader that use the file system //----------------------------------------------------------------------------- -int CFSIOReadBinary::open( const char *pFileName ) +intp CFSIOReadBinary::open( const char *pFileName ) { - return (int)g_pFullFileSystem->Open( pFileName, "rb" ); + return (intp)g_pFullFileSystem->Open( pFileName, "rb" ); } -int CFSIOReadBinary::read( void *pOutput, int size, int file ) +int CFSIOReadBinary::read( void *pOutput, int size, intp file ) { if ( !file ) return 0; @@ -74,7 +74,7 @@ int CFSIOReadBinary::read( void *pOutput, int size, int file ) return g_pFullFileSystem->Read( pOutput, size, (FileHandle_t)file ); } -void CFSIOReadBinary::seek( int file, int pos ) +void CFSIOReadBinary::seek( intp file, int pos ) { if ( !file ) return; @@ -82,7 +82,7 @@ void CFSIOReadBinary::seek( int file, int pos ) g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); } -unsigned int CFSIOReadBinary::tell( int file ) +unsigned int CFSIOReadBinary::tell( intp file ) { if ( !file ) return 0; @@ -90,7 +90,7 @@ unsigned int CFSIOReadBinary::tell( int file ) return g_pFullFileSystem->Tell( (FileHandle_t)file ); } -unsigned int CFSIOReadBinary::size( int file ) +unsigned int CFSIOReadBinary::size( intp file ) { if ( !file ) return 0; @@ -98,7 +98,7 @@ unsigned int CFSIOReadBinary::size( int file ) return g_pFullFileSystem->Size( (FileHandle_t)file ); } -void CFSIOReadBinary::close( int file ) +void CFSIOReadBinary::close( intp file ) { if ( !file ) return; @@ -113,7 +113,7 @@ void CFSIOReadBinary::close( int file ) int CFSIOWriteBinary::create( const char *pFileName ) { g_pFullFileSystem->SetFileWritable( pFileName, true ); - return (int)g_pFullFileSystem->Open( pFileName, "wb" ); + return (intp)g_pFullFileSystem->Open( pFileName, "wb" ); } int CFSIOWriteBinary::write( void *pData, int size, int file ) diff --git a/tier3/studiohdrstub.cpp b/tier3/studiohdrstub.cpp index 44d05ad7..371048fe 100644 --- a/tier3/studiohdrstub.cpp +++ b/tier3/studiohdrstub.cpp @@ -27,21 +27,21 @@ const studiohdr_t *studiohdr_t::FindModel( void **cache, char const *pModelName virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const { - return g_pMDLCache->GetVirtualModel( (MDLHandle_t)((int)virtualModel&0xffff) ); + return g_pMDLCache->GetVirtualModel( VoidPtrToMDLHandle( VirtualModel() ) ); } byte *studiohdr_t::GetAnimBlock( int i ) const { - return g_pMDLCache->GetAnimBlock( (MDLHandle_t)((int)virtualModel&0xffff), i ); + return g_pMDLCache->GetAnimBlock( VoidPtrToMDLHandle( VirtualModel() ), i ); } int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const { - return g_pMDLCache->GetAutoplayList( (MDLHandle_t)((int)virtualModel&0xffff), pOut ); + return g_pMDLCache->GetAutoplayList( VoidPtrToMDLHandle( VirtualModel() ), pOut ); } const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const { - return g_pMDLCache->GetStudioHdr( (MDLHandle_t)((int)cache&0xffff) ); + return g_pMDLCache->GetStudioHdr( VoidPtrToMDLHandle( cache ) ); } diff --git a/togl/linuxwin/dxabstract.cpp b/togl/linuxwin/dxabstract.cpp index f4459e8e..b6432ae6 100644 --- a/togl/linuxwin/dxabstract.cpp +++ b/togl/linuxwin/dxabstract.cpp @@ -1876,7 +1876,7 @@ HRESULT IDirect3DQuery9::GetData(void* pData,DWORD dwSize,DWORD dwGetDataFlags) GL_BATCH_PERF_CALL_TIMER; Assert( m_device->m_nValidMarker == D3D_DEVICE_VALID_MARKER ); HRESULT result = S_FALSE ; - DWORD nCurThreadId = ThreadGetCurrentId(); + uintp nCurThreadId = ThreadGetCurrentId(); // Make sure calling thread owns the GL context. Assert( m_ctx->m_nCurOwnerThreadId == nCurThreadId ); diff --git a/utils/common/bsplib.cpp b/utils/common/bsplib.cpp index a1725a0e..a3975bd1 100644 --- a/utils/common/bsplib.cpp +++ b/utils/common/bsplib.cpp @@ -3400,10 +3400,10 @@ public: int LeafCount() const; // Enumerates the leaves along a ray, box, etc. - bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context ); - bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context ); - bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context ); - bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ); + bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, intp context ); + bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, intp context ); + bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, intp context ); + bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context ); }; @@ -3422,7 +3422,7 @@ int CToolBSPTree::LeafCount() const //----------------------------------------------------------------------------- bool CToolBSPTree::EnumerateLeavesAtPoint( Vector const& pt, - ISpatialLeafEnumerator* pEnum, int context ) + ISpatialLeafEnumerator* pEnum, intp context ) { int node = 0; while( node >= 0 ) @@ -3449,7 +3449,7 @@ bool CToolBSPTree::EnumerateLeavesAtPoint( Vector const& pt, //----------------------------------------------------------------------------- static bool EnumerateLeavesInBox_R( int node, Vector const& mins, - Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context ) + Vector const& maxs, ISpatialLeafEnumerator* pEnum, intp context ) { Vector cornermin, cornermax; @@ -3496,7 +3496,7 @@ static bool EnumerateLeavesInBox_R( int node, Vector const& mins, } bool CToolBSPTree::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, - ISpatialLeafEnumerator* pEnum, int context ) + ISpatialLeafEnumerator* pEnum, intp context ) { return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context ); } @@ -3506,7 +3506,7 @@ bool CToolBSPTree::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, //----------------------------------------------------------------------------- static bool EnumerateLeavesInSphere_R( int node, Vector const& origin, - float radius, ISpatialLeafEnumerator* pEnum, int context ) + float radius, ISpatialLeafEnumerator* pEnum, intp context ) { while( node >= 0 ) { @@ -3537,7 +3537,7 @@ static bool EnumerateLeavesInSphere_R( int node, Vector const& origin, return pEnum->EnumerateLeaf( - node - 1, context ); } -bool CToolBSPTree::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context ) +bool CToolBSPTree::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, intp context ) { return EnumerateLeavesInSphere_R( 0, center, radius, pEnum, context ); } @@ -3548,7 +3548,7 @@ bool CToolBSPTree::EnumerateLeavesInSphere( Vector const& center, float radius, //----------------------------------------------------------------------------- static bool EnumerateLeavesAlongRay_R( int node, Ray_t const& ray, - Vector const& start, Vector const& end, ISpatialLeafEnumerator* pEnum, int context ) + Vector const& start, Vector const& end, ISpatialLeafEnumerator* pEnum, intp context ) { float front,back; @@ -3611,7 +3611,7 @@ static bool EnumerateLeavesAlongRay_R( int node, Ray_t const& ray, return pEnum->EnumerateLeaf( - node - 1, context ); } -bool CToolBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context ) +bool CToolBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context ) { if (!ray.m_IsSwept) { @@ -3650,7 +3650,7 @@ ISpatialQuery* ToolBSPTree() // FIXME: Do we want this in the IBSPTree interface? static bool EnumerateNodesAlongRay_R( int node, Ray_t const& ray, float start, float end, - IBSPNodeEnumerator* pEnum, int context ) + IBSPNodeEnumerator* pEnum, intp context ) { float front, back; float startDotN, deltaDotN; @@ -3719,7 +3719,7 @@ static bool EnumerateNodesAlongRay_R( int node, Ray_t const& ray, float start, f } -bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, int context ) +bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, intp context ) { Vector end; VectorAdd( ray.m_Start, ray.m_Delta, end ); diff --git a/utils/common/bsplib.h b/utils/common/bsplib.h index f7e50f3f..d718458e 100644 --- a/utils/common/bsplib.h +++ b/utils/common/bsplib.h @@ -361,16 +361,16 @@ class IBSPNodeEnumerator { public: // call back with a node and a context - virtual bool EnumerateNode( int node, Ray_t const& ray, float f, int context ) = 0; + virtual bool EnumerateNode( int node, Ray_t const& ray, float f, intp context ) = 0; // call back with a leaf and a context - virtual bool EnumerateLeaf( int leaf, Ray_t const& ray, float start, float end, int context ) = 0; + virtual bool EnumerateLeaf( int leaf, Ray_t const& ray, float start, float end, intp context ) = 0; }; //----------------------------------------------------------------------------- // Enumerates nodes + leafs in front to back order... //----------------------------------------------------------------------------- -bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, int context ); +bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, intp context ); //----------------------------------------------------------------------------- diff --git a/utils/studiomdl/perfstats.cpp b/utils/studiomdl/perfstats.cpp index c450843c..815ff980 100644 --- a/utils/studiomdl/perfstats.cpp +++ b/utils/studiomdl/perfstats.cpp @@ -53,7 +53,7 @@ Cache model's specified dynamic data vertexFileHeader_t *CStudioDataCache::CacheVertexData( studiohdr_t *pStudioHdr ) { // minimal implementation - return persisted data - return (vertexFileHeader_t*)pStudioHdr->pVertexBase; + return (vertexFileHeader_t*)pStudioHdr->VertexBase(); } static void UpdateStudioRenderConfig( void ) diff --git a/utils/vrad/leaf_ambient_lighting.cpp b/utils/vrad/leaf_ambient_lighting.cpp index 3836592e..c9680454 100644 --- a/utils/vrad/leaf_ambient_lighting.cpp +++ b/utils/vrad/leaf_ambient_lighting.cpp @@ -463,7 +463,7 @@ float AABBDistance( const Vector &mins0, const Vector &maxs0, const Vector &mins class CLeafList : public ISpatialLeafEnumerator { public: - virtual bool EnumerateLeaf( int leaf, int context ) + virtual bool EnumerateLeaf( int leaf, intp context ) { m_list.AddToTail(leaf); return true; diff --git a/utils/vrad/vraddetailprops.cpp b/utils/vrad/vraddetailprops.cpp index 87d0e054..a024af9c 100644 --- a/utils/vrad/vraddetailprops.cpp +++ b/utils/vrad/vraddetailprops.cpp @@ -361,7 +361,7 @@ public: CLightSurface(int iThread) : m_pSurface(0), m_HitFrac(1.0f), m_bHasLuxel(false), m_iThread(iThread) {} // call back with a node and a context - bool EnumerateNode( int node, Ray_t const& ray, float f, int context ) + bool EnumerateNode( int node, Ray_t const& ray, float f, intp context ) { dface_t* pSkySurface = 0; @@ -410,7 +410,7 @@ public: } // call back with a leaf and a context - virtual bool EnumerateLeaf( int leaf, Ray_t const& ray, float start, float end, int context ) + virtual bool EnumerateLeaf( int leaf, Ray_t const& ray, float start, float end, intp context ) { bool hit = false; dleaf_t* pLeaf = &dleafs[leaf]; diff --git a/utils/vrad/vraddisps.cpp b/utils/vrad/vraddisps.cpp index d6bc6f7a..d0fe3e76 100644 --- a/utils/vrad/vraddisps.cpp +++ b/utils/vrad/vraddisps.cpp @@ -41,10 +41,10 @@ public: } // ISpatialLeafEnumerator - bool EnumerateLeaf( int ndxLeaf, int context ); + bool EnumerateLeaf( int ndxLeaf, intp context ); // IBSPTreeDataEnumerator - bool FASTCALL EnumerateElement( int userId, int context ); + bool FASTCALL EnumerateElement( int userId, intp context ); public: @@ -61,10 +61,10 @@ class CBSPDispRayEnumerator : public ISpatialLeafEnumerator, public IBSPTreeData { public: // ISpatialLeafEnumerator - bool EnumerateLeaf( int ndxLeaf, int context ); + bool EnumerateLeaf( int ndxLeaf, intp context ); // IBSPTreeDataEnumerator - bool FASTCALL EnumerateElement( int userId, int context ); + bool FASTCALL EnumerateElement( int userId, intp context ); }; //============================================================================= @@ -127,12 +127,12 @@ public: // // Enumeration Methods // - bool DispRay_EnumerateLeaf( int ndxLeaf, int context ); - bool DispRay_EnumerateElement( int userId, int context ); + bool DispRay_EnumerateLeaf( int ndxLeaf, intp context ); + bool DispRay_EnumerateElement( int userId, intp context ); bool DispRayDistance_EnumerateElement( int userId, CBSPDispRayDistanceEnumerator* pEnum ); - bool DispFaceList_EnumerateLeaf( int ndxLeaf, int context ); - bool DispFaceList_EnumerateElement( int userId, int context ); + bool DispFaceList_EnumerateLeaf( int ndxLeaf, intp context ); + bool DispFaceList_EnumerateElement( int userId, intp context ); private: @@ -215,13 +215,13 @@ IVRadDispMgr *StaticDispMgr( void ) // Displacement/Face List // // ISpatialLeafEnumerator -bool CBSPDispFaceListEnumerator::EnumerateLeaf( int ndxLeaf, int context ) +bool CBSPDispFaceListEnumerator::EnumerateLeaf( int ndxLeaf, intp context ) { return s_DispMgr.DispFaceList_EnumerateLeaf( ndxLeaf, context ); } // IBSPTreeDataEnumerator -bool FASTCALL CBSPDispFaceListEnumerator::EnumerateElement( int userId, int context ) +bool FASTCALL CBSPDispFaceListEnumerator::EnumerateElement( int userId, intp context ) { return s_DispMgr.DispFaceList_EnumerateElement( userId, context ); } @@ -231,12 +231,12 @@ bool FASTCALL CBSPDispFaceListEnumerator::EnumerateElement( int userId, int cont // // RayEnumerator // -bool CBSPDispRayEnumerator::EnumerateLeaf( int ndxLeaf, int context ) +bool CBSPDispRayEnumerator::EnumerateLeaf( int ndxLeaf, intp context ) { return s_DispMgr.DispRay_EnumerateLeaf( ndxLeaf, context ); } -bool FASTCALL CBSPDispRayEnumerator::EnumerateElement( int userId, int context ) +bool FASTCALL CBSPDispRayEnumerator::EnumerateElement( int userId, intp context ) { return s_DispMgr.DispRay_EnumerateElement( userId, context ); } @@ -252,7 +252,7 @@ public: CBSPDispRayDistanceEnumerator() : m_Distance(1.0f), m_pSurface(0) {} // IBSPTreeDataEnumerator - bool FASTCALL EnumerateElement( int userId, int context ) + bool FASTCALL EnumerateElement( int userId, intp context ) { return s_DispMgr.DispRayDistance_EnumerateElement( userId, this ); } @@ -669,7 +669,7 @@ void CVRadDispMgr::GetDispSurf( int ndxFace, CVRADDispColl **ppDispTree ) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -bool CVRadDispMgr::DispRay_EnumerateLeaf( int ndxLeaf, int context ) +bool CVRadDispMgr::DispRay_EnumerateLeaf( int ndxLeaf, intp context ) { return m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispRay, context ); } @@ -677,7 +677,7 @@ bool CVRadDispMgr::DispRay_EnumerateLeaf( int ndxLeaf, int context ) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -bool CVRadDispMgr::DispRay_EnumerateElement( int userId, int context ) +bool CVRadDispMgr::DispRay_EnumerateElement( int userId, intp context ) { DispCollTree_t &dispTree = m_DispTrees[userId]; EnumContext_t *pCtx = ( EnumContext_t* )context; @@ -766,7 +766,7 @@ float CVRadDispMgr::ClipRayToDisp( Ray_t const &ray, int dispinfo ) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -bool CVRadDispMgr::DispFaceList_EnumerateLeaf( int ndxLeaf, int context ) +bool CVRadDispMgr::DispFaceList_EnumerateLeaf( int ndxLeaf, intp context ) { // // add the faces found in this leaf to the face list @@ -799,7 +799,7 @@ bool CVRadDispMgr::DispFaceList_EnumerateLeaf( int ndxLeaf, int context ) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -bool CVRadDispMgr::DispFaceList_EnumerateElement( int userId, int context ) +bool CVRadDispMgr::DispFaceList_EnumerateElement( int userId, intp context ) { DispCollTree_t &dispTree = m_DispTrees[userId]; CVRADDispColl *pDispTree = dispTree.m_pDispTree; diff --git a/vgui2/matsys_controls/baseassetpicker.cpp b/vgui2/matsys_controls/baseassetpicker.cpp index 99e6ecab..30144f2b 100644 --- a/vgui2/matsys_controls/baseassetpicker.cpp +++ b/vgui2/matsys_controls/baseassetpicker.cpp @@ -671,7 +671,7 @@ bool CAssetCache::AddFilesInDirectory( CachedAssetList_t& list, const char *pSta //----------------------------------------------------------------------------- bool CAssetCache::ContinueSearchForAssets( AssetList_t hList, float flDuration ) { - CachedAssetList_t& list = m_CachedAssets[ (int)hList ]; + CachedAssetList_t& list = m_CachedAssets[ (intp)hList ]; float flStartTime = Plat_FloatTime(); while ( list.m_DirectoriesToCheck.Count() ) @@ -710,7 +710,7 @@ bool CAssetCache::ContinueSearchForAssets( AssetList_t hList, float flDuration ) //----------------------------------------------------------------------------- bool CAssetCache::BeginAssetScan( AssetList_t hList, bool bForceRescan ) { - CachedAssetList_t& list = m_CachedAssets[ (int)hList ]; + CachedAssetList_t& list = m_CachedAssets[ (intp)hList ]; if ( bForceRescan ) { list.m_bAssetScanComplete = false; @@ -758,27 +758,27 @@ AssetList_t CAssetCache::FindAssetList( const char *pAssetType, const char *pSub list.m_pFileTree = new CAssetTreeView( NULL, "FolderFilter", pAssetType, pSubDir ); } - return (AssetList_t)nIndex; + return (AssetList_t)(intp)nIndex; } CAssetTreeView* CAssetCache::GetFileTree( AssetList_t hList ) { if ( hList == ASSET_LIST_INVALID ) return NULL; - return m_CachedAssets[ (int)hList ].m_pFileTree; + return m_CachedAssets[ (intp)hList ].m_pFileTree; } int CAssetCache::GetAssetCount( AssetList_t hList ) const { if ( hList == ASSET_LIST_INVALID ) return 0; - return m_CachedAssets[ (int)hList ].m_AssetList.Count(); + return m_CachedAssets[ (intp)hList ].m_AssetList.Count(); } const CAssetCache::CachedAssetInfo_t& CAssetCache::GetAsset( AssetList_t hList, int nIndex ) const { Assert( nIndex < GetAssetCount(hList) ); - return m_CachedAssets[ (int)hList ].m_AssetList[ nIndex ]; + return m_CachedAssets[ (intp)hList ].m_AssetList[ nIndex ]; } diff --git a/vgui2/vgui_controls/ListPanel.cpp b/vgui2/vgui_controls/ListPanel.cpp index 4c1c1c56..8a5139fc 100644 --- a/vgui2/vgui_controls/ListPanel.cpp +++ b/vgui2/vgui_controls/ListPanel.cpp @@ -862,7 +862,7 @@ int ListPanel::FindColumn(const char *columnName) // data->GetName() is used to uniquely identify an item // data sub items are matched against column header name to be used in the table //----------------------------------------------------------------------------- -int ListPanel::AddItem( const KeyValues *item, unsigned int userData, bool bScrollToItem, bool bSortOnAdd) +int ListPanel::AddItem( const KeyValues *item, uintp userData, bool bScrollToItem, bool bSortOnAdd) { FastSortListPanelItem *newitem = new FastSortListPanelItem; newitem->kv = item->MakeCopy(); @@ -898,7 +898,7 @@ int ListPanel::AddItem( const KeyValues *item, unsigned int userData, bool bScro //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void ListPanel::SetUserData( int itemID, unsigned int userData ) +void ListPanel::SetUserData( int itemID, uintp userData ) { if ( !m_DataItems.IsValidIndex(itemID) ) return; @@ -909,7 +909,7 @@ void ListPanel::SetUserData( int itemID, unsigned int userData ) //----------------------------------------------------------------------------- // Purpose: Finds the first itemID with a matching userData //----------------------------------------------------------------------------- -int ListPanel::GetItemIDFromUserData( unsigned int userData ) +int ListPanel::GetItemIDFromUserData( uintp userData ) { FOR_EACH_LL( m_DataItems, itemID ) { @@ -1064,7 +1064,7 @@ ListPanelItem *ListPanel::GetItemData( int itemID ) //----------------------------------------------------------------------------- // Purpose: returns user data for itemID //----------------------------------------------------------------------------- -unsigned int ListPanel::GetItemUserData(int itemID) +uintp ListPanel::GetItemUserData(int itemID) { if ( !m_DataItems.IsValidIndex(itemID) ) return 0; @@ -2828,7 +2828,7 @@ void ListPanel::SortList( void ) //----------------------------------------------------------------------------- void ListPanel::SetFont(HFont font) { - Assert( font ); + Assert( font ); if ( !font ) return; diff --git a/vgui2/vgui_controls/RichText.cpp b/vgui2/vgui_controls/RichText.cpp index b3c38330..20bb89d4 100644 --- a/vgui2/vgui_controls/RichText.cpp +++ b/vgui2/vgui_controls/RichText.cpp @@ -2547,12 +2547,12 @@ int RichText::ParseTextStringForUrls( const char *text, int startPos, char *pchU // get the url i += Q_strlen( "" ); - Q_strncpy( pchURL, text + i, min( pchURLEnd - text - i + 1, cchURL ) ); + Q_strncpy( pchURL, text + i, min( (int)(pchURLEnd - text) - i + 1, cchURL ) ); i += ( pchURLEnd - text - i + 1 ); // get the url text pchURLEnd = Q_strstr( text, "" ); - Q_strncpy( pchURLText, text + i, min( pchURLEnd - text - i + 1, cchURLText ) ); + Q_strncpy( pchURLText, text + i, min( (int)(pchURLEnd - text) - i + 1, cchURLText ) ); i += ( pchURLEnd - text - i ); i += Q_strlen( "" ); diff --git a/vphysics/main.cpp b/vphysics/main.cpp index 6aa6a7eb..cb8424e4 100644 --- a/vphysics/main.cpp +++ b/vphysics/main.cpp @@ -198,7 +198,7 @@ IPhysicsCollisionSet *CPhysicsInterface::FindCollisionSet( unsigned int id ) { if ( m_pCollisionSetHash ) { - int index = (int)m_pCollisionSetHash->find_elem( (void *)id ); + intp index = (intp)m_pCollisionSetHash->find_elem( (void *)id ); if ( index > 0 ) { Assert( index <= m_collisionSets.Count() ); diff --git a/vphysics/physics_environment.cpp b/vphysics/physics_environment.cpp index 4ed5415b..a22670f7 100644 --- a/vphysics/physics_environment.cpp +++ b/vphysics/physics_environment.cpp @@ -2041,7 +2041,7 @@ public: if ( !pHash ) return m_objectList.InvalidIndex(); - unsigned int hash = (unsigned int)pHash; + uintp hash = (uintp)pHash; // mask off the extra bit we added to avoid zeros hash &= 0xFFFF; return (unsigned short)hash; diff --git a/vphysics/physics_virtualmesh.cpp b/vphysics/physics_virtualmesh.cpp index fbd67b90..7f447a80 100644 --- a/vphysics/physics_virtualmesh.cpp +++ b/vphysics/physics_virtualmesh.cpp @@ -148,7 +148,7 @@ void CMeshInstance::Init( const virtualmeshlist_t &list ) m_memSize = memSize; m_hullCount = 0; m_pMemory = (char *)ivp_malloc_aligned( memSize, 16 ); - Assert( (int(m_pMemory) & 15) == 0 ); // make sure it is aligned + Assert( (intp(m_pMemory) & 15) == 0 ); // make sure it is aligned IVP_Compact_Poly_Point *pPoints = (IVP_Compact_Poly_Point *)&m_pMemory[ledgeSize]; triangleledge_t *pLedges = (triangleledge_t *) m_pMemory; memset( m_pMemory, 0, memSize ); diff --git a/vstdlib/KeyValuesSystem.cpp b/vstdlib/KeyValuesSystem.cpp index 0665d94f..8bd4035f 100644 --- a/vstdlib/KeyValuesSystem.cpp +++ b/vstdlib/KeyValuesSystem.cpp @@ -68,7 +68,7 @@ private: CMemoryStack m_Strings; struct hash_item_t { - int stringIndex; + intp stringIndex; hash_item_t *next; }; CUtlMemoryPool m_HashItemMemPool; @@ -79,7 +79,7 @@ private: struct MemoryLeakTracker_t { - int nameIndex; + intp nameIndex; void *pMem; }; static bool MemoryLeakTrackerLessFunc( const MemoryLeakTracker_t &lhs, const MemoryLeakTracker_t &rhs ) From ff588a8810e4d31963fe831f99f1823357b2298e Mon Sep 17 00:00:00 2001 From: hymei Date: Wed, 23 Feb 2022 19:56:29 +0800 Subject: [PATCH 15/34] osx : malloc.h => malloc/malloc.h --- bitmap/colorconversion.cpp | 1 - bitmap/imageformat.cpp | 1 - bitmap/resample.cpp | 1 - bitmap/tgawriter.cpp | 1 - common/GameUI/ObjectList.cpp | 4 +++ common/freetype/config/ftconfig.h | 2 ++ engine/common.cpp | 4 +++ engine/decals.cpp | 4 +++ engine/materialproxyfactory.cpp | 1 - engine/packed_entity.cpp | 4 +++ engine/pr_edict.cpp | 4 +++ engine/zone.cpp | 7 ++++ materialsystem/CMaterialSubRect.cpp | 2 +- materialsystem/cmaterial.cpp | 4 +++ materialsystem/materialsystem_global.cpp | 1 - materialsystem/pch_materialsystem.h | 4 +++ materialsystem/shaderapidx9/shaderapidx8.cpp | 1 - public/builddisp.cpp | 1 - public/saverestoretypes.h | 2 +- public/tier0/memalloc.h | 15 +++++--- public/tier0/memdbgon.h | 4 +++ public/tier1/mempool.h | 2 +- public/vallocator.cpp | 4 +++ public/vstdlib/pch_vstdlib.h | 4 +++ studiorender/r_studiodraw.cpp | 1 - tier0/dbg.cpp | 6 +++- tier0/mem.cpp | 4 +++ tier0/mem_helpers.cpp | 4 +++ tier0/memdbg.cpp | 36 +++++++++++++------- tier0/memstd.cpp | 4 +++ tier0/memstd.h | 8 +++-- tier0/memvalidate.cpp | 8 ++--- tier0/pch_tier0.h | 4 +++ tier0/platform_posix.cpp | 10 ++++-- tier1/mempool.cpp | 4 +++ vgui2/src/vgui.cpp | 4 +++ vgui2/vgui_controls/TextImage.cpp | 4 +++ vgui2/vgui_surfacelib/BitmapFont.cpp | 4 +++ vgui2/vgui_surfacelib/linuxfont.cpp | 4 +++ vguimatsurface/MatSystemSurface.cpp | 21 +++++------- 40 files changed, 152 insertions(+), 52 deletions(-) diff --git a/bitmap/colorconversion.cpp b/bitmap/colorconversion.cpp index 9b9432fe..38601ed1 100644 --- a/bitmap/colorconversion.cpp +++ b/bitmap/colorconversion.cpp @@ -10,7 +10,6 @@ #include "bitmap/imageformat.h" #include "basetypes.h" #include "tier0/dbg.h" -#include #include #include "mathlib/mathlib.h" #include "mathlib/vector.h" diff --git a/bitmap/imageformat.cpp b/bitmap/imageformat.cpp index 2808f77e..c2222653 100644 --- a/bitmap/imageformat.cpp +++ b/bitmap/imageformat.cpp @@ -11,7 +11,6 @@ #include "bitmap/imageformat.h" #include "basetypes.h" #include "tier0/dbg.h" -#include #include #include "nvtc.h" #include "mathlib/mathlib.h" diff --git a/bitmap/resample.cpp b/bitmap/resample.cpp index 0ca61f0d..98998899 100644 --- a/bitmap/resample.cpp +++ b/bitmap/resample.cpp @@ -8,7 +8,6 @@ #include "bitmap/imageformat.h" #include "basetypes.h" #include "tier0/dbg.h" -#include #include #include "mathlib/mathlib.h" #include "mathlib/vector.h" diff --git a/bitmap/tgawriter.cpp b/bitmap/tgawriter.cpp index a73c9965..d1324fbc 100644 --- a/bitmap/tgawriter.cpp +++ b/bitmap/tgawriter.cpp @@ -7,7 +7,6 @@ #include #include #include "tier0/dbg.h" -#include #include "filesystem.h" #include "bitmap/tgawriter.h" #include "tier1/utlbuffer.h" diff --git a/common/GameUI/ObjectList.cpp b/common/GameUI/ObjectList.cpp index 7da11005..4b8758ce 100644 --- a/common/GameUI/ObjectList.cpp +++ b/common/GameUI/ObjectList.cpp @@ -6,7 +6,11 @@ // //=============================================================================// #include +#ifdef OSX +#include +#else #include +#endif #include "ObjectList.h" #include "tier1/strtools.h" diff --git a/common/freetype/config/ftconfig.h b/common/freetype/config/ftconfig.h index 5e19c414..200dd57f 100644 --- a/common/freetype/config/ftconfig.h +++ b/common/freetype/config/ftconfig.h @@ -3,6 +3,8 @@ #ifdef ANDROID #include +#elif defined(OSX) +#include #else #include #endif diff --git a/engine/common.cpp b/engine/common.cpp index a7a3ec5d..f9348c95 100644 --- a/engine/common.cpp +++ b/engine/common.cpp @@ -16,7 +16,11 @@ #include #include #include "common.h" +#ifdef OSX +#include +#else #include +#endif #include "traceinit.h" #include #include "filesystem_engine.h" diff --git a/engine/decals.cpp b/engine/decals.cpp index d7de7122..106ff7fd 100644 --- a/engine/decals.cpp +++ b/engine/decals.cpp @@ -14,7 +14,11 @@ #include "filesystem.h" #include "filesystem_engine.h" #include "materialsystem/imaterial.h" +#ifdef OSX +#include +#else #include +#endif #include "utldict.h" // memdbgon must be the last include file in a .cpp file!!! diff --git a/engine/materialproxyfactory.cpp b/engine/materialproxyfactory.cpp index e4936195..9ea00252 100644 --- a/engine/materialproxyfactory.cpp +++ b/engine/materialproxyfactory.cpp @@ -6,7 +6,6 @@ //=============================================================================// #include -#include #include #include "materialsystem/imaterialproxy.h" #include "materialproxyfactory.h" diff --git a/engine/packed_entity.cpp b/engine/packed_entity.cpp index 9944f823..72e592c4 100644 --- a/engine/packed_entity.cpp +++ b/engine/packed_entity.cpp @@ -5,7 +5,11 @@ // $NoKeywords: $ // //=============================================================================// +#ifdef OSX +#include +#else #include +#endif #include #include #include "packed_entity.h" diff --git a/engine/pr_edict.cpp b/engine/pr_edict.cpp index 755adc1c..b8b13bd0 100644 --- a/engine/pr_edict.cpp +++ b/engine/pr_edict.cpp @@ -32,7 +32,11 @@ #ifdef _DEBUG +#ifdef OSX +#include +#else #include +#endif #endif // _DEBUG static ConVar sv_useexplicitdelete( "sv_useexplicitdelete", "1", FCVAR_DEVELOPMENTONLY, "Explicitly delete dormant client entities caused by AllowImmediateReuse()." ); diff --git a/engine/zone.cpp b/engine/zone.cpp index 5d90fa57..83363497 100644 --- a/engine/zone.cpp +++ b/engine/zone.cpp @@ -133,7 +133,14 @@ void Hunk_Print() void Memory_Init( void ) { MEM_ALLOC_CREDIT(); + +#ifdef PLATFORM_64BITS + // Seems to need to be larger to not get exhausted on + // 64-bit. Perhaps because of larger pointer sizes. + int nMaxBytes = 128*1024*1024; +#else int nMaxBytes = 48*1024*1024; +#endif const int nMinCommitBytes = 0x8000; #ifndef HUNK_USE_16MB_PAGE const int nInitialCommit = 0x280000; diff --git a/materialsystem/CMaterialSubRect.cpp b/materialsystem/CMaterialSubRect.cpp index 1b4d3866..e0f1b372 100644 --- a/materialsystem/CMaterialSubRect.cpp +++ b/materialsystem/CMaterialSubRect.cpp @@ -17,7 +17,7 @@ #include "materialsystem/imaterialproxyfactory.h" #include "IHardwareConfigInternal.h" #include "utlsymbol.h" -#include +#include #include "filesystem.h" #include #include "mempool.h" diff --git a/materialsystem/cmaterial.cpp b/materialsystem/cmaterial.cpp index 6c6ebe85..cb64757c 100644 --- a/materialsystem/cmaterial.cpp +++ b/materialsystem/cmaterial.cpp @@ -17,7 +17,11 @@ #include "materialsystem/imaterialproxyfactory.h" #include "IHardwareConfigInternal.h" #include "utlsymbol.h" +#ifdef OSX +#include +#else #include +#endif #include "filesystem.h" #include #include "mempool.h" diff --git a/materialsystem/materialsystem_global.cpp b/materialsystem/materialsystem_global.cpp index f64c1559..06dafd5f 100644 --- a/materialsystem/materialsystem_global.cpp +++ b/materialsystem/materialsystem_global.cpp @@ -7,7 +7,6 @@ #include "materialsystem_global.h" #include "shaderapi/ishaderapi.h" #include "shadersystem.h" -#include #include "filesystem.h" // memdbgon must be the last include file in a .cpp file!!! diff --git a/materialsystem/pch_materialsystem.h b/materialsystem/pch_materialsystem.h index f6935b50..3d2e7a1a 100644 --- a/materialsystem/pch_materialsystem.h +++ b/materialsystem/pch_materialsystem.h @@ -16,7 +16,11 @@ #include "windows.h" #endif +#ifdef OSX +#include +#else #include +#endif #include #include "crtmemdebug.h" diff --git a/materialsystem/shaderapidx9/shaderapidx8.cpp b/materialsystem/shaderapidx9/shaderapidx8.cpp index 69a510c7..15562e5d 100644 --- a/materialsystem/shaderapidx9/shaderapidx8.cpp +++ b/materialsystem/shaderapidx9/shaderapidx8.cpp @@ -42,7 +42,6 @@ mat_fullbright 1 doesn't work properly on alpha materials in testroom_standards #include "colorformatdx8.h" #include "texturedx8.h" #include "textureheap.h" -#include #include "interface.h" #include "utlrbtree.h" #include "utlsymbol.h" diff --git a/public/builddisp.cpp b/public/builddisp.cpp index 3cce06dc..da749e2c 100644 --- a/public/builddisp.cpp +++ b/public/builddisp.cpp @@ -9,7 +9,6 @@ //#include #include -#include #include "builddisp.h" #include "collisionutils.h" #include "tier1/strtools.h" diff --git a/public/saverestoretypes.h b/public/saverestoretypes.h index da06298e..55fa0042 100644 --- a/public/saverestoretypes.h +++ b/public/saverestoretypes.h @@ -512,7 +512,7 @@ inline const char *CSaveRestoreSegment::StringFromSymbol( int token ) /// compilers. Either way, there's no portable intrinsic. // Newer GCC versions provide this in this header, older did by default. -#if !defined( _rotr ) && defined( COMPILER_GCC ) && !defined( __arm__ ) +#if !defined( _rotr ) && defined( COMPILER_GCC ) && !defined( __arm__ ) && !defined( __arm64__ ) #include #endif diff --git a/public/tier0/memalloc.h b/public/tier0/memalloc.h index 0a1c0895..3a64fc32 100644 --- a/public/tier0/memalloc.h +++ b/public/tier0/memalloc.h @@ -96,8 +96,8 @@ public: virtual bool IsDebugHeap() = 0; virtual void GetActualDbgInfo( const char *&pFileName, int &nLine ) = 0; - virtual void RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) = 0; - virtual void RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) = 0; + virtual void RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) = 0; + virtual void RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) = 0; virtual int GetVersion() = 0; @@ -473,9 +473,14 @@ inline void MemAlloc_CheckAlloc( void *ptr, size_t nSize ) } #if defined( OSX ) -// Mac always aligns allocs, don't need to call posix_memalign which doesn't exist in 10.5.8 which TF2 still needs to run on -//inline void *memalign(size_t alignment, size_t size) {void *pTmp=NULL; posix_memalign(&pTmp, alignment, size); return pTmp;} -inline void *memalign(size_t alignment, size_t size) {void *pTmp=NULL; pTmp = malloc(size); MemAlloc_CheckAlloc( pTmp, size ); return pTmp;} +inline void *memalign(size_t alignment, size_t size) { + // MoeMod : 64bit fix + if(alignment < sizeof(void *)) + alignment = sizeof(void *); + void *pTmp = nullptr; + posix_memalign(&pTmp, alignment, size); + return pTmp; +} #endif inline void *_aligned_malloc( size_t nSize, size_t align ) { void *ptr = memalign( align, nSize ); MemAlloc_CheckAlloc( ptr, nSize ); return ptr; } diff --git a/public/tier0/memdbgon.h b/public/tier0/memdbgon.h index 3998b223..b9eec5dd 100644 --- a/public/tier0/memdbgon.h +++ b/public/tier0/memdbgon.h @@ -29,7 +29,11 @@ #include #endif #include +#ifdef OSX +#include +#else #include +#endif #include "commonmacros.h" #include "memalloc.h" diff --git a/public/tier1/mempool.h b/public/tier1/mempool.h index 01d3a33f..0e3931b9 100644 --- a/public/tier1/mempool.h +++ b/public/tier1/mempool.h @@ -458,7 +458,7 @@ inline void CAlignedMemPool inline int __cdecl CAlignedMemPool::CompareChunk( void * const *ppLeft, void * const *ppRight ) { - return ((unsigned)*ppLeft) - ((unsigned)*ppRight); + return (int)(((uintp)*ppLeft) - ((uintp)*ppRight)); } template diff --git a/public/vallocator.cpp b/public/vallocator.cpp index be717033..c1476536 100644 --- a/public/vallocator.cpp +++ b/public/vallocator.cpp @@ -8,7 +8,11 @@ #if !defined(_STATIC_LINKED) || defined(_SHARED_LIB) +#ifdef OSX +#include +#else #include +#endif #include "vallocator.h" #include "basetypes.h" diff --git a/public/vstdlib/pch_vstdlib.h b/public/vstdlib/pch_vstdlib.h index bef1b7f1..ee8a9c7a 100644 --- a/public/vstdlib/pch_vstdlib.h +++ b/public/vstdlib/pch_vstdlib.h @@ -19,7 +19,11 @@ #include #include #include +#ifdef OSX +#include +#else #include +#endif #include #include diff --git a/studiorender/r_studiodraw.cpp b/studiorender/r_studiodraw.cpp index 4e6d18cd..19748fd8 100644 --- a/studiorender/r_studiodraw.cpp +++ b/studiorender/r_studiodraw.cpp @@ -15,7 +15,6 @@ #include "optimize.h" #include "mathlib/mathlib.h" #include "mathlib/vector.h" -#include #include "mathlib/vmatrix.h" #include "studiorendercontext.h" #include "tier2/tier2.h" diff --git a/tier0/dbg.cpp b/tier0/dbg.cpp index 931ea21f..2a64e77c 100644 --- a/tier0/dbg.cpp +++ b/tier0/dbg.cpp @@ -17,7 +17,11 @@ #endif #include +#ifdef OSX +#include +#else #include +#endif #include #include #include @@ -319,7 +323,7 @@ static SpewRetval_t _SpewMessage( SpewType_t spewType, const char *pGroupName, i g_pSpewInfo = &spewInfo; ret = s_SpewOutputFunc( spewType, pTempBuffer ); - g_pSpewInfo = (int)NULL; + g_pSpewInfo = NULL; switch (ret) { diff --git a/tier0/mem.cpp b/tier0/mem.cpp index 3e716d56..f7d5c140 100644 --- a/tier0/mem.cpp +++ b/tier0/mem.cpp @@ -7,7 +7,11 @@ #include "pch_tier0.h" #include "tier0/mem.h" +#ifdef OSX +#include +#else #include +#endif #include "tier0/dbg.h" #include "tier0/minidump.h" diff --git a/tier0/mem_helpers.cpp b/tier0/mem_helpers.cpp index b55c4e4b..82eaaf84 100644 --- a/tier0/mem_helpers.cpp +++ b/tier0/mem_helpers.cpp @@ -7,7 +7,11 @@ #include "pch_tier0.h" #include "mem_helpers.h" #include +#ifdef OSX +#include +#else #include +#endif bool g_bInitMemory = true; diff --git a/tier0/memdbg.cpp b/tier0/memdbg.cpp index ef23e9a3..6b9379f0 100644 --- a/tier0/memdbg.cpp +++ b/tier0/memdbg.cpp @@ -10,7 +10,11 @@ #if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) +#ifdef OSX +#include +#else #include +#endif #include #include "tier0/dbg.h" #include "tier0/memalloc.h" @@ -269,7 +273,7 @@ struct DbgMemHeader_t : CrtDbgMemHeader_t #endif { - unsigned nLogicalSize; + size_t nLogicalSize; byte reserved[12]; // MS allocator always returns mem aligned on 16 bytes, which some of our code depends on }; @@ -634,11 +638,11 @@ private: const char *FindOrCreateFilename( const char *pFileName ); // Updates stats - void RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ); - void RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ); + void RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ); + void RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ); - void RegisterAllocation( MemInfo_t &info, int nLogicalSize, int nActualSize, unsigned nTime ); - void RegisterDeallocation( MemInfo_t &info, int nLogicalSize, int nActualSize, unsigned nTime ); + void RegisterAllocation( MemInfo_t &info, size_t nLogicalSize, size_t nActualSize, unsigned nTime ); + void RegisterDeallocation( MemInfo_t &info, size_t nLogicalSize, size_t nActualSize, unsigned nTime ); // Gets the allocation file name const char *GetAllocatonFileName( void *pMem ); @@ -1056,21 +1060,21 @@ CDbgMemAlloc::MemInfo_t &CDbgMemAlloc::FindOrCreateEntry( const char *pFileName, //----------------------------------------------------------------------------- // Updates stats //----------------------------------------------------------------------------- -void CDbgMemAlloc::RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) +void CDbgMemAlloc::RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) { HEAP_LOCK(); RegisterAllocation( m_GlobalInfo, nLogicalSize, nActualSize, nTime ); RegisterAllocation( FindOrCreateEntry( pFileName, nLine ), nLogicalSize, nActualSize, nTime ); } -void CDbgMemAlloc::RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) +void CDbgMemAlloc::RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) { HEAP_LOCK(); RegisterDeallocation( m_GlobalInfo, nLogicalSize, nActualSize, nTime ); RegisterDeallocation( FindOrCreateEntry( pFileName, nLine ), nLogicalSize, nActualSize, nTime ); } -void CDbgMemAlloc::RegisterAllocation( MemInfo_t &info, int nLogicalSize, int nActualSize, unsigned nTime ) +void CDbgMemAlloc::RegisterAllocation( MemInfo_t &info, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) { ++info.m_nCurrentCount; ++info.m_nTotalCount; @@ -1107,7 +1111,7 @@ void CDbgMemAlloc::RegisterAllocation( MemInfo_t &info, int nLogicalSize, int nA info.m_nTime += nTime; } -void CDbgMemAlloc::RegisterDeallocation( MemInfo_t &info, int nLogicalSize, int nActualSize, unsigned nTime ) +void CDbgMemAlloc::RegisterDeallocation( MemInfo_t &info, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) { // Check for decrementing these counters below zero. The checks // must be done here because these unsigned counters will wrap-around and @@ -1117,7 +1121,7 @@ void CDbgMemAlloc::RegisterDeallocation( MemInfo_t &info, int nLogicalSize, int // It is technically legal for code to request allocations of zero bytes, and there are a number of places in our code // that do. So only assert that nLogicalSize >= 0. http://stackoverflow.com/questions/1087042/c-new-int0-will-it-allocate-memory Assert( nLogicalSize >= 0 ); - Assert( info.m_nCurrentSize >= (size_t)nLogicalSize ); + Assert( info.m_nCurrentSize >= nLogicalSize ); --info.m_nCurrentCount; info.m_nCurrentSize -= nLogicalSize; @@ -1250,8 +1254,8 @@ void CDbgMemAlloc::Free( void *pMem, const char * /*pFileName*/, int nLine ) return; } - int nOldLogicalSize = InternalLogicalSize( pMem ); - int nOldSize = InternalMSize( pMem ); + size_t nOldLogicalSize = InternalLogicalSize( pMem ); + size_t nOldSize = InternalMSize( pMem ); const char *pOldFileName = GetAllocatonFileName( pMem ); int oldLine = GetAllocatonLineNumber( pMem ); @@ -1832,6 +1836,10 @@ static inline void unprotect_malloc_zone( malloc_zone_t *malloc_zone ) // The version check may not be necessary, but we know it was RW before that. if ( malloc_zone->version >= 8 ) { +#ifdef __arm64__ + // MoeMod : this is required for Apple Silicon + pthread_jit_write_protect_np(false); +#endif vm_protect( mach_task_self(), (uintptr_t)malloc_zone, sizeof( malloc_zone_t ), 0, VM_PROT_READ | VM_PROT_WRITE ); } } @@ -1841,6 +1849,10 @@ static inline void protect_malloc_zone( malloc_zone_t *malloc_zone ) if ( malloc_zone->version >= 8 ) { vm_protect( mach_task_self(), (uintptr_t)malloc_zone, sizeof( malloc_zone_t ), 0, VM_PROT_READ ); +#ifdef __arm64__ + // MoeMod : this is required for Apple Silicon + pthread_jit_write_protect_np(true); +#endif } } diff --git a/tier0/memstd.cpp b/tier0/memstd.cpp index ab297ebc..36d9fb13 100644 --- a/tier0/memstd.cpp +++ b/tier0/memstd.cpp @@ -20,7 +20,11 @@ #define VA_RESERVE_FLAGS (MEM_RESERVE|MEM_LARGE_PAGES) #endif +#ifdef OSX +#include +#else #include +#endif #include "tier0/valve_minmax_off.h" // GCC 4.2.2 headers screw up our min/max defs. #include diff --git a/tier0/memstd.h b/tier0/memstd.h index 59ea7f70..bad033ba 100644 --- a/tier0/memstd.h +++ b/tier0/memstd.h @@ -18,7 +18,11 @@ #endif #endif +#ifdef OSX +#include +#else #include +#endif #include #include "tier0/dbg.h" #include "tier0/memalloc.h" @@ -253,8 +257,8 @@ public: virtual bool IsDebugHeap() { return false; } virtual void GetActualDbgInfo( const char *&pFileName, int &nLine ) {} - virtual void RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) {} - virtual void RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) {} + virtual void RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) {} + virtual void RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) {} virtual int GetVersion() { return MEMALLOC_VERSION; } diff --git a/tier0/memvalidate.cpp b/tier0/memvalidate.cpp index 73b15cc1..69c78a0e 100644 --- a/tier0/memvalidate.cpp +++ b/tier0/memvalidate.cpp @@ -102,8 +102,8 @@ private: void GetActualDbgInfo( const char *&pFileName, int &nLine ); // Updates stats - void RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ); - void RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ); + void RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ); + void RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ); HeapSuffix_t *Suffix( HeapPrefix_t *pPrefix ); void *AllocationStart( HeapPrefix_t *pBase ); @@ -460,12 +460,12 @@ void CValidateAlloc::GetActualDbgInfo( const char *&pFileName, int &nLine ) } // Updates stats -void CValidateAlloc::RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) +void CValidateAlloc::RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) { g_pActualAlloc->RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ); } -void CValidateAlloc::RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime ) +void CValidateAlloc::RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) { g_pActualAlloc->RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ); } diff --git a/tier0/pch_tier0.h b/tier0/pch_tier0.h index ad06d221..7ab82889 100644 --- a/tier0/pch_tier0.h +++ b/tier0/pch_tier0.h @@ -30,7 +30,11 @@ #include #include #include +#ifdef OSX +#include +#else #include +#endif #include #include #include diff --git a/tier0/platform_posix.cpp b/tier0/platform_posix.cpp index f5c7a22c..dbfaf36e 100644 --- a/tier0/platform_posix.cpp +++ b/tier0/platform_posix.cpp @@ -679,13 +679,17 @@ PLATFORM_INTERFACE void Plat_SetWatchdogHandlerFunction( Plat_WatchDogHandlerFun // memory logging this functionality is portable code, except for the way in which it hooks // malloc/free. glibc contains the ability for the app to install hooks into malloc/free. +#ifdef OSX +#include +#else #include +#endif #include #include #include #define MEMALLOC_HASHSIZE 8193 -typedef uint32 ptrint_t; +typedef uintp ptrint_t; @@ -993,7 +997,7 @@ static inline bool SortLessFunc( CLinuxMallocContext * const &left, CLinuxMalloc void DumpMemoryLog( int nThresh ) { AUTO_LOCK( s_MemoryMutex ); - EndWatchdogTimer(); + Plat_EndWatchdogTimer(); RemoveHooks(); std::vector memList; @@ -1028,7 +1032,7 @@ void DumpMemoryLog( int nThresh ) void DumpChangedMemory( int nThresh ) { AUTO_LOCK( s_MemoryMutex ); - EndWatchdogTimer(); + Plat_EndWatchdogTimer(); RemoveHooks(); std::vector memList; diff --git a/tier1/mempool.cpp b/tier1/mempool.cpp index fa49edb5..fc3fb9b1 100644 --- a/tier1/mempool.cpp +++ b/tier1/mempool.cpp @@ -6,7 +6,11 @@ #include "mempool.h" #include +#ifdef OSX +#include +#else #include +#endif #include #include "tier0/dbg.h" #include diff --git a/vgui2/src/vgui.cpp b/vgui2/src/vgui.cpp index 3508b1ad..b3de84e5 100644 --- a/vgui2/src/vgui.cpp +++ b/vgui2/src/vgui.cpp @@ -26,7 +26,11 @@ #include #include #include +#ifdef OSX +#include +#else #include +#endif #include #include #include "vgui_internal.h" diff --git a/vgui2/vgui_controls/TextImage.cpp b/vgui2/vgui_controls/TextImage.cpp index 61532126..ead30ed2 100644 --- a/vgui2/vgui_controls/TextImage.cpp +++ b/vgui2/vgui_controls/TextImage.cpp @@ -9,7 +9,11 @@ #include #include #include +#ifdef OSX +#include +#else #include +#endif #include #include diff --git a/vgui2/vgui_surfacelib/BitmapFont.cpp b/vgui2/vgui_surfacelib/BitmapFont.cpp index 36d6be93..b597ac47 100644 --- a/vgui2/vgui_surfacelib/BitmapFont.cpp +++ b/vgui2/vgui_surfacelib/BitmapFont.cpp @@ -10,7 +10,11 @@ #include #include #include +#ifdef OSX +#include +#else #include +#endif #include "vgui_surfacelib/BitmapFont.h" #include "vgui_surfacelib/FontManager.h" #include diff --git a/vgui2/vgui_surfacelib/linuxfont.cpp b/vgui2/vgui_surfacelib/linuxfont.cpp index e9170fdb..30126afa 100644 --- a/vgui2/vgui_surfacelib/linuxfont.cpp +++ b/vgui2/vgui_surfacelib/linuxfont.cpp @@ -12,7 +12,11 @@ #include #include #include +#ifdef OSX +#include +#else #include +#endif #include #include #include diff --git a/vguimatsurface/MatSystemSurface.cpp b/vguimatsurface/MatSystemSurface.cpp index 74265908..1f8d53e9 100644 --- a/vguimatsurface/MatSystemSurface.cpp +++ b/vguimatsurface/MatSystemSurface.cpp @@ -48,7 +48,11 @@ ILauncherMgr *g_pLauncherMgr = NULL; #include "mathlib/vmatrix.h" #include #include "materialsystem/itexture.h" +#ifdef OSX +#include +#else #include +#endif #include "../vgui2/src/VPanel.h" #include #if defined( _X360 ) @@ -142,7 +146,7 @@ CMatSystemSurface g_MatSystemSurface; EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CMatSystemSurface, ISurface, VGUI_SURFACE_INTERFACE_VERSION, g_MatSystemSurface ); -#ifdef LINUX +#if defined(LINUX) || defined(OSX) CUtlDict< CMatSystemSurface::font_entry, unsigned short > CMatSystemSurface::m_FontData; #endif @@ -403,7 +407,7 @@ InitReturnVal_t CMatSystemSurface::Init( void ) FontManager().SetLanguage( "english" ); } -#ifdef LINUX +#if defined(LINUX) || defined(OSX) FontManager().SetFontDataHelper( &CMatSystemSurface::FontDataHelper ); #endif @@ -1903,16 +1907,7 @@ bool CMatSystemSurface::AddCustomFontFile( const char *fontName, const char *fon } Assert( success ); return success; -#elif OSX - - FSRef ref; - OSStatus err = FSPathMakeRef( (const UInt8*)fullPath, &ref, NULL ); - if ( err == noErr ) - err = ATSFontActivateFromFileReference( &ref, kATSFontContextLocal, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, NULL ); - - return err == noErr; - -#elif LINUX +#elif defined(LINUX) || defined(OSX) int size; if ( CMatSystemSurface::FontDataHelper( fontName, size, fontFileName ) ) @@ -1926,7 +1921,7 @@ bool CMatSystemSurface::AddCustomFontFile( const char *fontName, const char *fon #endif } -#ifdef LINUX +#if defined(LINUX) || defined(OSX) static void RemoveSpaces( CUtlString &str ) { From c7308906d1accfd217193cbc2de16e4416a7f2d1 Mon Sep 17 00:00:00 2001 From: hymei Date: Wed, 23 Feb 2022 20:00:04 +0800 Subject: [PATCH 16/34] arm64 detect marcos --- materialsystem/cmatlightmaps.h | 2 +- mathlib/sse.cpp | 16 ++++++++------ public/mathlib/mathlib.h | 8 ++++--- public/mathlib/ssemath.h | 2 +- public/mathlib/vector4d.h | 6 ++--- public/steam/steamtypes.h | 4 ++-- public/tier0/wchartypes.h | 2 +- tier0/cpu.cpp | 2 +- tier0/cpu_posix.cpp | 12 +++++++++- tier1/processor_detect_linux.cpp | 38 ++++++++++++++++++++++++++------ tier1/reliabletimer.cpp | 2 +- 11 files changed, 66 insertions(+), 28 deletions(-) diff --git a/materialsystem/cmatlightmaps.h b/materialsystem/cmatlightmaps.h index 1103fd5c..0a6ee02a 100644 --- a/materialsystem/cmatlightmaps.h +++ b/materialsystem/cmatlightmaps.h @@ -26,7 +26,7 @@ class CMaterialDict; class IMaterial; class IMaterialInternal; class FloatBitMap_t; -typedef int ShaderAPITextureHandle_t; +typedef intp ShaderAPITextureHandle_t; struct MaterialSystem_SortInfo_t; typedef unsigned short MaterialHandle_t; diff --git a/mathlib/sse.cpp b/mathlib/sse.cpp index 83dda7d9..86377a6f 100644 --- a/mathlib/sse.cpp +++ b/mathlib/sse.cpp @@ -11,7 +11,7 @@ #include "tier0/dbg.h" #include "mathlib/mathlib.h" #include "mathlib/vector.h" -#ifdef __arm__ +#if defined(__arm__) || defined(__arm64__) #include "sse2neon.h" #endif @@ -180,7 +180,7 @@ float _SSE_RSqrtFast(float x) Assert( s_bMathlibInitialized ); float rroot; -#ifdef __arm__ +#if defined(__arm__) || defined(__arm64__) rroot = _SSE_RSqrtAccurate(x); #elif _WIN32 _asm @@ -217,7 +217,7 @@ float FASTCALL _SSE_VectorNormalize (Vector& vec) // be much of a performance win, considering you will very likely miss 3 branch predicts in a row. if ( v[0] || v[1] || v[2] ) { -#ifdef __arm__ +#if defined(__arm__) || defined(__arm64__) float rsqrt = _SSE_RSqrtAccurate( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); r[0] = v[0] * rsqrt; r[1] = v[1] * rsqrt; @@ -296,7 +296,7 @@ void FASTCALL _SSE_VectorNormalizeFast (Vector& vec) float _SSE_InvRSquared(const float* v) { float inv_r2 = 1.f; -#ifdef __arm__ +#if defined(__arm__) || defined(__arm64__) return _SSE_RSqrtAccurate( FLT_EPSILON + v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); #elif _WIN32 _asm { // Intel SSE only routine @@ -391,8 +391,10 @@ typedef __m64 v2si; // vector of 2 int (mmx) void _SSE_SinCos(float x, float* s, float* c) { -#ifdef __arm__ -#if defined( POSIX ) +#if defined(__arm__) || defined(__arm64__) +#if defined( OSX ) + __sincosf(x, s, c); +#elif defined( POSIX ) sincosf(x, s, c); #else *s = sin( x ); @@ -605,7 +607,7 @@ void _SSE_SinCos(float x, float* s, float* c) float _SSE_cos( float x ) { -#ifdef __arm__ +#if defined(__arm__) || defined(__arm64__) return cos(x); #elif _WIN32 float temp; diff --git a/public/mathlib/mathlib.h b/public/mathlib/mathlib.h index fe103e5e..4a765fcd 100644 --- a/public/mathlib/mathlib.h +++ b/public/mathlib/mathlib.h @@ -457,6 +457,8 @@ void inline SinCos( float radians, float *sine, float *cosine ) #elif defined( PLATFORM_WINDOWS_PC64 ) *sine = sin( radians ); *cosine = cos( radians ); +#elif defined( OSX ) + __sincosf(radians, sine, cosine); #elif defined( POSIX ) sincosf(radians, sine, cosine); #endif @@ -1213,7 +1215,7 @@ FORCEINLINE int RoundFloatToInt(float f) }; flResult = __fctiw( f ); return pResult[1]; -#elif defined (__arm__) +#elif defined (__arm__) || defined (__arm64__) return (int)(f + 0.5f); #else #error Unknown architecture @@ -1245,7 +1247,7 @@ FORCEINLINE unsigned long RoundFloatToUnsignedLong(float f) Assert( pIntResult[1] >= 0 ); return pResult[1]; #else // !X360 -#ifdef __arm__ +#if defined(__arm__) || defined(__arm64__) return (unsigned long)(f + 0.5f); #elif defined( PLATFORM_WINDOWS_PC64 ) uint nRet = ( uint ) f; @@ -2168,7 +2170,7 @@ inline bool CloseEnough( const Vector &a, const Vector &b, float epsilon = EQUAL // Fast compare // maxUlps is the maximum error in terms of Units in the Last Place. This // specifies how big an error we are willing to accept in terms of the value -// of the least significant digit of the floating point number’s +// of the least significant digit of the floating point number�s // representation. maxUlps can also be interpreted in terms of how many // representable floats we are willing to accept between A and B. // This function will allow maxUlps-1 floats between A and B. diff --git a/public/mathlib/ssemath.h b/public/mathlib/ssemath.h index 6a73b3f6..4580a4bd 100644 --- a/public/mathlib/ssemath.h +++ b/public/mathlib/ssemath.h @@ -8,7 +8,7 @@ #if defined( _X360 ) #include -#elif defined(__arm__) +#elif defined(__arm__) || defined(__arm64__) #include "sse2neon.h" #else #include diff --git a/public/mathlib/vector4d.h b/public/mathlib/vector4d.h index 89fcce01..72c63129 100644 --- a/public/mathlib/vector4d.h +++ b/public/mathlib/vector4d.h @@ -654,10 +654,10 @@ inline void Vector4DWeightMAD( vec_t w, Vector4DAligned const& vInA, Vector4DAli vOutB.z += vInB.z * w; vOutB.w += vInB.w * w; #else - __vector4 temp; + __vector4 temp; - temp = __lvlx( &w, 0 ); - temp = __vspltw( temp, 0 ); + temp = __lvlx( &w, 0 ); + temp = __vspltw( temp, 0 ); vOutA.AsM128() = __vmaddfp( vInA.AsM128(), temp, vOutA.AsM128() ); vOutB.AsM128() = __vmaddfp( vInB.AsM128(), temp, vOutB.AsM128() ); diff --git a/public/steam/steamtypes.h b/public/steam/steamtypes.h index 22ce3e61..f229f238 100644 --- a/public/steam/steamtypes.h +++ b/public/steam/steamtypes.h @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2008, Valve LLC, All rights reserved. ============ +//========= Copyright � 1996-2008, Valve LLC, All rights reserved. ============ // // Purpose: // @@ -24,7 +24,7 @@ typedef unsigned char uint8; #define POSIX 1 #endif -#if defined(__x86_64__) || defined(_WIN64) +#if defined(__x86_64__) || defined(_WIN64) || defined(__arm64__) #define X64BITS #endif diff --git a/public/tier0/wchartypes.h b/public/tier0/wchartypes.h index 814470fd..8d8838d8 100644 --- a/public/tier0/wchartypes.h +++ b/public/tier0/wchartypes.h @@ -20,7 +20,7 @@ // Temporarily turn off Valve defines #include "tier0/valve_off.h" -#if !defined(_WCHAR_T_DEFINED) && !defined(GNUC) +#if !defined(_WCHAR_T_DEFINED) && !defined( __WCHAR_TYPE__ ) && !defined(GNUC) typedef unsigned short wchar_t; #define _WCHAR_T_DEFINED #endif diff --git a/tier0/cpu.cpp b/tier0/cpu.cpp index 90ca43ac..a8a0814c 100644 --- a/tier0/cpu.cpp +++ b/tier0/cpu.cpp @@ -22,7 +22,7 @@ const tchar* GetProcessorVendorId(); static bool cpuid(unsigned long function, unsigned long& out_eax, unsigned long& out_ebx, unsigned long& out_ecx, unsigned long& out_edx) { -#if defined (__arm__) || defined( _X360 ) +#if defined (__arm__) || defined (__arm64__) || defined( _X360 ) return false; #elif defined(GNUC) asm("mov %%ebx, %%esi\n\t" diff --git a/tier0/cpu_posix.cpp b/tier0/cpu_posix.cpp index c0deed41..094bc435 100644 --- a/tier0/cpu_posix.cpp +++ b/tier0/cpu_posix.cpp @@ -99,6 +99,15 @@ uint64 GetCPUFreqFromPROC() uint64 CalculateCPUFreq() { +#ifdef __APPLE__ + uint64 freq_hz = 0; + size_t freq_size = sizeof(freq_hz); + int retval = sysctlbyname("hw.cpufrequency_max", &freq_hz, &freq_size, NULL, 0); + // MoeMod : TODO dont know how to get freq on Apple Silicon + if(!freq_hz) + freq_hz = 3200000; + return freq_hz; +#else // Try to open cpuinfo_max_freq. If the kernel was built with cpu scaling support disabled, this will fail. FILE *fp = fopen( "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r" ); if ( fp ) @@ -118,8 +127,9 @@ uint64 CalculateCPUFreq() return retVal * 1000; } } +#endif -#ifndef __arm__ +#if !defined(__arm__) && !defined(__arm64__) // Compute the period. Loop until we get 3 consecutive periods that // are the same to within a small error. The error is chosen // to be +/- 0.02% on a P-200. diff --git a/tier1/processor_detect_linux.cpp b/tier1/processor_detect_linux.cpp index 9e2490bd..8887926e 100644 --- a/tier1/processor_detect_linux.cpp +++ b/tier1/processor_detect_linux.cpp @@ -6,24 +6,48 @@ // $NoKeywords: $ //=============================================================================// +#include "platform.h" + #if defined __SANITIZE_ADDRESS__ bool CheckMMXTechnology(void) { return false; } bool CheckSSETechnology(void) { return false; } bool CheckSSE2Technology(void) { return false; } bool Check3DNowTechnology(void) { return false; } -#elif defined (__arm__) +#elif defined (__arm__) || defined (__arm64__) bool CheckMMXTechnology(void) { return false; } bool CheckSSETechnology(void) { return false; } bool CheckSSE2Technology(void) { return false; } bool Check3DNowTechnology(void) { return false; } #else -#define cpuid(in,a,b,c,d) \ - asm("pushl %%ebx\n\t" "cpuid\n\t" "movl %%ebx,%%esi\n\t" "pop %%ebx": "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (in)); +static void cpuid(uint32 function, uint32& out_eax, uint32& out_ebx, uint32& out_ecx, uint32& out_edx) +{ +#if defined(PLATFORM_64BITS) + asm("mov %%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchg %%rsi, %%rbx" + : "=a" (out_eax), + "=S" (out_ebx), + "=c" (out_ecx), + "=d" (out_edx) + : "a" (function) + ); +#else + asm("mov %%ebx, %%esi\n\t" + "cpuid\n\t" + "xchg %%esi, %%ebx" + : "=a" (out_eax), + "=S" (out_ebx), + "=c" (out_ecx), + "=d" (out_edx) + : "a" (function) + ); +#endif +} bool CheckMMXTechnology(void) { - unsigned long eax,ebx,edx,unused; + uint32 eax,ebx,edx,unused; cpuid(1,eax,ebx,unused,edx); return edx & 0x800000; @@ -31,7 +55,7 @@ bool CheckMMXTechnology(void) bool CheckSSETechnology(void) { - unsigned long eax,ebx,edx,unused; + uint32 eax,ebx,edx,unused; cpuid(1,eax,ebx,unused,edx); return edx & 0x2000000L; @@ -39,7 +63,7 @@ bool CheckSSETechnology(void) bool CheckSSE2Technology(void) { - unsigned long eax,ebx,edx,unused; + uint32 eax,ebx,edx,unused; cpuid(1,eax,ebx,unused,edx); return edx & 0x04000000; @@ -47,7 +71,7 @@ bool CheckSSE2Technology(void) bool Check3DNowTechnology(void) { - unsigned long eax, unused; + uint32 eax, unused; cpuid(0x80000000,eax,unused,unused,unused); if ( eax > 0x80000000L ) diff --git a/tier1/reliabletimer.cpp b/tier1/reliabletimer.cpp index ab46596f..73556e90 100644 --- a/tier1/reliabletimer.cpp +++ b/tier1/reliabletimer.cpp @@ -87,7 +87,7 @@ int64 CReliableTimer::GetPerformanceCountNow() uint64 ulNow; SYS_TIMEBASE_GET( ulNow ); return ulNow; -#elif defined( __arm__ ) && defined (POSIX) +#elif (defined( __arm__ ) || defined( __arm64__ )) && defined (POSIX) struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return ts.tv_sec * 1000000000ULL + ts.tv_nsec; From 3291cdf978a092dc80dc208804eaa5eac46ebcb5 Mon Sep 17 00:00:00 2001 From: hymei Date: Wed, 23 Feb 2022 20:04:52 +0800 Subject: [PATCH 17/34] osx : fix syscalls --- appframework/glmrendererinfo_osx.mm | 14 +++++------ appframework/sdlmgr.cpp | 2 ++ datamodel/clipboardmanager.cpp | 2 +- engine/filesystem_engine.cpp | 1 - engine/sys_mainwind.cpp | 2 +- public/tier0/protected_things.h | 13 +++++----- public/tier1/rangecheckedvar.h | 2 +- public/togl/linuxwin/glfuncs.h | 2 ++ public/togl/rendermechanism.h | 4 ++++ togl/linuxwin/cglmprogram.cpp | 9 +++---- togl/linuxwin/glmgr.cpp | 25 ++++++++++++++----- togl/linuxwin/glmgr_flush.inl | 5 ++-- togl/linuxwin/glmgrbasics.cpp | 4 +++- togl/linuxwin/intelglmallocworkaround.cpp | 29 ++++++++++++++++++++++- vgui2/src/system_posix.cpp | 8 +++++++ vguimatsurface/MatSystemSurface.h | 2 +- 16 files changed, 92 insertions(+), 32 deletions(-) diff --git a/appframework/glmrendererinfo_osx.mm b/appframework/glmrendererinfo_osx.mm index fbaf3150..a36f6249 100644 --- a/appframework/glmrendererinfo_osx.mm +++ b/appframework/glmrendererinfo_osx.mm @@ -206,7 +206,7 @@ GLMRendererInfo::GLMRendererInfo( GLMRendererInfoFields *info ) kCGLPFADoubleBuffer, kCGLPFANoRecovery, kCGLPFAAccelerated, kCGLPFADepthSize, 0, kCGLPFAColorSize, 32, - kCGLPFARendererID, info->m_rendererID, + kCGLPFARendererID, (unsigned int)info->m_rendererID, 0 }; @@ -859,7 +859,7 @@ void GLMDisplayDB::PopulateRenderers( void ) { // grab the OS version - long vMajor = 0; long vMinor = 0; long vMinorMinor = 0; + SInt32 vMajor = 0; SInt32 vMinor = 0; SInt32 vMinorMinor = 0; OSStatus gestalt_err = 0; gestalt_err = Gestalt(gestaltSystemVersionMajor, &vMajor); @@ -1374,7 +1374,7 @@ bool GLMDisplayDB::GetModeInfo( int rendererIndex, int displayIndex, int modeInd { int modeIndex=0; number = (CFNumberRef)CFDictionaryGetValue(curModeDict, kCGDisplayMode); - CFNumberGetValue(number, kCFNumberLongType, &modeIndex); + CFNumberGetValue(number, kCFNumberIntType, &modeIndex); // grab the width and height, I am unclear on whether this is the displayed FB width or the display device width. int screenWidth=0; @@ -1382,11 +1382,11 @@ bool GLMDisplayDB::GetModeInfo( int rendererIndex, int displayIndex, int modeInd int refreshHz=0; number = (CFNumberRef)CFDictionaryGetValue(curModeDict, kCGDisplayWidth); - CFNumberGetValue(number, kCFNumberLongType, &screenWidth); + CFNumberGetValue(number, kCFNumberIntType, &screenWidth); number = (CFNumberRef)CFDictionaryGetValue(curModeDict, kCGDisplayHeight); - CFNumberGetValue(number, kCFNumberLongType, &screenHeight); + CFNumberGetValue(number, kCFNumberIntType, &screenHeight); number = (CFNumberRef)CFDictionaryGetValue(curModeDict, kCGDisplayRefreshRate); - CFNumberGetValue(number, kCFNumberLongType, &refreshHz); + CFNumberGetValue(number, kCFNumberIntType, &refreshHz); GLMPRINTF(( "-D- GLMDisplayDB::GetModeInfo sees mode-index=%d, width=%d, height=%d on CGID %08x (display index %d on rendererindex %d)", modeIndex, @@ -1574,7 +1574,7 @@ void GLMDisplayInfo::PopulateModes( void ) void GLMDisplayInfo::Dump( int which ) { - GLMPRINTF(("\n #%d: GLMDisplayInfo @ %08x, cg-id=%08x display-mask=%08x pixwidth=%d pixheight=%d", which, (int)this, m_info.m_cgDisplayID, m_info.m_glDisplayMask, m_info.m_displayPixelWidth, m_info.m_displayPixelHeight )); + GLMPRINTF(("\n #%d: GLMDisplayInfo @ %08x, cg-id=%08x display-mask=%08x pixwidth=%d pixheight=%d", which, (int)(intp)this, m_info.m_cgDisplayID, m_info.m_glDisplayMask, m_info.m_displayPixelWidth, m_info.m_displayPixelHeight )); FOR_EACH_VEC( *m_modes, i ) { diff --git a/appframework/sdlmgr.cpp b/appframework/sdlmgr.cpp index 20a299c2..e8e5a388 100644 --- a/appframework/sdlmgr.cpp +++ b/appframework/sdlmgr.cpp @@ -19,7 +19,9 @@ #include "tier1/utllinkedlist.h" #include "tier1/convar.h" +#ifdef TOGLES #include +#endif // NOTE: This has to be the last file included! (turned off below, since this is included like a header) #include "tier0/memdbgon.h" diff --git a/datamodel/clipboardmanager.cpp b/datamodel/clipboardmanager.cpp index 5ffa5335..cb2d5a9d 100644 --- a/datamodel/clipboardmanager.cpp +++ b/datamodel/clipboardmanager.cpp @@ -8,7 +8,7 @@ #include "datamodel.h" #include "tier1/KeyValues.h" -#ifndef _LINUX +#ifdef _WIN32 #define USE_WINDOWS_CLIPBOARD #endif diff --git a/engine/filesystem_engine.cpp b/engine/filesystem_engine.cpp index e0944f85..35fd1081 100644 --- a/engine/filesystem_engine.cpp +++ b/engine/filesystem_engine.cpp @@ -8,7 +8,6 @@ #include "quakedef.h" // for MAX_OSPATH #include #include -#include #include "filesystem.h" #include "bitmap/tgawriter.h" #include diff --git a/engine/sys_mainwind.cpp b/engine/sys_mainwind.cpp index f454c2fc..21cb9487 100644 --- a/engine/sys_mainwind.cpp +++ b/engine/sys_mainwind.cpp @@ -1566,7 +1566,7 @@ void *CGame::GetMainWindowPlatformSpecificHandle( void ) #ifdef OSX id nsWindow = (id)pInfo.info.cocoa.window; SEL selector = sel_registerName("windowRef"); - id windowRef = objc_msgSend( nsWindow, selector ); + id windowRef = ((id(*)(id, SEL))objc_msgSend)( nsWindow, selector ); return windowRef; #else // Not used on Linux. diff --git a/public/tier0/protected_things.h b/public/tier0/protected_things.h index 8cbfa929..4d67e377 100644 --- a/public/tier0/protected_things.h +++ b/public/tier0/protected_things.h @@ -144,14 +144,15 @@ #define timeGetTime timeGetTime__USE_VCR_MODE #if defined( clock ) #undef clock - #endif - #define time time__USE_VCR_MODE + #endif + // MoeMod : breaks system header + //#define time time__USE_VCR_MODE - #if defined( recvfrom ) - #undef recvfrom - #endif - #define recvfrom recvfrom__USE_VCR_MODE + //#if defined( recvfrom ) + // #undef recvfrom + //#endif + //#define recvfrom recvfrom__USE_VCR_MODE #if defined( GetCursorPos ) diff --git a/public/tier1/rangecheckedvar.h b/public/tier1/rangecheckedvar.h index 52313f82..258f5fc3 100644 --- a/public/tier1/rangecheckedvar.h +++ b/public/tier1/rangecheckedvar.h @@ -34,7 +34,7 @@ inline void RangeCheck( const T &value, int minValue, int maxValue ) if ( ThreadInMainThread() && g_bDoRangeChecks ) { // Ignore the min/max stuff for now.. just make sure it's not a NAN. - Assert( _finite( value ) ); + Assert( IsFinite( value ) ); } #endif } diff --git a/public/togl/linuxwin/glfuncs.h b/public/togl/linuxwin/glfuncs.h index f543b4af..a141887b 100644 --- a/public/togl/linuxwin/glfuncs.h +++ b/public/togl/linuxwin/glfuncs.h @@ -116,6 +116,8 @@ GL_FUNC_VOID(OpenGL,true,glUniform1iARB,(GLint a,GLint b),(a,b)) GL_FUNC_VOID(OpenGL,true,glUniform4fv,(GLint a,GLsizei b,const GLfloat *c),(a,b,c)) GL_FUNC(OpenGL,true,GLboolean,glUnmapBuffer,(GLenum a),(a)) GL_FUNC_VOID(OpenGL,true,glUseProgram,(GLuint a),(a)) +GL_FUNC_VOID(OpenGL,true,glUseProgramObjectARB,(GLhandleARB a),(a)) +GL_FUNC_VOID(OpenGL,true,glValidateProgramARB,(GLhandleARB a),(a)) GL_FUNC_VOID(OpenGL,true,glVertex3f,(GLfloat a,GLfloat b,GLfloat c),(a,b,c)) GL_FUNC_VOID(OpenGL,true,glVertexAttribPointer,(GLuint a,GLint b,GLenum c,GLboolean d,GLsizei e,const GLvoid *f),(a,b,c,d,e,f)) GL_FUNC_VOID(OpenGL,true,glViewport,(GLint a,GLint b,GLsizei c,GLsizei d),(a,b,c,d)) diff --git a/public/togl/rendermechanism.h b/public/togl/rendermechanism.h index 374ccaa9..252095af 100644 --- a/public/togl/rendermechanism.h +++ b/public/togl/rendermechanism.h @@ -34,8 +34,12 @@ #undef PROTECTED_THINGS_ENABLE +#ifdef OSX +#include +#else #include #include +#endif #include "tier0/basetypes.h" #include "tier0/platform.h" diff --git a/togl/linuxwin/cglmprogram.cpp b/togl/linuxwin/cglmprogram.cpp index 8c0103b3..00109113 100644 --- a/togl/linuxwin/cglmprogram.cpp +++ b/togl/linuxwin/cglmprogram.cpp @@ -157,7 +157,8 @@ CGLMProgram::~CGLMProgram( ) GLMShaderDesc *glslDesc = &m_descs[kGLMGLSL]; if (glslDesc->m_object.glsl) { - gGL->glDeleteShader( (uint)glslDesc->m_object.glsl ); // why do I need a cast here again ? + //gGL->glDeleteShader( (uint)glslDesc->m_object.glsl ); // why do I need a cast here again ? + gGL->glDeleteObjectARB( glslDesc->m_object.glsl ); // because you call the wrong api glslDesc->m_object.glsl = 0; } @@ -814,7 +815,7 @@ void CGLMProgram::LogSlow( EGLMProgramLang lang ) m_type==kGLMVertexProgram ? "VS" : "FS", this, lang==kGLMGLSL ? "GLSL" : "ARB", - (int)(lang==kGLMGLSL ? (int)desc->m_object.glsl : (int)desc->m_object.arb), + (int)(lang==kGLMGLSL ? (intp)desc->m_object.glsl : (int)desc->m_object.arb), m_text ); #endif @@ -828,7 +829,7 @@ void CGLMProgram::LogSlow( EGLMProgramLang lang ) m_type==kGLMVertexProgram ? "VS" : "FS", this, lang==kGLMGLSL ? "GLSL" : "ARB", - (int)(lang==kGLMGLSL ? (int)desc->m_object.glsl : (int)desc->m_object.arb), + (int)(lang==kGLMGLSL ? (intp)desc->m_object.glsl : (int)desc->m_object.arb), desc->m_slowMark+1 ); } @@ -984,7 +985,7 @@ bool CGLMShaderPair::ValidateProgramPair() if (m_valid) { - gGL->glUseProgram( m_program ); + gGL->glUseProgramObjectARB( m_program ); m_ctx->NewLinkedProgram(); diff --git a/togl/linuxwin/glmgr.cpp b/togl/linuxwin/glmgr.cpp index 61fc979d..b97e6cf2 100644 --- a/togl/linuxwin/glmgr.cpp +++ b/togl/linuxwin/glmgr.cpp @@ -670,7 +670,7 @@ void GLMContext::DumpCaps( void ) #define dumpfield_hex( fff ) printf( "\n %-30s : 0x%08x", #fff, (int) m_caps.fff ) #define dumpfield_str( fff ) printf( "\n %-30s : %s", #fff, m_caps.fff ) - printf("\n-------------------------------- context caps for context %08x", (uint)this); + printf("\n-------------------------------- context caps for context %p", this); dumpfield( m_fullscreen ); dumpfield( m_accelerated ); @@ -1745,8 +1745,9 @@ void GLMContext::PreloadTex( CGLMTex *tex, bool force ) } } - gGL->glUseProgram( (GLuint)preloadPair->m_program ); - + gGL->glUseProgramObjectARB( preloadPair->m_program ); + //gGL->glUseProgram( (GLuint)preloadPair->m_program ); + m_pBoundPair = preloadPair; m_bDirtyPrograms = true; @@ -1793,7 +1794,7 @@ void GLMContext::PreloadTex( CGLMTex *tex, bool force ) gGL->glEnableVertexAttribArray( 0 ); - gGL->glVertexAttribPointer( 0, 3, GL_FLOAT, 0, 0, posns ); + gGL->glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), posns ); gGL->glDrawRangeElements( GL_TRIANGLES, 0, 2, 3, GL_UNSIGNED_SHORT, indices); @@ -2701,6 +2702,10 @@ GLMContext::GLMContext( IDirect3DDevice9 *pDevice, GLMDisplayParams *params ) // debug state m_debugFrameIndex = -1; + +#if defined( OSX ) && defined( GLMDEBUG ) + memset( m_boundProgram , 0, sizeof( m_boundProgram ) ); +#endif #if GLMDEBUG // ####################################################################################### @@ -5202,11 +5207,11 @@ void GLMContext::DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsize if ( pIndexBuf->m_bPseudo ) { // you have to pass actual address, not offset - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_pPseudoBuf ); } if (pIndexBuf->m_bUsingPersistentBuffer) { - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_nPersistentBufferStartOffset ); } #if GLMDEBUG @@ -5244,7 +5249,11 @@ void GLMContext::DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsize } else { +#if defined( OSX ) + // MoeMod: TOGL IS NOT USING m_boundProgram THIS AT ALL +#else AssertOnce(!"drawing with no vertex program bound"); +#endif } if (m_boundProgram[kGLMFragmentProgram]) @@ -5253,7 +5262,11 @@ void GLMContext::DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsize } else { +#if defined( OSX ) + // MoeMod: TOGL IS NOT USING m_boundProgram THIS AT ALL +#else AssertOnce(!"drawing with no fragment program bound"); +#endif } #endif diff --git a/togl/linuxwin/glmgr_flush.inl b/togl/linuxwin/glmgr_flush.inl index fcddd616..75325947 100644 --- a/togl/linuxwin/glmgr_flush.inl +++ b/togl/linuxwin/glmgr_flush.inl @@ -196,7 +196,8 @@ FORCEINLINE void GLMContext::FlushDrawStates( uint nStartIndex, uint nEndIndex, } } - gGL->glUseProgram( (GLuint)pNewPair->m_program ); + gGL->glUseProgramObjectARB(pNewPair->m_program); + //gGL->glUseProgram( (GLuint)pNewPair->m_program ); GL_BATCH_PERF( m_FlushStats.m_nTotalProgramPairChanges++; ) @@ -563,7 +564,7 @@ FORCEINLINE void GLMContext::FlushDrawStates( uint nStartIndex, uint nEndIndex, SetBufAndVertexAttribPointer( nIndex, pBuf->GetHandle(), pStream->m_stride, pDeclElem->m_gldecl.m_datatype, pDeclElem->m_gldecl.m_normalized, pDeclElem->m_gldecl.m_nCompCount, - reinterpret_cast< const GLvoid * >( reinterpret_cast< int >( pBuf->m_pPseudoBuf ) + nBufOffset ), + reinterpret_cast< const GLvoid * >( reinterpret_cast< intp >( pBuf->m_pPseudoBuf ) + nBufOffset ), pBuf->m_nRevision ); if ( !( m_lastKnownVertexAttribMask & nMask ) ) diff --git a/togl/linuxwin/glmgrbasics.cpp b/togl/linuxwin/glmgrbasics.cpp index adf60714..7a02f7f3 100644 --- a/togl/linuxwin/glmgrbasics.cpp +++ b/togl/linuxwin/glmgrbasics.cpp @@ -4243,7 +4243,9 @@ CGLMEditableTextItem::~CGLMEditableTextItem( ) if (m_mirror) { - free( m_mirror ); + //free( m_mirror ); + // MoeMod : should be delete here + delete m_mirror; } } diff --git a/togl/linuxwin/intelglmallocworkaround.cpp b/togl/linuxwin/intelglmallocworkaround.cpp index efe0e0ad..a0ab852b 100644 --- a/togl/linuxwin/intelglmallocworkaround.cpp +++ b/togl/linuxwin/intelglmallocworkaround.cpp @@ -27,6 +27,9 @@ // memdbgon -must- be the last include file in a .cpp file. #include "tier0/memdbgon.h" +// MoeMod : ARM Mac doesnt need this workround +#if (defined(__i386__) || defined(__x86_64__)) + IntelGLMallocWorkaround* IntelGLMallocWorkaround::s_pWorkaround = NULL; void *IntelGLMallocWorkaround::ZeroingAlloc(size_t size) @@ -68,4 +71,28 @@ bool IntelGLMallocWorkaround::Enable() } return true; -} \ No newline at end of file +} + +#else +IntelGLMallocWorkaround* IntelGLMallocWorkaround::s_pWorkaround = NULL; + +void *IntelGLMallocWorkaround::ZeroingAlloc(size_t size) +{ + return nullptr; +} + +IntelGLMallocWorkaround* IntelGLMallocWorkaround::Get() +{ + if (!s_pWorkaround) + { + s_pWorkaround = new IntelGLMallocWorkaround(); + } + + return s_pWorkaround; +} + +bool IntelGLMallocWorkaround::Enable() +{ + return true; +} +#endif \ No newline at end of file diff --git a/vgui2/src/system_posix.cpp b/vgui2/src/system_posix.cpp index 251cbb2d..349165b2 100644 --- a/vgui2/src/system_posix.cpp +++ b/vgui2/src/system_posix.cpp @@ -30,6 +30,8 @@ #ifdef OSX #include +#include +#include #elif defined(LINUX) #include #endif @@ -583,8 +585,14 @@ int CSystem::GetAvailableDrives(char *buf, int bufLen) //----------------------------------------------------------------------------- double CSystem::GetFreeDiskSpace(const char *path) { +#if __DARWIN_ONLY_64_BIT_INO_T + // MoeMod: newer macOS only support 64bit, so no statfs64 is provided + struct statfs buf; + int ret = statfs( path, &buf ); +#else struct statfs64 buf; int ret = statfs64( path, &buf ); +#endif if ( ret < 0 ) return 0.0; return (double) ( buf.f_bsize * buf.f_bfree ); diff --git a/vguimatsurface/MatSystemSurface.h b/vguimatsurface/MatSystemSurface.h index 5be5bf3f..33889513 100644 --- a/vguimatsurface/MatSystemSurface.h +++ b/vguimatsurface/MatSystemSurface.h @@ -556,7 +556,7 @@ private: int m_nFullscreenViewportHeight; ITexture *m_pFullscreenRenderTarget; -#ifdef LINUX +#if defined(LINUX) || defined(OSX) struct font_entry { void *data; From df78eef85fefa73143053395a9273d97ca070b11 Mon Sep 17 00:00:00 2001 From: hymei Date: Wed, 23 Feb 2022 20:06:43 +0800 Subject: [PATCH 18/34] osx : use freetype instead of deprecated carbon api --- common/vgui_surfacelib/FontManager.h | 6 +++--- common/vgui_surfacelib/vguifont.h | 5 +---- vgui2/vgui_surfacelib/FontManager.cpp | 12 ++++++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/common/vgui_surfacelib/FontManager.h b/common/vgui_surfacelib/FontManager.h index 56471364..0d7d1e58 100644 --- a/common/vgui_surfacelib/FontManager.h +++ b/common/vgui_surfacelib/FontManager.h @@ -17,7 +17,7 @@ #include "filesystem.h" #include "vguifont.h" -#ifdef LINUX +#if defined(LINUX) || defined(OSX) #include #include FT_FREETYPE_H typedef void *(*FontDataHelper)( const char *pchFontName, int &size, const char *fontFileName ); @@ -71,7 +71,7 @@ public: IFileSystem *FileSystem() { return m_pFileSystem; } IMaterialSystem *MaterialSystem() { return m_pMaterialSystem; } -#ifdef LINUX +#if defined(LINUX) || defined(OSX) FT_Library GetFontLibraryHandle() { return library; } void SetFontDataHelper( FontDataHelper helper ) { m_pFontDataHelper = helper; } #endif @@ -96,7 +96,7 @@ private: CUtlVector m_FontAmalgams; CUtlVector m_Win32Fonts; -#ifdef LINUX +#if defined(LINUX) || defined(OSX) FT_Library library; FontDataHelper m_pFontDataHelper; #endif diff --git a/common/vgui_surfacelib/vguifont.h b/common/vgui_surfacelib/vguifont.h index 34ee32c8..02374f36 100644 --- a/common/vgui_surfacelib/vguifont.h +++ b/common/vgui_surfacelib/vguifont.h @@ -23,10 +23,7 @@ struct newChar_t #ifdef WIN32 #include "Win32Font.h" typedef CWin32Font font_t; -#elif defined(OSX) -#include "osxfont.h" -typedef COSXFont font_t; -#elif defined(LINUX) +#elif defined(LINUX) || defined(OSX) #include "linuxfont.h" typedef CLinuxFont font_t; #else diff --git a/vgui2/vgui_surfacelib/FontManager.cpp b/vgui2/vgui_surfacelib/FontManager.cpp index 8942c158..dd86900e 100644 --- a/vgui2/vgui_surfacelib/FontManager.cpp +++ b/vgui2/vgui_surfacelib/FontManager.cpp @@ -43,7 +43,7 @@ CFontManager::CFontManager() m_FontAmalgams.AddToTail(); m_Win32Fonts.EnsureCapacity( MAX_INITIAL_FONTS ); -#ifdef LINUX +#if defined(LINUX) || defined(OSX) FT_Error error = FT_Init_FreeType( &library ); if ( error ) Error( "Unable to initalize freetype library, is it installed?" ); @@ -75,7 +75,7 @@ CFontManager::~CFontManager() { ClearAllFonts(); m_FontAmalgams.RemoveAll(); -#ifdef LINUX +#if defined(LINUX) || defined(OSX) FT_Done_FreeType( library ); #endif } @@ -280,7 +280,7 @@ font_t *CFontManager::CreateOrFindWin32Font(const char *windowsFontName, int tal i = m_Win32Fonts.AddToTail(); m_Win32Fonts[i] = NULL; -#ifdef LINUX +#if defined(LINUX) || defined(OSX) int memSize = 0; void *pchFontData = m_pFontDataHelper( windowsFontName, memSize, NULL ); @@ -730,7 +730,7 @@ void CFontManager::GetKernedCharWidth( vgui::HFont font, wchar_t ch, wchar_t chB { wide = 0.0f; flabcA = 0.0f; - + Assert( font != vgui::INVALID_FONT ); if ( font == vgui::INVALID_FONT ) return; @@ -749,8 +749,8 @@ void CFontManager::GetKernedCharWidth( vgui::HFont font, wchar_t ch, wchar_t chB if ( m_FontAmalgams[font].GetFontForChar( chAfter ) != pFont ) chAfter = 0; - -#if defined(LINUX) + +#if defined(LINUX) || defined(OSX) pFont->GetKernedCharWidth( ch, chBefore, chAfter, wide, flabcA, flabcC ); #else pFont->GetKernedCharWidth( ch, chBefore, chAfter, wide, flabcA ); From 0499fde7518b24a5806bb02a354bc43ab51d0820 Mon Sep 17 00:00:00 2001 From: hymei Date: Wed, 23 Feb 2022 20:10:25 +0800 Subject: [PATCH 19/34] arm64 : intp fixes --- engine/spatialpartition.cpp | 36 ++++++++++++++++----------------- game/client/c_baseanimating.cpp | 6 +++--- public/tier2/riff.h | 10 ++++----- tier1/byteswap.cpp | 4 ++++ tier2/soundutils.cpp | 20 +++++++++--------- 5 files changed, 40 insertions(+), 36 deletions(-) diff --git a/engine/spatialpartition.cpp b/engine/spatialpartition.cpp index 3bcc85f3..0b6b0b0a 100644 --- a/engine/spatialpartition.cpp +++ b/engine/spatialpartition.cpp @@ -95,14 +95,14 @@ struct EntityInfo_t uint8 m_flags; char m_nLevel[NUM_TREES]; // Which level voxel tree is it in? unsigned short m_nVisitBit[NUM_TREES]; - int m_iLeafList[NUM_TREES]; // Index into the leaf pool - leaf list for entity (m_aLeafList). + intp m_iLeafList[NUM_TREES]; // Index into the leaf pool - leaf list for entity (m_aLeafList). }; struct LeafListData_t { UtlHashFastHandle_t m_hVoxel; // Voxel handle the entity is in. - int m_iEntity; // Entity list index for voxel + intp m_iEntity; // Entity list index for voxel }; typedef CUtlFixedLinkedList CLeafList; @@ -206,7 +206,7 @@ private: inline void PackVoxel( int iX, int iY, int iZ, Voxel_t &voxel ); - typedef CUtlHashFixed > CHashTable; + typedef CUtlHashFixed > CHashTable; Vector m_vecVoxelOrigin; // Voxel space (hash) origin. CHashTable m_aVoxelHash; // Voxel tree (hash) - data = entity list head handle (m_aEntityList) @@ -603,7 +603,7 @@ void CVoxelHash::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vect #endif // Entity list. - int iEntity = m_aEntityList.Alloc( true ); + intp iEntity = m_aEntityList.Alloc( true ); m_aEntityList[iEntity] = hPartition; UtlHashFastHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); @@ -614,13 +614,13 @@ void CVoxelHash::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vect } else { - int iHead = m_aVoxelHash.Element( hHash ); + intp iHead = m_aVoxelHash.Element( hHash ); m_aEntityList.LinkBefore( iHead, iEntity ); m_aVoxelHash[hHash] = iEntity; } // Leaf list. - int iLeafList = leafList.Alloc( true ); + intp iLeafList = leafList.Alloc( true ); leafList[iLeafList].m_hVoxel = hHash; leafList[iLeafList].m_iEntity = iEntity; @@ -630,7 +630,7 @@ void CVoxelHash::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vect } else { - int iHead = info.m_iLeafList[treeId]; + intp iHead = info.m_iLeafList[treeId]; leafList.LinkBefore( iHead, iLeafList ); info.m_iLeafList[treeId] = iLeafList; } @@ -649,8 +649,8 @@ void CVoxelHash::RemoveFromTree( SpatialPartitionHandle_t hPartition ) CLeafList &leafList = m_pTree->LeafList(); int treeId = m_pTree->GetTreeId(); - int iLeaf = data.m_iLeafList[treeId]; - int iNext; + intp iLeaf = data.m_iLeafList[treeId]; + intp iNext; while ( iLeaf != leafList.InvalidIndex() ) { // Get the next voxel - if any. @@ -664,12 +664,12 @@ void CVoxelHash::RemoveFromTree( SpatialPartitionHandle_t hPartition ) } // Get the head of the entity list for the voxel. - int iEntity = leafList[iLeaf].m_iEntity; - int iEntityHead = m_aVoxelHash[hHash]; + intp iEntity = leafList[iLeaf].m_iEntity; + intp iEntityHead = m_aVoxelHash[hHash]; if ( iEntityHead == iEntity ) { - int iEntityNext = m_aEntityList.Next( iEntityHead ); + intp iEntityNext = m_aEntityList.Next( iEntityHead ); if ( iEntityNext == m_aEntityList.InvalidIndex() ) { m_aVoxelHash.Remove( hHash ); @@ -911,7 +911,7 @@ bool CVoxelHash::EnumerateElementsInVoxel( Voxel_t voxel, const T &intersectTest return true; SpatialPartitionHandle_t hPartition; - for ( int i = m_aVoxelHash.Element( hHash ); i != m_aEntityList.InvalidIndex(); i = m_aEntityList.Next(i) ) + for ( intp i = m_aVoxelHash.Element( hHash ); i != m_aEntityList.InvalidIndex(); i = m_aEntityList.Next(i) ) { hPartition = m_aEntityList[i]; if ( hPartition == PARTITION_INVALID_HANDLE ) @@ -952,7 +952,7 @@ bool CVoxelHash::EnumerateElementsInSingleVoxel( Voxel_t voxel, const T &interse { // NOTE: We don't have to do the enum id checking, nor do we have to up the // nesting level, since this only visits 1 voxel. - int iEntityList; + intp iEntityList; UtlHashFastHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); if ( hHash != m_aVoxelHash.InvalidHandle() ) { @@ -1394,7 +1394,7 @@ bool CVoxelHash::EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask, { // NOTE: We don't have to do the enum id checking, nor do we have to up the // nesting level, since this only visits 1 voxel. - int iEntityList; + intp iEntityList; UtlHashFastHandle_t hHash = m_aVoxelHash.Find( v.uiVoxel ); if ( hHash != m_aVoxelHash.InvalidHandle() ) { @@ -1533,7 +1533,7 @@ void CVoxelHash::RenderObjectsInVoxel( Voxel_t voxel, CPartitionVisitor *pVisito if ( hHash == m_aVoxelHash.InvalidHandle() ) return; - int iEntityList = m_aVoxelHash.Element( hHash ); + intp iEntityList = m_aVoxelHash.Element( hHash ); while ( iEntityList != m_aEntityList.InvalidIndex() ) { SpatialPartitionHandle_t hPartition = m_aEntityList[iEntityList]; @@ -1564,7 +1564,7 @@ int CVoxelHash::EntityCount() while ( hHash != m_aVoxelHash.m_aBuckets[iBucket].InvalidIndex() ) { - int iEntity = m_aVoxelHash.m_aBuckets[iBucket][hHash].m_Data; + intp iEntity = m_aVoxelHash.m_aBuckets[iBucket][hHash].m_Data; while ( iEntity!= m_aEntityList.InvalidIndex() ) { ++nCount; @@ -1645,7 +1645,7 @@ void CVoxelHash::RenderAllObjectsInTree( float flTime ) while ( hHash != m_aVoxelHash.m_aBuckets[iBucket].InvalidIndex() ) { - int iEntity = m_aVoxelHash.m_aBuckets[iBucket][hHash].m_Data; + intp iEntity = m_aVoxelHash.m_aBuckets[iBucket][hHash].m_Data; while ( iEntity!= m_aEntityList.InvalidIndex() ) { SpatialPartitionHandle_t hPartition = m_aEntityList[iEntity]; diff --git a/game/client/c_baseanimating.cpp b/game/client/c_baseanimating.cpp index 5727d7b0..d66339e5 100644 --- a/game/client/c_baseanimating.cpp +++ b/game/client/c_baseanimating.cpp @@ -929,7 +929,7 @@ void C_BaseAnimating::LockStudioHdr() if ( pNewWrapper->GetVirtualModel() ) { - MDLHandle_t hVirtualModel = (MDLHandle_t)(int)(pStudioHdr->virtualModel)&0xffff; + MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ); mdlcache->LockStudioHdr( hVirtualModel ); } @@ -950,7 +950,7 @@ void C_BaseAnimating::UnlockStudioHdr() // Parallel rendering: don't unlock model data until end of rendering if ( pStudioHdr->GetVirtualModel() ) { - MDLHandle_t hVirtualModel = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff; + MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( m_pStudioHdr->GetRenderHdr()->VirtualModel() ); pCallQueue->QueueCall( mdlcache, &IMDLCache::UnlockStudioHdr, hVirtualModel ); } pCallQueue->QueueCall( mdlcache, &IMDLCache::UnlockStudioHdr, m_hStudioHdr ); @@ -961,7 +961,7 @@ void C_BaseAnimating::UnlockStudioHdr() // Immediate-mode rendering, can unlock immediately if ( pStudioHdr->GetVirtualModel() ) { - MDLHandle_t hVirtualModel = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff; + MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( m_pStudioHdr->GetRenderHdr()->VirtualModel() ); mdlcache->UnlockStudioHdr( hVirtualModel ); } mdlcache->UnlockStudioHdr( m_hStudioHdr ); diff --git a/public/tier2/riff.h b/public/tier2/riff.h index cc8be167..0eb3cfc0 100644 --- a/public/tier2/riff.h +++ b/public/tier2/riff.h @@ -99,11 +99,11 @@ private: class IFileWriteBinary { public: - virtual int create( const char *pFileName ) = 0; - virtual int write( void *pData, int size, int file ) = 0; - virtual void close( int file ) = 0; - virtual void seek( int file, int pos ) = 0; - virtual unsigned int tell( int file ) = 0; + virtual intp create( const char *pFileName ) = 0; + virtual int write( void *pData, int size, intp file ) = 0; + virtual void close( intp file ) = 0; + virtual void seek( intp file, int pos ) = 0; + virtual unsigned int tell( intp file ) = 0; }; //----------------------------------------------------------------------------- // Purpose: Used to write a RIFF format file diff --git a/tier1/byteswap.cpp b/tier1/byteswap.cpp index 9f66297d..f2798793 100644 --- a/tier1/byteswap.cpp +++ b/tier1/byteswap.cpp @@ -34,6 +34,10 @@ void CByteswap::SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typed SwapBufferToTargetEndian( (int*)pOutputBuffer, (int*)pData, pField->fieldSize ); break; + case FIELD_INTEGER64: + SwapBufferToTargetEndian( (uint64*)pOutputBuffer, (uint64*)pData, pField->fieldSize ); + break; + case FIELD_VECTOR: SwapBufferToTargetEndian( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 3 ); break; diff --git a/tier2/soundutils.cpp b/tier2/soundutils.cpp index ed3e1196..8fb57a16 100644 --- a/tier2/soundutils.cpp +++ b/tier2/soundutils.cpp @@ -40,11 +40,11 @@ public: class CFSIOWriteBinary : public IFileWriteBinary { public: - virtual int create( const char *pFileName ); - virtual int write( void *pData, int size, int file ); - virtual void close( int file ); - virtual void seek( int file, int pos ); - virtual unsigned int tell( int file ); + virtual intp create( const char *pFileName ); + virtual int write( void *pData, int size, intp file ); + virtual void close( intp file ); + virtual void seek( intp file, int pos ); + virtual unsigned int tell( intp file ); }; @@ -110,28 +110,28 @@ void CFSIOReadBinary::close( intp file ) //----------------------------------------------------------------------------- // RIFF writer that use the file system //----------------------------------------------------------------------------- -int CFSIOWriteBinary::create( const char *pFileName ) +intp CFSIOWriteBinary::create( const char *pFileName ) { g_pFullFileSystem->SetFileWritable( pFileName, true ); return (intp)g_pFullFileSystem->Open( pFileName, "wb" ); } -int CFSIOWriteBinary::write( void *pData, int size, int file ) +int CFSIOWriteBinary::write( void *pData, int size, intp file ) { return g_pFullFileSystem->Write( pData, size, (FileHandle_t)file ); } -void CFSIOWriteBinary::close( int file ) +void CFSIOWriteBinary::close( intp file ) { g_pFullFileSystem->Close( (FileHandle_t)file ); } -void CFSIOWriteBinary::seek( int file, int pos ) +void CFSIOWriteBinary::seek( intp file, int pos ) { g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); } -unsigned int CFSIOWriteBinary::tell( int file ) +unsigned int CFSIOWriteBinary::tell( intp file ) { return g_pFullFileSystem->Tell( (FileHandle_t)file ); } From 3bc519aecf614f3f5a46369cd0ad33777f14d7c4 Mon Sep 17 00:00:00 2001 From: hymei Date: Wed, 23 Feb 2022 21:11:56 +0800 Subject: [PATCH 20/34] arm64 : fix vgui2 VPAMEL in messagemap --- .../client/cstrike/VGUI/buypreset_listbox.cpp | 6 ++-- game/client/cstrike/VGUI/buypreset_listbox.h | 15 ++++++--- gameui/BasePanel.cpp | 7 ++--- public/vgui_controls/BuildGroup.h | 1 + public/vgui_controls/Menu.h | 4 +-- public/vgui_controls/MessageMap.h | 3 +- public/vgui_controls/PHandle.h | 13 +++++--- public/vgui_controls/Panel.h | 2 +- vgui2/vgui_controls/BuildGroup.cpp | 12 +++++++ vgui2/vgui_controls/Menu.cpp | 6 ++-- vgui2/vgui_controls/MenuItem.cpp | 4 +-- vgui2/vgui_controls/Panel.cpp | 31 +++++++++++++------ 12 files changed, 69 insertions(+), 35 deletions(-) diff --git a/game/client/cstrike/VGUI/buypreset_listbox.cpp b/game/client/cstrike/VGUI/buypreset_listbox.cpp index add8dd75..70dc046a 100644 --- a/game/client/cstrike/VGUI/buypreset_listbox.cpp +++ b/game/client/cstrike/VGUI/buypreset_listbox.cpp @@ -135,7 +135,7 @@ int BuyPresetListBox::computeVPixelsNeeded( void ) /** * Adds an item to the end of the listbox. UserData is assumed to be a pointer that can be freed by the listbox if non-NULL. */ -int BuyPresetListBox::AddItem( vgui::Panel *panel, void * userData ) +int BuyPresetListBox::AddItem( vgui::Panel *panel, IBuyPresetListBoxUserData * userData ) { assert(panel); @@ -192,7 +192,7 @@ Panel * BuyPresetListBox::GetItemPanel(int index) const /** * Returns the userData in the given index, or NULL */ -void * BuyPresetListBox::GetItemUserData(int index) +auto BuyPresetListBox::GetItemUserData(int index) -> IBuyPresetListBoxUserData * { if ( index < 0 || index >= m_items.Count() ) { @@ -206,7 +206,7 @@ void * BuyPresetListBox::GetItemUserData(int index) /** * Sets the userData in the given index */ -void BuyPresetListBox::SetItemUserData( int index, void * userData ) +void BuyPresetListBox::SetItemUserData( int index, IBuyPresetListBoxUserData * userData ) { if ( index < 0 || index >= m_items.Count() ) return; diff --git a/game/client/cstrike/VGUI/buypreset_listbox.h b/game/client/cstrike/VGUI/buypreset_listbox.h index 68d6de69..a09abf0e 100644 --- a/game/client/cstrike/VGUI/buypreset_listbox.h +++ b/game/client/cstrike/VGUI/buypreset_listbox.h @@ -27,14 +27,21 @@ public: BuyPresetListBox( vgui::Panel *parent, char const *panelName ); ~BuyPresetListBox(); - virtual int AddItem( vgui::Panel *panel, void * userData ); ///< Adds an item to the end of the listbox. UserData is assumed to be a pointer that can be freed by the listbox if non-NULL. + class IBuyPresetListBoxUserData + { + protected: + friend BuyPresetListBox; + virtual ~IBuyPresetListBoxUserData() {}; + }; + + virtual int AddItem( vgui::Panel *panel, IBuyPresetListBoxUserData *userData ); ///< Adds an item to the end of the listbox. UserData is assumed to be a pointer that will be deleted by the listbox if non-NULL. virtual int GetItemCount( void ) const; ///< Returns the number of items in the listbox void SwapItems( int index1, int index2 ); ///< Exchanges two items in the listbox void MakeItemVisible( int index ); ///< Try to ensure that the given index is visible vgui::Panel * GetItemPanel( int index ) const; ///< Returns the panel in the given index, or NULL - void * GetItemUserData( int index ); ///< Returns the userData in the given index, or NULL - void SetItemUserData( int index, void * userData ); ///< Sets the userData in the given index + IBuyPresetListBoxUserData * GetItemUserData( int index ); ///< Returns the userData in the given index, or NULL + void SetItemUserData( int index, IBuyPresetListBoxUserData * userData ); ///< Sets the userData in the given index virtual void RemoveItem( int index ); ///< Removes an item from the table (changing the indices of all following items), deleting the panel and userData virtual void DeleteAllItems(); ///< clears the listbox, deleting all panels and userData @@ -60,7 +67,7 @@ private: typedef struct dataitem_s { vgui::Panel *panel; - void * userData; + IBuyPresetListBoxUserData * userData; } DataItem; CUtlVector< DataItem > m_items; diff --git a/gameui/BasePanel.cpp b/gameui/BasePanel.cpp index 09a4ece2..9f5a8854 100644 --- a/gameui/BasePanel.cpp +++ b/gameui/BasePanel.cpp @@ -633,7 +633,7 @@ public: } } - MESSAGE_FUNC_INT( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", VPanel); + MESSAGE_FUNC_HANDLE( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", menuItem); private: CFooterPanel *m_pConsoleFooter; @@ -644,9 +644,8 @@ private: //----------------------------------------------------------------------------- // Purpose: Respond to cursor entering a menuItem. //----------------------------------------------------------------------------- -void CGameMenu::OnCursorEnteredMenuItem(int VPanel) +void CGameMenu::OnCursorEnteredMenuItem(VPANEL menuItem) { - VPANEL menuItem = (VPANEL)VPanel; MenuItem *item = static_cast(ipanel()->GetPanel(menuItem, GetModuleName())); KeyValues *pCommand = item->GetCommand(); if ( !pCommand->GetFirstSubKey() ) @@ -655,7 +654,7 @@ void CGameMenu::OnCursorEnteredMenuItem(int VPanel) if ( !pszCmd || !pszCmd[0] ) return; - BaseClass::OnCursorEnteredMenuItem( VPanel ); + BaseClass::OnCursorEnteredMenuItem( menuItem ); } static CBackgroundMenuButton* CreateMenuButton( CBasePanel *parent, const char *panelName, const wchar_t *panelText ) diff --git a/public/vgui_controls/BuildGroup.h b/public/vgui_controls/BuildGroup.h index a0fcf352..c6ce0f4e 100644 --- a/public/vgui_controls/BuildGroup.h +++ b/public/vgui_controls/BuildGroup.h @@ -94,6 +94,7 @@ public: virtual const char *GetResourceName(void) { return m_pResourceName; } virtual void PanelAdded(Panel* panel); + virtual void PanelRemoved(Panel* panel); virtual bool MousePressed(MouseCode code,Panel* panel); virtual bool MouseReleased(MouseCode code,Panel* panel); diff --git a/public/vgui_controls/Menu.h b/public/vgui_controls/Menu.h index fbe44b29..f5a396cb 100644 --- a/public/vgui_controls/Menu.h +++ b/public/vgui_controls/Menu.h @@ -295,8 +295,8 @@ protected: void SetCurrentlySelectedItem(MenuItem *item); void SetCurrentlySelectedItem(int itemID); - MESSAGE_FUNC_INT( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", VPanel); - MESSAGE_FUNC_INT( OnCursorExitedMenuItem, "CursorExitedMenuItem", VPanel); + MESSAGE_FUNC_HANDLE( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", menuItem); + MESSAGE_FUNC_HANDLE( OnCursorExitedMenuItem, "CursorExitedMenuItem", menuItem); void MoveAlongMenuItemList(int direction, int loopCount); diff --git a/public/vgui_controls/MessageMap.h b/public/vgui_controls/MessageMap.h index 226c0adc..b8b2ed20 100644 --- a/public/vgui_controls/MessageMap.h +++ b/public/vgui_controls/MessageMap.h @@ -46,7 +46,7 @@ class __virtual_inheritance Panel; #else class Panel; #endif -typedef unsigned int VPANEL; +typedef uintp VPANEL; typedef void (Panel::*MessageFunc_t)(void); @@ -222,6 +222,7 @@ public: \ #define MESSAGE_FUNC_PTR_WCHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_CONSTWCHARPTR, #p2 ); virtual void name( vgui::Panel *p1, const wchar_t *p2 ) #define MESSAGE_FUNC_HANDLE_WCHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_CONSTWCHARPTR, #p2 ); virtual void name( vgui::VPANEL p1, const wchar_t *p2 ) #define MESSAGE_FUNC_CHARPTR_CHARPTR( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_CONSTCHARPTR, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 ); virtual void name( const char *p1, const char *p2 ) +#define MESSAGE_FUNC_HANDLE_HANDLE( name, scriptname, p1, p2 ) _MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_HANDLE, #p2 ); virtual void name( vgui::VPANEL p1, vgui::VPANEL p2 ) // unlimited parameters (passed in the whole KeyValues) #define MESSAGE_FUNC_PARAMS( name, scriptname, p1 ) _MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_KEYVALUES, NULL, 0, 0 ); virtual void name( KeyValues *p1 ) diff --git a/public/vgui_controls/PHandle.h b/public/vgui_controls/PHandle.h index 959ee4a9..5fdbc8bc 100644 --- a/public/vgui_controls/PHandle.h +++ b/public/vgui_controls/PHandle.h @@ -27,16 +27,21 @@ class PHandle public: PHandle() : m_iPanelID(INVALID_PANEL) {} //m_iSerialNumber(0), m_pListEntry(0) {} - Panel *Get(); + Panel *Get() const; Panel *Set( Panel *pPanel ); Panel *Set( HPanel hPanel ); - operator Panel *() { return Get(); } + operator Panel *() const { return Get(); } Panel * operator ->() { return Get(); } Panel * operator = (Panel *pPanel) { return Set(pPanel); } - bool operator == (Panel *pPanel) { return (Get() == pPanel); } - operator bool () { return Get() != 0; } + //bool operator == (Panel *pPanel) { return (Get() == pPanel); } + operator bool () const { return Get() != 0; } + + friend bool operator == ( const PHandle &p1, const PHandle &p2 ) + { + return p1.m_iPanelID == p2.m_iPanelID; + } private: HPanel m_iPanelID; diff --git a/public/vgui_controls/Panel.h b/public/vgui_controls/Panel.h index 5d1abd1f..0a3aa41a 100644 --- a/public/vgui_controls/Panel.h +++ b/public/vgui_controls/Panel.h @@ -673,7 +673,7 @@ protected: protected: virtual void OnChildSettingsApplied( KeyValues *pInResourceData, Panel *pChild ); - MESSAGE_FUNC_ENUM_ENUM( OnRequestFocus, "OnRequestFocus", VPANEL, subFocus, VPANEL, defaultPanel); + MESSAGE_FUNC_HANDLE_HANDLE( OnRequestFocus, "OnRequestFocus", subFocus, defaultPanel); MESSAGE_FUNC_INT_INT( OnScreenSizeChanged, "OnScreenSizeChanged", oldwide, oldtall ); virtual void *QueryInterface(EInterfaceID id); diff --git a/vgui2/vgui_controls/BuildGroup.cpp b/vgui2/vgui_controls/BuildGroup.cpp index bef4a3c0..a5001cbe 100644 --- a/vgui2/vgui_controls/BuildGroup.cpp +++ b/vgui2/vgui_controls/BuildGroup.cpp @@ -869,6 +869,18 @@ void BuildGroup::PanelAdded(Panel *panel) _panelDar.AddToTail(temp); } +//----------------------------------------------------------------------------- +// Purpose: Add panel the list of panels that are in the build group +//----------------------------------------------------------------------------- +void BuildGroup::PanelRemoved(Panel *panel) +{ + Assert(panel); + + PHandle temp; + temp = panel; + _panelDar.FindAndRemove(temp); +} + //----------------------------------------------------------------------------- // Purpose: loads the control settings from file //----------------------------------------------------------------------------- diff --git a/vgui2/vgui_controls/Menu.cpp b/vgui2/vgui_controls/Menu.cpp index 58536356..f578ed10 100644 --- a/vgui2/vgui_controls/Menu.cpp +++ b/vgui2/vgui_controls/Menu.cpp @@ -2365,9 +2365,8 @@ int Menu::GetCurrentlyHighlightedItem() //----------------------------------------------------------------------------- // Purpose: Respond to cursor entering a menuItem. //----------------------------------------------------------------------------- -void Menu::OnCursorEnteredMenuItem(int VPanel) +void Menu::OnCursorEnteredMenuItem(VPANEL menuItem) { - VPANEL menuItem = (VPANEL)VPanel; // if we are in mouse mode if (m_iInputMode == MOUSE) { @@ -2389,9 +2388,8 @@ void Menu::OnCursorEnteredMenuItem(int VPanel) //----------------------------------------------------------------------------- // Purpose: Respond to cursor exiting a menuItem //----------------------------------------------------------------------------- -void Menu::OnCursorExitedMenuItem(int VPanel) +void Menu::OnCursorExitedMenuItem(VPANEL menuItem) { - VPANEL menuItem = (VPANEL)VPanel; // only care if we are in mouse mode if (m_iInputMode == MOUSE) { diff --git a/vgui2/vgui_controls/MenuItem.cpp b/vgui2/vgui_controls/MenuItem.cpp index 209ec365..5db44276 100644 --- a/vgui2/vgui_controls/MenuItem.cpp +++ b/vgui2/vgui_controls/MenuItem.cpp @@ -222,7 +222,7 @@ void MenuItem::OnCursorEntered() // forward the message on to the parent of this menu. KeyValues *msg = new KeyValues ("CursorEnteredMenuItem"); // tell the parent this menuitem is the one that was entered so it can highlight it - msg->SetInt("VPanel", GetVPanel()); + msg->SetInt("menuItem", ToHandle() ); ivgui()->PostMessage(GetVParent(), msg, NULL); } @@ -236,7 +236,7 @@ void MenuItem::OnCursorExited() // forward the message on to the parent of this menu. KeyValues *msg = new KeyValues ("CursorExitedMenuItem"); // tell the parent this menuitem is the one that was entered so it can unhighlight it - msg->SetInt("VPanel", GetVPanel()); + msg->SetInt("menuItem", ToHandle() ); ivgui()->PostMessage(GetVParent(), msg, NULL); } diff --git a/vgui2/vgui_controls/Panel.cpp b/vgui2/vgui_controls/Panel.cpp index 7a8628e0..3c53f350 100644 --- a/vgui2/vgui_controls/Panel.cpp +++ b/vgui2/vgui_controls/Panel.cpp @@ -880,7 +880,7 @@ const char *Panel::GetClassName() { // loop up the panel map name PanelMessageMap *panelMap = GetMessageMap(); - if ( panelMap ) + if ( panelMap && panelMap->pfnClassName ) { return panelMap->pfnClassName(); } @@ -3575,7 +3575,7 @@ void Panel::RequestFocus(int direction) //----------------------------------------------------------------------------- void Panel::OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel) { - CallParentFunction(new KeyValues("OnRequestFocus", "subFocus", subFocus, "defaultPanel", defaultPanel)); + CallParentFunction(new KeyValues("OnRequestFocus", "subFocus", ivgui()->PanelToHandle( subFocus ), "defaultPanel", ivgui()->PanelToHandle( defaultPanel ))); } //----------------------------------------------------------------------------- @@ -3800,13 +3800,17 @@ void Panel::SetTall(int tall) void Panel::SetBuildGroup(BuildGroup* buildGroup) { - //TODO: remove from old group - - Assert(buildGroup != NULL); - - _buildGroup = buildGroup; - - _buildGroup->PanelAdded(this); + if ( _buildGroup == buildGroup ) + return; + if ( _buildGroup.Get() ) + { + _buildGroup->PanelRemoved( this ); + } + _buildGroup = buildGroup; + if ( _buildGroup.Get() ) + { + _buildGroup->PanelAdded(this); + } } bool Panel::IsBuildGroupEnabled() @@ -5134,6 +5138,13 @@ void Panel::OnMessage(const KeyValues *params, VPANEL ifromPanel) VPANEL vp = ivgui()->HandleToPanel( param1->GetInt() ); (this->*((MessageFunc_HandleConstCharPtr_t)pMap->func))( vp, param2->GetWString() ); } + else if ( (DATATYPE_HANDLE == pMap->firstParamType) && (DATATYPE_HANDLE == pMap->secondParamType) ) + { + typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, VPANEL); + VPANEL vp1 = ivgui()->HandleToPanel( param1->GetInt() ); + VPANEL vp2 = ivgui()->HandleToPanel( param1->GetInt() ); + (this->*((MessageFunc_HandleConstCharPtr_t)pMap->func))( vp1, vp2 ); + } else { // the message isn't handled @@ -5515,7 +5526,7 @@ void Panel::OnDelete() // Purpose: Panel handle implementation // Returns a pointer to a valid panel, NULL if the panel has been deleted //----------------------------------------------------------------------------- -Panel *PHandle::Get() +Panel *PHandle::Get() const { if (m_iPanelID != INVALID_PANEL) { From f96a163cf8e09c6258b0ed471bce495777308036 Mon Sep 17 00:00:00 2001 From: hymei Date: Sun, 27 Feb 2022 21:24:21 +0800 Subject: [PATCH 21/34] arm64 : fix clang compile errors --- datamodel/dmserializerkeyvalues.cpp | 2 +- dmxloader/dmxattribute.cpp | 2 ++ game/client/cstrike/VGUI/buypreset_panel.cpp | 2 +- game/server/props.cpp | 3 ++- game/shared/cstrike/cs_weapon_parse.cpp | 4 +++- public/dt_common.h | 9 +++++---- public/tier0/basetypes.h | 19 +++++++++++++------ 7 files changed, 27 insertions(+), 14 deletions(-) diff --git a/datamodel/dmserializerkeyvalues.cpp b/datamodel/dmserializerkeyvalues.cpp index 24a45de0..f446e7ab 100644 --- a/datamodel/dmserializerkeyvalues.cpp +++ b/datamodel/dmserializerkeyvalues.cpp @@ -264,7 +264,7 @@ DmAttributeType_t CDmSerializerKeyValues::DetermineAttributeType( KeyValues *pKe if ( sscanf( pKeyValues->GetString(), "%f %f", &f1, &f2 ) == 2 ) return AT_VECTOR2; - int i = pKeyValues->GetInt( NULL, INT_MAX ); + int i = pKeyValues->GetInt( nullptr, INT_MAX ); if ( ( sscanf( pKeyValues->GetString(), "%d", &i ) == 1 ) && ( !strchr( pKeyValues->GetString(), '.' ) ) ) return AT_INT; diff --git a/dmxloader/dmxattribute.cpp b/dmxloader/dmxattribute.cpp index aea474c7..293cce8b 100644 --- a/dmxloader/dmxattribute.cpp +++ b/dmxloader/dmxattribute.cpp @@ -73,8 +73,10 @@ struct CSizeTest COMPILE_TIME_ASSERT( sizeof( QAngle ) == 12 ); COMPILE_TIME_ASSERT( sizeof( Quaternion ) == 16 ); COMPILE_TIME_ASSERT( sizeof( VMatrix ) == 64 ); +#if !defined( PLATFORM_64BITS ) COMPILE_TIME_ASSERT( sizeof( CUtlString ) == 4 ); COMPILE_TIME_ASSERT( sizeof( CUtlBinaryBlock ) == 16 ); +#endif COMPILE_TIME_ASSERT( sizeof( DmObjectId_t ) == 16 ); }; }; diff --git a/game/client/cstrike/VGUI/buypreset_panel.cpp b/game/client/cstrike/VGUI/buypreset_panel.cpp index 321984b4..b6937036 100644 --- a/game/client/cstrike/VGUI/buypreset_panel.cpp +++ b/game/client/cstrike/VGUI/buypreset_panel.cpp @@ -93,7 +93,7 @@ public: KeyValues *line = lines->GetFirstValue(); while ( line ) { - const char *str = line->GetString( NULL, "" ); + const char *str = line->GetString( nullptr, "" ); Vector4D p; int numPoints = sscanf( str, "%f %f %f %f", &p[0], &p[1], &p[2], &p[3] ); if ( numPoints == 4 ) diff --git a/game/server/props.cpp b/game/server/props.cpp index 648191db..e536447b 100644 --- a/game/server/props.cpp +++ b/game/server/props.cpp @@ -5618,7 +5618,8 @@ class CPhysicsPropMultiplayer : public CPhysicsProp, public IMultiplayerPhysics SetCollisionGroup( COLLISION_GROUP_DEBRIS ); } - m_fMass = VPhysicsGetObject()->GetMass(); + if(VPhysicsGetObject()) + m_fMass = VPhysicsGetObject()->GetMass(); // VPhysicsGetObject() is NULL on the client, which prevents the client from finding a decent // AABB surrounding the collision bounds. If we've got a VPhysicsGetObject()->GetCollide(), we'll diff --git a/game/shared/cstrike/cs_weapon_parse.cpp b/game/shared/cstrike/cs_weapon_parse.cpp index d23ea72e..5f78b9c2 100644 --- a/game/shared/cstrike/cs_weapon_parse.cpp +++ b/game/shared/cstrike/cs_weapon_parse.cpp @@ -99,7 +99,9 @@ CCSWeaponInfo g_EquipmentInfo[MAX_EQUIPMENT]; void PrepareEquipmentInfo( void ) { - memset( g_EquipmentInfo, 0, ARRAYSIZE( g_EquipmentInfo ) ); + // MoeMod : dont use memset here + for(int i = 0; i < MAX_EQUIPMENT; ++i) + g_EquipmentInfo[i] = {}; g_EquipmentInfo[2].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_KEVLAR ) ); g_EquipmentInfo[2].SetDefaultPrice( KEVLAR_PRICE ); diff --git a/public/dt_common.h b/public/dt_common.h index 996300a5..ed4f1fa1 100644 --- a/public/dt_common.h +++ b/public/dt_common.h @@ -91,11 +91,12 @@ // Use this to extern send and receive datatables, and reference them. -#define EXTERN_SEND_TABLE(tableName) namespace tableName {extern SendTable g_SendTable;} -#define EXTERN_RECV_TABLE(tableName) namespace tableName {extern RecvTable g_RecvTable;} +#define EXTERN_SEND_TABLE(tableName) namespace tableName {extern SendTable g_SendTable; extern int g_SendTableInit;} +#define EXTERN_RECV_TABLE(tableName) namespace tableName {extern RecvTable g_RecvTable; extern int g_RecvTableInit;} -#define REFERENCE_SEND_TABLE(tableName) tableName::g_SendTable -#define REFERENCE_RECV_TABLE(tableName) tableName::g_RecvTable +// MoeMod: ODR Use it to prevent being dropped by linker +#define REFERENCE_SEND_TABLE(tableName) (tableName::g_SendTableInit + &tableName::g_SendTableInit, tableName::g_SendTable) +#define REFERENCE_RECV_TABLE(tableName) (tableName::g_RecvTableInit + &tableName::g_RecvTableInit, tableName::g_RecvTable) class SendProp; diff --git a/public/tier0/basetypes.h b/public/tier0/basetypes.h index 470effe9..c1ee2a96 100644 --- a/public/tier0/basetypes.h +++ b/public/tier0/basetypes.h @@ -171,17 +171,24 @@ typedef float vec_t; // This assumes the ANSI/IEEE 754-1985 standard //----------------------------------------------------------------------------- -inline unsigned long& FloatBits( vec_t& f ) +// MoeMod : fix reinterpret_cast UB - Maybe fail with strict alias +union FloatCast_u { - return *reinterpret_cast(&f); + vec_t f; + unsigned int i; +}; + +inline unsigned int& FloatBits( vec_t& f ) +{ + return reinterpret_cast(&f)->i; } -inline unsigned long const& FloatBits( vec_t const& f ) +inline unsigned int const& FloatBits( vec_t const& f ) { - return *reinterpret_cast(&f); + return reinterpret_cast(&f)->i; } -inline vec_t BitsToFloat( unsigned long i ) +inline vec_t BitsToFloat( unsigned int i ) { vec_t f; memcpy( &f, &i, sizeof(f)); @@ -193,7 +200,7 @@ inline bool IsFinite( vec_t f ) return ((FloatBits(f) & 0x7F800000) != 0x7F800000); } -inline unsigned long FloatAbsBits( vec_t f ) +inline unsigned int FloatAbsBits( vec_t f ) { return FloatBits(f) & 0x7FFFFFFF; } From fe2d89addbbda8e73c71fac96ef54046b48ec80e Mon Sep 17 00:00:00 2001 From: hymei Date: Sun, 27 Feb 2022 21:32:58 +0800 Subject: [PATCH 22/34] update ivp --- ivp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivp b/ivp index 65ec2e7f..88cca3a5 160000 --- a/ivp +++ b/ivp @@ -1 +1 @@ -Subproject commit 65ec2e7f5bf944892ed3f7e59a519bbbbde2ac86 +Subproject commit 88cca3a543744868ea0903ceff7ed920dc88bd56 From fd38243b54941aa8314456d20a6c15df7759d2db Mon Sep 17 00:00:00 2001 From: hymei <824395314@qq.com> Date: Wed, 2 Mar 2022 23:55:50 +0800 Subject: [PATCH 23/34] arm64 ptr size fix --- common/studiobyteswap.cpp | 9 +++++++ engine/cl_parse_event.cpp | 4 +-- .../hl2/c_info_teleporter_countdown.cpp | 2 +- public/sentence.cpp | 5 +++- public/studio.h | 25 ++++++++++++++++--- public/tier1/utllinkedlist.h | 2 +- tier0/cpu_posix.cpp | 2 +- 7 files changed, 39 insertions(+), 10 deletions(-) diff --git a/common/studiobyteswap.cpp b/common/studiobyteswap.cpp index 30b3383e..0e4f8fd1 100644 --- a/common/studiobyteswap.cpp +++ b/common/studiobyteswap.cpp @@ -2918,8 +2918,13 @@ BEGIN_BYTESWAP_DATADESC( mstudiomodel_t ) END_BYTESWAP_DATADESC() BEGIN_BYTESWAP_DATADESC( mstudio_modelvertexdata_t ) +#ifdef PLATFORM_64BITS + DEFINE_FIELD( unused_pVertexData, FIELD_INTEGER ), // void* + DEFINE_FIELD( unused_pTangentData, FIELD_INTEGER ), // void* +#else DEFINE_FIELD( pVertexData, FIELD_INTEGER ), // void* DEFINE_FIELD( pTangentData, FIELD_INTEGER ), // void* +#endif END_BYTESWAP_DATADESC() BEGIN_BYTESWAP_DATADESC( mstudioflexdesc_t ) @@ -2998,7 +3003,11 @@ BEGIN_BYTESWAP_DATADESC( mstudiomesh_t ) END_BYTESWAP_DATADESC() BEGIN_BYTESWAP_DATADESC( mstudio_meshvertexdata_t ) +#ifdef PLATFORM_64BITS + DEFINE_FIELD( unused_modelvertexdata, FIELD_INTEGER ), // mstudio_modelvertexdata_t* +#else DEFINE_FIELD( modelvertexdata, FIELD_INTEGER ), // mstudio_modelvertexdata_t* +#endif DEFINE_ARRAY( numLODVertexes, FIELD_INTEGER, MAX_NUM_LODS ), END_BYTESWAP_DATADESC() diff --git a/engine/cl_parse_event.cpp b/engine/cl_parse_event.cpp index 183d763f..bd1eed0b 100644 --- a/engine/cl_parse_event.cpp +++ b/engine/cl_parse_event.cpp @@ -18,7 +18,7 @@ static ConVar cl_showevents ( "cl_showevents", "0", FCVAR_CHEAT, "Print event fi // Input : slot - // *eventname - //----------------------------------------------------------------------------- -void CL_DescribeEvent( int slot, CEventInfo *event, const char *eventname ) +void CL_DescribeEvent( intp slot, CEventInfo *event, const char *eventname ) { int idx = (slot & 31); @@ -81,7 +81,7 @@ void CL_FireEvents( void ) return; } - int i, next; + intp i, next; for ( i = cl.events.Head(); i != cl.events.InvalidIndex(); i = next ) { next = cl.events.Next( i ); diff --git a/game/client/hl2/c_info_teleporter_countdown.cpp b/game/client/hl2/c_info_teleporter_countdown.cpp index e99277c9..d8ba5b2c 100644 --- a/game/client/hl2/c_info_teleporter_countdown.cpp +++ b/game/client/hl2/c_info_teleporter_countdown.cpp @@ -141,7 +141,7 @@ void CTeleportCountdownScreen::OnTick() // Find the active info teleporter countdown C_InfoTeleporterCountdown *pActiveCountdown = NULL; - for ( int i = g_InfoTeleporterCountdownList.Head(); i != g_InfoTeleporterCountdownList.InvalidIndex(); + for ( intp i = g_InfoTeleporterCountdownList.Head(); i != g_InfoTeleporterCountdownList.InvalidIndex(); i = g_InfoTeleporterCountdownList.Next(i) ) { if ( g_InfoTeleporterCountdownList[i]->m_bCountdownStarted ) diff --git a/public/sentence.cpp b/public/sentence.cpp index 251ca25a..49994780 100644 --- a/public/sentence.cpp +++ b/public/sentence.cpp @@ -345,7 +345,9 @@ unsigned int CPhonemeTag::ComputeDataCheckSum() //----------------------------------------------------------------------------- // Purpose: Simple language to string and string to language lookup dictionary //----------------------------------------------------------------------------- +#if defined(__i386__) || defined(__x86_64__) #pragma pack(1) +#endif struct CCLanguage { @@ -369,8 +371,9 @@ static CCLanguage g_CCLanguageLookup[] = { CC_THAI, "thai", 0 , 150, 250 }, { CC_PORTUGUESE,"portuguese", 0 , 0, 150 }, }; - +#if defined(__i386__) || defined(__x86_64__) #pragma pack() +#endif void CSentence::ColorForLanguage( int language, unsigned char& r, unsigned char& g, unsigned char& b ) { diff --git a/public/studio.h b/public/studio.h index 9829de8d..b02c2d48 100644 --- a/public/studio.h +++ b/public/studio.h @@ -1292,8 +1292,15 @@ struct mstudio_modelvertexdata_t int GetGlobalTangentIndex( int i ) const; // base of external vertex data stores +#ifdef PLATFORM_64BITS + int unused_pVertexData; + int unused_pTangentData; const void *pVertexData; const void *pTangentData; +#else + const void *pVertexData; + const void *pTangentData; +#endif }; #ifdef PLATFORM_64BITS @@ -1314,12 +1321,19 @@ struct mstudio_meshvertexdata_t int GetModelVertexIndex( int i ) const; int GetGlobalVertexIndex( int i ) const; +#ifdef PLATFORM_64BITS + // MoeMod : fix 64bit ptr size + int unused_modelvertexdata; + int numLODVertexes[MAX_NUM_LODS]; + const mstudio_modelvertexdata_t *modelvertexdata; +#else // indirection to this mesh's model's vertex data const mstudio_modelvertexdata_t *modelvertexdata; // used for fixup calcs when culling top level lods // expected number of mesh verts at desired lod int numLODVertexes[MAX_NUM_LODS]; +#endif }; struct mstudiomesh_t @@ -1353,7 +1367,7 @@ struct mstudiomesh_t #ifdef PLATFORM_64BITS mstudio_meshvertexdata_t vertexdata; - int unused[7]; // remove as appropriate + int unused[6]; // remove as appropriate #else mstudio_meshvertexdata_t vertexdata; @@ -1424,14 +1438,16 @@ inline bool mstudio_modelvertexdata_t::HasTangentData( void ) const inline int mstudio_modelvertexdata_t::GetGlobalVertexIndex( int i ) const { mstudiomodel_t *modelptr = (mstudiomodel_t *)((byte *)this - offsetof(mstudiomodel_t, vertexdata)); - //Assert( ( modelptr->vertexindex % sizeof( mstudiovertex_t ) ) == 0 ); + Assert(&modelptr->vertexdata == this); + Assert( ( modelptr->vertexindex % sizeof( mstudiovertex_t ) ) == 0 ); return ( i + ( modelptr->vertexindex / sizeof( mstudiovertex_t ) ) ); } inline int mstudio_modelvertexdata_t::GetGlobalTangentIndex( int i ) const { mstudiomodel_t *modelptr = (mstudiomodel_t *)((byte *)this - offsetof(mstudiomodel_t, vertexdata)); - //Assert( ( modelptr->tangentsindex % sizeof( Vector4D ) ) == 0 ); + Assert(&modelptr->vertexdata == this); + Assert( ( modelptr->tangentsindex % sizeof( Vector4D ) ) == 0 ); return ( i + ( modelptr->tangentsindex / sizeof( Vector4D ) ) ); } @@ -1499,7 +1515,8 @@ inline const thinModelVertices_t * mstudiomesh_t::GetThinVertexData( void *pMode inline int mstudio_meshvertexdata_t::GetModelVertexIndex( int i ) const { - mstudiomesh_t *meshptr = (mstudiomesh_t *)((byte *)this - offsetof(mstudiomesh_t,vertexdata)); + mstudiomesh_t *meshptr = (mstudiomesh_t *)((byte *)this - offsetof(mstudiomesh_t,vertexdata)); + Assert(&meshptr->vertexdata == this); return meshptr->vertexoffset + i; } diff --git a/public/tier1/utllinkedlist.h b/public/tier1/utllinkedlist.h index 04872008..2e201805 100644 --- a/public/tier1/utllinkedlist.h +++ b/public/tier1/utllinkedlist.h @@ -24,7 +24,7 @@ // This is a useful macro to iterate from head to tail in a linked list. #define FOR_EACH_LL( listName, iteratorName ) \ - for( int iteratorName=(listName).Head(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Next( iteratorName ) ) + for( auto iteratorName=(listName).Head(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Next( iteratorName ) ) //----------------------------------------------------------------------------- // class CUtlLinkedList: diff --git a/tier0/cpu_posix.cpp b/tier0/cpu_posix.cpp index 094bc435..2b158947 100644 --- a/tier0/cpu_posix.cpp +++ b/tier0/cpu_posix.cpp @@ -105,7 +105,7 @@ uint64 CalculateCPUFreq() int retval = sysctlbyname("hw.cpufrequency_max", &freq_hz, &freq_size, NULL, 0); // MoeMod : TODO dont know how to get freq on Apple Silicon if(!freq_hz) - freq_hz = 3200000; + freq_hz = 3200000000; return freq_hz; #else // Try to open cpuinfo_max_freq. If the kernel was built with cpu scaling support disabled, this will fail. From 01413fdd7138507a843a3fcfc2f04e6d07c8840d Mon Sep 17 00:00:00 2001 From: hymei Date: Tue, 8 Mar 2022 22:32:33 +0800 Subject: [PATCH 24/34] arm64 : fix mempool align --- .gitignore | 1 + common/openal/alc.h | 4 +- common/studiobyteswap.cpp | 6 +- datacache/mdlcache.cpp | 6 +- engine/dt_stack.h | 4 +- engine/modelloader.cpp | 2 +- engine/r_decal.cpp | 2 +- .../NextBot/NextBotContextualQueryInterface.h | 2 +- public/studio.h | 93 +++++++++++++------ public/tier0/platform.h | 6 ++ public/tier1/mempool.h | 11 ++- public/zip_utils.cpp | 2 +- tier1/lzmaDecoder.cpp | 6 +- 13 files changed, 94 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index 0344d749..36b252a4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ build/ .lock-waf* __pycache__ *.pyc +.DS_Store \ No newline at end of file diff --git a/common/openal/alc.h b/common/openal/alc.h index 062e505a..e04c33f2 100644 --- a/common/openal/alc.h +++ b/common/openal/alc.h @@ -22,7 +22,7 @@ extern "C" { #define ALC_APIENTRY #endif -#if TARGET_OS_MAC +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC #pragma export on #endif @@ -279,7 +279,7 @@ typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)( ALCdevice *device, A #endif /* ALC_NO_PROTOTYPES */ -#if TARGET_OS_MAC +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC #pragma export off #endif diff --git a/common/studiobyteswap.cpp b/common/studiobyteswap.cpp index 0e4f8fd1..63e7ce37 100644 --- a/common/studiobyteswap.cpp +++ b/common/studiobyteswap.cpp @@ -2919,8 +2919,8 @@ END_BYTESWAP_DATADESC() BEGIN_BYTESWAP_DATADESC( mstudio_modelvertexdata_t ) #ifdef PLATFORM_64BITS - DEFINE_FIELD( unused_pVertexData, FIELD_INTEGER ), // void* - DEFINE_FIELD( unused_pTangentData, FIELD_INTEGER ), // void* + DEFINE_FIELD( index_ptr_pVertexData, FIELD_INTEGER ), // void* + DEFINE_FIELD( index_ptr_pTangentData, FIELD_INTEGER ), // void* #else DEFINE_FIELD( pVertexData, FIELD_INTEGER ), // void* DEFINE_FIELD( pTangentData, FIELD_INTEGER ), // void* @@ -3004,7 +3004,7 @@ END_BYTESWAP_DATADESC() BEGIN_BYTESWAP_DATADESC( mstudio_meshvertexdata_t ) #ifdef PLATFORM_64BITS - DEFINE_FIELD( unused_modelvertexdata, FIELD_INTEGER ), // mstudio_modelvertexdata_t* + DEFINE_FIELD( index_ptr_modelvertexdata, FIELD_INTEGER ), // mstudio_modelvertexdata_t* #else DEFINE_FIELD( modelvertexdata, FIELD_INTEGER ), // mstudio_modelvertexdata_t* #endif diff --git a/datacache/mdlcache.cpp b/datacache/mdlcache.cpp index 2b7a4e8d..eb676a95 100644 --- a/datacache/mdlcache.cpp +++ b/datacache/mdlcache.cpp @@ -126,7 +126,7 @@ struct studiodata_t // array of cache handles to demand loaded virtual model data int m_nAnimBlockCount; DataCacheHandle_t *m_pAnimBlock; - unsigned long *m_iFakeAnimBlockStall; + unsigned int *m_iFakeAnimBlockStall; // vertex data is usually compressed to save memory (model decal code only needs some data) DataCacheHandle_t m_VertexCache; @@ -1169,8 +1169,8 @@ void CMDLCache::AllocateAnimBlocks( studiodata_t *pStudioData, int nCount ) memset( pStudioData->m_pAnimBlock, 0, sizeof(DataCacheHandle_t) * pStudioData->m_nAnimBlockCount ); - pStudioData->m_iFakeAnimBlockStall = new unsigned long [pStudioData->m_nAnimBlockCount]; - memset( pStudioData->m_iFakeAnimBlockStall, 0, sizeof( unsigned long ) * pStudioData->m_nAnimBlockCount ); + pStudioData->m_iFakeAnimBlockStall = new unsigned int [pStudioData->m_nAnimBlockCount]; + memset( pStudioData->m_iFakeAnimBlockStall, 0, sizeof( unsigned int ) * pStudioData->m_nAnimBlockCount ); } void CMDLCache::FreeAnimBlocks( MDLHandle_t handle ) diff --git a/engine/dt_stack.h b/engine/dt_stack.h index 9fa48d4e..84e993de 100644 --- a/engine/dt_stack.h +++ b/engine/dt_stack.h @@ -121,7 +121,7 @@ inline unsigned char* UpdateRoutesExplicit_Template( DTStack *pStack, ProxyCalle // Early out. unsigned short iPropProxyIndex = pStack->m_pPrecalc->m_PropProxyIndices[pStack->m_iCurProp]; unsigned char **pTest = &pStack->m_pProxies[iPropProxyIndex]; - if ( *pTest != (unsigned char*)0xFFFFFFFF ) + if ( *pTest != (unsigned char*)-1 ) return *pTest; // Ok.. setup this proxy. @@ -133,7 +133,7 @@ inline unsigned char* UpdateRoutesExplicit_Template( DTStack *pStack, ProxyCalle CSendTablePrecalc::CProxyPathEntry *pEntry = &pStack->m_pPrecalc->m_ProxyPathEntries[proxyPath.m_iFirstEntry + i]; int iProxy = pEntry->m_iProxy; - if ( pStack->m_pProxies[iProxy] == (unsigned char*)0xFFFFFFFF ) + if ( pStack->m_pProxies[iProxy] == (unsigned char*)-1 ) { pStack->m_pProxies[iProxy] = ProxyCaller::CallProxy( pStack, pStructBase, pEntry->m_iDatatableProp ); if ( !pStack->m_pProxies[iProxy] ) diff --git a/engine/modelloader.cpp b/engine/modelloader.cpp index b3a851ad..481963a0 100644 --- a/engine/modelloader.cpp +++ b/engine/modelloader.cpp @@ -1831,7 +1831,7 @@ void *Hunk_AllocNameAlignedClear_( int size, int alignment, const char *pHunkNam Assert(IsPowerOfTwo(alignment)); void *pMem = Hunk_AllocName( alignment + size, pHunkName ); memset( pMem, 0, size + alignment ); - pMem = (void *)( ( ( ( unsigned long )pMem ) + (alignment-1) ) & ~(alignment-1) ); + pMem = (void *)( ( ( ( uintp )pMem ) + (alignment-1) ) & ~(alignment-1) ); return pMem; } diff --git a/engine/r_decal.cpp b/engine/r_decal.cpp index 69b11d68..1c76f4d0 100644 --- a/engine/r_decal.cpp +++ b/engine/r_decal.cpp @@ -2304,7 +2304,7 @@ inline void R_DrawDecalMeshList( DecalMeshList_t &meshList ) } #define DECALMARKERS_SWITCHSORTTREE ((decal_t *)0x00000000) -#define DECALMARKERS_SWITCHBUCKET ((decal_t *)0xFFFFFFFF) +#define DECALMARKERS_SWITCHBUCKET ((decal_t *)-1) //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- diff --git a/game/server/NextBot/NextBotContextualQueryInterface.h b/game/server/NextBot/NextBotContextualQueryInterface.h index d117bcab..d6040e0d 100644 --- a/game/server/NextBot/NextBotContextualQueryInterface.h +++ b/game/server/NextBot/NextBotContextualQueryInterface.h @@ -25,7 +25,7 @@ enum QueryResultType }; // Can pass this into IContextualQuery::IsHindrance to see if any hindrance is ever possible -#define IS_ANY_HINDRANCE_POSSIBLE ( (CBaseEntity*)0xFFFFFFFF ) +#define IS_ANY_HINDRANCE_POSSIBLE ( (CBaseEntity*)-1 ) //---------------------------------------------------------------------------------------------------------------- diff --git a/public/studio.h b/public/studio.h index b02c2d48..3b0edc98 100644 --- a/public/studio.h +++ b/public/studio.h @@ -1293,14 +1293,26 @@ struct mstudio_modelvertexdata_t // base of external vertex data stores #ifdef PLATFORM_64BITS - int unused_pVertexData; - int unused_pTangentData; - const void *pVertexData; - const void *pTangentData; + int index_ptr_pVertexData; + int index_ptr_pTangentData; #else const void *pVertexData; const void *pTangentData; #endif + const void *GetVertexData() const { +#ifdef PLATFORM_64BITS + return *(const void **)((byte *)this + index_ptr_pVertexData); +#else + return pVertexData; +#endif + } + const void *GetTangentData() const { +#ifdef PLATFORM_64BITS + return *(const void **)((byte *)this + index_ptr_pTangentData); +#else + return pTangentData; +#endif + } }; #ifdef PLATFORM_64BITS @@ -1323,17 +1335,22 @@ struct mstudio_meshvertexdata_t #ifdef PLATFORM_64BITS // MoeMod : fix 64bit ptr size - int unused_modelvertexdata; - int numLODVertexes[MAX_NUM_LODS]; - const mstudio_modelvertexdata_t *modelvertexdata; + int index_ptr_modelvertexdata; #else // indirection to this mesh's model's vertex data const mstudio_modelvertexdata_t *modelvertexdata; - +#endif // used for fixup calcs when culling top level lods // expected number of mesh verts at desired lod int numLODVertexes[MAX_NUM_LODS]; + + const mstudio_modelvertexdata_t *pModelVertexData() const { +#ifdef PLATFORM_64BITS + return *(const mstudio_modelvertexdata_t **)((byte *)this + index_ptr_modelvertexdata); +#else + return modelvertexdata; #endif + } }; struct mstudiomesh_t @@ -1364,13 +1381,12 @@ struct mstudiomesh_t Vector center; -#ifdef PLATFORM_64BITS mstudio_meshvertexdata_t vertexdata; +#ifdef PLATFORM_64BITS int unused[6]; // remove as appropriate + const mstudio_modelvertexdata_t *real_modelvertexdata; #else - mstudio_meshvertexdata_t vertexdata; - int unused[8]; // remove as appropriate #endif @@ -1414,14 +1430,12 @@ struct mstudiomodel_t int eyeballindex; inline mstudioeyeball_t *pEyeball( int i ) { return (mstudioeyeball_t *)(((byte *)this) + eyeballindex) + i; }; - -#ifdef PLATFORM_64BITS mstudio_modelvertexdata_t vertexdata; // sizeof(mstudio_modelvertexdata_t) == 16 - - int unused[6]; // remove as appropriate +#ifdef PLATFORM_64BITS + int unused[4]; // remove as appropriate + const void *real_pVertexData; + const void *real_pTangentData; #else - mstudio_modelvertexdata_t vertexdata; - int unused[8]; // remove as appropriate #endif }; @@ -1432,7 +1446,7 @@ struct mstudiomodel_t inline bool mstudio_modelvertexdata_t::HasTangentData( void ) const { - return (pTangentData != NULL); + return (GetTangentData() != NULL); } inline int mstudio_modelvertexdata_t::GetGlobalVertexIndex( int i ) const @@ -1453,7 +1467,7 @@ inline int mstudio_modelvertexdata_t::GetGlobalTangentIndex( int i ) const inline mstudiovertex_t *mstudio_modelvertexdata_t::Vertex( int i ) const { - return (mstudiovertex_t *)pVertexData + GetGlobalVertexIndex( i ); + return (mstudiovertex_t *)GetVertexData() + GetGlobalVertexIndex( i ); } inline Vector *mstudio_modelvertexdata_t::Position( int i ) const @@ -1471,7 +1485,7 @@ inline Vector4D *mstudio_modelvertexdata_t::TangentS( int i ) const // NOTE: The tangents vector is 16-bytes in a separate array // because it only exists on the high end, and if I leave it out // of the mstudiovertex_t, the vertex is 64-bytes (good for low end) - return (Vector4D *)pTangentData + GetGlobalTangentIndex( i ); + return (Vector4D *)GetTangentData() + GetGlobalTangentIndex( i ); } inline Vector2D *mstudio_modelvertexdata_t::Texcoord( int i ) const @@ -1491,7 +1505,7 @@ inline mstudiomodel_t *mstudiomesh_t::pModel() const inline bool mstudio_meshvertexdata_t::HasTangentData( void ) const { - return modelvertexdata->HasTangentData(); + return pModelVertexData()->HasTangentData(); } inline const mstudio_meshvertexdata_t *mstudiomesh_t::GetVertexData( void *pModelData ) @@ -1499,9 +1513,14 @@ inline const mstudio_meshvertexdata_t *mstudiomesh_t::GetVertexData( void *pMode // get this mesh's model's vertex data (allow for mstudiomodel_t::GetVertexData // returning NULL if the data has been converted to 'thin' vertices) this->pModel()->GetVertexData( pModelData ); +#ifdef PLATFORM_64BITS + real_modelvertexdata = &( this->pModel()->vertexdata ); + vertexdata.index_ptr_modelvertexdata = (byte *)&real_modelvertexdata - (byte *)&vertexdata; +#else vertexdata.modelvertexdata = &( this->pModel()->vertexdata ); +#endif - if ( !vertexdata.modelvertexdata->pVertexData ) + if ( !vertexdata.pModelVertexData()->GetVertexData() ) return NULL; return &vertexdata; @@ -1522,37 +1541,37 @@ inline int mstudio_meshvertexdata_t::GetModelVertexIndex( int i ) const inline int mstudio_meshvertexdata_t::GetGlobalVertexIndex( int i ) const { - return modelvertexdata->GetGlobalVertexIndex( GetModelVertexIndex( i ) ); + return pModelVertexData()->GetGlobalVertexIndex( GetModelVertexIndex( i ) ); } inline Vector *mstudio_meshvertexdata_t::Position( int i ) const { - return modelvertexdata->Position( GetModelVertexIndex( i ) ); + return pModelVertexData()->Position( GetModelVertexIndex( i ) ); }; inline Vector *mstudio_meshvertexdata_t::Normal( int i ) const { - return modelvertexdata->Normal( GetModelVertexIndex( i ) ); + return pModelVertexData()->Normal( GetModelVertexIndex( i ) ); }; inline Vector4D *mstudio_meshvertexdata_t::TangentS( int i ) const { - return modelvertexdata->TangentS( GetModelVertexIndex( i ) ); + return pModelVertexData()->TangentS( GetModelVertexIndex( i ) ); } inline Vector2D *mstudio_meshvertexdata_t::Texcoord( int i ) const { - return modelvertexdata->Texcoord( GetModelVertexIndex( i ) ); + return pModelVertexData()->Texcoord( GetModelVertexIndex( i ) ); }; inline mstudioboneweight_t *mstudio_meshvertexdata_t::BoneWeights( int i ) const { - return modelvertexdata->BoneWeights( GetModelVertexIndex( i ) ); + return pModelVertexData()->BoneWeights( GetModelVertexIndex( i ) ); }; inline mstudiovertex_t *mstudio_meshvertexdata_t::Vertex( int i ) const { - return modelvertexdata->Vertex( GetModelVertexIndex( i ) ); + return pModelVertexData()->Vertex( GetModelVertexIndex( i ) ); } // a group of studio model data @@ -1972,15 +1991,29 @@ inline const mstudio_modelvertexdata_t * mstudiomodel_t::GetVertexData( void *pM const vertexFileHeader_t * pVertexHdr = CacheVertexData( pModelData ); if ( !pVertexHdr ) { +#ifdef PLATFORM_64BITS + this->real_pVertexData = NULL; + this->real_pTangentData = NULL; + vertexdata.index_ptr_pVertexData = (byte *)&real_pVertexData - (byte *)&vertexdata; + vertexdata.index_ptr_pTangentData = (byte *)&real_pTangentData - (byte *)&vertexdata; +#else vertexdata.pVertexData = NULL; vertexdata.pTangentData = NULL; +#endif return NULL; } +#ifdef PLATFORM_64BITS + this->real_pVertexData = pVertexHdr->GetVertexData(); + this->real_pTangentData = pVertexHdr->GetTangentData(); + vertexdata.index_ptr_pVertexData = (byte *)&real_pVertexData - (byte *)&vertexdata; + vertexdata.index_ptr_pTangentData = (byte *)&real_pTangentData - (byte *)&vertexdata; +#else vertexdata.pVertexData = pVertexHdr->GetVertexData(); vertexdata.pTangentData = pVertexHdr->GetTangentData(); +#endif - if ( !vertexdata.pVertexData ) + if ( !vertexdata.GetVertexData() ) return NULL; return &vertexdata; diff --git a/public/tier0/platform.h b/public/tier0/platform.h index 89b678b9..2d770f69 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -441,7 +441,13 @@ typedef void * HINSTANCE; // So if being debugged, use INT3 which is precise. #ifdef OSX #if defined(__arm__) || defined(__arm64__) +#ifdef __clang__ #define DebuggerBreak() do { if ( Plat_IsInDebugSession() ) { __builtin_debugtrap(); } else { raise(SIGTRAP); } } while(0) +#elif defined __GNUC__ +#define DebuggerBreak() do { if ( Plat_IsInDebugSession() ) { __builtin_trap(); } else { raise(SIGTRAP); } } while(0) +#else +#define DebuggerBreak() raise(SIGTRAP) +#endif #else #define DebuggerBreak() do { if ( Plat_IsInDebugSession() ) { __asm ( "int $3" ); } else { raise(SIGTRAP); } } while(0) #endif diff --git a/public/tier1/mempool.h b/public/tier1/mempool.h index 0e3931b9..26b9ea23 100644 --- a/public/tier1/mempool.h +++ b/public/tier1/mempool.h @@ -111,7 +111,8 @@ protected: class CMemoryPoolMT : public CUtlMemoryPool { public: - CMemoryPoolMT(int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner) {} + // MoeMod : add alignment + CMemoryPoolMT(int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment) {} void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); } @@ -135,7 +136,8 @@ template< class T > class CClassMemoryPool : public CUtlMemoryPool { public: - CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) : + // MoeMod : bad default align here, should be alignof(T) + CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = alignof(T) ) : CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) { #ifdef PLATFORM_64BITS COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 64 ); @@ -315,7 +317,8 @@ inline void CClassMemoryPool::Clear() for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) { - T *p = (T *)pCur->m_Data; + // MoeMod : should realign to real data. + T *p = (T *)AlignValue( pCur->m_Data, m_nAlignment ); T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes); while ( p < pLimit ) { @@ -361,7 +364,7 @@ inline void CClassMemoryPool::Clear() static CMemoryPoolMT s_Allocator #define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \ - CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") + CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", alignof(_class)) //----------------------------------------------------------------------------- // Macros that make it simple to make a class use a fixed-size allocator diff --git a/public/zip_utils.cpp b/public/zip_utils.cpp index 4366f47c..858931ab 100644 --- a/public/zip_utils.cpp +++ b/public/zip_utils.cpp @@ -1569,7 +1569,7 @@ void CZipFile::SaveDirectory( IWriteStream& stream ) free( e->m_pData ); // temp hackery for the logic below to succeed - e->m_pData = (void*)0xFFFFFFFF; + e->m_pData = (void*)-1; } } } diff --git a/tier1/lzmaDecoder.cpp b/tier1/lzmaDecoder.cpp index 209c7fc5..57f7745f 100644 --- a/tier1/lzmaDecoder.cpp +++ b/tier1/lzmaDecoder.cpp @@ -145,8 +145,8 @@ unsigned int CLZMA::Uncompress( unsigned char *pInput, unsigned char *pOutput ) } // These are in/out variables - SizeT outProcessed = pHeader->actualSize; - SizeT inProcessed = pHeader->lzmaSize; + SizeT outProcessed = LittleLong(pHeader->actualSize); + SizeT inProcessed = LittleLong(pHeader->lzmaSize); ELzmaStatus status; SRes result = LzmaDecode( (Byte *)pOutput, &outProcessed, (Byte *)(pInput + sizeof( lzma_header_t ) ), &inProcessed, (Byte *)pHeader->properties, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc ); @@ -154,7 +154,7 @@ unsigned int CLZMA::Uncompress( unsigned char *pInput, unsigned char *pOutput ) LzmaDec_Free(&state, &g_Alloc); - if ( result != SZ_OK || pHeader->actualSize != outProcessed ) + if ( result != SZ_OK || LittleLong(pHeader->actualSize) != outProcessed ) { Warning( "LZMA Decompression failed (%i)\n", result ); return 0; From 9ee21ecf904f9d7e34f2933b2d342457e9eeb631 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 5 Jun 2022 01:44:42 +0300 Subject: [PATCH 25/34] amd64: fix multithread, fix vgui, fix physmodels --- common/GameUI/scriptobject.cpp | 3 +- datacache/mdlcache.cpp | 45 +- engine/cmodel_bsp.cpp | 2 +- engine/console.cpp | 2 +- engine/download.cpp | 8 +- engine/hltvdemo.cpp | 1 + engine/r_decal.cpp | 14 +- engine/spatialpartition.cpp | 6 +- engine/sys_dll.cpp | 2 +- engine/tmessage.cpp | 5 +- engine/vengineserver_impl.cpp | 1 + filesystem/basefilesystem.cpp | 2 +- game/client/detailobjectsystem.cpp | 25 +- game/server/basecombatcharacter.cpp | 15 +- game/server/basecombatcharacter.h | 12 +- game/server/hl2/npc_barnacle.cpp | 2 +- game/server/info_camera_link.cpp | 4 +- game/server/nav_mesh.h | 5 +- game/server/tactical_mission.cpp | 2 + game/shared/collisionproperty.cpp | 24 +- game/shared/hl2/hl2_gamerules.cpp | 2 +- game/shared/physics_saverestore.cpp | 2 +- game/shared/ragdoll_shared.cpp | 2 +- game/shared/saverestore.cpp | 29 +- game/shared/saverestore_utlmap.h | 4 +- materialsystem/cmaterialsystem.cpp | 11 +- materialsystem/cmaterialsystem.h | 6 +- materialsystem/ctexture.cpp | 2 +- materialsystem/imaterialsysteminternal.h | 2 +- materialsystem/texturemanager.cpp | 4 +- public/XZip.cpp | 2 +- public/builddisp.cpp | 6 +- public/datamap.h | 17 +- public/dt_send.cpp | 2 +- public/optimize.h | 2 +- public/phyfile.h | 3 +- public/studio.h | 2 +- public/tier0/platform.h | 2 +- public/tier0/threadtools.h | 1667 +++++++++---- public/tier0/threadtools.inl | 653 +++++ public/tier0/tslist.h | 171 +- public/tier1/stringpool.h | 442 +++- public/tier1/utlbuffer.h | 570 ++++- public/tier1/utllinkedlist.h | 70 +- public/tier1/utlmemory.h | 136 +- public/tier1/utlsymbol.h | 162 +- public/vgui_controls/BuildGroup.h | 1 - public/vstdlib/jobthread.h | 2 +- studiorender/r_studiodecal.cpp | 2 +- tier0/cpu.cpp | 50 +- tier0/dbg.cpp | 3 +- tier0/threadtools.cpp | 2873 ++++++++++++++-------- tier1/KeyValues.cpp | 4 +- tier1/stringpool.cpp | 228 +- tier1/utlbuffer.cpp | 481 ++-- tier1/utlsymbol.cpp | 253 +- vgui2/vgui_controls/BuildGroup.cpp | 15 +- vgui2/vgui_controls/Panel.cpp | 16 +- vphysics/physics_virtualmesh.cpp | 2 +- vphysics/vphysics_saverestore.cpp | 17 +- vstdlib/coroutine.cpp | 4 +- vstdlib/jobthread.cpp | 32 +- wscript | 13 +- 63 files changed, 5679 insertions(+), 2468 deletions(-) create mode 100644 public/tier0/threadtools.inl diff --git a/common/GameUI/scriptobject.cpp b/common/GameUI/scriptobject.cpp index e83f5fd5..f810fb8c 100644 --- a/common/GameUI/scriptobject.cpp +++ b/common/GameUI/scriptobject.cpp @@ -15,6 +15,7 @@ #include "filesystem.h" #include "tier1/convar.h" #include "cdll_int.h" +#include "vcrmode.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -1150,4 +1151,4 @@ void CInfoDescription::WriteFileHeader( FileHandle_t fp ) g_pFullFileSystem->FPrintf( fp, "//\r\n//\r\n// Cvar\t-\tSetting\r\n\r\n" ); } -//----------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------- diff --git a/datacache/mdlcache.cpp b/datacache/mdlcache.cpp index eb676a95..11e88ca5 100644 --- a/datacache/mdlcache.cpp +++ b/datacache/mdlcache.cpp @@ -1973,39 +1973,18 @@ studiohdr_t *CMDLCache::UnserializeMDL( MDLHandle_t handle, void *pData, int nDa // critical! store a back link to our data // this is fetched when re-establishing dependent cached data (vtx/vvd) -#ifndef PLATFORM_64BITS - pStudioHdrIn->SetVirtualModel( MDLHandleToVirtual( handle ) ); -#endif + pStudioHdrIn->SetVirtualModel( MDLHandleToVirtual( handle ) ); MdlCacheMsg( "MDLCache: Alloc studiohdr %s\n", GetModelName( handle ) ); // allocate cache space MemAlloc_PushAllocDbgInfo( "Models:StudioHdr", 0); -#ifdef PLATFORM_64BITS - studiohdr_t *pHdr = (studiohdr_t *)AllocData( MDLCACHE_STUDIOHDR, pStudioHdrIn->length + sizeof(studiohdr_shim64_index) ); -#else studiohdr_t *pHdr = (studiohdr_t *)AllocData( MDLCACHE_STUDIOHDR, pStudioHdrIn->length ); -#endif MemAlloc_PopAllocDbgInfo(); if ( !pHdr ) return NULL; -#ifdef PLATFORM_64BITS - // MoeMod : fix shim64 index - studiohdr_shim64_index *pHdrIndex = (studiohdr_shim64_index *)(((byte *)pHdr)+ pStudioHdrIn->length); - pHdrIndex->virtualModel = nullptr; - pHdrIndex->animblockModel = nullptr; - pHdrIndex->pVertexBase = nullptr; - pHdrIndex->pIndexBase = nullptr; - pStudioHdrIn->index_ptr_virtualModel = (byte *)&pHdrIndex->virtualModel - (byte *)pHdr; - pStudioHdrIn->index_ptr_animblockModel = (byte *)&pHdrIndex->animblockModel - (byte *)pHdr; - pStudioHdrIn->index_ptr_pVertexBase = (byte *)&pHdrIndex->pVertexBase - (byte *)pHdr; - pStudioHdrIn->index_ptr_pIndexBase = (byte *)&pHdrIndex->pIndexBase - (byte *)pHdr; - pStudioHdrIn->SetVirtualModel( MDLHandleToVirtual( handle ) ); - CacheData( &m_MDLDict[handle]->m_MDLCache, pHdr, pStudioHdrIn->length + sizeof(studiohdr_shim64_index), GetModelName( handle ), MDLCACHE_STUDIOHDR, MakeCacheID( handle, MDLCACHE_STUDIOHDR) ); -#else CacheData( &m_MDLDict[handle]->m_MDLCache, pHdr, pStudioHdrIn->length, GetModelName( handle ), MDLCACHE_STUDIOHDR, MakeCacheID( handle, MDLCACHE_STUDIOHDR) ); -#endif if ( mod_lock_mdls_on_load.GetBool() ) { @@ -2103,27 +2082,7 @@ bool CMDLCache::ReadMDLFile( MDLHandle_t handle, const char *pMDLFileName, CUtlB // critical! store a back link to our data // this is fetched when re-establishing dependent cached data (vtx/vvd) -#if PLATFORM_64BITS - int length = buf.Size(); - { - studiohdr_shim64_index shim; - buf.Put( &shim, sizeof(shim) ); - } - studiohdr_shim64_index *pHdrIndex = (studiohdr_shim64_index *)(((byte *)buf.PeekGet())+ length); - pStudioHdr = (studiohdr_t*)buf.PeekGet(); - - pHdrIndex->virtualModel = nullptr; - pHdrIndex->animblockModel = nullptr; - pHdrIndex->pVertexBase = nullptr; - pHdrIndex->pIndexBase = nullptr; - pStudioHdr->index_ptr_virtualModel = (byte *)&pHdrIndex->virtualModel - (byte *)pStudioHdr; - pStudioHdr->index_ptr_animblockModel = (byte *)&pHdrIndex->animblockModel - (byte *)pStudioHdr; - pStudioHdr->index_ptr_pVertexBase = (byte *)&pHdrIndex->pVertexBase - (byte *)pStudioHdr; - pStudioHdr->index_ptr_pIndexBase = (byte *)&pHdrIndex->pIndexBase - (byte *)pStudioHdr; - pStudioHdr->SetVirtualModel( MDLHandleToVirtual( handle ) ); -#else - pStudioHdr->SetVirtualModel( MDLHandleToVirtual( handle ) ); -#endif + pStudioHdr->SetVirtualModel( MDLHandleToVirtual( handle ) ); // Make sure all dependent files are valid if ( !VerifyHeaders( pStudioHdr ) ) diff --git a/engine/cmodel_bsp.cpp b/engine/cmodel_bsp.cpp index cdecce69..5d4faed3 100644 --- a/engine/cmodel_bsp.cpp +++ b/engine/cmodel_bsp.cpp @@ -288,7 +288,7 @@ bool CollisionBSPData_Load( const char *pName, CCollisionBSPData *pBSPData ) CollisionBSPData_LoadPhysics( pBSPData ); COM_TimestampedLog( " CollisionBSPData_LoadDispInfo" ); - CollisionBSPData_LoadDispInfo( pBSPData ); + CollisionBSPData_LoadDispInfo( pBSPData ); return true; } diff --git a/engine/console.cpp b/engine/console.cpp index b68d68b2..95dce891 100644 --- a/engine/console.cpp +++ b/engine/console.cpp @@ -479,7 +479,7 @@ Handles cursor positioning, line wrapping, etc */ static bool g_fColorPrintf = false; static bool g_bInColorPrint = false; -extern CThreadLocalInt<> g_bInSpew; +extern CTHREADLOCALINT g_bInSpew; void Con_Printf( const char *fmt, ... ); diff --git a/engine/download.cpp b/engine/download.cpp index eb58261c..f09f47dc 100644 --- a/engine/download.cpp +++ b/engine/download.cpp @@ -924,14 +924,14 @@ void CDownloadManager::StartNewDownload() m_lastPercent = 0; // Start the thread - uintp threadID; + uintp threadID; VCRHook_CreateThread(NULL, 0, #ifdef POSIX (void *) #endif DownloadThread, m_activeRequest, 0, &threadID ); - ThreadDetach( ( ThreadHandle_t )threadID ); + ReleaseThreadHandle( ( ThreadHandle_t )threadID ); } else { @@ -1072,14 +1072,14 @@ class CDownloadSystem : public IDownloadSystem public: virtual uintp CreateDownloadThread( RequestContext_t *pContext ) { - uintp nThreadID; + uintp nThreadID; VCRHook_CreateThread(NULL, 0, #ifdef POSIX (void*) #endif DownloadThread, pContext, 0, (uintp *)&nThreadID ); - ThreadDetach( ( ThreadHandle_t )nThreadID ); + ReleaseThreadHandle( ( ThreadHandle_t )nThreadID ); return nThreadID; } }; diff --git a/engine/hltvdemo.cpp b/engine/hltvdemo.cpp index 5dc25b44..02dd0594 100644 --- a/engine/hltvdemo.cpp +++ b/engine/hltvdemo.cpp @@ -22,6 +22,7 @@ #include "host.h" #include "server.h" #include "networkstringtableclient.h" +#include "vcrmode.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" diff --git a/engine/r_decal.cpp b/engine/r_decal.cpp index 1c76f4d0..923e6ba9 100644 --- a/engine/r_decal.cpp +++ b/engine/r_decal.cpp @@ -2003,7 +2003,7 @@ void R_DrawDecalsAllImmediate_GatherDecals( IMatRenderContext *pRenderContext, i intp iHead = g_aDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iBucket ).m_iHead; - intp iElement = iHead; + intp iElement = iHead; while ( iElement != g_aDecalSortPool.InvalidIndex() ) { decal_t *pDecal = g_aDecalSortPool.Element( iElement ); @@ -2154,11 +2154,11 @@ void R_DrawDecalsAllImmediate( IMatRenderContext *pRenderContext, int iGroup, in { if ( g_aDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iBucket ).m_nCheckCount != nCheckCount ) continue; - + intp iHead = g_aDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iBucket ).m_iHead; - + int nCount; - intp iElement = iHead; + intp iElement = iHead; while ( iElement != g_aDecalSortPool.InvalidIndex() ) { decal_t *pDecal = g_aDecalSortPool.Element( iElement ); @@ -2330,7 +2330,7 @@ void R_DrawDecalsAll_GatherDecals( IMatRenderContext *pRenderContext, int iGroup if ( bucket.m_nCheckCount != nCheckCount ) continue; - intp iHead = bucket.m_iHead; + intp iHead = bucket.m_iHead; if ( !g_aDecalSortPool.IsValidIndex( iHead ) ) continue; @@ -2647,7 +2647,7 @@ void R_DrawDecalsAll( IMatRenderContext *pRenderContext, int iGroup, int iTreeTy if ( bucket.m_nCheckCount != nCheckCount ) continue; - int iHead = bucket.m_iHead; + intp iHead = bucket.m_iHead; if ( !g_aDecalSortPool.IsValidIndex( iHead ) ) continue; @@ -2666,7 +2666,7 @@ void R_DrawDecalsAll( IMatRenderContext *pRenderContext, int iGroup, int iTreeTy bool bBatchInit = true; int nCount; - int iElement = iHead; + intp iElement = iHead; while ( iElement != g_aDecalSortPool.InvalidIndex() ) { decal_t *pDecal = g_aDecalSortPool.Element( iElement ); diff --git a/engine/spatialpartition.cpp b/engine/spatialpartition.cpp index 0b6b0b0a..68a51a13 100644 --- a/engine/spatialpartition.cpp +++ b/engine/spatialpartition.cpp @@ -282,7 +282,7 @@ private: CVoxelHash* m_pVoxelHash; CLeafList m_aLeafList; // Pool - Linked list(multilist) of leaves per entity. int m_TreeId; - CThreadLocalPtr m_pVisits; + CTHREADLOCALPTR(CPartitionVisits) m_pVisits; CSpatialPartition * m_pOwner; CUtlVector m_AvailableVisitBits; unsigned short m_nNextVisitBit; @@ -1775,7 +1775,7 @@ void CVoxelTree::Shutdown( void ) //----------------------------------------------------------------------------- void CVoxelTree::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs ) { - bool bWasReading = ( m_pVisits != NULL ); + bool bWasReading = ( m_pVisits != static_cast(nullptr) ); if ( bWasReading ) { // If we're recursing in this thread, need to release our read lock to allow ourselves to write @@ -1832,7 +1832,7 @@ void CVoxelTree::RemoveFromTree( SpatialPartitionHandle_t hPartition ) int nLevel = info.m_nLevel[GetTreeId()]; if ( nLevel >= 0 ) { - bool bWasReading = ( m_pVisits != NULL ); + bool bWasReading = ( m_pVisits != static_cast(nullptr) ); if ( bWasReading ) { // If we're recursing in this thread, need to release our read lock to allow ourselves to write diff --git a/engine/sys_dll.cpp b/engine/sys_dll.cpp index a7795f44..2d8b30e2 100644 --- a/engine/sys_dll.cpp +++ b/engine/sys_dll.cpp @@ -797,7 +797,7 @@ void Sys_ShutdownAuthentication( void ) //----------------------------------------------------------------------------- // Debug library spew output //----------------------------------------------------------------------------- -CThreadLocalInt<> g_bInSpew; +CTHREADLOCALINT g_bInSpew; #include "tier1/fmtstr.h" diff --git a/engine/tmessage.cpp b/engine/tmessage.cpp index 3188f166..72c65f22 100644 --- a/engine/tmessage.cpp +++ b/engine/tmessage.cpp @@ -367,7 +367,8 @@ void TextMessageParse( byte *pMemFile, int fileSize ) client_textmessage_t textMessages[ MAX_MESSAGES ]; - int i, nameHeapSize, textHeapSize, messageSize, nameOffset; + int i, nameHeapSize, textHeapSize, messageSize; + intp nameOffset; lastNamePos = 0; lineNumber = 0; @@ -633,4 +634,4 @@ client_textmessage_t *TextMessageGet( const char *pName ) } return NULL; -} \ No newline at end of file +} diff --git a/engine/vengineserver_impl.cpp b/engine/vengineserver_impl.cpp index c10bc806..37dc07c6 100644 --- a/engine/vengineserver_impl.cpp +++ b/engine/vengineserver_impl.cpp @@ -48,6 +48,7 @@ #include "replay_internal.h" #include "replayserver.h" #include "replay/iserverengine.h" +#include "vcrmode.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" diff --git a/filesystem/basefilesystem.cpp b/filesystem/basefilesystem.cpp index e1ed24db..8a371b17 100644 --- a/filesystem/basefilesystem.cpp +++ b/filesystem/basefilesystem.cpp @@ -1804,7 +1804,7 @@ const char *CBaseFileSystem::GetWritePath( const char *pFilename, const char *pa //----------------------------------------------------------------------------- // Reads/writes files to utlbuffers. Attempts alignment fixups for optimal read //----------------------------------------------------------------------------- -CThreadLocal g_pszReadFilename; +CTHREADLOCAL(char *) g_pszReadFilename; bool CBaseFileSystem::ReadToBuffer( FileHandle_t fp, CUtlBuffer &buf, int nMaxBytes, FSAllocFunc_t pfnAlloc ) { SetBufferSize( fp, 0 ); // TODO: what if it's a pack file? restore buffer size? diff --git a/game/client/detailobjectsystem.cpp b/game/client/detailobjectsystem.cpp index 3c033714..ca2a6351 100644 --- a/game/client/detailobjectsystem.cpp +++ b/game/client/detailobjectsystem.cpp @@ -2331,7 +2331,16 @@ void CDetailObjectSystem::RenderFastSprites( const Vector &viewOrigin, const Vec color[2] = pquad->m_RGBColor[0][2]; color[3] = pColorsCasted[MANTISSA_LSB_OFFSET]; - DetailPropSpriteDict_t *pDict = pquad->m_pSpriteDefs[0]; + DetailPropSpriteDict_t *pDict; +#ifdef PLATFORM_64BITS + if( nSubIdx == 1 ) + pDict = ((FastSpriteQuadBuildoutBufferNonSIMDView_t*)((intp)pquad+4))->m_pSpriteDefs[0]; + else if( nSubIdx == 3 ) + pDict = ((FastSpriteQuadBuildoutBufferNonSIMDView_t*)((intp)pquad-4))->m_pSpriteDefs[0]; + else +#endif + pDict = pquad->m_pSpriteDefs[0]; + meshBuilder.Position3f( pquad->m_flX0[0], pquad->m_flY0[0], pquad->m_flZ0[0] ); meshBuilder.Color4ubv( color ); @@ -2545,6 +2554,7 @@ void CDetailObjectSystem::RenderFastTranslucentDetailObjectsInLeaf( const Vector int nToDraw = MIN( nCount, nQuadsRemaining ); nCount -= nToDraw; nQuadsRemaining -= nToDraw; + while( nToDraw-- ) { // draw the sucker @@ -2553,17 +2563,28 @@ void CDetailObjectSystem::RenderFastTranslucentDetailObjectsInLeaf( const Vector FastSpriteQuadBuildoutBufferNonSIMDView_t const *pquad = pQuadBuffer+nSIMDIdx; + // voodoo - since everything is in 4s, offset structure pointer by a couple of floats to handle sub-index pquad = (FastSpriteQuadBuildoutBufferNonSIMDView_t const *) ( ( (intp) ( pquad ) )+ ( nSubIdx << 2 ) ); + uint8 const *pColorsCasted = reinterpret_cast ( pquad->m_Alpha ); + uint8 color[4]; color[0] = pquad->m_RGBColor[0][0]; color[1] = pquad->m_RGBColor[0][1]; color[2] = pquad->m_RGBColor[0][2]; color[3] = pColorsCasted[MANTISSA_LSB_OFFSET]; - DetailPropSpriteDict_t *pDict = pquad->m_pSpriteDefs[0]; + DetailPropSpriteDict_t *pDict; +#ifdef PLATFORM_64BITS + if( nSubIdx == 1 ) + pDict = ((FastSpriteQuadBuildoutBufferNonSIMDView_t*)((intp)pquad+4))->m_pSpriteDefs[0]; + else if( nSubIdx == 3 ) + pDict = ((FastSpriteQuadBuildoutBufferNonSIMDView_t*)((intp)pquad-4))->m_pSpriteDefs[0]; + else +#endif + pDict = pquad->m_pSpriteDefs[0]; meshBuilder.Position3f( pquad->m_flX0[0], pquad->m_flY0[0], pquad->m_flZ0[0] ); meshBuilder.Color4ubv( color ); diff --git a/game/server/basecombatcharacter.cpp b/game/server/basecombatcharacter.cpp index 9f6a8674..698ebe2c 100644 --- a/game/server/basecombatcharacter.cpp +++ b/game/server/basecombatcharacter.cpp @@ -731,7 +731,10 @@ CBaseCombatCharacter::CBaseCombatCharacter( void ) } // not standing on a nav area yet +#ifdef MEXT_BOT m_lastNavArea = NULL; +#endif + m_registeredNavTeam = TEAM_INVALID; for (int i = 0; i < MAX_WEAPONS; i++) @@ -3481,17 +3484,20 @@ void CBaseCombatCharacter::UpdateLastKnownArea( void ) //----------------------------------------------------------------------------- bool CBaseCombatCharacter::IsAreaTraversable( const CNavArea *area ) const { +#ifdef NEXT_BOT return area ? !area->IsBlocked( GetTeamNumber() ) : false; +#endif + return false; } - //----------------------------------------------------------------------------- // Purpose: Leaving the nav mesh //----------------------------------------------------------------------------- void CBaseCombatCharacter::ClearLastKnownArea( void ) { +#ifdef NEXT_BOT OnNavAreaChanged( NULL, m_lastNavArea ); - + if ( m_lastNavArea ) { m_lastNavArea->DecrementPlayerCount( m_registeredNavTeam, entindex() ); @@ -3499,21 +3505,22 @@ void CBaseCombatCharacter::ClearLastKnownArea( void ) m_lastNavArea = NULL; m_registeredNavTeam = TEAM_INVALID; } +#endif } - //----------------------------------------------------------------------------- // Purpose: Handling editor removing the area we're standing upon //----------------------------------------------------------------------------- void CBaseCombatCharacter::OnNavAreaRemoved( CNavArea *removedArea ) { +#ifdef NEXT_BOT if ( m_lastNavArea == removedArea ) { ClearLastKnownArea(); } +#endif } - //----------------------------------------------------------------------------- // Purpose: Changing team, maintain associated data //----------------------------------------------------------------------------- diff --git a/game/server/basecombatcharacter.h b/game/server/basecombatcharacter.h index 3e92332b..b6860fd7 100644 --- a/game/server/basecombatcharacter.h +++ b/game/server/basecombatcharacter.h @@ -400,11 +400,19 @@ public: void SetPreventWeaponPickup( bool bPrevent ) { m_bPreventWeaponPickup = bPrevent; } bool m_bPreventWeaponPickup; - virtual CNavArea *GetLastKnownArea( void ) const { return m_lastNavArea; } // return the last nav area the player occupied - NULL if unknown - virtual bool IsAreaTraversable( const CNavArea *area ) const; // return true if we can use the given area + virtual CNavArea *GetLastKnownArea( void ) const + { +#ifdef NEXT_BOT + return m_lastNavArea; +#else + return NULL; +#endif + } // return the last nav area the player occupied - NULL if unknown + virtual void ClearLastKnownArea( void ); virtual void UpdateLastKnownArea( void ); // invoke this to update our last known nav area (since there is no think method chained to CBaseCombatCharacter) virtual void OnNavAreaChanged( CNavArea *enteredArea, CNavArea *leftArea ) { } // invoked (by UpdateLastKnownArea) when we enter a new nav area (or it is reset to NULL) + virtual bool IsAreaTraversable( const CNavArea *area ) const; // return true if we can use the given area virtual void OnNavAreaRemoved( CNavArea *removedArea ); // ----------------------- diff --git a/game/server/hl2/npc_barnacle.cpp b/game/server/hl2/npc_barnacle.cpp index 1c195b90..9e824351 100644 --- a/game/server/hl2/npc_barnacle.cpp +++ b/game/server/hl2/npc_barnacle.cpp @@ -1968,7 +1968,7 @@ void CNPC_Barnacle::OnTongueTipUpdated() //----------------------------------------------------------------------------- void CNPC_Barnacle::UpdateTongue( void ) { - if ( m_hTongueTip == NULL ) + if ( m_hTongueTip == NULL || m_hTongueTip->m_pSpring == NULL ) return; // Set the spring's length to that of the tongue's extension diff --git a/game/server/info_camera_link.cpp b/game/server/info_camera_link.cpp index bdc8a8c8..8724008d 100644 --- a/game/server/info_camera_link.cpp +++ b/game/server/info_camera_link.cpp @@ -150,8 +150,8 @@ void PointCameraSetupVisibility( CBaseEntity *pPlayer, int area, unsigned char * pCameraEnt->SetActive( false ); } - int nNext; - for ( int i = g_InfoCameraLinkList.Head(); i != g_InfoCameraLinkList.InvalidIndex(); i = nNext ) + intp nNext; + for ( intp i = g_InfoCameraLinkList.Head(); i != g_InfoCameraLinkList.InvalidIndex(); i = nNext ) { nNext = g_InfoCameraLinkList.Next( i ); diff --git a/game/server/nav_mesh.h b/game/server/nav_mesh.h index cb757709..80920dce 100644 --- a/game/server/nav_mesh.h +++ b/game/server/nav_mesh.h @@ -73,7 +73,6 @@ public: bool operator()( CBaseCombatCharacter *actor ) { actor->OnNavAreaRemoved( m_deadArea ); - return true; } }; @@ -200,12 +199,12 @@ public: { #if PLATFORM_64BITS COMPILE_TIME_ASSERT( sizeof(CNavArea *) == 8 ); - int64 key[2] = { (int64)item.pAreas[0] + (int64)item.pAreas[1]->GetID(), (int64)item.pAreas[1] + (int64)item.pAreas[0]->GetID() }; + int64 key[2] = { (int64)(item.pAreas[0] + item.pAreas[1]->GetID()), (int64)(item.pAreas[1] + item.pAreas[0]->GetID()) }; return Hash16( key ); #else COMPILE_TIME_ASSERT( sizeof(CNavArea *) == 4 ); int key[2] = { (int)(item.pAreas[0] + item.pAreas[1]->GetID()), (int)(item.pAreas[1] + item.pAreas[0]->GetID()) }; - return Hash8( key ); + return Hash8( key ); #endif } }; diff --git a/game/server/tactical_mission.cpp b/game/server/tactical_mission.cpp index 6cac72c7..33da872d 100644 --- a/game/server/tactical_mission.cpp +++ b/game/server/tactical_mission.cpp @@ -45,7 +45,9 @@ class CShowZone : public IForEachNavArea public: virtual bool Inspect( const CNavArea *area ) { +#ifdef NEXT_BOT area->DrawFilled( 255, 255, 0, 255, 9999.9f ); +#endif return true; } }; diff --git a/game/shared/collisionproperty.cpp b/game/shared/collisionproperty.cpp index 461deb14..d2f1b6c3 100644 --- a/game/shared/collisionproperty.cpp +++ b/game/shared/collisionproperty.cpp @@ -50,20 +50,22 @@ public: virtual void OnPostQuery( SpatialPartitionListMask_t listMask ); void AddEntity( CBaseEntity *pEntity ); - + ~CDirtySpatialPartitionEntityList(); void LockPartitionForRead() { - if ( m_readLockCount == 0 ) + int nThreadId = g_nThreadID; + if ( m_nReadLockCount[nThreadId] == 0 ) { m_partitionMutex.LockForRead(); } - m_readLockCount++; + m_nReadLockCount[nThreadId]++; } void UnlockPartitionForRead() { - m_readLockCount--; - if ( m_readLockCount == 0 ) + int nThreadId = g_nThreadID; + m_nReadLockCount[nThreadId]--; + if ( m_nReadLockCount[nThreadId] == 0 ) { m_partitionMutex.UnlockRead(); } @@ -71,6 +73,8 @@ public: private: + int m_nReadLockCount[MAX_THREADS_SUPPORTED]; + CTSListWithFreeList m_DirtyEntities; CThreadSpinRWLock m_partitionMutex; uint32 m_partitionWriteId; @@ -106,7 +110,7 @@ void UpdateDirtySpatialPartitionEntities() CDirtySpatialPartitionEntityList::CDirtySpatialPartitionEntityList( char const *name ) : CAutoGameSystem( name ) { m_DirtyEntities.Purge(); - m_readLockCount = 0; + memset( m_nReadLockCount, 0, sizeof( m_nReadLockCount ) ); } //----------------------------------------------------------------------------- @@ -164,7 +168,9 @@ void CDirtySpatialPartitionEntityList::OnPreQuery( SpatialPartitionListMask_t li if ( !( listMask & validMask ) ) return; - if ( m_partitionWriteId != 0 && m_partitionWriteId == ThreadGetCurrentId() ) + int nThreadID = g_nThreadID; + + if ( m_partitionWriteId != 0 && m_partitionWriteId == nThreadID + 1 ) return; #ifdef CLIENT_DLL @@ -180,11 +186,11 @@ void CDirtySpatialPartitionEntityList::OnPreQuery( SpatialPartitionListMask_t li // or became dirty due to some other thread or callback. Updating them may cause corruption further up the // stack (e.g. partition iterator). Ignoring the state change should be safe since it happened after the // trace was requested or was unable to be resolved in a previous attempt (still dirty). - if ( m_DirtyEntities.Count() && !m_readLockCount ) + if ( m_DirtyEntities.Count() && !m_nReadLockCount[nThreadID] ) { CUtlVector< CBaseHandle > vecStillDirty; m_partitionMutex.LockForWrite(); - m_partitionWriteId = ThreadGetCurrentId(); + m_partitionWriteId = nThreadID + 1; CTSListWithFreeList::Node_t *pCurrent, *pNext; while ( ( pCurrent = m_DirtyEntities.Detach() ) != NULL ) { diff --git a/game/shared/hl2/hl2_gamerules.cpp b/game/shared/hl2/hl2_gamerules.cpp index bdd5abec..cf7dd629 100644 --- a/game/shared/hl2/hl2_gamerules.cpp +++ b/game/shared/hl2/hl2_gamerules.cpp @@ -1814,7 +1814,7 @@ CAmmoDef *GetAmmoDef() def.AddAmmoType("Thumper", DMG_SONIC, TRACER_NONE, 10, 10, 2, 0, 0 ); def.AddAmmoType("Gravity", DMG_CLUB, TRACER_NONE, 0, 0, 8, 0, 0 ); // def.AddAmmoType("Extinguisher", DMG_BURN, TRACER_NONE, 0, 0, 100, 0, 0 ); - def.AddAmmoType("Battery", DMG_CLUB, TRACER_NONE, NULL, NULL, NULL, 0, 0 ); + def.AddAmmoType("Battery", DMG_CLUB, TRACER_NONE, 0, 0, 0, 0, 0 ); def.AddAmmoType("GaussEnergy", DMG_SHOCK, TRACER_NONE, "sk_jeep_gauss_damage", "sk_jeep_gauss_damage", "sk_max_gauss_round", BULLET_IMPULSE(650, 8000), 0 ); // hit like a 10kg weight at 400 in/s def.AddAmmoType("CombineCannon", DMG_BULLET, TRACER_LINE, "sk_npc_dmg_gunship_to_plr", "sk_npc_dmg_gunship", NULL, 1.5 * 750 * 12, 0 ); // hit like a 1.5kg weight at 750 ft/s def.AddAmmoType("AirboatGun", DMG_AIRBOAT, TRACER_LINE, "sk_plr_dmg_airboat", "sk_npc_dmg_airboat", NULL, BULLET_IMPULSE(10, 600), 0 ); diff --git a/game/shared/physics_saverestore.cpp b/game/shared/physics_saverestore.cpp index 434be1f4..43cad8a4 100644 --- a/game/shared/physics_saverestore.cpp +++ b/game/shared/physics_saverestore.cpp @@ -43,7 +43,7 @@ struct PhysBlockHeader_t BEGIN_SIMPLE_DATADESC( PhysBlockHeader_t ) DEFINE_FIELD( nSaved, FIELD_INTEGER ), // NOTE: We want to save the actual address here for remapping, so use an integer - DEFINE_FIELD( pWorldObject, FIELD_INTEGER ), + DEFINE_FIELD( pWorldObject, FIELD_POINTER ), END_DATADESC() #if defined(_STATIC_LINKED) && defined(CLIENT_DLL) diff --git a/game/shared/ragdoll_shared.cpp b/game/shared/ragdoll_shared.cpp index e77e9a75..b43109a4 100644 --- a/game/shared/ragdoll_shared.cpp +++ b/game/shared/ragdoll_shared.cpp @@ -40,7 +40,7 @@ void CRagdollLowViolenceManager::SetLowViolence( const char *pMapName ) #if !defined( CLIENT_DLL ) // the server doesn't worry about low violence during multiplayer games - if ( g_pGameRules->IsMultiplayer() ) + if ( g_pGameRules && g_pGameRules->IsMultiplayer() ) { m_bLowViolence = false; } diff --git a/game/shared/saverestore.cpp b/game/shared/saverestore.cpp index e1eb4f66..818def3a 100644 --- a/game/shared/saverestore.cpp +++ b/game/shared/saverestore.cpp @@ -91,7 +91,8 @@ static int gSizes[FIELD_TYPECOUNT] = FIELD_SIZE( FIELD_MATERIALINDEX ), FIELD_SIZE( FIELD_VECTOR2D ), - FIELD_SIZE( FIELD_INTEGER64 ), + FIELD_SIZE( FIELD_INTEGER64 ), + FIELD_SIZE( FIELD_POINTER ), }; @@ -687,7 +688,7 @@ bool CSave::ShouldSaveField( const void *pData, typedescription_t *pField ) int *pEHandle = (int *)pData; for ( int i = 0; i < pField->fieldSize; ++i, ++pEHandle ) { - if ( (*pEHandle) != 0xFFFFFFFF ) + if ( (*pEHandle) != INVALID_EHANDLE_INDEX ) return true; } } @@ -721,11 +722,11 @@ bool CSave::WriteBasicField( const char *pname, void *pData, datamap_t *pRootMap case FIELD_FLOAT: WriteFloat( pField->fieldName, (float *)pData, pField->fieldSize ); break; - + case FIELD_STRING: WriteString( pField->fieldName, (string_t *)pData, pField->fieldSize ); break; - + case FIELD_VECTOR: WriteVector( pField->fieldName, (Vector *)pData, pField->fieldSize ); break; @@ -1242,19 +1243,19 @@ bool CSave::WriteGameField( const char *pname, void *pData, datamap_t *pRootMap, case FIELD_CLASSPTR: WriteEntityPtr( pField->fieldName, (CBaseEntity **)pData, pField->fieldSize ); break; - + case FIELD_EDICT: WriteEdictPtr( pField->fieldName, (edict_t **)pData, pField->fieldSize ); break; - + case FIELD_EHANDLE: WriteEHandle( pField->fieldName, (EHANDLE *)pData, pField->fieldSize ); break; - + case FIELD_POSITION_VECTOR: WritePositionVector( pField->fieldName, (Vector *)pData, pField->fieldSize ); break; - + case FIELD_TIME: WriteTime( pField->fieldName, (float *)pData, pField->fieldSize ); break; @@ -1262,7 +1263,7 @@ bool CSave::WriteGameField( const char *pname, void *pData, datamap_t *pRootMap, case FIELD_TICK: WriteTick( pField->fieldName, (int *)pData, pField->fieldSize ); break; - + case FIELD_MODELINDEX: { int nModelIndex = *(int*)pData; @@ -1298,7 +1299,7 @@ bool CSave::WriteGameField( const char *pname, void *pData, datamap_t *pRootMap, case FIELD_FUNCTION: WriteFunction( pRootMap, pField->fieldName, (inputfunc_t **)(char *)pData, pField->fieldSize ); break; - + case FIELD_VMATRIX: WriteVMatrix( pField->fieldName, (VMatrix *)pData, pField->fieldSize ); break; @@ -1314,6 +1315,10 @@ bool CSave::WriteGameField( const char *pname, void *pData, datamap_t *pRootMap, WriteInterval( pField->fieldName, (interval_t *)pData, pField->fieldSize ); break; + case FIELD_POINTER: + WriteData( pField->fieldName, sizeof(void*)*pField->fieldSize, (char *)pData ); + break; + default: Warning( "Bad field type\n" ); Assert(0); @@ -2154,6 +2159,10 @@ void CRestore::ReadGameField( const SaveRestoreRecordHeader_t &header, void *pDe ReadInterval( (interval_t *)pDest, pField->fieldSize, header.size ); break; + case FIELD_POINTER: + ReadData( (char *)pDest, sizeof(void*)*pField->fieldSize, header.size ); + break; + default: Warning( "Bad field type\n" ); Assert(0); diff --git a/game/shared/saverestore_utlmap.h b/game/shared/saverestore_utlmap.h index 06b624ab..d73dec6f 100644 --- a/game/shared/saverestore_utlmap.h +++ b/game/shared/saverestore_utlmap.h @@ -14,7 +14,7 @@ #pragma once #endif -template +template class CUtlMapDataOps : public CDefSaveRestoreOps { public: @@ -169,7 +169,7 @@ public: //------------------------------------- -template +template class CUtlMapDataopsInstantiator { public: diff --git a/materialsystem/cmaterialsystem.cpp b/materialsystem/cmaterialsystem.cpp index 0618d0c0..66edb8ac 100644 --- a/materialsystem/cmaterialsystem.cpp +++ b/materialsystem/cmaterialsystem.cpp @@ -517,7 +517,7 @@ void CMaterialSystem::CleanUpErrorMaterial() //----------------------------------------------------------------------------- CMaterialSystem::CMaterialSystem() { - m_nRenderThreadID = 0xFFFFFFFF; + m_nRenderThreadID = (uintp)-1; m_hAsyncLoadFileCache = NULL; m_ShaderHInst = 0; m_pMaterialProxyFactory = NULL; @@ -2785,8 +2785,8 @@ IMaterial* CMaterialSystem::FindMaterialEx( char const* pMaterialName, const cha { // We need lower-case symbols for this to work int nLen = Q_strlen( pMaterialName ) + 1; - char *pFixedNameTemp = (char*)stackalloc( nLen ); - char *pTemp = (char*)stackalloc( nLen ); + char *pFixedNameTemp = (char*)malloc( nLen ); + char *pTemp = (char*)malloc( nLen ); Q_strncpy( pFixedNameTemp, pMaterialName, nLen ); Q_strlower( pFixedNameTemp ); #ifdef POSIX @@ -2888,6 +2888,9 @@ IMaterial* CMaterialSystem::FindMaterialEx( char const* pMaterialName, const cha } } + free(pTemp); + free(pFixedNameTemp); + return g_pErrorMaterial->GetRealTimeVersion(); } @@ -3547,7 +3550,7 @@ void CMaterialSystem::ThreadExecuteQueuedContext( CMatQueuedRenderContext *pCont m_pRenderContext.Set( &m_HardwareRenderContext ); pContext->EndQueue( true ); m_pRenderContext.Set( pSavedRenderContext ); - m_nRenderThreadID = 0xFFFFFFFF; + m_nRenderThreadID = (uintp)-1; } IThreadPool *CMaterialSystem::CreateMatQueueThreadPool() diff --git a/materialsystem/cmaterialsystem.h b/materialsystem/cmaterialsystem.h index a5c890dc..60aad1fd 100644 --- a/materialsystem/cmaterialsystem.h +++ b/materialsystem/cmaterialsystem.h @@ -572,7 +572,7 @@ public: MaterialLock_t Lock(); void Unlock( MaterialLock_t ); CMatCallQueue * GetRenderCallQueue(); - uint GetRenderThreadId() const { return m_nRenderThreadID; } + ThreadId_t GetRenderThreadId() const { return m_nRenderThreadID; } void UnbindMaterial( IMaterial *pMaterial ); IMaterialProxy *DetermineProxyReplacements( IMaterial *pMaterial, KeyValues *pFallbackKeyValues ); @@ -617,7 +617,7 @@ private: CMaterialDict m_MaterialDict; CMatLightmaps m_Lightmaps; - CThreadLocal m_pRenderContext; + CTHREADLOCAL(IMatRenderContextInternal *) m_pRenderContext; CMatRenderContext m_HardwareRenderContext; CMatQueuedRenderContext m_QueuedRenderContexts[2]; @@ -698,7 +698,7 @@ private: const char * m_pForcedTextureLoadPathID; FileCacheHandle_t m_hAsyncLoadFileCache; - uint m_nRenderThreadID; + ThreadId_t m_nRenderThreadID; bool m_bAllocatingRenderTargets; bool m_bInStubMode; bool m_bGeneratedConfig; diff --git a/materialsystem/ctexture.cpp b/materialsystem/ctexture.cpp index e4353a0b..977d2deb 100644 --- a/materialsystem/ctexture.cpp +++ b/materialsystem/ctexture.cpp @@ -4039,7 +4039,7 @@ void CTexture::DeleteIfUnreferenced() if ( ThreadInMainThread() ) { // Render thread better not be active or bad things can happen. - Assert( MaterialSystem()->GetRenderThreadId() == 0xFFFFFFFF ); + Assert( MaterialSystem()->GetRenderThreadId() == (uintp)-1 ); TextureManager()->RemoveTexture( this ); return; } diff --git a/materialsystem/imaterialsysteminternal.h b/materialsystem/imaterialsysteminternal.h index dc55bfae..40f775d4 100644 --- a/materialsystem/imaterialsysteminternal.h +++ b/materialsystem/imaterialsysteminternal.h @@ -215,7 +215,7 @@ public: virtual CMatCallQueue *GetRenderCallQueue() = 0; virtual void UnbindMaterial( IMaterial *pMaterial ) = 0; - virtual uint GetRenderThreadId() const = 0 ; + virtual ThreadId_t GetRenderThreadId() const = 0 ; virtual IMaterialProxy *DetermineProxyReplacements( IMaterial *pMaterial, KeyValues *pFallbackKeyValues ) = 0; }; diff --git a/materialsystem/texturemanager.cpp b/materialsystem/texturemanager.cpp index 9719db4f..ae2838b1 100644 --- a/materialsystem/texturemanager.cpp +++ b/materialsystem/texturemanager.cpp @@ -1819,7 +1819,7 @@ void CTextureManager::RestoreTexture( ITextureInternal* pTexture ) //----------------------------------------------------------------------------- void CTextureManager::CleanupPossiblyUnreferencedTextures() { - if ( !ThreadInMainThread() || MaterialSystem()->GetRenderThreadId() != 0xFFFFFFFF ) + if ( !ThreadInMainThread() || MaterialSystem()->GetRenderThreadId() != (uintp)-1 ) { Assert( !"CTextureManager::CleanupPossiblyUnreferencedTextures should never be called here" ); // This is catastrophically bad, don't do this. Someone needs to fix this. See JohnS or McJohn @@ -2368,7 +2368,7 @@ void CTextureManager::RemoveTexture( ITextureInternal *pTexture ) Assert( pTexture->GetReferenceCount() <= 0 ); - if ( !ThreadInMainThread() || MaterialSystem()->GetRenderThreadId() != 0xFFFFFFFF ) + if ( !ThreadInMainThread() || MaterialSystem()->GetRenderThreadId() != (uintp)-1 ) { Assert( !"CTextureManager::RemoveTexture should never be called here"); // This is catastrophically bad, don't do this. Someone needs to fix this. diff --git a/public/XZip.cpp b/public/XZip.cpp index f576f1d4..d5d8f02a 100644 --- a/public/XZip.cpp +++ b/public/XZip.cpp @@ -125,7 +125,7 @@ static ZRESULT lasterrorZ=ZR_OK; #else #include "tier0/threadtools.h" -static CThreadLocalInt lasterrorZ; +static CTHREADLOCALINTEGER(ZRESULT) lasterrorZ; #endif typedef unsigned char uch; // unsigned 8-bit value diff --git a/public/builddisp.cpp b/public/builddisp.cpp index da749e2c..948b4f45 100644 --- a/public/builddisp.cpp +++ b/public/builddisp.cpp @@ -840,9 +840,9 @@ void CCoreDispInfo::InitDispInfo( int power, int minTess, float smoothingAngle, void CCoreDispInfo::InitDispInfo( int power, int minTess, float smoothingAngle, const CDispVert *pVerts, const CDispTri *pTris ) { - Vector vectors[MAX_DISPVERTS]; - float dists[MAX_DISPVERTS]; - float alphas[MAX_DISPVERTS]; + static Vector vectors[MAX_DISPVERTS]; + static float dists[MAX_DISPVERTS]; + static float alphas[MAX_DISPVERTS]; int nVerts = NUM_DISP_POWER_VERTS( power ); for ( int i=0; i < nVerts; i++ ) diff --git a/public/datamap.h b/public/datamap.h index 7c664265..d4eee4ee 100644 --- a/public/datamap.h +++ b/public/datamap.h @@ -62,9 +62,10 @@ typedef enum _fieldtypes FIELD_INTERVAL, // a start and range floating point interval ( e.g., 3.2->3.6 == 3.2 and 0.4 ) FIELD_MODELINDEX, // a model index FIELD_MATERIALINDEX, // a material index (using the material precache string table) - + FIELD_VECTOR2D, // 2 floats - FIELD_INTEGER64, // 64bit integer + FIELD_INTEGER64, // 64bit integer + FIELD_POINTER, FIELD_TYPECOUNT, // MUST BE LAST } fieldtype_t; @@ -94,7 +95,7 @@ public: #define FIELD_BITS( _fieldType ) (FIELD_SIZE( _fieldType ) * 8) DECLARE_FIELD_SIZE( FIELD_FLOAT, sizeof(float) ) -DECLARE_FIELD_SIZE( FIELD_STRING, sizeof(int) ) + DECLARE_FIELD_SIZE( FIELD_VECTOR, 3 * sizeof(float) ) DECLARE_FIELD_SIZE( FIELD_VECTOR2D, 2 * sizeof(float) ) DECLARE_FIELD_SIZE( FIELD_QUATERNION, 4 * sizeof(float)) @@ -103,14 +104,16 @@ DECLARE_FIELD_SIZE( FIELD_BOOLEAN, sizeof(char)) DECLARE_FIELD_SIZE( FIELD_SHORT, sizeof(short)) DECLARE_FIELD_SIZE( FIELD_CHARACTER, sizeof(char)) DECLARE_FIELD_SIZE( FIELD_COLOR32, sizeof(int)) -DECLARE_FIELD_SIZE( FIELD_CLASSPTR, sizeof(int)) -DECLARE_FIELD_SIZE( FIELD_EHANDLE, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_STRING, sizeof(void*)) +DECLARE_FIELD_SIZE( FIELD_POINTER, sizeof(void*)) +DECLARE_FIELD_SIZE( FIELD_MODELNAME, sizeof(void*)) +DECLARE_FIELD_SIZE( FIELD_SOUNDNAME, sizeof(void*)) +DECLARE_FIELD_SIZE( FIELD_EHANDLE, sizeof(void*)) +DECLARE_FIELD_SIZE( FIELD_CLASSPTR, sizeof(void*)) DECLARE_FIELD_SIZE( FIELD_EDICT, sizeof(int)) DECLARE_FIELD_SIZE( FIELD_POSITION_VECTOR, 3 * sizeof(float)) DECLARE_FIELD_SIZE( FIELD_TIME, sizeof(float)) DECLARE_FIELD_SIZE( FIELD_TICK, sizeof(int)) -DECLARE_FIELD_SIZE( FIELD_MODELNAME, sizeof(int)) -DECLARE_FIELD_SIZE( FIELD_SOUNDNAME, sizeof(int)) DECLARE_FIELD_SIZE( FIELD_INPUT, sizeof(int)) #ifdef POSIX // pointer to members under gnuc are 8bytes if you have a virtual func diff --git a/public/dt_send.cpp b/public/dt_send.cpp index 27580f8f..211bc107 100644 --- a/public/dt_send.cpp +++ b/public/dt_send.cpp @@ -265,7 +265,7 @@ void SendProxy_UInt16ToInt32( const SendProp *pProp, const void *pStruct, const void SendProxy_UInt32ToInt32( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) { - memcpy( &pOut->m_Int, pData, sizeof(unsigned long) ); + memcpy( &pOut->m_Int, pData, sizeof(uint32) ); } #ifdef SUPPORTS_INT64 void SendProxy_UInt64ToInt64( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) diff --git a/public/optimize.h b/public/optimize.h index 4a14bf31..2dae8174 100644 --- a/public/optimize.h +++ b/public/optimize.h @@ -48,7 +48,7 @@ struct Vertex_t // for sw skinned verts, these are indices into the global list of bones // for hw skinned verts, these are hardware bone indices - char boneID[MAX_NUM_BONES_PER_VERT]; + byte boneID[MAX_NUM_BONES_PER_VERT]; }; enum StripHeaderFlags_t { diff --git a/public/phyfile.h b/public/phyfile.h index c6b37720..c7b9747a 100644 --- a/public/phyfile.h +++ b/public/phyfile.h @@ -11,13 +11,14 @@ #include "datamap.h" + typedef struct phyheader_s { DECLARE_BYTESWAP_DATADESC(); int size; int id; int solidCount; - long checkSum; // checksum of source .mdl file + int checkSum; // checksum of source .mdl file } phyheader_t; #endif // PHYFILE_H diff --git a/public/studio.h b/public/studio.h index 3b0edc98..cf489807 100644 --- a/public/studio.h +++ b/public/studio.h @@ -2433,7 +2433,7 @@ struct studiohdr_t void* VertexBase() const { return pVertexBase; } void SetVertexBase( void* ptr ) { pVertexBase = ptr; } void* IndexBase() const { return pIndexBase; } - void SetIndexBase( void* ptr ) { pIndexBase = ptr; } } + void SetIndexBase( void* ptr ) { pIndexBase = ptr; } #endif // NOTE: No room to add stuff? Up the .mdl file format version diff --git a/public/tier0/platform.h b/public/tier0/platform.h index 2d770f69..0e46b970 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -1500,7 +1500,7 @@ inline void ConstructThreeArg( T* pMemory, P1 const& arg1, P2 const& arg2, P3 co template inline T* CopyConstruct( T* pMemory, T const& src ) { - return reinterpret_cast(::new( pMemory ) T(src)); + return ::new( pMemory ) T(src); } template diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h index df481cc1..00a38422 100644 --- a/public/tier0/threadtools.h +++ b/public/tier0/threadtools.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========== Copyright 2005, Valve Corporation, All rights reserved. ======== // // Purpose: A collection of utility classes to simplify thread handling, and // as much as possible contain portability problems. Here avoiding @@ -9,51 +9,69 @@ #ifndef THREADTOOLS_H #define THREADTOOLS_H -#include "tier0/type_traits.h" - #include -#if defined( __arm__ ) || defined( __arm64__ ) -#include -#endif #include "tier0/platform.h" #include "tier0/dbg.h" -#include "tier0/vcrmode.h" -#include "tier0/vprof_telemetry.h" -#ifdef PLATFORM_WINDOWS_PC -#include -#endif - -#ifdef POSIX +#if defined( POSIX ) && !defined( _PS3 ) && !defined( _X360 ) #include #include -#include #define WAIT_OBJECT_0 0 #define WAIT_TIMEOUT 0x00000102 #define WAIT_FAILED -1 #define THREAD_PRIORITY_HIGHEST 2 #endif +#if !defined( _X360 ) && !defined( _PS3 ) && defined(COMPILER_MSVC) +// For _ReadWriteBarrier() +#include +#endif + +#if defined( _PS3 ) +#include +#include +#include +#include +#endif + +#ifdef OSX +// Add some missing defines +#define PTHREAD_MUTEX_TIMED_NP PTHREAD_MUTEX_NORMAL +#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE +#define PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_ERRORCHECK +#define PTHREAD_MUTEX_ADAPTIVE_NP 3 +#endif + +#ifdef _PS3 +#define PS3_SYS_PPU_THREAD_COMMON_STACK_SIZE ( 256 * 1024 ) +#endif + + #if defined( _WIN32 ) #pragma once #pragma warning(push) #pragma warning(disable:4251) #endif +#ifdef COMPILER_MSVC64 +#include +#endif + // #define THREAD_PROFILER 1 -#ifndef _RETAIL #define THREAD_MUTEX_TRACING_SUPPORTED -#if defined(_WIN32) && defined(_DEBUG) +#if defined(_WIN32) && defined(_DEBUG) && !defined(THREAD_MUTEX_TRACING_ENABLED) #define THREAD_MUTEX_TRACING_ENABLED #endif -#endif #ifdef _WIN32 typedef void *HANDLE; #endif +// maximum number of threads that can wait on one object +#define CTHREADEVENT_MAX_WAITING_THREADS 4 + // Start thread running - error if already running enum ThreadPriorityEnum_t { @@ -85,29 +103,71 @@ enum ThreadPriorityEnum_t #endif // PLATFORM_PS3 }; +#if defined( PLATFORM_LINUX ) +#define TP_IS_PRIORITY_HIGHER( a, b ) ( ( a ) < ( b ) ) +#else +#define TP_IS_PRIORITY_HIGHER( a, b ) ( ( a ) > ( b ) ) +#endif + +#if (defined( PLATFORM_WINDOWS_PC ) || defined( PLATFORM_X360 )) && !defined( STEAM ) && !defined( _CERT ) +//Thread parent stack trace linkage requires ALL executing binaries to disable frame pointer omission to operate speedily/successfully. (/Oy-) "vpc /nofpo" +#define THREAD_PARENT_STACK_TRACE_SUPPORTED 1 //uncomment to support joining the root of a thread's stack trace to its parent's at time of invocation. Must also set ENABLE_THREAD_PARENT_STACK_TRACING in stacktools.h +#endif + +#if defined( THREAD_PARENT_STACK_TRACE_SUPPORTED ) +#include "tier0/stacktools.h" +# if defined( ENABLE_THREAD_PARENT_STACK_TRACING ) //stacktools.h opted in +# define THREAD_PARENT_STACK_TRACE_ENABLED 1 //both threadtools.h and stacktools.h have opted into the feature, enable it +# endif +#endif + +extern bool gbCheckNotMultithreaded; + +#ifdef _PS3 + +#define USE_INTRINSIC_INTERLOCKED + +#define CHECK_NOT_MULTITHREADED() \ +{ \ + static int init = 0; \ + static sys_ppu_thread_t threadIDPrev; \ + \ + if (!init) \ + { \ + sys_ppu_thread_get_id(&threadIDPrev); \ + init = 1; \ + } \ + else if (gbCheckNotMultithreaded) \ + { \ + sys_ppu_thread_t threadID; \ + sys_ppu_thread_get_id(&threadID); \ + if (threadID != threadIDPrev) \ + { \ + printf("CHECK_NOT_MULTITHREADED: prev thread = %x, cur thread = %x\n", \ + (uint)threadIDPrev, (uint)threadID); \ + *(int*)0 = 0; \ + } \ + } \ +} + +#else // _PS3 + #define CHECK_NOT_MULTITHREADED() +#endif // _PS3 + +#if defined( _X360 ) || defined( _PS3 ) +#define MAX_THREADS_SUPPORTED 16 +#else +#define MAX_THREADS_SUPPORTED 32 +#endif + + + //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- const unsigned TT_INFINITE = 0xffffffff; - -#ifndef NO_THREAD_LOCAL - -#ifndef THREAD_LOCAL -#ifdef _WIN32 -#define THREAD_LOCAL __declspec(thread) -#elif POSIX -#define THREAD_LOCAL __thread -#endif -#endif - -#endif // NO_THREAD_LOCAL - -#ifdef PLATFORM_64BITS -typedef uint64 ThreadId_t; -#else -typedef uint32 ThreadId_t; -#endif +typedef uintp ThreadId_t; //----------------------------------------------------------------------------- // @@ -115,73 +175,83 @@ typedef uint32 ThreadId_t; // in that it accepts a standard C function rather than compiler specific one. // //----------------------------------------------------------------------------- +#ifdef COMPILER_SNC +typedef uint64 ThreadHandle_t; +#else // COMPILER_SNC FORWARD_DECLARE_HANDLE( ThreadHandle_t ); +#endif // !COMPILER_SNC typedef uintp (*ThreadFunc_t)( void *pParam ); +#if defined( _PS3 ) +PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0x10000 /*64*/ ); +PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0x10000 /*64*/ ); +#else //_PS3 PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0 ); PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0 ); +#endif //_PS3 PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t ); //----------------------------------------------------------------------------- PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0); +PLATFORM_INTERFACE void ThreadNanoSleep(unsigned ns); PLATFORM_INTERFACE ThreadId_t ThreadGetCurrentId(); PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle(); PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL ); PLATFORM_INTERFACE bool ThreadSetPriority( ThreadHandle_t hThread, int priority ); inline bool ThreadSetPriority( int priority ) { return ThreadSetPriority( NULL, priority ); } +#ifndef _X360 PLATFORM_INTERFACE bool ThreadInMainThread(); PLATFORM_INTERFACE void DeclareCurrentThreadIsMainThread(); +#else +PLATFORM_INTERFACE byte *g_pBaseMainStack; +PLATFORM_INTERFACE byte *g_pLimitMainStack; +inline bool ThreadInMainThread() +{ + byte b; + byte *p = &b; + return ( p < g_pBaseMainStack && p >= g_pLimitMainStack ); +} +#endif // NOTE: ThreadedLoadLibraryFunc_t needs to return the sleep time in milliseconds or TT_INFINITE typedef int (*ThreadedLoadLibraryFunc_t)(); PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc( ThreadedLoadLibraryFunc_t func ); PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc(); -#if defined( _WIN32 ) && !defined( _WIN64 ) && !defined( _X360 ) -extern "C" unsigned long __declspec(dllimport) __stdcall GetCurrentThreadId(); +#if defined( PLATFORM_WINDOWS_PC32 ) +DLL_IMPORT unsigned long STDCALL GetCurrentThreadId(); #define ThreadGetCurrentId GetCurrentThreadId #endif inline void ThreadPause() { -#if defined( PLATFORM_WINDOWS_PC ) - // Intrinsic for __asm pause; from - _mm_pause(); -#elif POSIX && ( defined( __i386__ ) || defined( __x86_64__ ) ) +#if defined( COMPILER_PS3 ) + __db16cyc(); +#elif defined( COMPILER_GCC ) __asm __volatile( "pause" ); -#elif defined( _X360 ) -#elif defined(__arm__) || defined(__arm64__) - sched_yield(); +#elif defined ( COMPILER_MSVC64 ) + _mm_pause(); +#elif defined( COMPILER_MSVC32 ) + __asm pause; +#elif defined( COMPILER_MSVCX360 ) + YieldProcessor(); + __asm { or r0,r0,r0 } + YieldProcessor(); + __asm { or r1,r1,r1 } #else #error "implement me" #endif } PLATFORM_INTERFACE bool ThreadJoin( ThreadHandle_t, unsigned timeout = TT_INFINITE ); -// If you're not calling ThreadJoin, you need to call ThreadDetach so pthreads on Linux knows it can -// free the memory for this thread. Otherwise you wind up leaking threads until you run out and -// CreateSimpleThread() will fail. -PLATFORM_INTERFACE void ThreadDetach( ThreadHandle_t ); -PLATFORM_INTERFACE void ThreadSetDebugName( ThreadId_t id, const char *pszName ); -inline void ThreadSetDebugName( const char *pszName ) { ThreadSetDebugName( (ThreadId_t)-1, pszName ); } +PLATFORM_INTERFACE void ThreadSetDebugName( ThreadHandle_t hThread, const char *pszName ); +inline void ThreadSetDebugName( const char *pszName ) { ThreadSetDebugName( NULL, pszName ); } PLATFORM_INTERFACE void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinityMask ); -//----------------------------------------------------------------------------- - -enum ThreadWaitResult_t -{ - TW_FAILED = 0xffffffff, // WAIT_FAILED - TW_TIMEOUT = 0x00000102, // WAIT_TIMEOUT -}; - -#ifdef _WIN32 -PLATFORM_INTERFACE int ThreadWaitForObjects( int nEvents, const HANDLE *pHandles, bool bWaitAll = true, unsigned timeout = TT_INFINITE ); -inline int ThreadWaitForObject( HANDLE handle, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) { return ThreadWaitForObjects( 1, &handle, bWaitAll, timeout ); } -#endif //----------------------------------------------------------------------------- // @@ -192,44 +262,83 @@ inline int ThreadWaitForObject( HANDLE handle, bool bWaitAll = true, unsigned ti #ifdef _WIN32 #define NOINLINE -#elif POSIX +#elif defined( _PS3 ) +#define NOINLINE __attribute__ ((noinline)) +#elif defined(POSIX) #define NOINLINE __attribute__ ((noinline)) #endif -// ThreadMemoryBarrier is a fence/barrier sufficient for most uses. It prevents reads -// from moving past reads, and writes moving past writes. It is sufficient for -// read-acquire and write-release barriers. It is not a full barrier and it does -// not prevent reads from moving past writes -- that would require a full __sync() -// on PPC and is significantly more expensive. #if defined( _X360 ) || defined( _PS3 ) - #define ThreadMemoryBarrier() __lwsync() - -#elif defined(_MSC_VER) - // Prevent compiler reordering across this barrier. This is - // sufficient for most purposes on x86/x64. - - #if _MSC_VER < 1500 - // !KLUDGE! For VC 2005 - // http://connect.microsoft.com/VisualStudio/feedback/details/100051 - #pragma intrinsic(_ReadWriteBarrier) - #endif - #define ThreadMemoryBarrier() _ReadWriteBarrier() -#elif defined(GNUC) - // Prevent compiler reordering across this barrier. This is - // sufficient for most purposes on x86/x64. - // http://preshing.com/20120625/memory-ordering-at-compile-time - #define ThreadMemoryBarrier() asm volatile("" ::: "memory") +#define ThreadMemoryBarrier() __lwsync() +#elif defined(COMPILER_MSVC) +// Prevent compiler reordering across this barrier. This is +// sufficient for most purposes on x86/x64. +#define ThreadMemoryBarrier() _ReadWriteBarrier() +#elif defined(COMPILER_GCC) +// Prevent compiler reordering across this barrier. This is +// sufficient for most purposes on x86/x64. +// http://preshing.com/20120625/memory-ordering-at-compile-time +#define ThreadMemoryBarrier() asm volatile("" ::: "memory") #else - #error Every platform needs to define ThreadMemoryBarrier to at least prevent compiler reordering +#error Every platform needs to define ThreadMemoryBarrier to at least prevent compiler reordering #endif -#if defined(_WIN32) && !defined(_X360) - #if ( _MSC_VER >= 1310 ) - #define USE_INTRINSIC_INTERLOCKED - #endif -#endif +#if defined( _LINUX ) || defined( _OSX ) +#define USE_INTRINSIC_INTERLOCKED +// linux implementation +inline int32 ThreadInterlockedIncrement( int32 volatile *p ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_fetch_and_add( p, 1 ) + 1; +} + +inline int32 ThreadInterlockedDecrement( int32 volatile *p ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_fetch_and_add( p, -1 ) - 1; +} + +inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) +{ + Assert( (size_t)p % 4 == 0 ); + int32 nRet; + + // Note: The LOCK instruction prefix is assumed on the XCHG instruction and GCC gets very confused on the Mac when we use it. + __asm __volatile( + "xchgl %2,(%1)" + : "=r" (nRet) + : "r" (p), "0" (value) + : "memory"); + return nRet; +} + +inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_fetch_and_add( p, value ); +} +inline int64 ThreadInterlockedExchangeAdd64( int64 volatile *p, int64 value ) +{ + Assert( ( (size_t)p ) % 8 == 0 ); + return __sync_fetch_and_add( p, value ); +} +inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_val_compare_and_swap( p, comperand, value ); +} + + +inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_bool_compare_and_swap( p, comperand, value ); +} + +#elif ( defined( COMPILER_MSVC32 ) && ( _MSC_VER >= 1310 ) ) +// windows 32 implemnetation using compiler intrinsics +#define USE_INTRINSIC_INTERLOCKED -#ifdef USE_INTRINSIC_INTERLOCKED extern "C" { long __cdecl _InterlockedIncrement(volatile long*); @@ -245,72 +354,106 @@ extern "C" #pragma intrinsic( _InterlockedExchangeAdd ) #pragma intrinsic( _InterlockedIncrement ) -inline int32 ThreadInterlockedIncrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( p ); } -inline int32 ThreadInterlockedDecrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( p ); } -inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchange( p, value ); } -inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( p, value ); } -inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( p, value, comperand ); } -inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( p, value, comperand ) == comperand ); } +inline int32 ThreadInterlockedIncrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( (volatile long*)p ); } +inline int32 ThreadInterlockedDecrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( (volatile long*)p ); } +inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchange( (volatile long*)p, value ); } +inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( (volatile long*)p, value ); } +inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( (volatile long*)p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( (volatile long*)p, value, comperand ) == comperand ); } +#elif defined( _PS3 ) +PLATFORM_INTERFACE inline int32 ThreadInterlockedIncrement( int32 volatile * ea ) { return cellAtomicIncr32( (uint32_t*)ea ) + 1; } +PLATFORM_INTERFACE inline int32 ThreadInterlockedDecrement( int32 volatile * ea ) { return cellAtomicDecr32( (uint32_t*)ea ) - 1; } +PLATFORM_INTERFACE inline int32 ThreadInterlockedExchange( int32 volatile * ea, int32 value ) { return cellAtomicStore32( ( uint32_t* )ea, value); } +PLATFORM_INTERFACE inline int32 ThreadInterlockedExchangeAdd( int32 volatile * ea, int32 value ) { return cellAtomicAdd32( ( uint32_t* )ea, value ); } +PLATFORM_INTERFACE inline int32 ThreadInterlockedCompareExchange( int32 volatile * ea, int32 value, int32 comperand ) { return cellAtomicCompareAndSwap32( (uint32_t*)ea, comperand, value ) ; } +PLATFORM_INTERFACE inline bool ThreadInterlockedAssignIf( int32 volatile * ea, int32 value, int32 comperand ) { return ( cellAtomicCompareAndSwap32( (uint32_t*)ea, comperand, value ) == ( uint32_t ) comperand ); } + +PLATFORM_INTERFACE inline int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand ) { return cellAtomicCompareAndSwap64( ( uint64_t* ) pDest, comperand, value ); } +PLATFORM_INTERFACE inline bool ThreadInterlockedAssignIf64( volatile int64 *pDest, int64 value, int64 comperand ) { return ( cellAtomicCompareAndSwap64( ( uint64_t* ) pDest, comperand, value ) == ( uint64_t ) comperand ); } + +#elif defined( _X360 ) +#define TO_INTERLOCK_PARAM(p) ((volatile long *)p) +#define TO_INTERLOCK_PTR_PARAM(p) ((void **)p) +FORCEINLINE int32 ThreadInterlockedIncrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedIncrement( TO_INTERLOCK_PARAM(pDest) ); } +FORCEINLINE int32 ThreadInterlockedDecrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedDecrement( TO_INTERLOCK_PARAM(pDest) ); } +FORCEINLINE int32 ThreadInterlockedExchange( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchange( TO_INTERLOCK_PARAM(pDest), value ); } +FORCEINLINE int32 ThreadInterlockedExchangeAdd( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchangeAdd( TO_INTERLOCK_PARAM(pDest), value ); } +FORCEINLINE int32 ThreadInterlockedCompareExchange( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ); } +FORCEINLINE bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return ( InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ) == comperand ); } #else -PLATFORM_INTERFACE int32 ThreadInterlockedIncrement( int32 volatile * ); -PLATFORM_INTERFACE int32 ThreadInterlockedDecrement( int32 volatile * ); -PLATFORM_INTERFACE int32 ThreadInterlockedExchange( int32 volatile *, int32 value ); -PLATFORM_INTERFACE int32 ThreadInterlockedExchangeAdd( int32 volatile *, int32 value ); -PLATFORM_INTERFACE int32 ThreadInterlockedCompareExchange( int32 volatile *, int32 value, int32 comperand ); -PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( int32 volatile *, int32 value, int32 comperand ); +// non 32-bit windows and 360 implementation +PLATFORM_INTERFACE int32 ThreadInterlockedIncrement( int32 volatile * ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedDecrement( int32 volatile * ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedExchange( int32 volatile *, int32 value ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedExchangeAdd( int32 volatile *, int32 value ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedCompareExchange( int32 volatile *, int32 value, int32 comperand ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( int32 volatile *, int32 value, int32 comperand ) NOINLINE; #endif -inline unsigned ThreadInterlockedExchangeSubtract( int32 volatile *p, int32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, -value ); } -#if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( _WIN64 ) +#if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( PLATFORM_64BITS ) #define TIPTR() -inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)_InterlockedExchange( reinterpret_cast(p), reinterpret_cast(value) ); } -inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)_InterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ); } -inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( _InterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ) == reinterpret_cast(comperand) ); } +inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)( ( intp )ThreadInterlockedExchange( reinterpret_cast(p), reinterpret_cast(value) ) ); } +inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)( ( intp )ThreadInterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ) ); } +inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( ThreadInterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ) == reinterpret_cast(comperand) ); } #else PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE; PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE; PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf( void * volatile *, void *value, void *comperand ) NOINLINE; #endif + +inline unsigned ThreadInterlockedExchangeSubtract( int32 volatile *p, int32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, -value ); } + inline void const *ThreadInterlockedExchangePointerToConst( void const * volatile *p, void const *value ) { return ThreadInterlockedExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ) ); } inline void const *ThreadInterlockedCompareExchangePointerToConst( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedCompareExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); } inline bool ThreadInterlockedAssignPointerToConstIf( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedAssignPointerIf( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); } -#if defined( PLATFORM_64BITS ) -#if defined (_WIN32) -typedef __m128i int128; -inline int128 int128_zero() { return _mm_setzero_si128(); } -#else -typedef __int128_t int128; -#define int128_zero() int128() + +#ifndef _PS3 +PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64( volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE; #endif -PLATFORM_INTERFACE bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand ) NOINLINE; - -#endif +PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE; +#ifdef COMPILER_MSVC32 PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE; PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE; -PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE; -PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE; PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE; -PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE; +#elif defined(POSIX) -inline uint32 ThreadInterlockedExchangeSubtract( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } -inline uint32 ThreadInterlockedIncrement( uint32 volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); } -inline uint32 ThreadInterlockedDecrement( uint32 volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); } -inline uint32 ThreadInterlockedExchange( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); } -inline uint32 ThreadInterlockedExchangeAdd( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } -inline uint32 ThreadInterlockedCompareExchange( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); } -inline bool ThreadInterlockedAssignIf( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); } +inline int64 ThreadInterlockedIncrement64( int64 volatile *p ) +{ + Assert( (size_t)p % 8 == 0 ); + return __sync_fetch_and_add( p, 1 ) + 1; +} -inline uint64 ThreadInterlockedIncrement64( uint64 volatile *p ) { return ThreadInterlockedIncrement64( (int64 volatile *)p ); } -inline uint64 ThreadInterlockedDecrement64( uint64 volatile *p ) { return ThreadInterlockedDecrement64( (int64 volatile *)p ); } -inline uint64 ThreadInterlockedCompareExchange64( uint64 volatile *p, uint64 value, uint64 comperand ) { return ThreadInterlockedCompareExchange64( (int64 volatile *)p, value, comperand ); } -inline uint64 ThreadInterlockedExchange64( uint64 volatile *p, uint64 value ) { return ThreadInterlockedExchange64( (int64 volatile *)p, value ); } -inline uint64 ThreadInterlockedExchangeAdd64( uint64 volatile *p, uint64 value ) { return ThreadInterlockedExchangeAdd64( (int64 volatile *)p, value ); } -inline bool ThreadInterlockedAssignIf64( uint64 volatile *p, uint64 value, uint64 comperand ) { return ThreadInterlockedAssignIf64( (int64 volatile *)p, value, comperand ); } +inline int64 ThreadInterlockedDecrement64( int64 volatile *p ) +{ + Assert( (size_t)p % 8 == 0 ); + return __sync_fetch_and_add( p, -1 ) - 1; +} + +#endif + +#ifdef COMPILER_MSVC64 +// 64 bit windows can use intrinsics for these, 32-bit can't +#pragma intrinsic( _InterlockedCompareExchange64 ) +#pragma intrinsic( _InterlockedExchange64 ) +#pragma intrinsic( _InterlockedExchangeAdd64 ) +inline int64 ThreadInterlockedCompareExchange64( int64 volatile *p, int64 value, int64 comparand ) { AssertDbg( (size_t)p % 8 == 0 ); return _InterlockedCompareExchange64( (volatile int64*)p, value, comparand ); } +inline int64 ThreadInterlockedExchangeAdd64( int64 volatile *p, int64 value ) { AssertDbg( (size_t)p % 8 == 0 ); return _InterlockedExchangeAdd64( (volatile int64*)p, value ); } +#endif + +inline unsigned ThreadInterlockedExchangeSubtract( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } + +inline unsigned ThreadInterlockedIncrement( uint32 volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); } +inline unsigned ThreadInterlockedDecrement( uint32 volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); } +inline unsigned ThreadInterlockedExchange( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); } +inline unsigned ThreadInterlockedExchangeAdd( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +inline unsigned ThreadInterlockedCompareExchange( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); } //inline int ThreadInterlockedExchangeSubtract( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } //inline int ThreadInterlockedIncrement( int volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); } @@ -320,6 +463,13 @@ inline bool ThreadInterlockedAssignIf64( uint64 volatile *p, uint64 value, uint6 //inline int ThreadInterlockedCompareExchange( int volatile *p, int value, int comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); } //inline bool ThreadInterlockedAssignIf( int volatile *p, int value, int comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); } + +#if defined( _WIN64 ) +typedef __m128i int128; +inline int128 int128_zero() { return _mm_setzero_si128(); } +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand ) NOINLINE; +#endif + //----------------------------------------------------------------------------- // Access to VTune thread profiling //----------------------------------------------------------------------------- @@ -342,7 +492,8 @@ PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void *p); #ifndef NO_THREAD_LOCAL -#if defined(_LINUX) && !defined(OSX) + +#if ( defined(_LINUX) && defined(DEDICATED) ) && !defined(OSX) // linux totally supports compiler thread locals, even across dll's. #define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1 #define CTHREADLOCALINTEGER( typ ) __thread int @@ -350,24 +501,38 @@ PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void *p); #define CTHREADLOCALPTR( typ ) __thread typ * #define CTHREADLOCAL( typ ) __thread typ #define GETLOCAL( x ) ( x ) -#endif // _LINUX && !OSX +#ifndef TIER0_DLL_EXPORT +DLL_IMPORT __thread int g_nThreadID; +#endif +#endif -#if defined(WIN32) || defined(OSX) + +#if defined(WIN32) || defined(OSX) || defined( _PS3 ) || ( defined (_LINUX) && !defined(DEDICATED) ) #ifndef __AFXTLS_H__ // not compatible with some Windows headers + +#if defined(_PS3) #define CTHREADLOCALINT CThreadLocalInt #define CTHREADLOCALINTEGER( typ ) CThreadLocalInt #define CTHREADLOCALPTR( typ ) CThreadLocalPtr #define CTHREADLOCAL( typ ) CThreadLocal #define GETLOCAL( x ) ( x.Get() ) +#else +#define CTHREADLOCALINT GenericThreadLocals::CThreadLocalInt +#define CTHREADLOCALINTEGER( typ ) GenericThreadLocals::CThreadLocalInt +#define CTHREADLOCALPTR( typ ) GenericThreadLocals::CThreadLocalPtr +#define CTHREADLOCAL( typ ) GenericThreadLocals::CThreadLocal +#define GETLOCAL( x ) ( x.Get() ) + #endif -#endif // WIN32 || OSX -#endif // NO_THREAD_LOCALS +#if !defined(_PS3) +namespace GenericThreadLocals +{ +#endif + // a (not so efficient) implementation of thread locals for compilers without full support (i.e. visual c). + // don't use this explicity - instead, use the CTHREADxxx macros above. -#ifndef __AFXTLS_H__ // not compatible with some Windows headers -#ifndef NO_THREAD_LOCAL - -class PLATFORM_CLASS CThreadLocalBase + class PLATFORM_CLASS CThreadLocalBase { public: CThreadLocalBase(); @@ -377,17 +542,15 @@ public: void Set(void *); private: -#ifdef _WIN32 - uint32 m_index; -#elif POSIX +#if defined(POSIX) && !defined( _GAMECONSOLE ) pthread_key_t m_index; +#else + uint32 m_index; #endif }; //--------------------------------------------------------- -#ifndef __AFXTLS_H__ - template class CThreadLocal : public CThreadLocalBase { @@ -395,19 +558,21 @@ private: CThreadLocal() { #ifdef PLATFORM_64BITS - COMPILE_TIME_ASSERT( sizeof(T) <= sizeof(void *) ); + COMPILE_TIME_ASSERT( sizeof(T) <= sizeof(void *) ); #else - COMPILE_TIME_ASSERT( sizeof(T) == sizeof(void *) ); + COMPILE_TIME_ASSERT( sizeof(T) == sizeof(void *) ); #endif } + void operator=( T i ) { Set( i ); } + T Get() const { #ifdef PLATFORM_64BITS - void *pData = CThreadLocalBase::Get(); - return *reinterpret_cast( &pData ); + void *pData = CThreadLocalBase::Get(); + return *reinterpret_cast( &pData ); #else - #ifdef COMPILER_MSVC + #ifdef COMPILER_MSVC #pragma warning ( disable : 4311 ) #endif return reinterpret_cast( CThreadLocalBase::Get() ); @@ -420,11 +585,11 @@ private: void Set(T val) { #ifdef PLATFORM_64BITS - void* pData = 0; - *reinterpret_cast( &pData ) = val; - CThreadLocalBase::Set( pData ); + void* pData = 0; + *reinterpret_cast( &pData ) = val; + CThreadLocalBase::Set( pData ); #else - #ifdef COMPILER_MSVC + #ifdef COMPILER_MSVC #pragma warning ( disable : 4312 ) #endif CThreadLocalBase::Set( reinterpret_cast(val) ); @@ -435,27 +600,27 @@ private: } }; -#endif //--------------------------------------------------------- -template + template class CThreadLocalInt : public CThreadLocal { public: - CThreadLocalInt() - { - COMPILE_TIME_ASSERT( sizeof(T) >= sizeof(int) ); - } + operator const T() const { return this->Get(); } + int operator=( T i ) { this->Set( i ); return i; } - operator int() const { return (int)this->Get(); } - int operator=( int i ) { this->Set( (intp)i ); return i; } + T operator++() { T i = this->Get(); this->Set( ++i ); return i; } + T operator++(int) { T i = this->Get(); this->Set( i + 1 ); return i; } - int operator++() { T i = this->Get(); this->Set( ++i ); return (int)i; } - int operator++(int) { T i = this->Get(); this->Set( i + 1 ); return (int)i; } + T operator--() { T i = this->Get(); this->Set( --i ); return i; } + T operator--(int) { T i = this->Get(); this->Set( i - 1 ); return i; } - int operator--() { T i = this->Get(); this->Set( --i ); return (int)i; } - int operator--(int) { T i = this->Get(); this->Set( i - 1 ); return (int)i; } + inline CThreadLocalInt( ) { } + inline CThreadLocalInt( const T &initialvalue ) + { + this->Set( initialvalue ); + } }; @@ -467,26 +632,30 @@ template public: CThreadLocalPtr() {} - operator const void *() const { return (T *)Get(); } + operator const void *() const { return (const T *)Get(); } operator void *() { return (T *)Get(); } - operator const T *() const { return (T *)Get(); } - operator const T *() { return (T *)Get(); } + operator const T *() const { return (const T *)Get(); } + operator const T *() { return (const T *)Get(); } operator T *() { return (T *)Get(); } T * operator=( T *p ) { Set( p ); return p; } bool operator !() const { return (!Get()); } + bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() != NULL); } + bool operator==( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() == NULL); } bool operator==( const void *p ) const { return (Get() == p); } bool operator!=( const void *p ) const { return (Get() != p); } + bool operator==( const T *p ) const { return operator==((const void*)p); } + bool operator!=( const T *p ) const { return operator!=((const void*)p); } T * operator->() { return (T *)Get(); } T & operator *() { return *((T *)Get()); } - const T * operator->() const { return (T *)Get(); } - const T & operator *() const { return *((T *)Get()); } + const T * operator->() const { return (const T *)Get(); } + const T & operator *() const { return *((const T *)Get()); } - const T & operator[]( int i ) const { return *((T *)Get() + i); } + const T & operator[]( int i ) const { return *((const T *)Get() + i); } T & operator[]( int i ) { return *((T *)Get() + i); } private: @@ -499,9 +668,37 @@ template bool operator==( const CThreadLocalPtr &p ) const; bool operator!=( const CThreadLocalPtr &p ) const; }; +#if !defined(_PS3) +} +using namespace GenericThreadLocals; +#endif + + +#ifdef _OSX +PLATFORM_INTERFACE GenericThreadLocals::CThreadLocalInt g_nThreadID; +#else // _OSX +#ifndef TIER0_DLL_EXPORT + +#ifndef _PS3 +DLL_GLOBAL_IMPORT CTHREADLOCALINT g_nThreadID; +#endif // !_PS3 + +#endif // TIER0_DLL_EXPORT +#endif // _OSX + +#endif /// afx32 +#endif //__win32 #endif // NO_THREAD_LOCAL -#endif // !__AFXTLS_H__ + +#ifdef _WIN64 +// 64 bit windows can use intrinsics for these, 32-bit can't +#pragma intrinsic( _InterlockedCompareExchange64 ) +#pragma intrinsic( _InterlockedExchange64 ) +#pragma intrinsic( _InterlockedExchangeAdd64 ) +inline int64 ThreadInterlockedIncrement64(int64 volatile *p) { AssertDbg((size_t)p % 8 == 0); return _InterlockedIncrement64((volatile int64*)p); } +inline int64 ThreadInterlockedDecrement64(int64 volatile *p) { AssertDbg((size_t)p % 8 == 0); return _InterlockedDecrement64((volatile int64*)p); } +#endif //----------------------------------------------------------------------------- // @@ -516,45 +713,67 @@ template class CInterlockedIntT { public: - CInterlockedIntT() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T) == sizeof(int) ); } + CInterlockedIntT() : m_value( 0 ) { COMPILE_TIME_ASSERT( ( sizeof(T) == sizeof(int32) ) || ( sizeof(T) == sizeof(int64) ) ); } + CInterlockedIntT( T value ) : m_value( value ) {} - T GetRaw() const { return m_value; } - + T operator()( void ) const { return m_value; } operator T() const { return m_value; } bool operator!() const { return ( m_value == 0 ); } bool operator==( T rhs ) const { return ( m_value == rhs ); } bool operator!=( T rhs ) const { return ( m_value != rhs ); } - -#if defined( __arm__ ) || defined( __arm64__ ) - CInterlockedIntT( const CInterlockedIntT &rhs ) : m_value( rhs ) {} - CInterlockedIntT &operator=( const CInterlockedIntT &rhs ) { m_value.store(rhs.m_value.load()); return *this; } - T operator++() { return m_value.fetch_add(1) + 1; } - T operator++(int) { return m_value.fetch_add(1); } - - T operator--() { return m_value.fetch_sub(1) - 1; } - T operator--(int) { return m_value.fetch_sub(1); } - - bool AssignIf( T conditionValue, T newValue ) { return m_value.compare_exchange_strong(conditionValue, newValue); } - - T operator=( T newValue ) { m_value.store(newValue); return newValue; } - - void operator+=( T add ) { m_value.fetch_add(add); } -#else - T operator++() { return (T)ThreadInterlockedIncrement( (int *)&m_value ); } + T operator++() { + if ( sizeof(T) == sizeof(int32) ) + return (T)ThreadInterlockedIncrement( (int32 *)&m_value ); + else + return (T)ThreadInterlockedIncrement64( (int64 *)&m_value ); + } T operator++(int) { return operator++() - 1; } - T operator--() { return (T)ThreadInterlockedDecrement( (int *)&m_value ); } + T operator--() { + if ( sizeof(T) == sizeof(int32) ) + return (T)ThreadInterlockedDecrement( (int32 *)&m_value ); + else + return (T)ThreadInterlockedDecrement64( (int64 *)&m_value ); + } + T operator--(int) { return operator--() + 1; } - bool AssignIf( T conditionValue, T newValue ) { return ThreadInterlockedAssignIf( (int *)&m_value, (int)newValue, (int)conditionValue ); } + bool AssignIf( T conditionValue, T newValue ) + { + if ( sizeof(T) == sizeof(int32) ) + return ThreadInterlockedAssignIf( (int32 *)&m_value, (int32)newValue, (int32)conditionValue ); + else + return ThreadInterlockedAssignIf64( (int64 *)&m_value, (int64)newValue, (int64)conditionValue ); + } - T operator=( T newValue ) { ThreadInterlockedExchange((int *)&m_value, newValue); return m_value; } - void operator+=( T add ) { ThreadInterlockedExchangeAdd( (int *)&m_value, (int)add ); } -#endif + T operator=( T newValue ) { + if ( sizeof(T) == sizeof(int32) ) + ThreadInterlockedExchange((int32 *)&m_value, newValue); + else + ThreadInterlockedExchange64((int64 *)&m_value, newValue); + return m_value; + } + + // Atomic add is like += except it returns the previous value as its return value + T AtomicAdd( T add ) { + if ( sizeof(T) == sizeof(int32) ) + return (T)ThreadInterlockedExchangeAdd( (int32 *)&m_value, (int32)add ); + else + return (T)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, (int64)add ); + } + + + void operator+=( T add ) { + if ( sizeof(T) == sizeof(int32) ) + ThreadInterlockedExchangeAdd( (int32 *)&m_value, (int32)add ); + else + ThreadInterlockedExchangeAdd64( (int64 *)&m_value, (int64)add ); + } + void operator-=( T subtract ) { operator+=( -subtract ); } void operator*=( T multiplier ) { T original, result; @@ -576,19 +795,22 @@ public: T operator+( T rhs ) const { return m_value + rhs; } T operator-( T rhs ) const { return m_value - rhs; } + T InterlockedExchange(T newValue) { + if (sizeof(T) == sizeof(int32)) + return (T)ThreadInterlockedExchange((int32*)&m_value, newValue); + else + return (T)ThreadInterlockedExchange64((int64*)&m_value, newValue); + } + private: -#if defined( __arm__ ) || defined( __arm64__ ) - std::atomic m_value; -#else volatile T m_value; -#endif }; typedef CInterlockedIntT CInterlockedInt; typedef CInterlockedIntT CInterlockedUInt; //----------------------------------------------------------------------------- - +#ifdef _M_X64 template class CInterlockedPtr { @@ -601,50 +823,23 @@ public: bool operator!() const { return ( m_value == 0 ); } bool operator==( T *rhs ) const { return ( m_value == rhs ); } bool operator!=( T *rhs ) const { return ( m_value != rhs ); } -#if defined( __arm__ ) || defined( __arm64__ ) - CInterlockedPtr( const CInterlockedPtr &rhs ) : m_value( rhs ) {} - CInterlockedPtr &operator=( const CInterlockedPtr &rhs ) { m_value.store(rhs.m_value.load()); return *this; } - T *operator++() { return m_value.fetch_add(1) + 1; } - T *operator++(int) { return m_value.fetch_add(1); } - T *operator--() { return m_value.fetch_sub(1) - 1; } - T *operator--(int) { return m_value.fetch_sub(1); } + T *operator++() { return ((T *)_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, sizeof(T) )) + 1; } + T *operator++(int) { return (T *)_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, sizeof(T) ); } - bool AssignIf( T *conditionValue, T *newValue ) { return m_value.compare_exchange_strong(conditionValue, newValue); } + T *operator--() { return ((T *)_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, -sizeof(T) )) - 1; } + T *operator--(int) { return (T *)_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, -sizeof(T) ); } - T *operator=( T *newValue ) { m_value.store(newValue); return newValue; } + bool AssignIf( T *conditionValue, T *newValue ) { return _InterlockedCompareExchangePointer( (void * volatile *)&m_value, newValue, conditionValue ) == conditionValue; } - void operator+=( int add ) { m_value.fetch_add(add); } -#else -#if defined( PLATFORM_64BITS ) - T *operator++() { return ((T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, sizeof(T) )) + 1; } - T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, sizeof(T) ); } - - T *operator--() { return ((T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, -sizeof(T) )) - 1; } - T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, -sizeof(T) ); } - - bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); } - - T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; } - - void operator+=( int add ) { ThreadInterlockedExchangeAdd64( (int64 *)&m_value, add * sizeof(T) ); } -#else - T *operator++() { return ((T *)ThreadInterlockedExchangeAdd( (long *)&m_value, sizeof(T) )) + 1; } - T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd( (long *)&m_value, sizeof(T) ); } - - T *operator--() { return ((T *)ThreadInterlockedExchangeAdd( (long *)&m_value, -sizeof(T) )) - 1; } - T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd( (long *)&m_value, -sizeof(T) ); } - - bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); } - - T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; } - - void operator+=( int add ) { ThreadInterlockedExchangeAdd( (long *)&m_value, add * sizeof(T) ); } -#endif -#endif + T *operator=( T *newValue ) { _InterlockedExchangePointer( (void * volatile *) &m_value, newValue ); return newValue; } + void operator+=( int add ) { _InterlockedExchangeAdd64( (volatile __int64 *)&m_value, add * sizeof(T) ); } void operator-=( int subtract ) { operator+=( -subtract ); } + // Atomic add is like += except it returns the previous value as its return value + T *AtomicAdd( int add ) { return ( T * )_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, add * sizeof(T) ); } + T *operator+( int rhs ) const { return m_value + rhs; } T *operator-( int rhs ) const { return m_value - rhs; } T *operator+( unsigned rhs ) const { return m_value + rhs; } @@ -653,47 +848,61 @@ public: size_t operator-( const CInterlockedPtr &p ) const { return m_value - p.m_value; } private: -#if defined( __arm__ ) || defined( __arm64__ ) - std::atomic m_value; -#else T * volatile m_value; -#endif }; - -//----------------------------------------------------------------------------- -// -// Platform independent verification that multiple threads aren't getting into the same code at the same time. -// Note: This is intended for use to identify problems, it doesn't provide any sort of thread safety. -// -//----------------------------------------------------------------------------- -class ReentrancyVerifier +#else +template +class CInterlockedPtr { public: - inline ReentrancyVerifier(CInterlockedInt* counter, int sleepTimeMS) - : mCounter(counter) + CInterlockedPtr() : m_value( 0 ) { - Assert(mCounter != NULL); - - if (++(*mCounter) != 1) { - DebuggerBreakIfDebugging_StagingOnly(); - } - - if (sleepTimeMS > 0) - { - ThreadSleep(sleepTimeMS); - } +#ifdef PLATFORM_64BITS + COMPILE_TIME_ASSERT( sizeof(T *) == sizeof(int64) ); +#define THREADINTERLOCKEDEXCHANGEADD( _dest, _value ) ThreadInterlockedExchangeAdd64( (int64 *)(_dest), _value ) +#else // PLATFORM_64BITS + COMPILE_TIME_ASSERT( sizeof(T *) == sizeof(int32) ); +#define THREADINTERLOCKEDEXCHANGEADD( _dest, _value ) ThreadInterlockedExchangeAdd( (int32 *)_dest, _value ) +#endif // PLATFORM_64BITS } - inline ~ReentrancyVerifier() - { - if (--(*mCounter) != 0) { - DebuggerBreakIfDebugging_StagingOnly(); - } - } + CInterlockedPtr( T *value ) : m_value( value ) {} + + operator T *() const { return m_value; } + + bool operator!() const { return ( m_value == 0 ); } + bool operator==( T *rhs ) const { return ( m_value == rhs ); } + bool operator!=( T *rhs ) const { return ( m_value != rhs ); } + + T *operator++() { return ((T *)THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, sizeof(T) )) + 1; } + T *operator++(int) { return (T *)THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, sizeof(T) ); } + + T *operator--() { return ((T *)THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, -sizeof(T) )) - 1; } + T *operator--(int) { return (T *)THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, -sizeof(T) ); } + + bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); } + + T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; } + + void operator+=( int add ) { THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, add * sizeof(T) ); } + void operator-=( int subtract ) { operator+=( -subtract ); } + + // Atomic add is like += except it returns the previous value as its return value + T *AtomicAdd( int add ) { return ( T * ) THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, add * sizeof(T) ); } + + T *operator+( int rhs ) const { return m_value + rhs; } + T *operator-( int rhs ) const { return m_value - rhs; } + T *operator+( unsigned rhs ) const { return m_value + rhs; } + T *operator-( unsigned rhs ) const { return m_value - rhs; } + size_t operator-( T *p ) const { return m_value - p; } + size_t operator-( const CInterlockedPtr &p ) const { return m_value - p.m_value; } private: - CInterlockedInt* mCounter; + T * volatile m_value; + +#undef THREADINTERLOCKEDEXCHANGEADD }; +#endif //----------------------------------------------------------------------------- @@ -719,12 +928,21 @@ public: bool TryLock(); bool TryLock() const { return (const_cast(this))->TryLock(); } + void LockSilent(); // A Lock() operation which never spews. Required by the logging system to prevent badness. + void UnlockSilent(); // An Unlock() operation which never spews. Required by the logging system to prevent badness. + //------------------------------------------------------ // Use this to make deadlocks easier to track by asserting // when it is expected that the current thread owns the mutex //------------------------------------------------------ bool AssertOwnedByCurrentThread(); + //------------------------------------------------------ + // On windows with THREAD_MUTEX_TRACING_ENABLED defined, this returns + // true if the mutex is owned by the current thread. + //------------------------------------------------------ + bool IsOwnedByCurrentThread_DebugOnly(); + //------------------------------------------------------ // Enable tracing to track deadlock problems //------------------------------------------------------ @@ -744,9 +962,11 @@ private: #define TT_SIZEOF_CRITICALSECTION 24 #else #define TT_SIZEOF_CRITICALSECTION 28 -#endif // !_XBOX +#endif // !_X360 #endif // _WIN64 byte m_CriticalSection[TT_SIZEOF_CRITICALSECTION]; +#elif defined( _PS3 ) + sys_mutex_t m_Mutex; #elif defined(POSIX) pthread_mutex_t m_Mutex; pthread_mutexattr_t m_Attr; @@ -755,7 +975,7 @@ private: #endif #ifdef THREAD_MUTEX_TRACING_SUPPORTED - // Debugging (always here to allow mixed debug/release builds w/o changing size) + // Debugging (always herge to allow mixed debug/release builds w/o changing size) uint m_currentOwnerID; uint16 m_lockCount; bool m_bTrace; @@ -784,13 +1004,9 @@ public: } private: - FORCEINLINE bool TryLockInline( const uintp threadId ) volatile + FORCEINLINE bool TryLockInline( const uint32 threadId ) volatile { -#if PLATFORM_64BITS - if ( threadId != m_ownerID && !ThreadInterlockedAssignIf64( &m_ownerID, threadId, 0 ) ) -#else - if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( &m_ownerID, threadId, 0 ) ) -#endif + if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( (volatile int32 *)&m_ownerID, (int32)threadId, 0 ) ) return false; ThreadMemoryBarrier(); @@ -798,12 +1014,12 @@ private: return true; } - bool TryLock( const uintp threadId ) volatile + bool TryLock( const uint32 threadId ) volatile { return TryLockInline( threadId ); } - PLATFORM_CLASS void Lock( const uintp threadId, unsigned nSpinSleepTime ) volatile; + PLATFORM_CLASS void Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile; public: bool TryLock() volatile @@ -823,7 +1039,7 @@ public: #endif void Lock( unsigned int nSpinSleepTime = 0 ) volatile { - const uintp threadId = ThreadGetCurrentId(); + const uint32 threadId = ThreadGetCurrentId(); if ( !TryLockInline( threadId ) ) { @@ -831,7 +1047,7 @@ public: Lock( threadId, nSpinSleepTime ); } #ifdef _DEBUG - if ( m_ownerID != ThreadGetCurrentId() ) + if ( m_ownerID != (int32)ThreadGetCurrentId() ) DebuggerBreak(); if ( m_depth == INT_MAX ) @@ -848,7 +1064,7 @@ public: void Unlock() volatile { #ifdef _DEBUG - if ( m_ownerID != ThreadGetCurrentId() ) + if ( m_ownerID != (int32)ThreadGetCurrentId() ) DebuggerBreak(); if ( m_depth <= 0 ) @@ -859,35 +1075,25 @@ public: if ( !m_depth ) { ThreadMemoryBarrier(); -#if PLATFORM_64BITS - ThreadInterlockedExchange64( &m_ownerID, 0 ); -#else - ThreadInterlockedExchange( &m_ownerID, 0 ); -#endif - } - } + ThreadInterlockedExchange( &m_ownerID, 0 ); + } + } -#ifdef WIN32 bool TryLock() const volatile { return (const_cast(this))->TryLock(); } - void Lock(unsigned nSpinSleepTime = 1 ) const volatile { (const_cast(this))->Lock( nSpinSleepTime ); } + void Lock(unsigned nSpinSleepTime = 0 ) const volatile { (const_cast(this))->Lock( nSpinSleepTime ); } void Unlock() const volatile { (const_cast(this))->Unlock(); } -#endif + // To match regular CThreadMutex: bool AssertOwnedByCurrentThread() { return true; } void SetTrace( bool ) {} - uintp GetOwnerId() const { return m_ownerID; } + uint32 GetOwnerId() const { return m_ownerID; } int GetDepth() const { return m_depth; } private: - volatile uintp m_ownerID; + volatile uint32 m_ownerID; int m_depth; }; -#ifdef COMPILER_CLANG -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunused-private-field" -#endif // Q_CC_CLANG - class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex { public: @@ -898,14 +1104,65 @@ public: private: uint8 pad[128-sizeof(CThreadFastMutex)]; -} ALIGN128_POST; - -#ifdef COMPILER_CLANG -# pragma clang diagnostic pop -#endif +}; #else +#ifdef _PS3 + +class CThreadFastMutex +{ +public: + CThreadFastMutex(); + ~CThreadFastMutex(); + + //------------------------------------------------------ + // Mutex acquisition/release. Const intentionally defeated. + //------------------------------------------------------ + void Lock(); + void Lock() const { (const_cast(this))->Lock(); } + void Unlock(); + void Unlock() const { (const_cast(this))->Unlock(); } + + bool TryLock(); + bool TryLock() const { return (const_cast(this))->TryLock(); } + + //------------------------------------------------------ + // Use this to make deadlocks easier to track by asserting + // when it is expected that the current thread owns the mutex + //------------------------------------------------------ + bool AssertOwnedByCurrentThread(); + + //------------------------------------------------------ + // Enable tracing to track deadlock problems + //------------------------------------------------------ + void SetTrace( bool ); + +private: + // Disallow copying + CThreadFastMutex( const CThreadFastMutex & ); + //CThreadFastMutex &operator=( const CThreadFastMutex & ); + sys_lwmutex_t m_Mutex; + sys_mutex_t m_SlowMutex; +}; + +#else + typedef CThreadMutex CThreadFastMutex; + +#endif + +class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex +{ +public: + CAlignedThreadFastMutex() + { + Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 ); + } + +private: + uint8 pad[128-sizeof(CThreadFastMutex)]; +}; + #endif //----------------------------------------------------------------------------- @@ -922,7 +1179,7 @@ public: static bool AssertOwnedByCurrentThread() { return true; } static void SetTrace( bool b ) {} - static uintp GetOwnerId() { return 0; } + static uint32 GetOwnerId() { return 0; } static int GetDepth() { return 0; } }; @@ -974,75 +1231,71 @@ template class CAutoLockT { public: - FORCEINLINE CAutoLockT( MUTEX_TYPE &lock, const char* pMutexName, const char* pFilename, int nLineNum, uint64 minReportDurationUs ) - : m_lock( const_cast< typename V_remove_const< MUTEX_TYPE >::type & >( lock ) ) - , m_pMutexName( pMutexName ) - , m_pFilename( pFilename ) - , m_nLineNum( nLineNum ) - , m_bOwned( true ) + FORCEINLINE CAutoLockT( MUTEX_TYPE &lock) + : m_lock(lock) { - tmTryLockEx( TELEMETRY_LEVEL0, &m_uLockMatcher, minReportDurationUs, pFilename, nLineNum, &m_lock, pMutexName ); m_lock.Lock(); - tmEndTryLockEx( TELEMETRY_LEVEL0, m_uLockMatcher, pFilename, nLineNum, &m_lock, TMLR_SUCCESS ); - tmSetLockStateEx( TELEMETRY_LEVEL0, pFilename, nLineNum, &m_lock, TMLS_LOCKED, pMutexName ); } - FORCEINLINE CAutoLockT( CAutoLockT && rhs ) - : m_lock( const_cast< typename V_remove_const< MUTEX_TYPE >::type &>( rhs.m_lock ) ) + FORCEINLINE CAutoLockT(const MUTEX_TYPE &lock) + : m_lock(const_cast(lock)) { - m_pMutexName = rhs.m_pMutexName; - m_pFilename = rhs.m_pFilename; - m_nLineNum = rhs.m_nLineNum; - #ifdef RAD_TELEMETRY_ENABLED - m_uLockMatcher = rhs.m_uLockMatcher; - #endif - m_bOwned = true; - rhs.m_bOwned = false; + m_lock.Lock(); } FORCEINLINE ~CAutoLockT() { - if ( m_bOwned ) - { - m_lock.Unlock(); - tmSetLockStateEx( TELEMETRY_LEVEL0, m_pFilename, m_nLineNum, &m_lock, TMLS_RELEASED, m_pMutexName ); - } + m_lock.Unlock(); } -private: - typename V_remove_const< MUTEX_TYPE >::type &m_lock; - const char* m_pMutexName; - const char* m_pFilename; - int m_nLineNum; - bool m_bOwned; // Did owenership of the lock pass to another instance? -#ifdef RAD_TELEMETRY_ENABLED - TmU64 m_uLockMatcher; -#endif +private: + MUTEX_TYPE &m_lock; // Disallow copying CAutoLockT( const CAutoLockT & ); CAutoLockT &operator=( const CAutoLockT & ); - - // No move assignment because no default construction. - CAutoLockT &operator=( CAutoLockT && ); }; typedef CAutoLockT CAutoLock; -template < typename MUTEX_TYPE > -inline CAutoLockT make_auto_lock( MUTEX_TYPE& lock, const char* pMutexname, const char* pFilename, int nLineNum, int nMinReportDurationUs = 1 ) -{ - return CAutoLockT( lock, pMutexname, pFilename, nLineNum, nMinReportDurationUs ); -} - //--------------------------------------------------------- -#define AUTO_LOCK( mutex ) \ - auto UNIQUE_ID = make_auto_lock( mutex, #mutex, __FILE__, __LINE__ ); +template struct CAutoLockTypeDeducer {}; +template <> struct CAutoLockTypeDeducer { typedef CThreadMutex Type_t; }; +template <> struct CAutoLockTypeDeducer { typedef CThreadNullMutex Type_t; }; +#if !defined(THREAD_PROFILER) +template <> struct CAutoLockTypeDeducer { typedef CThreadFastMutex Type_t; }; +template <> struct CAutoLockTypeDeducer { typedef CAlignedThreadFastMutex Type_t; }; +#else +template <> struct CAutoLockTypeDeducer { typedef CAlignedThreadFastMutex Type_t; }; +#endif -#define AUTO_LOCK_D( mutex, minDurationUs ) \ - auto UNIQUE_ID = make_auto_lock( mutex, #mutex, __FILE__, __LINE__, minDurationUs ); + +#define AUTO_LOCK_( type, mutex ) \ + CAutoLockT< type > UNIQUE_ID( static_cast( mutex ) ) + +#if defined(GNUC) + +template T strip_cv_quals_for_mutex(T&); +template T strip_cv_quals_for_mutex(const T&); +template T strip_cv_quals_for_mutex(volatile T&); +template T strip_cv_quals_for_mutex(const volatile T&); + +#define AUTO_LOCK( mutex ) \ + AUTO_LOCK_( decltype(::strip_cv_quals_for_mutex(mutex)), mutex ) + +#elif defined( __clang__ ) +#define AUTO_LOCK( mutex ) \ + AUTO_LOCK_( typename CAutoLockTypeDeducer::Type_t, mutex ) +#else +#define AUTO_LOCK( mutex ) \ + AUTO_LOCK_( CAutoLockTypeDeducer::Type_t, mutex ) +#endif + + +#define AUTO_LOCK_FM( mutex ) \ + AUTO_LOCK_( CThreadFastMutex, mutex ) #define LOCAL_THREAD_LOCK_( tag ) \ ; \ @@ -1058,6 +1311,11 @@ inline CAutoLockT make_auto_lock( MUTEX_TYPE& lock, const char* pMut // //----------------------------------------------------------------------------- +// TW_TIMEOUT must match WAIT_TIMEOUT definition +#define TW_TIMEOUT 0x00000102 +// TW_FAILED must match WAIT_FAILED definition +#define TW_FAILED 0xFFFFFFFF + class PLATFORM_CLASS CThreadSyncObject { public: @@ -1080,6 +1338,21 @@ public: //----------------------------------------------------- bool Wait( uint32 dwTimeout = TT_INFINITE ); + //----------------------------------------------------- + // Wait for a signal from any of the specified objects. + // + // Returns the index of the object that signaled the event + // or THREADSYNC_TIMEOUT if the timeout was hit before the wait condition was met. + // + // Returns TW_FAILED if an incoming object is invalid. + // + // If bWaitAll=true, then it'll return 0 if all the objects were set. + //----------------------------------------------------- + static uint32 WaitForMultiple( int nObjects, CThreadSyncObject **ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + + // This builds a list of pointers and calls straight through to the other WaitForMultiple. + static uint32 WaitForMultiple( int nObjects, CThreadSyncObject *ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + protected: CThreadSyncObject(); void AssertUseable(); @@ -1087,6 +1360,10 @@ protected: #ifdef _WIN32 HANDLE m_hSyncObject; bool m_bCreatedHandle; +#elif defined( _PS3 ) + static sys_lwmutex_t m_staticMutex; + static uint32_t m_bstaticMutexInitialized; + static uint32_t m_bstaticMutexInitializing; #elif defined(POSIX) pthread_mutex_t m_Mutex; pthread_cond_t m_Condition; @@ -1110,7 +1387,6 @@ private: // //----------------------------------------------------------------------------- -#if defined( _WIN32 ) //----------------------------------------------------------------------------- // @@ -1121,19 +1397,30 @@ private: class PLATFORM_CLASS CThreadSemaphore : public CThreadSyncObject { public: - CThreadSemaphore(long initialValue, long maxValue); + CThreadSemaphore(int32 initialValue, int32 maxValue); //----------------------------------------------------- // Increases the count of the semaphore object by a specified // amount. Wait() decreases the count by one on return. //----------------------------------------------------- - bool Release(long releaseCount = 1, long * pPreviousCount = NULL ); + bool Release(int32 releaseCount = 1, int32 * pPreviousCount = NULL ); + bool Wait( uint32 dwTimeout = TT_INFINITE ); private: CThreadSemaphore(const CThreadSemaphore &); CThreadSemaphore &operator=(const CThreadSemaphore &); +#ifdef _PS3 + bool AddWaitingThread(); + void RemoveWaitingThread(); + sys_semaphore_t m_Semaphore; + sys_semaphore_value_t m_sema_max_val; + uint32_t m_numWaitingThread; + uint32_t m_bInitalized; + uint32_t m_semaCount; +#endif }; +#if defined( _WIN32 ) //----------------------------------------------------------------------------- // @@ -1164,12 +1451,54 @@ private: }; #endif +enum NamedEventResult_t +{ + TT_EventDoesntExist = 0, + TT_EventNotSignaled, + TT_EventSignaled +}; +#if defined( _PS3 ) +//--------------------------------------------------------------------------- +// CThreadEventWaitObject - the purpose of this class is to help implement +// WaitForMultipleObejcts on PS3. +// +// Each event maintains a linked list of CThreadEventWaitObjects. When a +// thread wants to wait on an event it passes the event a semaphore that +// ptr to see the index of the event that triggered it +// +// The thread-specific mutex is to ensure that setting the index and setting the +// semaphore are atomic +//--------------------------------------------------------------------------- + +class CThreadEventWaitObject +{ +public: + CThreadEventWaitObject *m_pPrev, *m_pNext; + sys_semaphore_t *m_pSemaphore; + int m_index; + int *m_pFlag; + + CThreadEventWaitObject() {} + + void Init(sys_semaphore_t *pSem, int index, int *pFlag) + { + m_pSemaphore = pSem; + m_index = index; + m_pFlag = pFlag; + } + + void Set(); +}; +#endif //_PS3 class PLATFORM_CLASS CThreadEvent : public CThreadSyncObject { public: CThreadEvent( bool fManualReset = false ); -#ifdef WIN32 +#ifdef PLATFORM_WINDOWS + CThreadEvent( const char *name, bool initialState = false, bool bManualReset = false ); + static NamedEventResult_t CheckNamedEvent( const char *name, uint32 dwTimeout = 0 ); + CThreadEvent( HANDLE hHandle ); #endif //----------------------------------------------------- @@ -1185,13 +1514,88 @@ public: //----------------------------------------------------- // Check if the event is signaled //----------------------------------------------------- - bool Check(); + bool Check(); // Please, use for debugging only! bool Wait( uint32 dwTimeout = TT_INFINITE ); + // See CThreadSyncObject for definitions of these functions. + static uint32 WaitForMultiple( int nObjects, CThreadEvent **ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + // To implement these, I need to check that casts are safe + static uint32 WaitForMultiple( int nObjects, CThreadEvent *ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + +#ifdef _PS3 + void RegisterWaitingThread(sys_semaphore_t *pSemaphore, int index, int *flag); + void UnregisterWaitingThread(sys_semaphore_t *pSemaphore); +#endif + +protected: +#ifdef _PS3 + // These virtual functions need to be inline in order for the class to be exported from tier0.prx + virtual bool AddWaitingThread() + { + //This checks if the event is already signaled and if not creates a semaphore which will be signaled + //when the event is finally signaled. + bool result; + + sys_lwmutex_lock(&m_staticMutex, 0); + + if (m_bSet) + result=false; + else + { + result=true; + + m_numWaitingThread++; + + if ( m_numWaitingThread == 1 ) + { + sys_semaphore_attribute_t semAttr; + sys_semaphore_attribute_initialize( semAttr ); + int err = sys_semaphore_create( &m_Semaphore, &semAttr, 0, 256 ); + Assert( err == CELL_OK ); + m_bInitalized = true; + } + } + + sys_lwmutex_unlock(&m_staticMutex); + return result; + } + + virtual void RemoveWaitingThread() + { + sys_lwmutex_lock(&m_staticMutex, 0); + + m_numWaitingThread--; + + if ( m_numWaitingThread == 0) + { + int err = sys_semaphore_destroy( m_Semaphore ); + Assert( err == CELL_OK ); + m_bInitalized = false; + } + + sys_lwmutex_unlock(&m_staticMutex); + } +#endif private: CThreadEvent( const CThreadEvent & ); CThreadEvent &operator=( const CThreadEvent & ); +#if defined( _PS3 ) + uint32_t m_bSet; + bool m_bManualReset; + + sys_semaphore_t m_Semaphore; + uint32_t m_numWaitingThread; + uint32_t m_bInitalized; + + CThreadEventWaitObject m_waitObjects[CTHREADEVENT_MAX_WAITING_THREADS+2]; + CThreadEventWaitObject *m_pWaitObjectsPool; + CThreadEventWaitObject *m_pWaitObjectsList; + + CThreadEventWaitObject* LLUnlinkNode(CThreadEventWaitObject *node); + CThreadEventWaitObject* LLLinkNode(CThreadEventWaitObject* list, CThreadEventWaitObject *node); + +#endif }; // Hard-wired manual event for use in array declarations @@ -1204,21 +1608,8 @@ public: } }; -inline int ThreadWaitForEvents( int nEvents, CThreadEvent * const *pEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) -{ -#ifdef POSIX - Assert( nEvents == 1); - if ( pEvents[0]->Wait( timeout ) ) - return WAIT_OBJECT_0; - else - return WAIT_TIMEOUT; -#else - HANDLE handles[64]; - for ( int i = 0; i < min( nEvents, (int)ARRAYSIZE(handles) ); i++ ) - handles[i] = pEvents[i]->GetHandle(); - return ThreadWaitForObjects( nEvents, handles, bWaitAll, timeout ); -#endif -} +PLATFORM_INTERFACE int ThreadWaitForObjects( int nEvents, const HANDLE *pHandles, bool bWaitAll = true, unsigned timeout = TT_INFINITE ); +inline int ThreadWaitForEvents( int nEvents, const CThreadEvent *pEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) { return ThreadWaitForObjects( nEvents, (const HANDLE *)pEvents, bWaitAll, timeout ); } //----------------------------------------------------------------------------- // @@ -1263,10 +1654,80 @@ private: // //----------------------------------------------------------------------------- +#ifndef OLD_SPINRWLOCK class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock { public: - CThreadSpinRWLock() { Assert( (intp)this % 8 == 0 ); memset( this, 0, sizeof( *this ) ); } + CThreadSpinRWLock() + { + m_lockInfo.m_i32 = 0; + m_writerId = 0; +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + m_iWriteDepth = 0; +#endif + } + + bool IsLockedForWrite(); + bool IsLockedForRead(); + + FORCEINLINE bool TryLockForWrite(); + bool TryLockForWrite_UnforcedInline(); + + void LockForWrite(); + void SpinLockForWrite(); + + FORCEINLINE bool TryLockForRead(); + bool TryLockForRead_UnforcedInline(); + + void LockForRead(); + void SpinLockForRead(); + + void UnlockWrite(); + void UnlockRead(); + + bool TryLockForWrite() const { return const_cast(this)->TryLockForWrite(); } + bool TryLockForRead() const { return const_cast(this)->TryLockForRead(); } + void LockForRead() const { const_cast(this)->LockForRead(); } + void UnlockRead() const { const_cast(this)->UnlockRead(); } + void LockForWrite() const { const_cast(this)->LockForWrite(); } + void UnlockWrite() const { const_cast(this)->UnlockWrite(); } + +private: + enum + { + THREAD_SPIN = (8*1024) + }; + + union LockInfo_t + { + struct + { +#if PLAT_LITTLE_ENDIAN + uint16 m_nReaders; + uint16 m_fWriting; +#else + uint16 m_fWriting; + uint16 m_nReaders; +#endif + }; + uint32 m_i32; + }; + + LockInfo_t m_lockInfo; + ThreadId_t m_writerId; +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + int m_iWriteDepth; + uint32 pad; +#endif +} ALIGN8_POST; + +#else + +/* (commented out to reduce distraction in colorized editor, remove entirely when new implementation settles) +class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock +{ +public: + CThreadSpinRWLock() { COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); Assert( (intp)this % 8 == 0 ); memset( this, 0, sizeof( *this ) ); } bool TryLockForWrite(); bool TryLockForRead(); @@ -1284,32 +1745,43 @@ public: void UnlockWrite() const { const_cast(this)->UnlockWrite(); } private: - - struct LockInfo_t + // This structure is used as an atomic & exchangeable 64-bit value. It would probably be better to just have one 64-bit value + // and accessor functions that make/break it, but at this late stage of development, I'm just wrapping it into union + // Beware of endianness: on Xbox/PowerPC m_writerId is high-word of m_i64; on PC, it's low-dword of m_i64 + union LockInfo_t { - LockInfo_t(uint32 thread_id = 0, int readers = 0) + struct { - m_writerId = thread_id; - m_nReaders = readers; - } - - uint32 m_writerId; - int m_nReaders; + uint32 m_writerId; + int m_nReaders; + }; + int64 m_i64; }; bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ); - bool TryLockForWrite( const uintp threadId ); - void SpinLockForWrite( const uintp threadId ); + bool TryLockForWrite( const uint32 threadId ); + void SpinLockForWrite( const uint32 threadId ); volatile LockInfo_t m_lockInfo; CInterlockedInt m_nWriters; } ALIGN8_POST; +*/ +#endif //----------------------------------------------------------------------------- // // A thread wrapper similar to a Java thread. // //----------------------------------------------------------------------------- +#ifdef _PS3 +// Everything must be inline for this to work across PRX boundaries + +class CThread; +PLATFORM_INTERFACE CThread *GetCurThreadPS3(); +PLATFORM_INTERFACE void SetCurThreadPS3( CThread * ); +PLATFORM_INTERFACE void AllocateThreadID( void ); +PLATFORM_INTERFACE void FreeThreadID( void ); +#endif class PLATFORM_CLASS CThread { @@ -1320,7 +1792,7 @@ public: //----------------------------------------------------- const char *GetName(); - void SetName( const char * ); + void SetName( const char *pszName ); size_t CalcStackDepth( void *pStackVariable ) { return ((byte *)m_pStackBase - (byte *)pStackVariable); } @@ -1329,7 +1801,7 @@ public: //----------------------------------------------------- // Start thread running - error if already running - virtual bool Start( unsigned nBytesStack = 0 ); + virtual bool Start( unsigned nBytesStack = 0, ThreadPriorityEnum_t nPriority = TP_PRIORITY_DEFAULT ); // Returns true if thread has been created and hasn't yet exited bool IsAlive(); @@ -1338,11 +1810,10 @@ public: // is no longer alive. bool Join( unsigned timeout = TT_INFINITE ); -#ifdef _WIN32 // Access the thread handle directly - HANDLE GetThreadHandle(); - uint GetThreadId(); -#elif defined( LINUX ) + ThreadHandle_t GetThreadHandle(); + +#ifdef _WIN32 uint GetThreadId(); #endif @@ -1361,26 +1832,16 @@ public: int GetPriority() const; // Set the priority - bool SetPriority( int ); + bool SetPriority( int priority ); - // Request a thread to suspend, this must ONLY be called from the thread itself, not the main thread - // This suspend variant causes the thread in question to suspend at a known point in its execution - // which means you don't risk the global deadlocks/hangs potentially caused by the raw Suspend() call - void SuspendCooperative(); + // Suspend a thread, can only call from the thread itself + unsigned Suspend(); - // Resume a previously suspended thread from the Cooperative call - void ResumeCooperative(); + // Resume a suspended thread + unsigned Resume(); - // wait for a thread to execute its SuspendCooperative call - void BWaitForThreadSuspendCooperative(); - -#ifndef LINUX - // forcefully Suspend a thread - unsigned int Suspend(); - - // forcefully Resume a previously suspended thread - unsigned int Resume(); -#endif + // Check if thread is suspended + bool IsSuspended() { return !m_NotSuspendedEvent.Check(); } // Force hard-termination of thread. Used for critical failures. bool Terminate( int exitCode = 0 ); @@ -1402,7 +1863,7 @@ public: // This method causes the current thread to yield and not to be // scheduled for further execution until a certain amount of real - // time has elapsed, more or less. + // time has elapsed, more or less. Duration is in milliseconds static void Sleep( unsigned duration ); protected: @@ -1415,27 +1876,29 @@ protected: // derived class, performs the intended action of the thread. virtual int Run() = 0; - // Called when the thread is about to exit, by the about-to-exit thread. + // Called when the thread exits virtual void OnExit(); - // Called after OnExit when a thread finishes or is killed. Not virtual because no inherited classes - // override it and we don't want to change the vtable from the published SDK version. - void Cleanup(); + // Allow for custom start waiting + virtual bool WaitForCreateComplete( CThreadEvent *pEvent ); + const ThreadId_t GetThreadID() const { return (ThreadId_t)m_threadId; } - bool WaitForCreateComplete( CThreadEvent *pEvent ); +#ifdef PLATFORM_WINDOWS + const ThreadHandle_t GetThreadHandle() const { return (ThreadHandle_t)m_hThread; } + + static unsigned long __stdcall ThreadProc( void * pv ); + typedef unsigned long (__stdcall *ThreadProc_t)( void * ); +#else + static void* ThreadProc( void * pv ); + typedef void* (*ThreadProc_t)( void * pv ); +#endif + static void ThreadProcRunWithMinidumpHandler( void *pv ); - // "Virtual static" facility - typedef unsigned (__stdcall *ThreadProc_t)( void * ); virtual ThreadProc_t GetThreadProc(); virtual bool IsThreadRunning(); CThreadMutex m_Lock; - -#ifdef WIN32 - ThreadHandle_t GetThreadID() const { return (ThreadHandle_t)m_hThread; } -#else - ThreadId_t GetThreadID() const { return (ThreadId_t)m_threadId; } -#endif + CThreadEvent m_ExitEvent; // Set right before the thread's function exits. private: enum Flags @@ -1450,10 +1913,11 @@ private: CThread * pThread; CThreadEvent *pInitCompleteEvent; bool * pfInitSuccess; +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + void * ParentStackTrace[THREAD_PARENT_STACK_TRACE_LENGTH]; +#endif }; - static unsigned __stdcall ThreadProc( void * pv ); - // make copy constructor and assignment operator inaccessible CThread( const CThread & ); CThread &operator=( const CThread & ); @@ -1461,18 +1925,37 @@ private: #ifdef _WIN32 HANDLE m_hThread; ThreadId_t m_threadId; +#elif defined( _PS3 ) + sys_ppu_thread_t m_threadId; + volatile sys_ppu_thread_t m_threadZombieId; + + // Mutex and condition variable used by the Suspend / Resume logic + sys_mutex_t m_mutexSuspend; + sys_cond_t m_condSuspend; + + //EAPS3 Event to indicate that a thread has terminated. This helps with the replacing of WaitForMultipleObjects + // on the PS3, since it waits for a thread to finish. + CThreadEvent m_threadEnd; #elif defined(POSIX) pthread_t m_threadId; + volatile pthread_t m_threadZombieId; + //lwss add - Thread params. These were previously allocated on the heap and leaked. + ThreadInit_t m_threadInit; + //lwss end #endif - CInterlockedInt m_nSuspendCount; - CThreadEvent m_SuspendEvent; - CThreadEvent m_SuspendEventSignal; int m_result; char m_szName[32]; void * m_pStackBase; unsigned m_flags; + CThreadManualEvent m_NotSuspendedEvent; }; +// The CThread implementation needs to be inlined for performance on the PS3 - It makes a difference of more than 1ms/frame +// Since the dependency checker isn't smart enough to take an #ifdef _PS3 into account, all platforms will inline it. +#ifdef _PS3 +#include "threadtools.inl" +#endif + //----------------------------------------------------------------------------- // // A helper class to let you sleep a thread for memory validation, you need to handle @@ -1503,7 +1986,6 @@ protected: // synchronized communication. //----------------------------------------------------------------------------- - // These are internal reserved error results from a call attempt enum WTCallResult_t { @@ -1512,7 +1994,6 @@ enum WTCallResult_t WTCR_THREAD_GONE = -3, }; -class CFunctor; class PLATFORM_CLASS CWorkerThread : public CThread { public: @@ -1528,7 +2009,7 @@ public: //----------------------------------------------------- // Master: Signal the thread, and block for a response - int CallWorker( unsigned, unsigned timeout = TT_INFINITE, bool fBoostWorkerPriorityToMaster = true, CFunctor *pParamFunctor = NULL ); + int CallWorker( unsigned, unsigned timeout = TT_INFINITE, bool fBoostWorkerPriorityToMaster = true ); // Worker: Signal the thread, and block for a response int CallMaster( unsigned, unsigned timeout = TT_INFINITE ); @@ -1538,7 +2019,7 @@ public: bool WaitForCall( unsigned *pResult = NULL ); // Is there a request? - bool PeekCall( unsigned *pParam = NULL, CFunctor **ppParamFunctor = NULL ); + bool PeekCall( unsigned *pParam = NULL ); // Reply to the request void Reply( unsigned ); @@ -1548,20 +2029,17 @@ public: // If you want to do WaitForMultipleObjects you'll need to include // this handle in your wait list or you won't be responsive - CThreadEvent &GetCallHandle(); + CThreadEvent& GetCallHandle(); // (returns m_EventSend) + // Find out what the request was - unsigned GetCallParam( CFunctor **ppParamFunctor = NULL ) const; + unsigned GetCallParam() const; // Boost the worker thread to the master thread, if worker thread is lesser, return old priority int BoostPriority(); protected: -#ifndef _WIN32 -#define __stdcall -#endif - typedef uint32 (__stdcall *WaitFunc_t)( int nEvents, CThreadEvent * const *pEvents, int bWaitAll, uint32 timeout ); - - int Call( unsigned, unsigned timeout, bool fBoost, WaitFunc_t = NULL, CFunctor *pParamFunctor = NULL ); + typedef uint32 ( *WaitFunc_t)( uint32 nHandles, CThreadEvent** ppHandles, int bWaitAll, uint32 timeout ); + int Call( unsigned, unsigned timeout, bool fBoost, WaitFunc_t = NULL ); int WaitForReply( unsigned timeout, WaitFunc_t ); private: @@ -1572,7 +2050,6 @@ private: CThreadEvent m_EventComplete; unsigned m_Param; - CFunctor *m_pParamFunctor; int m_ReturnVal; }; @@ -1660,7 +2137,7 @@ public: // //----------------------------------------------------------------------------- -#ifdef _WIN32 +#ifdef MSVC typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION; typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; @@ -1673,18 +2150,25 @@ extern "C" void __declspec(dllimport) __stdcall DeleteCriticalSection(CRITICAL_SECTION *); }; #endif +#endif //--------------------------------------------------------- +#if !defined(POSIX) || defined( _GAMECONSOLE ) inline void CThreadMutex::Lock() { -#ifdef THREAD_MUTEX_TRACING_ENABLED +#if defined(_PS3) + #ifndef NO_THREAD_SYNC + sys_mutex_lock( m_Mutex, 0 ); + #endif +#else + #if defined( THREAD_MUTEX_TRACING_ENABLED ) uint thisThreadID = ThreadGetCurrentId(); if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) ) - Msg( "Thread %u about to wait for lock %p owned by %u\n", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); + Msg( _T( "Thread %u about to wait for lock %p owned by %u\n" ), ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); #endif - VCRHook_EnterCriticalSection((CRITICAL_SECTION *)&m_CriticalSection); + LockSilent(); #ifdef THREAD_MUTEX_TRACING_ENABLED if (m_lockCount == 0) @@ -1692,27 +2176,58 @@ inline void CThreadMutex::Lock() // we now own it for the first time. Set owner information m_currentOwnerID = thisThreadID; if ( m_bTrace ) - Msg( "Thread %u now owns lock %p\n", m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); + Msg( _T( "Thread %u now owns lock 0x%p\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); } m_lockCount++; #endif +#endif } //--------------------------------------------------------- inline void CThreadMutex::Unlock() { +#if defined( _PS3 ) + + #ifndef NO_THREAD_SYNC + sys_mutex_unlock( m_Mutex ); + #endif + +#else #ifdef THREAD_MUTEX_TRACING_ENABLED AssertMsg( m_lockCount >= 1, "Invalid unlock of thread lock" ); m_lockCount--; if (m_lockCount == 0) { if ( m_bTrace ) - Msg( "Thread %u releasing lock %p\n", m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); + Msg( _T( "Thread %u releasing lock 0x%p\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); m_currentOwnerID = 0; } #endif + UnlockSilent(); +#endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::LockSilent() +{ + #ifdef MSVC + EnterCriticalSection((CRITICAL_SECTION *)&m_CriticalSection); + #else + DebuggerBreak(); // should not be called - not defined for this platform/compiler!!! + #endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::UnlockSilent() +{ + #ifdef MSVC LeaveCriticalSection((CRITICAL_SECTION *)&m_CriticalSection); + #else + DebuggerBreak(); // should not be called - not defined for this platform/compiler!!! + #endif } //--------------------------------------------------------- @@ -1720,10 +2235,23 @@ inline void CThreadMutex::Unlock() inline bool CThreadMutex::AssertOwnedByCurrentThread() { #ifdef THREAD_MUTEX_TRACING_ENABLED +#ifdef _WIN32 if (ThreadGetCurrentId() == m_currentOwnerID) return true; - AssertMsg3( 0, "Expected thread %u as owner of lock %p, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); + AssertMsg3( 0, "Expected thread %u as owner of lock 0x%p, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); return false; +#elif defined( _PS3 ) + return true; +#endif +#else + return true; +#endif +} + +inline bool CThreadMutex::IsOwnedByCurrentThread_DebugOnly() +{ +#if defined ( THREAD_MUTEX_TRACING_ENABLED ) && defined ( _WIN32 ) + return ThreadGetCurrentId() == m_currentOwnerID; #else return true; #endif @@ -1733,14 +2261,19 @@ inline bool CThreadMutex::AssertOwnedByCurrentThread() inline void CThreadMutex::SetTrace( bool bTrace ) { +#ifdef _WIN32 #ifdef THREAD_MUTEX_TRACING_ENABLED m_bTrace = bTrace; #endif +#elif defined _PS3 + //EAPS3 +#endif + } //--------------------------------------------------------- -#elif defined(POSIX) +#elif defined(POSIX) && !defined( _GAMECONSOLE ) inline CThreadMutex::CThreadMutex() { @@ -1773,6 +2306,20 @@ inline void CThreadMutex::Unlock() //--------------------------------------------------------- +inline void CThreadMutex::LockSilent() +{ + pthread_mutex_lock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::UnlockSilent() +{ + pthread_mutex_unlock( &m_Mutex ); +} + +//--------------------------------------------------------- + inline bool CThreadMutex::AssertOwnedByCurrentThread() { return true; @@ -1784,6 +2331,8 @@ inline void CThreadMutex::SetTrace(bool fTrace) { } +#else +#error #endif // POSIX //----------------------------------------------------------------------------- @@ -1829,18 +2378,165 @@ inline void CThreadRWLock::UnlockRead() // //----------------------------------------------------------------------------- -inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ) -{ -#if PLATFORM_64BITS - COMPILE_TIME_ASSERT(sizeof(LockInfo_t) == 16); - return ThreadInterlockedAssignIf128( (int128 *)&m_lockInfo, *((int128 *)&newValue), *((int128 *)&comperand) ); +#ifndef OLD_SPINRWLOCK + +#if defined(TEST_THREAD_SPIN_RW_LOCK) +#define RWLAssert( exp ) if ( exp ) ; else DebuggerBreak(); #else - COMPILE_TIME_ASSERT(sizeof(LockInfo_t) == 8); - return ThreadInterlockedAssignIf64( (int64 *)&m_lockInfo, *((int64 *)&newValue), *((int64 *)&comperand) ); +#define RWLAssert( exp ) ((void)0) +#endif + +inline bool CThreadSpinRWLock::IsLockedForWrite() +{ + return ( m_lockInfo.m_fWriting == 1 ); +} + +inline bool CThreadSpinRWLock::IsLockedForRead() +{ + return ( m_lockInfo.m_nReaders > 0 ); +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite() +{ + volatile LockInfo_t &curValue = m_lockInfo; + if ( !( curValue.m_i32 & 0x00010000 ) && ThreadInterlockedAssignIf( &curValue.m_i32, 0x00010000, 0 ) ) + { + ThreadMemoryBarrier(); + RWLAssert( m_iWriteDepth == 0 && m_writerId == 0 ); + m_writerId = ThreadGetCurrentId(); +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + m_iWriteDepth++; +#endif + return true; + } + + return false; +} + +inline bool CThreadSpinRWLock::TryLockForWrite_UnforcedInline() +{ + if ( TryLockForWrite() ) + { + return true; + } + +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( m_writerId != ThreadGetCurrentId() ) + { + return false; + } + m_iWriteDepth++; + return true; +#else + return false; #endif } -inline bool CThreadSpinRWLock::TryLockForWrite( const uintp threadId ) +FORCEINLINE void CThreadSpinRWLock::LockForWrite() +{ + if ( !TryLockForWrite() ) + { + SpinLockForWrite(); + } +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForRead() +{ + volatile LockInfo_t &curValue = m_lockInfo; + if ( !( curValue.m_i32 & 0x00010000 ) ) // !m_lockInfo.m_fWriting + { + LockInfo_t oldValue; + LockInfo_t newValue; + oldValue.m_i32 = ( curValue.m_i32 & 0xffff ); + newValue.m_i32 = oldValue.m_i32 + 1; + + if ( ThreadInterlockedAssignIf( &m_lockInfo.m_i32, newValue.m_i32, oldValue.m_i32 ) ) + { + ThreadMemoryBarrier(); + RWLAssert( m_lockInfo.m_fWriting == 0 ); + return true; + } + } + return false; +} + +inline bool CThreadSpinRWLock::TryLockForRead_UnforcedInline() +{ +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( m_lockInfo.m_i32 & 0x00010000 ) // m_lockInfo.m_fWriting + { + if ( m_writerId == ThreadGetCurrentId() ) + { + m_lockInfo.m_nReaders++; + return true; + } + + return false; + } +#endif + return TryLockForRead(); +} + +FORCEINLINE void CThreadSpinRWLock::LockForRead() +{ + if ( !TryLockForRead() ) + { + SpinLockForRead(); + } +} + +FORCEINLINE void CThreadSpinRWLock::UnlockWrite() +{ + RWLAssert( m_writerId == ThreadGetCurrentId() ); +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( --m_iWriteDepth == 0 ) +#endif + { + m_writerId = 0; + ThreadMemoryBarrier(); + m_lockInfo.m_i32 = 0; + } +} + +#ifndef REENTRANT_THREAD_SPIN_RW_LOCK +FORCEINLINE +#else +inline +#endif +void CThreadSpinRWLock::UnlockRead() +{ + RWLAssert( m_writerId == 0 || ( m_writerId == ThreadGetCurrentId() && m_lockInfo.m_fWriting ) ); +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( !( m_lockInfo.m_i32 & 0x00010000 ) ) // !m_lockInfo.m_fWriting +#endif + { + ThreadMemoryBarrier(); + ThreadInterlockedDecrement( &m_lockInfo.m_i32 ); + RWLAssert( m_writerId == 0 && !m_lockInfo.m_fWriting ); + } +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + else if ( m_writerId == ThreadGetCurrentId() ) + { + m_lockInfo.m_nReaders--; + } + else + { + RWLAssert( 0 ); + } +#endif +} + +#else +/* (commented out to reduce distraction in colorized editor, remove entirely when new implementation settles) +inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ) +{ + // Note: using unions guarantees no aliasing bugs. Casting structures through *(int64*)& + // may create hard-to-catch bugs because when you do that, compiler doesn't know that the newly computed pointer + // is actually aliased with LockInfo_t structure. It's rarely a problem in practice, but when it is, it's a royal pain to debug. + return ThreadInterlockedAssignIf64( &m_lockInfo.m_i64, newValue.m_i64, comperand.m_i64 ); +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId ) { // In order to grab a write lock, there can be no readers and no owners of the write lock if ( m_lockInfo.m_nReaders > 0 || ( m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId ) ) @@ -1848,16 +2544,14 @@ inline bool CThreadSpinRWLock::TryLockForWrite( const uintp threadId ) return false; } - static const LockInfo_t oldValue( 0, 0 ); - LockInfo_t newValue( threadId, 0 ); - const bool bSuccess = AssignIf( newValue, oldValue ); -#if defined(_X360) - if ( bSuccess ) + static const LockInfo_t oldValue = { {0, 0} }; + LockInfo_t newValue = { { threadId, 0 } }; + if ( AssignIf( newValue, oldValue ) ) { - // X360TBD: Serious perf implications. Not Yet. __sync(); + ThreadMemoryBarrier(); + return true; } -#endif - return bSuccess; + return false; } inline bool CThreadSpinRWLock::TryLockForWrite() @@ -1871,7 +2565,7 @@ inline bool CThreadSpinRWLock::TryLockForWrite() return true; } -inline bool CThreadSpinRWLock::TryLockForRead() +FORCEINLINE bool CThreadSpinRWLock::TryLockForRead() { if ( m_nWriters != 0 ) { @@ -1881,24 +2575,33 @@ inline bool CThreadSpinRWLock::TryLockForRead() LockInfo_t oldValue; LockInfo_t newValue; + if( IsX360() || IsPS3() ) + { + // this is the code equivalent to original code (see below) that doesn't cause LHS on Xbox360 + // WARNING: This code assumes BIG Endian CPU + oldValue.m_i64 = uint32( m_lockInfo.m_nReaders ); + newValue.m_i64 = oldValue.m_i64 + 1; // NOTE: when we have -1 (or 0xFFFFFFFF) readers, this will result in non-equivalent code + } + else + { + // this is the original code that worked here for a while oldValue.m_nReaders = m_lockInfo.m_nReaders; oldValue.m_writerId = 0; newValue.m_nReaders = oldValue.m_nReaders + 1; newValue.m_writerId = 0; - - const bool bSuccess = AssignIf( newValue, oldValue ); -#if defined(_X360) - if ( bSuccess ) - { - // X360TBD: Serious perf implications. Not Yet. __sync(); } -#endif - return bSuccess; + + if ( AssignIf( newValue, oldValue ) ) + { + ThreadMemoryBarrier(); + return true; + } + return false; } inline void CThreadSpinRWLock::LockForWrite() { - const uintp threadId = ThreadGetCurrentId(); + const uint32 threadId = ThreadGetCurrentId(); m_nWriters++; @@ -1908,6 +2611,8 @@ inline void CThreadSpinRWLock::LockForWrite() SpinLockForWrite( threadId ); } } +*/ +#endif // read data from a memory address template FORCEINLINE T ReadVolatileMemory( T const *pPtr ) @@ -1916,10 +2621,16 @@ template FORCEINLINE T ReadVolatileMemory( T const *pPtr ) return *pVolatilePtr; } + //----------------------------------------------------------------------------- #if defined( _WIN32 ) #pragma warning(pop) #endif +#if defined( _PS3 ) +BOOL SetEvent( CThreadEvent *pEvent ); +BOOL ResetEvent( CThreadEvent *pEvent ); +DWORD WaitForMultipleObjects(DWORD nCount, CThreadEvent **lppHandles, BOOL bWaitAll, DWORD dwMilliseconds ); +#endif // _PS3 #endif // THREADTOOLS_H diff --git a/public/tier0/threadtools.inl b/public/tier0/threadtools.inl new file mode 100644 index 00000000..037a64ed --- /dev/null +++ b/public/tier0/threadtools.inl @@ -0,0 +1,653 @@ +#ifndef THREADTOOLS_INL +#define THREADTOOLS_INL + +// This file is included in threadtools.h for PS3 and threadtools.cpp for all other platforms +// +// Do not #include other files here + +#ifndef _PS3 +// this is defined in the .cpp for the PS3 to avoid introducing a dependency for files including the header +CTHREADLOCALPTR(CThread) g_pCurThread; + +#define INLINE_ON_PS3 +#else +// Inlining these functions on PS3 (which are called across PRX boundaries) saves us over 1ms per frame +#define INLINE_ON_PS3 inline +#endif + +INLINE_ON_PS3 CThread::CThread() : +#ifdef _WIN32 +m_hThread( NULL ), +m_threadId( 0 ), +#elif defined( _PS3 ) || defined(_POSIX) +m_threadId( 0 ), +m_threadZombieId( 0 ) , +#endif +m_result( 0 ), +m_flags( 0 ) +{ + m_szName[0] = 0; + m_NotSuspendedEvent.Set(); +} + +//--------------------------------------------------------- + +INLINE_ON_PS3 CThread::~CThread() +{ +#ifdef MSVC + if (m_hThread) +#elif defined(POSIX) && !defined( _PS3 ) + if ( m_threadId ) +#endif + { + if ( IsAlive() ) + { + Msg( "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" ); +#ifdef _WIN32 + + DoNewAssertDialog( __FILE__, __LINE__, "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" ); +#endif + if ( GetCurrentCThread() == this ) + { + Stop(); // BUGBUG: Alfred - this doesn't make sense, this destructor fires from the hosting thread not the thread itself!! + } + } + } +#if defined(POSIX) || defined( _PS3 ) + if ( m_threadZombieId ) + { + // just clean up zombie threads immediately (the destructor is fired from the hosting thread) + Join(); + } +#endif +} + + +//--------------------------------------------------------- + +INLINE_ON_PS3 const char *CThread::GetName() +{ + AUTO_LOCK( m_Lock ); + if ( !m_szName[0] ) + { +#if defined( _WIN32 ) + _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/%p)", this, m_hThread ); +#elif defined( _PS3 ) + snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p)", this ); +#elif defined( POSIX ) + _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/0x%p)", this, m_threadId ); +#endif + m_szName[sizeof(m_szName) - 1] = 0; + } + return m_szName; +} + +//--------------------------------------------------------- + +INLINE_ON_PS3 void CThread::SetName(const char *pszName) +{ + AUTO_LOCK( m_Lock ); + strncpy( m_szName, pszName, sizeof(m_szName) - 1 ); + m_szName[sizeof(m_szName) - 1] = 0; +} + +//----------------------------------------------------- +// Functions for the other threads +//----------------------------------------------------- + +// Start thread running - error if already running +INLINE_ON_PS3 bool CThread::Start( unsigned nBytesStack, ThreadPriorityEnum_t nPriority ) +{ + AUTO_LOCK( m_Lock ); + + if ( IsAlive() ) + { + AssertMsg( 0, "Tried to create a thread that has already been created!" ); + return false; + } + + bool bInitSuccess = false; + CThreadEvent createComplete; + ThreadInit_t init = { this, &createComplete, &bInitSuccess }; + +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + { + int iValidEntries = GetCallStack_Fast( init.ParentStackTrace, ARRAYSIZE( init.ParentStackTrace ), 0 ); + for( int i = iValidEntries; i < ARRAYSIZE( init.ParentStackTrace ); ++i ) + { + init.ParentStackTrace[i] = NULL; + } + } +#endif + +#ifdef PLATFORM_WINDOWS + m_hThread = (HANDLE)CreateThread( NULL, + nBytesStack, + (LPTHREAD_START_ROUTINE)GetThreadProc(), + new ThreadInit_t(init), + nBytesStack ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0, + (LPDWORD)&m_threadId ); + + if( nPriority != TP_PRIORITY_DEFAULT ) + { + SetThreadPriority( m_hThread, nPriority ); + } + + if ( !m_hThread ) + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() ); + return false; + } +#elif PLATFORM_PS3 + // On the PS3, a stack size of 0 doesn't imply a default stack size, so we need to force it to our + // own default size. + if ( nBytesStack == 0 ) + { + nBytesStack = PS3_SYS_PPU_THREAD_COMMON_STACK_SIZE; + } + + //The thread is about to begin + m_threadEnd.Reset(); + + // sony documentation: + // "If the PPU thread is not joined by sys_ppu_thread_join() after exit, + // it should always be created as non-joinable (not specifying + // SYS_PPU_THREAD_CREATE_JOINABLE). Otherwise, some resources are left + // allocated after termination of the PPU thread as if memory leaks." + const char* threadName=m_szName; + if ( sys_ppu_thread_create( &m_threadId, + (void(*)(uint64_t))GetThreadProc(), + (uint64_t)(new ThreadInit_t( init )), + nPriority, + nBytesStack, + SYS_PPU_THREAD_CREATE_JOINABLE , + threadName ) != CELL_OK ) + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", errno ); + return false; + } + + bInitSuccess = true; +#elif PLATFORM_POSIX + pthread_attr_t attr; + pthread_attr_init( &attr ); + pthread_attr_setstacksize( &attr, MAX( nBytesStack, 1024u*1024 ) ); + //lwss - fix memory leak here + m_threadInit = ThreadInit_t( init ); + //if ( pthread_create( &m_threadId, &attr, (void *(*)(void *))GetThreadProc(), new ThreadInit_t( init ) ) != 0 ) + if ( pthread_create( &m_threadId, &attr, (void *(*)(void *))GetThreadProc(), &m_threadInit ) != 0 ) + //lwss end + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() ); + return false; + } + bInitSuccess = true; +#endif + + + + if ( !WaitForCreateComplete( &createComplete ) ) + { + Msg( "Thread failed to initialize\n" ); +#ifdef _WIN32 + CloseHandle( m_hThread ); + m_hThread = NULL; +#elif defined( _PS3 ) + m_threadEnd.Set(); + m_threadId = NULL; + m_threadZombieId = 0; +#endif + + return false; + } + + if ( !bInitSuccess ) + { + Msg( "Thread failed to initialize\n" ); +#ifdef _WIN32 + CloseHandle( m_hThread ); + m_hThread = NULL; +#elif defined(POSIX) && !defined( _PS3 ) + m_threadId = 0; + m_threadZombieId = 0; +#endif + return false; + } + +#ifdef _WIN32 + if ( !m_hThread ) + { + Msg( "Thread exited immediately\n" ); + } +#endif + +#ifdef _WIN32 + AddThreadHandleToIDMap( m_hThread, m_threadId ); + return !!m_hThread; +#elif defined(POSIX) + return !!m_threadId; +#endif +} + +//--------------------------------------------------------- +// +// Return true if the thread has been created and hasn't yet exited +// + +INLINE_ON_PS3 bool CThread::IsAlive() +{ +#ifdef PLATFORM_WINDOWS + DWORD dwExitCode; + return ( + m_hThread + && GetExitCodeThread(m_hThread, &dwExitCode) + && dwExitCode == STILL_ACTIVE ); +#elif defined(POSIX) + return !!m_threadId; +#endif +} + +// This method causes the current thread to wait until this thread +// is no longer alive. +INLINE_ON_PS3 bool CThread::Join( unsigned timeout ) +{ +#ifdef _WIN32 + if ( m_hThread ) +#elif defined(POSIX) + if ( m_threadId || m_threadZombieId ) +#endif + { + AssertMsg(GetCurrentCThread() != this, _T("Thread cannot be joined with self")); + +#ifdef _WIN32 + return ThreadJoin( (ThreadHandle_t)m_hThread, timeout ); +#elif defined(POSIX) + bool ret = ThreadJoin( (ThreadHandle_t)(m_threadId ? m_threadId : m_threadZombieId), timeout ); + m_threadZombieId = 0; + return ret; +#endif + } + return true; +} + +//--------------------------------------------------------- + +INLINE_ON_PS3 ThreadHandle_t CThread::GetThreadHandle() +{ +#ifdef _WIN32 + return (ThreadHandle_t)m_hThread; +#else + return (ThreadHandle_t)m_threadId; +#endif +} + + +//--------------------------------------------------------- + +INLINE_ON_PS3 int CThread::GetResult() +{ + return m_result; +} + +//----------------------------------------------------- +// Functions for both this, and maybe, and other threads +//----------------------------------------------------- + +// Forcibly, abnormally, but relatively cleanly stop the thread +// + +INLINE_ON_PS3 void CThread::Stop(int exitCode) +{ + if ( !IsAlive() ) + return; + + if ( GetCurrentCThread() == this ) + { +#if !defined( _PS3 ) + m_result = exitCode; + if ( !( m_flags & SUPPORT_STOP_PROTOCOL ) ) + { + OnExit(); + g_pCurThread = NULL; + +#ifdef _WIN32 + CloseHandle( m_hThread ); + RemoveThreadHandleToIDMap( m_hThread ); + m_hThread = NULL; +#else + m_threadId = 0; + m_threadZombieId = 0; +#endif + } + else + { + throw exitCode; + } +#else + AssertMsg( false, "Called CThread::Stop() for a platform that doesn't have it!\n"); +#endif + } + else + AssertMsg( 0, "Only thread can stop self: Use a higher-level protocol"); +} + +//--------------------------------------------------------- + +// Get the priority +INLINE_ON_PS3 int CThread::GetPriority() const +{ +#ifdef _WIN32 + return GetThreadPriority(m_hThread); +#elif defined( _PS3 ) + return ThreadGetPriority( (ThreadHandle_t) m_threadId ); +#elif defined(POSIX) + struct sched_param thread_param; + int policy; + pthread_getschedparam( m_threadId, &policy, &thread_param ); + return thread_param.sched_priority; +#endif +} + +//--------------------------------------------------------- + +// Set the priority +INLINE_ON_PS3 bool CThread::SetPriority(int priority) +{ +#ifdef WIN32 + return ThreadSetPriority( (ThreadHandle_t)m_hThread, priority ); +#else + return ThreadSetPriority( (ThreadHandle_t)m_threadId, priority ); +#endif +} + +//--------------------------------------------------------- + +// Suspend a thread +INLINE_ON_PS3 unsigned CThread::Suspend() +{ + AssertMsg( ThreadGetCurrentId() == (ThreadId_t)m_threadId, "Cannot call CThread::Suspend from outside thread" ); + + if ( ThreadGetCurrentId() != (ThreadId_t)m_threadId ) + { + DebuggerBreakIfDebugging(); + } + + m_NotSuspendedEvent.Reset(); + m_NotSuspendedEvent.Wait(); + + return 0; +} + + +//--------------------------------------------------------- + +INLINE_ON_PS3 unsigned CThread::Resume() +{ + if ( m_NotSuspendedEvent.Check() ) + { + DevWarning( "Called Resume() on a thread that is not suspended!\n" ); + } + m_NotSuspendedEvent.Set(); + return 0; +} + +//--------------------------------------------------------- + +// Force hard-termination of thread. Used for critical failures. +INLINE_ON_PS3 bool CThread::Terminate(int exitCode) +{ +#if defined( _X360 ) + AssertMsg( 0, "Cannot terminate a thread on the Xbox!" ); + return false; +#elif defined( _WIN32 ) + // I hope you know what you're doing! + if (!TerminateThread(m_hThread, exitCode)) + return false; + CloseHandle( m_hThread ); + RemoveThreadHandleToIDMap( m_hThread ); + m_hThread = NULL; +#elif defined( _PS3 ) + m_threadEnd.Set(); + m_threadId = NULL; +#elif defined(POSIX) + pthread_kill( m_threadId, SIGKILL ); + m_threadId = 0; +#endif + return true; +} + +//----------------------------------------------------- +// Global methods +//----------------------------------------------------- + +// Get the Thread object that represents the current thread, if any. +// Can return NULL if the current thread was not created using +// CThread +// + +INLINE_ON_PS3 CThread *CThread::GetCurrentCThread() +{ +#ifdef _PS3 + return GetCurThreadPS3(); +#else + return g_pCurThread; +#endif +} + +//--------------------------------------------------------- +// +// Offer a context switch. Under Win32, equivalent to Sleep(0) +// + +#ifdef Yield +#undef Yield +#endif +INLINE_ON_PS3 void CThread::Yield() +{ +#ifdef _WIN32 + ::Sleep(0); +#elif defined( _PS3 ) + // sys_ppu_thread_yield doesn't seem to function properly, so sleep instead. + sys_timer_usleep( 60 ); +#elif defined(POSIX) + sched_yield(); +#endif +} + +//--------------------------------------------------------- +// +// This method causes the current thread to yield and not to be +// scheduled for further execution until a certain amount of real +// time has elapsed, more or less. Duration is in milliseconds + +INLINE_ON_PS3 void CThread::Sleep( unsigned duration ) +{ +#ifdef _WIN32 + ::Sleep(duration); +#elif defined (_PS3) + sys_timer_usleep( duration * 1000 ); +#elif defined(POSIX) + usleep( duration * 1000 ); +#endif +} + +//--------------------------------------------------------- + +// Optional pre-run call, with ability to fail-create. Note Init() +// is forced synchronous with Start() +INLINE_ON_PS3 bool CThread::Init() +{ + return true; +} + +//--------------------------------------------------------- + +#if defined( _PS3 ) +INLINE_ON_PS3 int CThread::Run() +{ + return -1; +} +#endif // _PS3 + +// Called when the thread exits +INLINE_ON_PS3 void CThread::OnExit() { } + +// Allow for custom start waiting +INLINE_ON_PS3 bool CThread::WaitForCreateComplete( CThreadEvent *pEvent ) +{ + // Force serialized thread creation... + if (!pEvent->Wait(60000)) + { + AssertMsg( 0, "Probably deadlock or failure waiting for thread to initialize." ); + return false; + } + return true; +} + +INLINE_ON_PS3 bool CThread::IsThreadRunning() +{ +#ifdef _PS3 + // ThreadIsThreadIdRunning() doesn't work on PS3 if the thread is in a zombie state + return m_eventTheadExit.Check(); +#else + return ThreadIsThreadIdRunning( (ThreadId_t)m_threadId ); +#endif +} + +//--------------------------------------------------------- +INLINE_ON_PS3 CThread::ThreadProc_t CThread::GetThreadProc() +{ + return ThreadProc; +} + +INLINE_ON_PS3 void CThread::ThreadProcRunWithMinidumpHandler( void *pv ) +{ + ThreadInit_t *pInit = reinterpret_cast(pv); + pInit->pThread->m_result = pInit->pThread->Run(); +} + +#ifdef PLATFORM_WINDOWS +unsigned long STDCALL CThread::ThreadProc(LPVOID pv) +#else +INLINE_ON_PS3 void* CThread::ThreadProc(LPVOID pv) +#endif +{ +#if defined( POSIX ) || defined( _PS3 ) + ThreadInit_t *pInit = reinterpret_cast(pv); +#else + std::auto_ptr pInit((ThreadInit_t *)pv); +#endif + +#ifdef _X360 + // Make sure all threads are consistent w.r.t floating-point math + SetupFPUControlWord(); +#endif + AllocateThreadID(); + + CThread *pThread = pInit->pThread; +#ifdef _PS3 + SetCurThreadPS3( pThread ); +#else + g_pCurThread = pThread; +#endif + + pThread->m_pStackBase = AlignValue( &pThread, 4096 ); + + pInit->pThread->m_result = -1; + +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + CStackTop_ReferenceParentStack stackTop( pInit->ParentStackTrace, ARRAYSIZE( pInit->ParentStackTrace ) ); +#endif + + bool bInitSuccess = true; + if ( pInit->pfInitSuccess ) + *(pInit->pfInitSuccess) = false; + +#ifdef _PS3 + *(pInit->pfInitSuccess) = pInit->pThread->Init(); +#else + try + { + bInitSuccess = pInit->pThread->Init(); + } + + catch (...) + { + pInit->pInitCompleteEvent->Set(); + throw; + } +#endif // _PS3 + + if ( pInit->pfInitSuccess ) + *(pInit->pfInitSuccess) = bInitSuccess; + pInit->pInitCompleteEvent->Set(); + if (!bInitSuccess) + return 0; + + if ( !Plat_IsInDebugSession() && (pInit->pThread->m_flags & SUPPORT_STOP_PROTOCOL) ) + { +#ifndef _PS3 + try +#endif + { + pInit->pThread->m_result = pInit->pThread->Run(); + } + +#ifndef _PS3 + catch (...) + { + } +#endif + } + else + { +#if defined( _WIN32 ) + CatchAndWriteMiniDumpForVoidPtrFn( ThreadProcRunWithMinidumpHandler, pv, false ); +#else + pInit->pThread->m_result = pInit->pThread->Run(); +#endif + } + + pInit->pThread->OnExit(); +#ifdef _PS3 + SetCurThreadPS3( NULL ); +#else + g_pCurThread = NULL; +#endif + FreeThreadID(); + + AUTO_LOCK( pThread->m_Lock ); +#ifdef _WIN32 + CloseHandle( pThread->m_hThread ); + RemoveThreadHandleToIDMap( pThread->m_hThread ); + pThread->m_hThread = NULL; +#elif defined( _PS3 ) + pThread->m_threadZombieId = pThread->m_threadId; + pThread->m_threadEnd.Set(); + pThread->m_threadId = 0; +#elif defined(POSIX) + pThread->m_threadZombieId = pThread->m_threadId; + pThread->m_threadId = 0; +#else +#error +#endif + + pThread->m_ExitEvent.Set(); +#ifdef _PS3 + { + pThread->m_Lock.Unlock(); + sys_ppu_thread_exit( pInit->pThread->m_result ); + // reacquire the lock in case thread exit didn't actually exit the thread, so that + // AUTO_LOCK won't double-unlock the lock (to keep it paired) + pThread->m_Lock.Lock(); + } +#endif + +#if defined( POSIX )|| defined( _PS3 ) + return (void*)(uintp)pInit->pThread->m_result; +#else + return pInit->pThread->m_result; +#endif +} + +#endif // THREADTOOLS_INL diff --git a/public/tier0/tslist.h b/public/tier0/tslist.h index ab530c59..09c03177 100644 --- a/public/tier0/tslist.h +++ b/public/tier0/tslist.h @@ -36,15 +36,38 @@ #if defined( PLATFORM_64BITS ) +#if defined (PLATFORM_WINDOWS) +//typedef __m128i int128; +//inline int128 int128_zero() { return _mm_setzero_si128(); } +#else // PLATFORM_WINDOWS +typedef __int128_t int128; +#define int128_zero() 0 +#endif// PLATFORM_WINDOWS + #define TSLIST_HEAD_ALIGNMENT 16 #define TSLIST_NODE_ALIGNMENT 16 + +#ifdef POSIX +inline bool ThreadInterlockedAssignIf128( int128 volatile * pDest, const int128 &value, const int128 &comparand ) +{ + // We do not want the original comparand modified by the swap + // so operate on a local copy. + int128 local_comparand = comparand; + return __sync_bool_compare_and_swap( pDest, local_comparand, value ); +} +#endif + inline bool ThreadInterlockedAssignIf64x128( volatile int128 *pDest, const int128 &value, const int128 &comperand ) - { return ThreadInterlockedAssignIf128( pDest, value, comperand ); } +{ + return ThreadInterlockedAssignIf128( pDest, value, comperand ); +} #else #define TSLIST_HEAD_ALIGNMENT 8 #define TSLIST_NODE_ALIGNMENT 8 inline bool ThreadInterlockedAssignIf64x128( volatile int64 *pDest, const int64 value, const int64 comperand ) - { return ThreadInterlockedAssignIf64( pDest, value, comperand ); } +{ + return ThreadInterlockedAssignIf64( pDest, value, comperand ); +} #endif #ifdef _MSC_VER @@ -99,13 +122,13 @@ union TSLIST_HEAD_ALIGN TSLHead_t // because Sequence can be pretty much random. We could operate on both of them separately, // but it could perhaps (?) lead to problems with store forwarding. I don't know 'cause I didn't // performance-test or design original code, I'm just making it work on PowerPC. - #ifdef VALVE_BIG_ENDIAN +#ifdef VALVE_BIG_ENDIAN int16 Sequence; int16 Depth; - #else +#else int16 Depth; int16 Sequence; - #endif +#endif #ifdef PLATFORM_64BITS int32 Padding; #endif @@ -132,33 +155,33 @@ class CTSListBase public: // override new/delete so we can guarantee 8-byte aligned allocs - static void * operator new( size_t size ) + static void * operator new(size_t size) { - CTSListBase *pNode = (CTSListBase *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); + CTSListBase *pNode = (CTSListBase *)MemAlloc_AllocAlignedFileLine( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); return pNode; } - static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) + static void * operator new(size_t size, int nBlockUse, const char *pFileName, int nLine) { - CTSListBase *pNode = (CTSListBase *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine ); + CTSListBase *pNode = (CTSListBase *)MemAlloc_AllocAlignedFileLine( size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine ); return pNode; } - static void operator delete( void *p) + static void operator delete(void *p) { MemAlloc_FreeAligned( p ); } - static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine ) + static void operator delete(void *p, int nBlockUse, const char *pFileName, int nLine) { MemAlloc_FreeAligned( p ); } private: // These ain't gonna work - static void * operator new[] ( size_t size ); - static void operator delete [] ( void *p); - + static void * operator new[]( size_t size ); + static void operator delete[]( void *p ); + public: CTSListBase() @@ -204,22 +227,22 @@ public: TSLHead_t oldHead; TSLHead_t newHead; - #if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) +#if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) __lwsync(); // write-release barrier - #endif +#endif #ifdef PLATFORM_64BITS newHead.value.Padding = 0; #endif - for (;;) + for ( ;; ) { oldHead.value64x128 = m_Head.value64x128; pNode->Next = oldHead.value.Next; newHead.value.Next = pNode; - + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence + 0x10001; - - + + if ( ThreadInterlockedAssignIf64x128( &m_Head.value64x128, newHead.value64x128, oldHead.value64x128 ) ) { break; @@ -231,7 +254,7 @@ public: #endif } - __attribute__((no_sanitize("address"))) TSLNodeBase_t *Pop() + TSLNodeBase_t *Pop() { #ifdef USE_NATIVE_SLIST #ifdef _X360 @@ -248,21 +271,21 @@ public: #ifdef PLATFORM_64BITS newHead.value.Padding = 0; #endif - for (;;) + for ( ;; ) { oldHead.value64x128 = m_Head.value64x128; if ( !oldHead.value.Next ) return NULL; newHead.value.Next = oldHead.value.Next->Next; - newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence - 1; + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence - 1; if ( ThreadInterlockedAssignIf64x128( &m_Head.value64x128, newHead.value64x128, oldHead.value64x128 ) ) { - #if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) - __lwsync(); // read-acquire barrier - #endif +#if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) + __lwsync(); // read-acquire barrier +#endif break; } ThreadPause(); @@ -301,7 +324,7 @@ public: // I didn't construct this code. In any case, leaving it as is on big-endian newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence & 0xffff0000; - } while( !ThreadInterlockedAssignIf64x128( &m_Head.value64x128, newHead.value64x128, oldHead.value64x128 ) ); + } while ( !ThreadInterlockedAssignIf64x128( &m_Head.value64x128, newHead.value64x128, oldHead.value64x128 ) ); return (TSLNodeBase_t *)oldHead.value.Next; #endif @@ -315,7 +338,7 @@ public: int Count() const { #ifdef USE_NATIVE_SLIST - return QueryDepthSList( const_cast( &m_Head ) ); + return QueryDepthSList( const_cast(&m_Head) ); #else return m_Head.value.Depth; #endif @@ -349,7 +372,7 @@ public: // similar to CTSSimpleList except that it allocates it's own pool objects // and frees them on destruct. Also it does not overlay the TSNodeBase_t memory // on T's memory -template< class T > +template< class T > class TSLIST_HEAD_ALIGN CTSPool : public CTSListBase { // packs the node and the item (T) into a single struct and pools those @@ -380,7 +403,7 @@ public: void PutObject( T *pInfo ) { char *pElem = (char *)pInfo; - pElem -= offsetof(simpleTSPoolStruct_t,elem); + pElem -= offsetof( simpleTSPoolStruct_t, elem ); simpleTSPoolStruct_t *pNode = (simpleTSPoolStruct_t *)pElem; CTSListBase::Push( pNode ); @@ -414,25 +437,25 @@ public: Node_t( const T &init ) : elem( init ) {} T elem; - // override new/delete so we can guarantee 8-byte aligned allocs - static void * operator new( size_t size ) - { - Node_t *pNode = (Node_t *)MemAlloc_AllocAligned( size, TSLIST_NODE_ALIGNMENT, __FILE__, __LINE__ ); - return pNode; - } - // override new/delete so we can guarantee 8-byte aligned allocs - static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) + static void * operator new(size_t size) { - Node_t *pNode = (Node_t *)MemAlloc_AllocAligned( size, TSLIST_NODE_ALIGNMENT, pFileName, nLine ); + Node_t *pNode = (Node_t *)MemAlloc_AllocAlignedFileLine( size, TSLIST_NODE_ALIGNMENT, __FILE__, __LINE__ ); return pNode; } - static void operator delete( void *p) - { + // override new/delete so we can guarantee 8-byte aligned allocs + static void * operator new(size_t size, int nBlockUse, const char *pFileName, int nLine) + { + Node_t *pNode = (Node_t *)MemAlloc_AllocAlignedFileLine( size, TSLIST_NODE_ALIGNMENT, pFileName, nLine ); + return pNode; + } + + static void operator delete(void *p) + { MemAlloc_FreeAligned( p ); - } - static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine ) + } + static void operator delete(void *p, int nBlockUse, const char *pFileName, int nLine) { MemAlloc_FreeAligned( p ); } @@ -476,7 +499,7 @@ public: Push( new Node_t( init ) ); } - bool PopItem( T *pResult) + bool PopItem( T *pResult ) { Node_t *pNode = Pop(); if ( !pNode ) @@ -564,7 +587,7 @@ public: Push( pNode ); } - bool PopItem( T *pResult) + bool PopItem( T *pResult ) { Node_t *pNode = Pop(); if ( !pNode ) @@ -608,37 +631,37 @@ class TSLIST_HEAD_ALIGN CTSQueue public: // override new/delete so we can guarantee 8-byte aligned allocs - static void * operator new( size_t size ) + static void * operator new(size_t size) { - CTSQueue *pNode = (CTSQueue *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); + CTSQueue *pNode = (CTSQueue *)MemAlloc_AllocAlignedFileLine( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); return pNode; } // override new/delete so we can guarantee 8-byte aligned allocs - static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) + static void * operator new(size_t size, int nBlockUse, const char *pFileName, int nLine) { - CTSQueue *pNode = (CTSQueue *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine ); + CTSQueue *pNode = (CTSQueue *)MemAlloc_AllocAlignedFileLine( size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine ); return pNode; } - static void operator delete( void *p) + static void operator delete(void *p) { MemAlloc_FreeAligned( p ); } - static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine ) + static void operator delete(void *p, int nBlockUse, const char *pFileName, int nLine) { MemAlloc_FreeAligned( p ); } private: // These ain't gonna work - static void * operator new[] ( size_t size ) throw() + static void * operator new[]( size_t size ) throw() { return NULL; } - static void operator delete [] ( void *p) + static void operator delete []( void *p ) { } @@ -647,24 +670,24 @@ public: struct TSLIST_NODE_ALIGN Node_t { // override new/delete so we can guarantee 8-byte aligned allocs - static void * operator new( size_t size ) + static void * operator new(size_t size) { - Node_t *pNode = (Node_t *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); + Node_t *pNode = (Node_t *)MemAlloc_AllocAlignedFileLine( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); return pNode; } - static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) + static void * operator new(size_t size, int nBlockUse, const char *pFileName, int nLine) { - Node_t *pNode = (Node_t *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine ); + Node_t *pNode = (Node_t *)MemAlloc_AllocAlignedFileLine( size, TSLIST_HEAD_ALIGNMENT, pFileName, nLine ); return pNode; } - static void operator delete( void *p) + static void operator delete(void *p) { MemAlloc_FreeAligned( p ); } - static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine ) + static void operator delete(void *p, int nBlockUse, const char *pFileName, int nLine) { MemAlloc_FreeAligned( p ); } @@ -679,13 +702,13 @@ public: union TSLIST_HEAD_ALIGN NodeLink_t { // override new/delete so we can guarantee 8-byte aligned allocs - static void * operator new( size_t size ) + static void * operator new(size_t size) { - NodeLink_t *pNode = (NodeLink_t *)MemAlloc_AllocAligned( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); + NodeLink_t *pNode = (NodeLink_t *)MemAlloc_AllocAlignedFileLine( size, TSLIST_HEAD_ALIGNMENT, __FILE__, __LINE__ ); return pNode; } - static void operator delete( void *p) + static void operator delete(void *p) { MemAlloc_FreeAligned( p ); } @@ -740,12 +763,12 @@ public: } Node_t *pNode; - while ( ( pNode = Pop() ) != NULL ) + while ( (pNode = Pop()) != NULL ) { delete pNode; } - while ( ( pNode = (Node_t *)m_FreeNodes.Pop() ) != NULL ) + while ( (pNode = (Node_t *)m_FreeNodes.Pop()) != NULL ) { delete pNode; } @@ -765,7 +788,7 @@ public: } Node_t *pNode; - while ( ( pNode = Pop() ) != NULL ) + while ( (pNode = Pop()) != NULL ) { m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); } @@ -846,7 +869,7 @@ public: pNode->pNext = End(); - for (;;) + for ( ;; ) { oldTail.value.sequence = m_Tail.value.sequence; oldTail.value.pNode = m_Tail.value.pNode; @@ -870,7 +893,7 @@ public: Node_t *Pop() { - #define TSQUEUE_BAD_NODE_LINK ( (Node_t *)INT_TO_POINTER( 0xdeadbeef ) ) +#define TSQUEUE_BAD_NODE_LINK ( (Node_t *)INT_TO_POINTER( 0xdeadbeef ) ) NodeLink_t * volatile pHead = &m_Head; NodeLink_t * volatile pTail = &m_Tail; Node_t * volatile * pHeadNode = &m_Head.value.pNode; @@ -883,17 +906,17 @@ public: intp tailSequence; T elem; - for (;;) + for ( ;; ) { head.value.sequence = *pHeadSequence; // must grab sequence first, which allows condition below to ensure pNext is valid ThreadMemoryBarrier(); // need a barrier to prevent reordering of these assignments - head.value.pNode = *pHeadNode; - tailSequence = pTail->value.sequence; - pNext = head.value.pNode->pNext; + head.value.pNode = *pHeadNode; + tailSequence = pTail->value.sequence; + pNext = head.value.pNode->pNext; // Checking pNext only to force optimizer to not reorder the assignment // to pNext and the compare of the sequence - if ( !pNext || head.value.sequence != *pHeadSequence ) + if ( !pNext || head.value.sequence != *pHeadSequence ) continue; if ( bTestOptimizer ) @@ -916,7 +939,7 @@ public: FinishPush( pNext, oldTail ); continue; } - + if ( pNext != End() ) { elem = pNext->elem; // NOTE: next could be a freed node here, by design @@ -991,7 +1014,7 @@ private: NodeLink_t m_Tail; CInterlockedInt m_Count; - + CTSListBase m_FreeNodes; } TSLIST_NODE_ALIGN_POST; diff --git a/public/tier1/stringpool.h b/public/tier1/stringpool.h index 6b1dfaef..903a1cb5 100644 --- a/public/tier1/stringpool.h +++ b/public/tier1/stringpool.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -14,21 +14,33 @@ #include "utlrbtree.h" #include "utlvector.h" +#include "utlbuffer.h" +#include "generichash.h" //----------------------------------------------------------------------------- // Purpose: Allocates memory for strings, checking for duplicates first, // reusing exising strings if duplicate found. //----------------------------------------------------------------------------- +enum StringPoolCase_t +{ + StringPoolCaseInsensitive, + StringPoolCaseSensitive +}; + class CStringPool { public: - CStringPool(); + CStringPool( StringPoolCase_t caseSensitivity = StringPoolCaseInsensitive ); ~CStringPool(); unsigned int Count() const; const char * Allocate( const char *pszValue ); + // This feature is deliberately not supported because it's pretty dangerous + // given current uses of CStringPool, which assume they can copy string pointers without + // any refcounts. + //void Free( const char *pszValue ); void FreeAll(); // searches for a string already in the pool @@ -48,14 +60,15 @@ protected: // // At some point this should replace CStringPool //----------------------------------------------------------------------------- -class CCountedStringPool +template +class CCountedStringPoolBase { public: // HACK, hash_item_t structure should not be public. struct hash_item_t { char* pString; - unsigned short nNextElement; + T nNextElement; unsigned char nReferenceCount; unsigned char pad; }; @@ -67,13 +80,14 @@ public: // HACK, hash_item_t structure should not be public. HASH_TABLE_SIZE = 1024 }; - CUtlVector m_HashTable; // Points to each element + CUtlVector m_HashTable; // Points to each element CUtlVector m_Elements; - unsigned short m_FreeListStart; + T m_FreeListStart; + StringPoolCase_t m_caseSensitivity; public: - CCountedStringPool(); - virtual ~CCountedStringPool(); + CCountedStringPoolBase( StringPoolCase_t caseSensitivity = StringPoolCaseInsensitive ); + virtual ~CCountedStringPoolBase(); void FreeAll(); @@ -82,10 +96,416 @@ public: void DereferenceString( const char* pIntrinsic ); // These are only reliable if there are less than 64k strings in your string pool - unsigned short FindStringHandle( const char* pIntrinsic ); - unsigned short ReferenceStringHandle( const char* pIntrinsic ); - char *HandleToString( unsigned short handle ); + T FindStringHandle( const char* pIntrinsic ); + T ReferenceStringHandle( const char* pIntrinsic ); + char *HandleToString( T handle ); void SpewStrings(); + unsigned Hash( const char *pszKey ); + + bool SaveToBuffer( CUtlBuffer &buffer ); + bool RestoreFromBuffer( CUtlBuffer &buffer ); + + // Debug helper method to validate that we didn't overflow + void VerifyNotOverflowed( unsigned int value ); }; +typedef CCountedStringPoolBase CCountedStringPool; + +template +inline CCountedStringPoolBase::CCountedStringPoolBase( StringPoolCase_t caseSensitivity ) +{ + MEM_ALLOC_CREDIT(); + m_HashTable.EnsureCount(HASH_TABLE_SIZE); + + for( int i = 0; i < m_HashTable.Count(); i++ ) + { + m_HashTable[i] = INVALID_ELEMENT; + } + + m_FreeListStart = INVALID_ELEMENT; + m_Elements.AddToTail(); + m_Elements[0].pString = NULL; + m_Elements[0].nReferenceCount = 0; + m_Elements[0].nNextElement = INVALID_ELEMENT; + + m_caseSensitivity = caseSensitivity; +} + +template +inline CCountedStringPoolBase::~CCountedStringPoolBase() +{ + FreeAll(); +} + +template +inline void CCountedStringPoolBase::FreeAll() +{ + int i; + + // Reset the hash table: + for( i = 0; i < m_HashTable.Count(); i++ ) + { + m_HashTable[i] = INVALID_ELEMENT; + } + + // Blow away the free list: + m_FreeListStart = INVALID_ELEMENT; + + for( i = 0; i < m_Elements.Count(); i++ ) + { + if( m_Elements[i].pString ) + { + delete [] m_Elements[i].pString; + m_Elements[i].pString = NULL; + m_Elements[i].nReferenceCount = 0; + m_Elements[i].nNextElement = INVALID_ELEMENT; + } + } + + // Remove all but the invalid element: + m_Elements.RemoveAll(); + m_Elements.AddToTail(); + m_Elements[0].pString = NULL; + m_Elements[0].nReferenceCount = 0; + m_Elements[0].nNextElement = INVALID_ELEMENT; +} + +template +inline unsigned CCountedStringPoolBase::Hash( const char *pszKey ) +{ + if ( m_caseSensitivity == StringPoolCaseInsensitive ) + { + return HashStringCaseless( pszKey ); + } + return HashString( pszKey ); +} + +template +inline T CCountedStringPoolBase::FindStringHandle( const char* pIntrinsic ) +{ + if( pIntrinsic == NULL ) + return INVALID_ELEMENT; + + T nHashBucketIndex = ( Hash( pIntrinsic ) %HASH_TABLE_SIZE); + T nCurrentBucket = m_HashTable[ nHashBucketIndex ]; + + // Does the bucket already exist? + if( nCurrentBucket != INVALID_ELEMENT ) + { + for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement ) + { + if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) ) + { + return nCurrentBucket; + } + } + } + + return 0; + +} + +template +inline char* CCountedStringPoolBase::FindString( const char* pIntrinsic ) +{ + if( pIntrinsic == NULL ) + return NULL; + + // Yes, this will be NULL on failure. + return m_Elements[FindStringHandle(pIntrinsic)].pString; +} + +template +inline T CCountedStringPoolBase::ReferenceStringHandle( const char* pIntrinsic ) +{ + if( pIntrinsic == NULL ) + return INVALID_ELEMENT; + + T nHashBucketIndex = ( Hash( pIntrinsic ) % HASH_TABLE_SIZE); + T nCurrentBucket = m_HashTable[ nHashBucketIndex ]; + + // Does the bucket already exist? + if( nCurrentBucket != INVALID_ELEMENT ) + { + for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement ) + { + if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) ) + { + // Anyone who hits 65k references is permanant + if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE ) + { + m_Elements[nCurrentBucket].nReferenceCount ++ ; + } + return nCurrentBucket; + } + } + } + + if( m_FreeListStart != INVALID_ELEMENT ) + { + nCurrentBucket = m_FreeListStart; + m_FreeListStart = m_Elements[nCurrentBucket].nNextElement; + } + else + { + unsigned int newElement = m_Elements.AddToTail(); + VerifyNotOverflowed( newElement ); + nCurrentBucket = newElement; + } + + m_Elements[nCurrentBucket].nReferenceCount = 1; + + // Insert at the beginning of the bucket: + m_Elements[nCurrentBucket].nNextElement = m_HashTable[ nHashBucketIndex ]; + m_HashTable[ nHashBucketIndex ] = nCurrentBucket; + + m_Elements[nCurrentBucket].pString = new char[Q_strlen( pIntrinsic ) + 1]; + Q_strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic ); + + return nCurrentBucket; +} + +template<> +inline void CCountedStringPoolBase::VerifyNotOverflowed( unsigned int value ) { Assert( value < 0xffff ); } + +template<> +inline void CCountedStringPoolBase::VerifyNotOverflowed( unsigned int value ) {} + +template +inline char* CCountedStringPoolBase::ReferenceString( const char* pIntrinsic ) +{ + if(!pIntrinsic) + return NULL; + + return m_Elements[ReferenceStringHandle( pIntrinsic)].pString; +} + +template +inline void CCountedStringPoolBase::DereferenceString( const char* pIntrinsic ) +{ + // If we get a NULL pointer, just return + if (!pIntrinsic) + return; + + T nHashBucketIndex = (Hash( pIntrinsic ) % m_HashTable.Count()); + T nCurrentBucket = m_HashTable[ nHashBucketIndex ]; + + // If there isn't anything in the bucket, just return. + if ( nCurrentBucket == INVALID_ELEMENT ) + return; + + for( T previous = INVALID_ELEMENT; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement ) + { + if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) ) + { + // Anyone who hits 65k references is permanant + if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE ) + { + m_Elements[nCurrentBucket].nReferenceCount --; + } + + if( m_Elements[nCurrentBucket].nReferenceCount == 0 ) + { + if( previous == INVALID_ELEMENT ) + { + m_HashTable[nHashBucketIndex] = m_Elements[nCurrentBucket].nNextElement; + } + else + { + m_Elements[previous].nNextElement = m_Elements[nCurrentBucket].nNextElement; + } + + delete [] m_Elements[nCurrentBucket].pString; + m_Elements[nCurrentBucket].pString = NULL; + m_Elements[nCurrentBucket].nReferenceCount = 0; + + m_Elements[nCurrentBucket].nNextElement = m_FreeListStart; + m_FreeListStart = nCurrentBucket; + break; + + } + } + + previous = nCurrentBucket; + } +} + +template +inline char* CCountedStringPoolBase::HandleToString( T handle ) +{ + return m_Elements[handle].pString; +} + +template +inline void CCountedStringPoolBase::SpewStrings() +{ + int i; + for ( i = 0; i < m_Elements.Count(); i++ ) + { + char* string = m_Elements[i].pString; + + Msg("String %d: ref:%d %s\n", i, m_Elements[i].nReferenceCount, string == NULL? "EMPTY - ok for slot zero only!" : string); + } + + Msg("\n%d total counted strings.", m_Elements.Count()); +} + +#define STRING_POOL_VERSION MAKEID( 'C', 'S', 'P', '1' ) +#define MAX_STRING_SAVE 1024 + +template<> +inline bool CCountedStringPoolBase::SaveToBuffer( CUtlBuffer &buffer ) +{ + if ( m_Elements.Count() <= 1 ) + { + // pool is empty, saving nothing + // caller can check put position of buffer to detect + return true; + } + + // signature/version + buffer.PutInt( STRING_POOL_VERSION ); + + buffer.PutUnsignedShort( m_FreeListStart ); + + buffer.PutInt( m_HashTable.Count() ); + for ( int i = 0; i < m_HashTable.Count(); i++ ) + { + buffer.PutUnsignedShort( m_HashTable[i] ); + } + + buffer.PutInt( m_Elements.Count() ); + for ( int i = 1; i < m_Elements.Count(); i++ ) + { + buffer.PutUnsignedShort( m_Elements[i].nNextElement ); + buffer.PutUnsignedChar( m_Elements[i].nReferenceCount ); + + const char *pString = m_Elements[i].pString; + if ( strlen( pString ) >= MAX_STRING_SAVE ) + { + return false; + } + buffer.PutString( pString ? pString : "" ); + } + + return buffer.IsValid(); +} + +template<> +inline bool CCountedStringPoolBase::RestoreFromBuffer( CUtlBuffer &buffer ) +{ + int signature = buffer.GetInt(); + if ( signature != STRING_POOL_VERSION ) + { + // wrong version + return false; + } + + FreeAll(); + + m_FreeListStart = buffer.GetUnsignedShort(); + + int hashCount = buffer.GetInt(); + m_HashTable.SetCount( hashCount ); + + for ( int i = 0; i < hashCount; i++ ) + { + m_HashTable[i] = buffer.GetUnsignedShort(); + } + + int tableCount = buffer.GetInt(); + if ( tableCount > 1 ) + { + m_Elements.AddMultipleToTail( tableCount-1 ); + } + + char tempString[MAX_STRING_SAVE]; + for ( int i = 1; i < tableCount; i++ ) + { + m_Elements[i].nNextElement = buffer.GetUnsignedShort(); + m_Elements[i].nReferenceCount = buffer.GetUnsignedChar(); + buffer.GetString( tempString, sizeof( tempString ) ); + m_Elements[i].pString = strdup( tempString ); + } + + return buffer.IsValid(); +} + +template<> +inline bool CCountedStringPoolBase::SaveToBuffer( CUtlBuffer &buffer ) +{ + if ( m_Elements.Count() <= 1 ) + { + // pool is empty, saving nothing + // caller can check put position of buffer to detect + return true; + } + + // signature/version + buffer.PutInt( STRING_POOL_VERSION ); + + buffer.PutUnsignedInt( m_FreeListStart ); + + buffer.PutInt( m_HashTable.Count() ); + for ( int i = 0; i < m_HashTable.Count(); i++ ) + { + buffer.PutUnsignedInt( m_HashTable[i] ); + } + + buffer.PutInt( m_Elements.Count() ); + for ( int i = 1; i < m_Elements.Count(); i++ ) + { + buffer.PutUnsignedInt( m_Elements[i].nNextElement ); + buffer.PutUnsignedChar( m_Elements[i].nReferenceCount ); + + const char *pString = m_Elements[i].pString; + if ( strlen( pString ) >= MAX_STRING_SAVE ) + { + return false; + } + buffer.PutString( pString ? pString : "" ); + } + + return buffer.IsValid(); +} + +template<> +inline bool CCountedStringPoolBase::RestoreFromBuffer( CUtlBuffer &buffer ) +{ + int signature = buffer.GetInt(); + if ( signature != STRING_POOL_VERSION ) + { + // wrong version + return false; + } + + FreeAll(); + + m_FreeListStart = buffer.GetUnsignedInt(); + + int hashCount = buffer.GetInt(); + m_HashTable.SetCount( hashCount ); + + for ( int i = 0; i < hashCount; i++ ) + { + m_HashTable[i] = buffer.GetUnsignedInt(); + } + + int tableCount = buffer.GetInt(); + if ( tableCount > 1 ) + { + m_Elements.AddMultipleToTail( tableCount-1 ); + } + + char tempString[MAX_STRING_SAVE]; + for ( int i = 1; i < tableCount; i++ ) + { + m_Elements[i].nNextElement = buffer.GetUnsignedInt(); + m_Elements[i].nReferenceCount = buffer.GetUnsignedChar(); + buffer.GetString( tempString, sizeof( tempString ) ); + m_Elements[i].pString = strdup( tempString ); + } + + return buffer.IsValid(); +} #endif // STRINGPOOL_H diff --git a/public/tier1/utlbuffer.h b/public/tier1/utlbuffer.h index ec1b1188..59909410 100644 --- a/public/tier1/utlbuffer.h +++ b/public/tier1/utlbuffer.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. =======// // // Purpose: // @@ -14,6 +14,8 @@ #pragma once #endif +#include "unitlib/unitlib.h" // just here for tests - remove before checking in!!! + #include "tier1/utlmemory.h" #include "tier1/byteswap.h" #include @@ -102,11 +104,48 @@ CUtlCharConversion *GetNoEscCharConversion(); SetOverflowFuncs( static_cast ( _get ), static_cast ( _put ) ) + +typedef unsigned short ushort; + +template < class A > +static const char *GetFmtStr( int nRadix = 10, bool bPrint = true ) { Assert( 0 ); return ""; } +#if defined( LINUX ) || defined( __clang__ ) || ( defined( _MSC_VER ) && _MSC_VER >= 1900 ) +template <> const char *GetFmtStr< short > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hd"; } +template <> const char *GetFmtStr< ushort > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hu"; } +template <> const char *GetFmtStr< int > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%d"; } +template <> const char *GetFmtStr< uint > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 || nRadix == 16 ); return nRadix == 16 ? "%x" : "%u"; } +template <> const char *GetFmtStr< int64 > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%lld"; } +template <> const char *GetFmtStr< float > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%f"; } +template <> const char *GetFmtStr< double > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return bPrint ? "%.15lf" : "%lf"; } // force Printf to print DBL_DIG=15 digits of precision for doubles - defaults to FLT_DIG=6 +#else +template <> static const char *GetFmtStr< short > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hd"; } +template <> static const char *GetFmtStr< ushort > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hu"; } +template <> static const char *GetFmtStr< int > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%d"; } +template <> static const char *GetFmtStr< uint > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 || nRadix == 16 ); return nRadix == 16 ? "%x" : "%u"; } +template <> static const char *GetFmtStr< int64 > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%lld"; } +template <> static const char *GetFmtStr< float > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%f"; } +template <> static const char *GetFmtStr< double > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return bPrint ? "%.15lf" : "%lf"; } // force Printf to print DBL_DIG=15 digits of precision for doubles - defaults to FLT_DIG=6 +#endif //----------------------------------------------------------------------------- // Command parsing.. //----------------------------------------------------------------------------- class CUtlBuffer { +// Brian has on his todo list to revisit this as there are issues in some cases with CUtlVector using operator = instead of copy construtor in InsertMultiple, etc. +// The unsafe case is something like this: +// CUtlVector< CUtlBuffer > vecFoo; +// +// CUtlBuffer buf; +// buf.Put( xxx ); +// vecFoo.Insert( buf ); +// +// This will cause memory corruption when vecFoo is cleared +// +//private: +// // Disallow copying +// CUtlBuffer( const CUtlBuffer & );// { Assert( 0 ); } +// CUtlBuffer &operator=( const CUtlBuffer & );// { Assert( 0 ); return *this; } + public: enum SeekType_t { @@ -132,7 +171,19 @@ public: CUtlBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 ); CUtlBuffer( const void* pBuffer, int size, int nFlags = 0 ); // This one isn't actually defined so that we catch contructors that are trying to pass a bool in as the third param. - CUtlBuffer( const void *pBuffer, int size, bool crap ); + CUtlBuffer( const void *pBuffer, int size, bool crap ) = delete; + + // UtlBuffer objects should not be copyable; we do a slow copy if you use this but it asserts. + // (REI: I'd like to delete these but we have some python bindings that currently rely on being able to copy these objects) + CUtlBuffer( const CUtlBuffer& ); // = delete; + CUtlBuffer& operator= ( const CUtlBuffer& ); // = delete; + +#if VALVE_CPP11 + // UtlBuffer is non-copyable (same as CUtlMemory), but it is moveable. We would like to declare these with '= default' + // but unfortunately VS2013 isn't fully C++11 compliant, so we have to manually declare these in the boilerplate way. + CUtlBuffer( CUtlBuffer&& moveFrom ); // = default; + CUtlBuffer& operator= ( CUtlBuffer&& moveFrom ); // = default; +#endif unsigned char GetFlags() const; @@ -143,11 +194,15 @@ public: // Makes sure we've got at least this much memory void EnsureCapacity( int num ); + // Access for direct read into buffer + void * AccessForDirectRead( int nBytes ); + // Attaches the buffer to external memory.... void SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags = 0 ); bool IsExternallyAllocated() const; - // Takes ownership of the passed memory, including freeing it when this buffer is destroyed. void AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags = 0 ); + void *Detach(); + void* DetachMemory(); // copies data from another buffer void CopyBuffer( const CUtlBuffer &buffer ); @@ -156,9 +211,10 @@ public: void Swap( CUtlBuffer &buf ); void Swap( CUtlMemory &mem ); + FORCEINLINE void ActivateByteSwappingIfBigEndian( void ) { - if ( IsX360() ) + if ( ( IsX360() || IsPS3() ) ) ActivateByteSwapping( true ); } @@ -174,6 +230,9 @@ public: // Clears out the buffer; frees memory void Purge(); + // Dump the buffer to stdout + void Spew( ); + // Read stuff out. // Binary mode: it'll just read the bits directly in, and characters will be // read for strings until a null character is reached. @@ -185,28 +244,25 @@ public: unsigned short GetUnsignedShort( ); int GetInt( ); int64 GetInt64( ); - int GetIntHex( ); + unsigned int GetIntHex( ); unsigned int GetUnsignedInt( ); + uint64 GetUnsignedInt64( ); float GetFloat( ); double GetDouble( ); - void * GetPtr(); - template void GetString( char( &pString )[maxLenInChars] ) - { - GetStringInternal( pString, maxLenInChars ); - } - - void GetString( char *pString, size_t maxLenInChars ) - { - GetStringInternal( pString, maxLenInChars ); - } + void * GetPtr(); + void GetString( char* pString, int nMaxChars ); + bool Get( void* pMem, int size ); + void GetLine( char* pLine, int nMaxChars ); void GetStringManualCharCount( char *pString, size_t maxLenInChars ) { - GetStringInternal( pString, maxLenInChars ); + GetString( pString, maxLenInChars ); } - void Get( void* pMem, int size ); - void GetLine( char* pLine, int nMaxChars = 0 ); + template void GetString( char( &pString )[maxLenInChars] ) + { + GetString( pString, maxLenInChars ); + } // Used for getting objects that have a byteswap datadesc defined template void GetObjects( T *dest, int count = 1 ); @@ -238,7 +294,7 @@ public: // Just like scanf, but doesn't work in binary mode int Scanf( SCANF_FORMAT_STRING const char* pFmt, ... ); - int VaScanf( const char* pFmt, va_list list ); + int VaScanf( const char* pFmt, va_list list ); // Eats white space, advances Get index void EatWhiteSpace(); @@ -270,16 +326,16 @@ public: // PutString will not write a terminating character void PutChar( char c ); void PutUnsignedChar( unsigned char uc ); - void PutUint64( uint64 ub ); - void PutInt16( int16 s16 ); void PutShort( short s ); void PutUnsignedShort( unsigned short us ); void PutInt( int i ); void PutInt64( int64 i ); void PutUnsignedInt( unsigned int u ); + void PutUnsignedInt64( uint64 u ); + void PutUint64( uint64 u ); void PutFloat( float f ); void PutDouble( double d ); - void PutPtr( void * ); // Writes the pointer, not the pointed to + void PutPtr( void * ); // Writes the pointer, not the pointed to void PutString( const char* pString ); void Put( const void* pMem, int size ); @@ -318,8 +374,8 @@ public: // Buffer base const void* Base() const; void* Base(); - // Returns the base as a const char*, only valid in text mode. - const char *String() const; + + const void* String() const; // memory allocation size, does *not* reflect size written or read, // use TellPut or TellGet for that @@ -352,6 +408,12 @@ public: // Temporarily disables pretty print void EnableTabs( bool bEnable ); +#if !defined( _GAMECONSOLE ) + // Swap my internal memory with another buffer, + // and copy all of its other members + void SwapCopy( CUtlBuffer &other ) ; +#endif + protected: // error flags enum @@ -371,7 +433,10 @@ protected: bool CheckPut( int size ); bool CheckGet( int size ); + // NOTE: Pass in nPut here even though it is just a copy of m_Put. This is almost always called immediately + // after modifying m_Put and this lets it stay in a register void AddNullTermination( ); + void AddNullTermination( int nPut ); // Methods to help with pretty-printing bool WasLastCharacterCR(); @@ -400,16 +465,18 @@ protected: // Call this to peek arbitrarily long into memory. It doesn't fail unless // it can't read *anything* new bool CheckArbitraryPeekGet( int nOffset, int &nIncrement ); - void GetStringInternal( char *pString, size_t maxLenInChars ); - template void GetType( T& dest, const char *pszFmt ); + template void GetType( T& dest ); template void GetTypeBin( T& dest ); + template bool GetTypeText( T &value, int nRadix = 10 ); template void GetObject( T *src ); - template void PutType( T src, const char *pszFmt ); + template void PutType( T src ); template void PutTypeBin( T src ); template void PutObject( T *src ); + // be sure to also update the copy constructor + // and SwapCopy() when adding members. CUtlMemory m_Memory; int m_Get; int m_Put; @@ -417,7 +484,7 @@ protected: unsigned char m_Error; unsigned char m_Flags; unsigned char m_Reserved; -#if defined( _X360 ) +#if defined( _GAMECONSOLE ) unsigned char pad; #endif @@ -605,7 +672,7 @@ inline void CUtlBuffer::GetObject( T *dest ) { if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) { - Q_memcpy( dest, PeekGet(), sizeof( T ) ); + *dest = *(T *)PeekGet(); } else { @@ -615,7 +682,7 @@ inline void CUtlBuffer::GetObject( T *dest ) } else { - Q_memset( dest, 0, sizeof(T) ); + Q_memset( &dest, 0, sizeof(T) ); } } @@ -637,18 +704,18 @@ inline void CUtlBuffer::GetTypeBin( T &dest ) { if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) { - Q_memcpy(&dest, PeekGet(), sizeof(T) ); + dest = *(T *)PeekGet(); } else { m_Byteswap.SwapBufferToTargetEndian( &dest, (T*)PeekGet() ); } - m_Get += sizeof(T); - } + m_Get += sizeof(T); + } else { dest = 0; - } + } } template <> @@ -656,8 +723,8 @@ inline void CUtlBuffer::GetTypeBin< float >( float &dest ) { if ( CheckGet( sizeof( float ) ) ) { - uintptr_t pData = (uintptr_t)PeekGet(); - if ( IsX360() && ( pData & 0x03 ) ) + uintp pData = (uintp)PeekGet(); + if ( ( IsX360() || IsPS3() ) && ( pData & 0x03 ) ) { // handle unaligned read ((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0]; @@ -668,22 +735,148 @@ inline void CUtlBuffer::GetTypeBin< float >( float &dest ) else { // aligned read - Q_memcpy( &dest, (void*)pData, sizeof(float) ); + dest = *(float *)pData; } if ( m_Byteswap.IsSwappingBytes() ) { m_Byteswap.SwapBufferToTargetEndian< float >( &dest, &dest ); } - m_Get += sizeof( float ); - } + m_Get += sizeof( float ); + } else { dest = 0; + } +} + +template <> +inline void CUtlBuffer::GetTypeBin< double >( double &dest ) +{ + if ( CheckGet( sizeof( double ) ) ) + { + uintp pData = (uintp)PeekGet(); + if ( ( IsX360() || IsPS3() ) && ( pData & 0x07 ) ) + { + // handle unaligned read + ((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0]; + ((unsigned char*)&dest)[1] = ((unsigned char*)pData)[1]; + ((unsigned char*)&dest)[2] = ((unsigned char*)pData)[2]; + ((unsigned char*)&dest)[3] = ((unsigned char*)pData)[3]; + ((unsigned char*)&dest)[4] = ((unsigned char*)pData)[4]; + ((unsigned char*)&dest)[5] = ((unsigned char*)pData)[5]; + ((unsigned char*)&dest)[6] = ((unsigned char*)pData)[6]; + ((unsigned char*)&dest)[7] = ((unsigned char*)pData)[7]; + } + else + { + // aligned read + dest = *(double *)pData; + } + if ( m_Byteswap.IsSwappingBytes() ) + { + m_Byteswap.SwapBufferToTargetEndian< double >( &dest, &dest ); + } + m_Get += sizeof( double ); + } + else + { + dest = 0; + } +} + +template < class T > +inline T StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + Assert( 0 ); + *ppEnd = pString; + return 0; +} + +template <> +inline int8 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( int8 )strtol( pString, ppEnd, nRadix ); +} + +template <> +inline uint8 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( uint8 )strtoul( pString, ppEnd, nRadix ); +} + +template <> +inline int16 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( int16 )strtol( pString, ppEnd, nRadix ); +} + +template <> +inline uint16 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( uint16 )strtoul( pString, ppEnd, nRadix ); +} + +template <> +inline int32 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( int32 )strtol( pString, ppEnd, nRadix ); +} + +template <> +inline uint32 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( uint32 )strtoul( pString, ppEnd, nRadix ); +} + +template <> +inline int64 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ +#if defined(_PS3) || defined(POSIX) + return ( int64 )strtoll( pString, ppEnd, nRadix ); +#else // !_PS3 + return ( int64 )_strtoi64( pString, ppEnd, nRadix ); +#endif // _PS3 +} + +template <> +inline float StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + NOTE_UNUSED( nRadix ); + return ( float )strtod( pString, ppEnd ); +} + +template <> +inline double StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + NOTE_UNUSED( nRadix ); + return ( double )strtod( pString, ppEnd ); +} + +template +inline bool CUtlBuffer::GetTypeText( T &value, int nRadix /*= 10*/ ) +{ + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + int nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + value = 0; + return false; } + + char *pStart = (char*)PeekGet(); + char* pEnd = pStart; + value = StringToNumber< T >( pStart, &pEnd, nRadix ); + + int nBytesRead = (int)( pEnd - pStart ); + if ( nBytesRead == 0 ) + return false; + + m_Get += nBytesRead; + return true; } template -inline void CUtlBuffer::GetType( T &dest, const char *pszFmt ) +inline void CUtlBuffer::GetType( T &dest ) { if (!IsText()) { @@ -691,93 +884,115 @@ inline void CUtlBuffer::GetType( T &dest, const char *pszFmt ) } else { - dest = 0; - Scanf( pszFmt, &dest ); + GetTypeText( dest ); } } inline char CUtlBuffer::GetChar( ) { + // LEGACY WARNING: this behaves differently than GetUnsignedChar() char c; - GetType( c, "%c" ); + GetTypeBin( c ); // always reads as binary return c; } inline unsigned char CUtlBuffer::GetUnsignedChar( ) { + // LEGACY WARNING: this behaves differently than GetChar() unsigned char c; - GetType( c, "%u" ); + if (!IsText()) + { + GetTypeBin( c ); + } + else + { + c = ( unsigned char )GetUnsignedShort(); + } return c; } inline short CUtlBuffer::GetShort( ) { short s; - GetType( s, "%d" ); + GetType( s ); return s; } inline unsigned short CUtlBuffer::GetUnsignedShort( ) { unsigned short s; - GetType( s, "%u" ); + GetType( s ); return s; } inline int CUtlBuffer::GetInt( ) { int i; - GetType( i, "%d" ); + GetType( i ); return i; } inline int64 CUtlBuffer::GetInt64( ) { int64 i; - GetType( i, "%lld" ); + GetType( i ); return i; } -inline int CUtlBuffer::GetIntHex( ) +inline unsigned int CUtlBuffer::GetIntHex( ) { - int i; - GetType( i, "%x" ); + uint i; + if (!IsText()) + { + GetTypeBin( i ); + } + else + { + GetTypeText( i, 16 ); + } return i; } inline unsigned int CUtlBuffer::GetUnsignedInt( ) { - unsigned int u; - GetType( u, "%u" ); - return u; + unsigned int i; + GetType( i ); + return i; } +inline uint64 CUtlBuffer::GetUnsignedInt64() +{ + uint64 i; + GetType( i ); + return i; +} + + inline float CUtlBuffer::GetFloat( ) { float f; - GetType( f, "%f" ); + GetType( f ); return f; } -inline void *CUtlBuffer::GetPtr( ) -{ - void *p; - // LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal -#ifndef PLATFORM_64BITS - p = ( void* )GetUnsignedInt(); -#else - p = ( void* )GetInt64(); -#endif - return p; -} - inline double CUtlBuffer::GetDouble( ) { double d; - GetType( d, "%f" ); + GetType( d ); return d; } +inline void *CUtlBuffer::GetPtr( ) +{ + void *p; + // LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal +#if !defined(X64BITS) && !defined(PLATFORM_64BITS) + p = ( void* )GetUnsignedInt(); +#else + p = ( void* )GetInt64(); +#endif + return p; +} //----------------------------------------------------------------------------- // Where am I writing? @@ -835,14 +1050,14 @@ inline void CUtlBuffer::PutObject( T *src ) { if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) { - Q_memcpy( PeekPut(), src, sizeof( T ) ); + *(T *)PeekPut() = *src; } else { m_Byteswap.SwapFieldsToTargetEndian( (T*)PeekPut(), src ); } m_Put += sizeof(T); - AddNullTermination(); + AddNullTermination( m_Put ); } } @@ -864,19 +1079,93 @@ inline void CUtlBuffer::PutTypeBin( T src ) { if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) { - Q_memcpy( PeekPut(), &src, sizeof( T ) ); + *(T *)PeekPut() = src; } else { m_Byteswap.SwapBufferToTargetEndian( (T*)PeekPut(), &src ); } m_Put += sizeof(T); - AddNullTermination(); + AddNullTermination( m_Put ); } } +#if defined( _GAMECONSOLE ) +template <> +inline void CUtlBuffer::PutTypeBin< float >( float src ) +{ + if ( CheckPut( sizeof( src ) ) ) + { + if ( m_Byteswap.IsSwappingBytes() ) + { + m_Byteswap.SwapBufferToTargetEndian( &src, &src ); + } + + // + // Write the data + // + unsigned pData = (unsigned)PeekPut(); + if ( pData & 0x03 ) + { + // handle unaligned write + byte* dst = (byte*)pData; + byte* srcPtr = (byte*)&src; + dst[0] = srcPtr[0]; + dst[1] = srcPtr[1]; + dst[2] = srcPtr[2]; + dst[3] = srcPtr[3]; + } + else + { + *(float *)pData = src; + } + + m_Put += sizeof(float); + AddNullTermination( m_Put ); + } +} + +template <> +inline void CUtlBuffer::PutTypeBin< double >( double src ) +{ + if ( CheckPut( sizeof( src ) ) ) + { + if ( m_Byteswap.IsSwappingBytes() ) + { + m_Byteswap.SwapBufferToTargetEndian( &src, &src ); + } + + // + // Write the data + // + unsigned pData = (unsigned)PeekPut(); + if ( pData & 0x07 ) + { + // handle unaligned write + byte* dst = (byte*)pData; + byte* srcPtr = (byte*)&src; + dst[0] = srcPtr[0]; + dst[1] = srcPtr[1]; + dst[2] = srcPtr[2]; + dst[3] = srcPtr[3]; + dst[4] = srcPtr[4]; + dst[5] = srcPtr[5]; + dst[6] = srcPtr[6]; + dst[7] = srcPtr[7]; + } + else + { + *(double *)pData = src; + } + + m_Put += sizeof(double); + AddNullTermination( m_Put ); + } +} +#endif + template -inline void CUtlBuffer::PutType( T src, const char *pszFmt ) +inline void CUtlBuffer::PutType( T src ) { if (!IsText()) { @@ -884,7 +1173,7 @@ inline void CUtlBuffer::PutType( T src, const char *pszFmt ) } else { - Printf( pszFmt, src ); + Printf( GetFmtStr< T >(), src ); } } @@ -952,68 +1241,74 @@ inline void CUtlBuffer::PutChar( char c ) inline void CUtlBuffer::PutUnsignedChar( unsigned char c ) { - PutType( c, "%u" ); -} - -inline void CUtlBuffer::PutUint64( uint64 ub ) -{ - PutType( ub, "%llu" ); -} - -inline void CUtlBuffer::PutInt16( int16 s16 ) -{ - PutType( s16, "%d" ); + if (!IsText()) + { + PutTypeBin( c ); + } + else + { + PutUnsignedShort( c ); + } } inline void CUtlBuffer::PutShort( short s ) { - PutType( s, "%d" ); + PutType( s ); } inline void CUtlBuffer::PutUnsignedShort( unsigned short s ) { - PutType( s, "%u" ); + PutType( s ); } inline void CUtlBuffer::PutInt( int i ) { - PutType( i, "%d" ); + PutType( i ); } inline void CUtlBuffer::PutInt64( int64 i ) { - PutType( i, "%llu" ); + PutType( i ); } inline void CUtlBuffer::PutUnsignedInt( unsigned int u ) { - PutType( u, "%u" ); + PutType( u ); +} + +inline void CUtlBuffer::PutUnsignedInt64( uint64 i ) +{ + PutType( i ); +} + +inline void CUtlBuffer::PutUint64( uint64 i ) +{ + PutType( i ); } inline void CUtlBuffer::PutFloat( float f ) { - PutType( f, "%f" ); + PutType( f ); } inline void CUtlBuffer::PutDouble( double d ) { - PutType( d, "%f" ); + PutType( d ); } inline void CUtlBuffer::PutPtr( void *p ) { - // LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal - if (!IsText()) - { - PutTypeBin( p ); - } - else - { - Printf( "0x%p", p ); - } + // LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal + if (!IsText()) + { + PutTypeBin( p ); + } + else + { + Printf( "0x%p", p ); + } } - //----------------------------------------------------------------------------- // Am I a text buffer? //----------------------------------------------------------------------------- @@ -1062,26 +1357,25 @@ inline bool CUtlBuffer::IsReadOnly() const //----------------------------------------------------------------------------- // Buffer base and size //----------------------------------------------------------------------------- -inline const void* CUtlBuffer::Base() const -{ - return m_Memory.Base(); +inline const void* CUtlBuffer::Base() const +{ + return m_Memory.Base(); } inline void* CUtlBuffer::Base() { - return m_Memory.Base(); + return m_Memory.Base(); } -// Returns the base as a const char*, only valid in text mode. -inline const char *CUtlBuffer::String() const +inline const void* CUtlBuffer::String() const { Assert( IsText() ); return reinterpret_cast( m_Memory.Base() ); } -inline int CUtlBuffer::Size() const -{ - return m_Memory.NumAllocated(); +inline int CUtlBuffer::Size() const +{ + return m_Memory.NumAllocated(); } @@ -1095,7 +1389,7 @@ inline void CUtlBuffer::Clear() m_Error = 0; m_nOffset = 0; m_nMaxPut = -1; - AddNullTermination(); + AddNullTermination( m_Put ); } inline void CUtlBuffer::Purge() @@ -1108,6 +1402,58 @@ inline void CUtlBuffer::Purge() m_Memory.Purge(); } +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +inline void *CUtlBuffer::AccessForDirectRead( int nBytes ) +{ + Assert( m_Get == 0 && m_Put == 0 && m_nMaxPut == 0 ); + EnsureCapacity( nBytes ); + m_nMaxPut = nBytes; + return Base(); +} + +inline void *CUtlBuffer::Detach() +{ + void *p = m_Memory.Detach(); + Clear(); + return p; +} + +//----------------------------------------------------------------------------- + +inline void CUtlBuffer::Spew( ) +{ + SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + + char pTmpLine[1024]; + while( IsValid() && GetBytesRemaining() ) + { + V_memset( pTmpLine, 0, sizeof(pTmpLine) ); + Get( pTmpLine, MIN( ( size_t )GetBytesRemaining(), sizeof(pTmpLine)-1 ) ); + Msg( _T( "%s" ), pTmpLine ); + } +} + +#if !defined(_GAMECONSOLE) +inline void CUtlBuffer::SwapCopy( CUtlBuffer &other ) +{ + m_Get = other.m_Get; + m_Put = other.m_Put; + m_Error = other.m_Error; + m_Flags = other.m_Flags; + m_Reserved = other.m_Reserved; + m_nTab = other.m_nTab; + m_nMaxPut = other.m_nMaxPut; + m_nOffset = other.m_nOffset; + m_GetOverflowFunc = other.m_GetOverflowFunc; + m_PutOverflowFunc = other.m_PutOverflowFunc; + m_Byteswap = other.m_Byteswap; + + m_Memory.Swap( other.m_Memory ); +} +#endif + inline void CUtlBuffer::CopyBuffer( const CUtlBuffer &buffer ) { CopyBuffer( buffer.Base(), buffer.TellPut() ); diff --git a/public/tier1/utllinkedlist.h b/public/tier1/utllinkedlist.h index 2e201805..d0f4249b 100644 --- a/public/tier1/utllinkedlist.h +++ b/public/tier1/utllinkedlist.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Linked list container class // @@ -26,6 +26,9 @@ #define FOR_EACH_LL( listName, iteratorName ) \ for( auto iteratorName=(listName).Head(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Next( iteratorName ) ) +#define FOR_EACH_LL_BACK( listName, iteratorName ) \ + for( auto iteratorName=(listName).Tail(); (listName).IsUtlLinkedList && iteratorName != (listName).InvalidIndex(); iteratorName = (listName).Previous( iteratorName ) ) + //----------------------------------------------------------------------------- // class CUtlLinkedList: // description: @@ -65,12 +68,15 @@ public: typedef S IndexType_t; // should really be called IndexStorageType_t, but that would be a huge change typedef I IndexLocalType_t; typedef M MemoryAllocator_t; - static const bool IsUtlLinkedList = true; // Used to match this at compiletime + enum { IsUtlLinkedList = true }; // Used to match this at compiletime // constructor, destructor CUtlLinkedList( int growSize = 0, int initSize = 0 ); ~CUtlLinkedList(); + CUtlLinkedList( const CUtlLinkedList& ) = delete; + CUtlLinkedList& operator=( const CUtlLinkedList& ) = delete; + // gets particular elements T& Element( I i ); T const& Element( I i ) const; @@ -115,6 +121,9 @@ public: I Alloc( bool multilist = false ); void Free( I elem ); + // Identify the owner of this linked list's memory: + void SetAllocOwner( const char *pszAllocOwner ); + // list modification void LinkBefore( I before, I elem ); void LinkAfter( I after, I elem ); @@ -348,16 +357,13 @@ protected: typedef UtlLinkedListElem_t ListElem_t; // constructs the class - I AllocInternal( bool multilist = false ); + I AllocInternal( bool multilist = false ) RESTRICT; void ConstructList(); // Gets at the list element.... ListElem_t& InternalElement( I i ) { return m_Memory[i]; } ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; } - // copy constructors not allowed - CUtlLinkedList( CUtlLinkedList const& list ) { Assert(0); } - M m_Memory; I m_Head; I m_Tail; @@ -379,17 +385,10 @@ protected: { m_pElements = m_Memory.Base(); } - -private: - // Faster version of Next that can only be used from tested code internal - // to this class, such as Find(). It avoids the cost of checking the index - // validity, which is a big win on debug builds. - I PrivateNext( I i ) const; }; // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice -// MoeMod : CUtlFixedMemory uses intp as index type template < class T > class CUtlFixedLinkedList : public CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > > { @@ -397,25 +396,24 @@ public: CUtlFixedLinkedList( int growSize = 0, int initSize = 0 ) : CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > >( growSize, initSize ) {} - typedef CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > > BaseClass; bool IsValidIndex( intp i ) const { - if ( !BaseClass::Memory().IsIdxValid( i ) ) + if ( !this->Memory().IsIdxValid( i ) ) return false; #ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElementIndex - if ( BaseClass::Memory().IsIdxAfter( i, this->m_LastAlloc ) ) + if ( this->Memory().IsIdxAfter( i, this->m_LastAlloc ) ) { Assert( 0 ); return false; // don't read values that have been allocated, but not constructed } #endif - return ( BaseClass::Memory()[ i ].m_Previous != i ) || ( BaseClass::Memory()[ i ].m_Next == i ); + return ( this->Memory()[ i ].m_Previous != i ) || ( this->Memory()[ i ].m_Next == i ); } private: - intp MaxElementIndex() const { Assert( 0 ); return BaseClass::InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1 + int MaxElementIndex() const { Assert( 0 ); return this->InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1 void ResetDbgInfo() {} }; @@ -439,8 +437,10 @@ template CUtlLinkedList::CUtlLinkedList( int growSize, int initSize ) : m_Memory( growSize, initSize ), m_LastAlloc( m_Memory.InvalidIterator() ) { +#if !defined( PLATFORM_WINDOWS_PC64 ) && !defined( PLATFORM_64BITS ) // Prevent signed non-int datatypes - COMPILE_TIME_ASSERT( sizeof(S) == sizeof(M::InvalidIndex()) || ( ( (S)-1 ) > 0 ) ); + COMPILE_TIME_ASSERT( sizeof(S) == 4 || ( ( (S)-1 ) > 0 ) ); +#endif ConstructList(); ResetDbgInfo(); } @@ -540,21 +540,13 @@ inline I CUtlLinkedList::Next( I i ) const return InternalElement(i).m_Next; } -template -inline I CUtlLinkedList::PrivateNext( I i ) const -{ - return InternalElement(i).m_Next; -} - //----------------------------------------------------------------------------- // Are nodes in the list or valid? //----------------------------------------------------------------------------- -#ifdef _WIN32 #pragma warning(push) #pragma warning( disable: 4310 ) // Allows "(I)(S)M::INVALID_INDEX" below -#endif template inline bool CUtlLinkedList::IndexInRange( I index ) // Static method { @@ -565,17 +557,17 @@ inline bool CUtlLinkedList::IndexInRange( I index ) // Static method // Do some static checks here: // 'I' needs to be able to store 'S' - COMPILE_TIME_ASSERT( sizeof(I) >= sizeof(S) ); + // These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks + // on MacOS and Linux due to a gcc bug. + { COMPILE_TIME_ASSERT( sizeof(I) >= sizeof(S) ); } // 'S' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges) - COMPILE_TIME_ASSERT( ( sizeof(S) > 2 ) || ( ( (S)-1 ) > 0 ) ); + { COMPILE_TIME_ASSERT( ( sizeof(S) > 2 ) || ( ( (S)-1 ) > 0 ) ); } // M::INVALID_INDEX should be storable in S to avoid ambiguities (e.g. with 65536) - COMPILE_TIME_ASSERT( ( M::INVALID_INDEX == -1 ) || ( M::INVALID_INDEX == (S)M::INVALID_INDEX ) ); + { COMPILE_TIME_ASSERT( ( M::INVALID_INDEX == -1 ) || ( M::INVALID_INDEX == (S)M::INVALID_INDEX ) ); } return ( ( (S)index == index ) && ( (S)index != InvalidIndex() ) ); } -#ifdef _WIN32 #pragma warning(pop) -#endif template inline bool CUtlLinkedList::IsValidIndex( I i ) const @@ -626,6 +618,12 @@ void CUtlLinkedList::SetGrowSize( int growSize ) ResetDbgInfo(); } +template< class T, class S, bool ML, class I, class M > +void CUtlLinkedList::SetAllocOwner( const char *pszAllocOwner ) +{ + m_Memory.SetAllocOwner( pszAllocOwner ); +} + //----------------------------------------------------------------------------- // Deallocate memory @@ -665,7 +663,7 @@ void CUtlLinkedList::PurgeAndDeleteElements() // Node allocation/deallocation //----------------------------------------------------------------------------- template -I CUtlLinkedList::AllocInternal( bool multilist ) +I CUtlLinkedList::AllocInternal( bool multilist ) RESTRICT { Assert( !multilist || ML ); #ifdef MULTILIST_PEDANTIC_ASSERTS @@ -798,7 +796,7 @@ inline I CUtlLinkedList::AddToHead( ) template inline I CUtlLinkedList::AddToTail( ) { - return InsertBefore( InvalidIndex() ); + return InsertBefore( InvalidIndex() ); } @@ -860,9 +858,7 @@ inline I CUtlLinkedList::AddToTail( T const& src ) template I CUtlLinkedList::Find( const T &src ) const { - // Cache the invalidIndex to avoid two levels of function calls on each iteration. - I invalidIndex = InvalidIndex(); - for ( I i=Head(); i != invalidIndex; i = PrivateNext( i ) ) + for ( I i=Head(); i != InvalidIndex(); i = Next( i ) ) { if ( Element( i ) == src ) return i; diff --git a/public/tier1/utlmemory.h b/public/tier1/utlmemory.h index 66c1f28d..a3a70fff 100644 --- a/public/tier1/utlmemory.h +++ b/public/tier1/utlmemory.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -17,22 +17,21 @@ #include "tier0/dbg.h" #include #include "tier0/platform.h" -#include "mathlib/mathlib.h" #include "tier0/memalloc.h" +#include "mathlib/mathlib.h" #include "tier0/memdbgon.h" -#ifdef _WIN32 #pragma warning (disable:4100) #pragma warning (disable:4514) -#endif + //----------------------------------------------------------------------------- #ifdef UTLMEMORY_TRACK -#define UTLMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlMemory", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) -#define UTLMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlMemory", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) +#define UTLMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) +#define UTLMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) #else #define UTLMEMORY_TRACK_ALLOC() ((void)0) #define UTLMEMORY_TRACK_FREE() ((void)0) @@ -46,6 +45,8 @@ template< class T, class I = int > class CUtlMemory { + template< class A, class B> friend class CUtlVector; + template< class A, size_t B> friend class CUtlVectorFixedGrowableCompat; public: // constructor, destructor CUtlMemory( int nGrowSize = 0, int nInitSize = 0 ); @@ -53,6 +54,12 @@ public: CUtlMemory( const T* pMemory, int numElements ); ~CUtlMemory(); + CUtlMemory( const CUtlMemory& ) = delete; + CUtlMemory& operator=( const CUtlMemory& ) = delete; + + CUtlMemory( CUtlMemory&& moveFrom ); + CUtlMemory& operator=( CUtlMemory&& moveFrom ); + // Set the size by which the memory grows void Init( int nGrowSize = 0, int nInitSize = 0 ); @@ -92,8 +99,9 @@ public: // Attaches the buffer to external memory.... void SetExternalBuffer( T* pMemory, int numElements ); void SetExternalBuffer( const T* pMemory, int numElements ); - // Takes ownership of the passed memory, including freeing it when this buffer is destroyed. void AssumeMemory( T *pMemory, int nSize ); + T* Detach(); + void *DetachMemory(); // Fast swap void Swap( CUtlMemory< T, I > &mem ); @@ -212,8 +220,7 @@ public: CUtlMemoryFixed( T* pMemory, int numElements ) { Assert( 0 ); } // Can we use this index? - // Use unsigned math to improve performance - bool IsIdxValid( int i ) const { return (size_t)i < SIZE; } + bool IsIdxValid( int i ) const { return (i >= 0) && (i < SIZE); } // Specify the invalid ('null') index that we'll only return on failure static const int INVALID_INDEX = -1; // For use with COMPILE_TIME_ASSERT @@ -224,11 +231,10 @@ public: const T* Base() const { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); } // element access - // Use unsigned math and inlined checks to improve performance. - T& operator[]( int i ) { Assert( (size_t)i < SIZE ); return Base()[i]; } - const T& operator[]( int i ) const { Assert( (size_t)i < SIZE ); return Base()[i]; } - T& Element( int i ) { Assert( (size_t)i < SIZE ); return Base()[i]; } - const T& Element( int i ) const { Assert( (size_t)i < SIZE ); return Base()[i]; } + T& operator[]( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& operator[]( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + T& Element( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& Element( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } // Attaches the buffer to external memory.... void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); } @@ -274,12 +280,7 @@ private: char m_Memory[ SIZE*sizeof(T) + nAlignment ]; }; -#if defined(POSIX) -// From Chris Green: Memory is a little fuzzy but I believe this class did -// something fishy with respect to msize and alignment that was OK under our -// allocator, the glibc allocator, etc but not the valgrind one (which has no -// padding because it detects all forms of head/tail overwrite, including -// writing 1 byte past a 1 byte allocation). +#ifdef _LINUX #define REMEMBER_ALLOC_SIZE_FOR_VALGRIND 1 #endif @@ -445,6 +446,44 @@ template< class T, class I > CUtlMemory::~CUtlMemory() { Purge(); + +#ifdef _DEBUG + m_pMemory = reinterpret_cast< T* >( 0xFEFEBAAD ); + m_nAllocationCount = 0x7BADF00D; +#endif +} + +template< class T, class I > +CUtlMemory::CUtlMemory( CUtlMemory&& moveFrom ) +: m_pMemory(moveFrom.m_pMemory) +, m_nAllocationCount(moveFrom.m_nAllocationCount) +, m_nGrowSize(moveFrom.m_nGrowSize) +{ + moveFrom.m_pMemory = nullptr; + moveFrom.m_nAllocationCount = 0; + moveFrom.m_nGrowSize = 0; +} + +template< class T, class I > +CUtlMemory& CUtlMemory::operator=( CUtlMemory&& moveFrom ) +{ + // Copy member variables to locals before purge to handle self-assignment + T* pMemory = moveFrom.m_pMemory; + int nAllocationCount = moveFrom.m_nAllocationCount; + int nGrowSize = moveFrom.m_nGrowSize; + + moveFrom.m_pMemory = nullptr; + moveFrom.m_nAllocationCount = 0; + moveFrom.m_nGrowSize = 0; + + // If this is a self-assignment, Purge() is a no-op here + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = nAllocationCount; + m_nGrowSize = nGrowSize; + + return *this; } template< class T, class I > @@ -493,7 +532,7 @@ void CUtlMemory::ConvertToGrowableMemory( int nGrowSize ) int nNumBytes = m_nAllocationCount * sizeof(T); T *pMemory = (T*)malloc( nNumBytes ); - memcpy( (void*)pMemory, (void*)m_pMemory, nNumBytes ); + memcpy( pMemory, m_pMemory, nNumBytes ); m_pMemory = pMemory; } else @@ -543,6 +582,24 @@ void CUtlMemory::AssumeMemory( T* pMemory, int numElements ) m_nAllocationCount = numElements; } +template< class T, class I > +void *CUtlMemory::DetachMemory() +{ + if ( IsExternallyAllocated() ) + return NULL; + + void *pMemory = m_pMemory; + m_pMemory = 0; + m_nAllocationCount = 0; + return pMemory; +} + +template< class T, class I > +inline T* CUtlMemory::Detach() +{ + return (T*)DetachMemory(); +} + //----------------------------------------------------------------------------- // element access @@ -550,35 +607,31 @@ void CUtlMemory::AssumeMemory( T* pMemory, int numElements ) template< class T, class I > inline T& CUtlMemory::operator[]( I i ) { - // Avoid function calls in the asserts to improve debug build performance - Assert( m_nGrowSize != EXTERNAL_CONST_BUFFER_MARKER ); //Assert( !IsReadOnly() ); - Assert( (uint32)i < (uint32)m_nAllocationCount ); - return m_pMemory[(uint32)i]; + Assert( !IsReadOnly() ); + Assert( IsIdxValid(i) ); + return m_pMemory[i]; } template< class T, class I > inline const T& CUtlMemory::operator[]( I i ) const { - // Avoid function calls in the asserts to improve debug build performance - Assert( (uint32)i < (uint32)m_nAllocationCount ); - return m_pMemory[(uint32)i]; + Assert( IsIdxValid(i) ); + return m_pMemory[i]; } template< class T, class I > inline T& CUtlMemory::Element( I i ) { - // Avoid function calls in the asserts to improve debug build performance - Assert( m_nGrowSize != EXTERNAL_CONST_BUFFER_MARKER ); //Assert( !IsReadOnly() ); - Assert( (uint32)i < (uint32)m_nAllocationCount ); - return m_pMemory[(uint32)i]; + Assert( !IsReadOnly() ); + Assert( IsIdxValid(i) ); + return m_pMemory[i]; } template< class T, class I > inline const T& CUtlMemory::Element( I i ) const { - // Avoid function calls in the asserts to improve debug build performance - Assert( (uint32)i < (uint32)m_nAllocationCount ); - return m_pMemory[(uint32)i]; + Assert( IsIdxValid(i) ); + return m_pMemory[i]; } @@ -651,10 +704,10 @@ inline int CUtlMemory::Count() const template< class T, class I > inline bool CUtlMemory::IsIdxValid( I i ) const { - // If we always cast 'i' and 'm_nAllocationCount' to unsigned then we can - // do our range checking with a single comparison instead of two. This gives - // a modest speedup in debug builds. - return (uint32)i < (uint32)m_nAllocationCount; + // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0). + // We get the warning even if we cast inside the expression. It only goes away if we assign to another variable. + long x = i; + return ( x >= 0 ) && ( x < m_nAllocationCount ); } //----------------------------------------------------------------------------- @@ -672,6 +725,11 @@ inline int UtlMemory_CalcNewAllocationCount( int nAllocationCount, int nGrowSize { // Compute an allocation which is at least as big as a cache line... nAllocationCount = (31 + nBytesItem) / nBytesItem; + // If the requested amount is larger then compute an allocation which + // is exactly the right size. Otherwise we can end up with wasted memory + // when CUtlVector::EnsureCount(n) is called. + if ( nAllocationCount < nNewSize ) + nAllocationCount = nNewSize; } while (nAllocationCount < nNewSize) diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h index e90be466..7eb89775 100644 --- a/public/tier1/utlsymbol.h +++ b/public/tier1/utlsymbol.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Defines a symbol table // @@ -13,9 +13,13 @@ #pragma once #endif +#include "tier0/platform.h" #include "tier0/threadtools.h" #include "tier1/utlrbtree.h" #include "tier1/utlvector.h" +#include "tier1/utlbuffer.h" +#include "tier1/utllinkedlist.h" +#include "tier1/stringpool.h" //----------------------------------------------------------------------------- @@ -24,6 +28,7 @@ class CUtlSymbolTable; class CUtlSymbolTableMT; +#define FILENAMEHANDLE_INVALID 0 //----------------------------------------------------------------------------- // This is a symbol, which is a easier way of dealing with strings. @@ -52,14 +57,19 @@ public: bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; } // Gets at the symbol - operator UtlSymId_t const() const { return m_Id; } + operator UtlSymId_t () const { return m_Id; } // Gets the string associated with the symbol const char* String( ) const; // Modules can choose to disable the static symbol table so to prevent accidental use of them. static void DisableStaticSymbolTable(); - + + // Methods with explicit locking mechanism. Only use for optimization reasons. + static void LockTableForRead(); + static void UnlockTableForRead(); + const char * StringNoLock() const; + protected: UtlSymId_t m_Id; @@ -85,13 +95,17 @@ protected: // of strings to symbols and back. The symbol class itself contains // a static version of this class for creating global strings, but this // class can also be instanced to create local symbol tables. +// +// This class stores the strings in a series of string pools. The first +// two bytes of each string are decorated with a hash to speed up +// comparisons. //----------------------------------------------------------------------------- class CUtlSymbolTable { public: // constructor, destructor - CUtlSymbolTable( int growSize = 0, int initSize = 32, bool caseInsensitive = false ); + CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false ); ~CUtlSymbolTable(); // Finds and/or creates a symbol based on the string @@ -102,6 +116,11 @@ public: // Look up the string associated with a particular symbol const char* String( CUtlSymbol id ) const; + + inline bool HasElement(const char* pStr) const + { + return Find(pStr) != UTL_INVAL_SYMBOL; + } // Remove all symbols in the table. void RemoveAll(); @@ -111,6 +130,10 @@ public: return m_Lookup.Count(); } + // We store one of these at the beginning of every string to speed + // up comparisons. + typedef unsigned short hashDecoration_t; + protected: class CStringPoolIndex { @@ -120,10 +143,8 @@ protected: } inline CStringPoolIndex( unsigned short iPool, unsigned short iOffset ) - { - m_iPool = iPool; - m_iOffset = iOffset; - } + : m_iPool(iPool), m_iOffset(iOffset) + {} inline bool operator==( const CStringPoolIndex &other ) const { @@ -158,7 +179,9 @@ protected: }; CTree m_Lookup; + bool m_bInsensitive; + mutable unsigned short m_nUserSearchStringHash; mutable const char* m_pUserSearchString; // stores the string data @@ -167,11 +190,14 @@ protected: private: int FindPoolWithSpace( int len ) const; const char* StringFromIndex( const CStringPoolIndex &index ) const; + const char* DecoratedStringFromIndex( const CStringPoolIndex &index ) const; friend class CLess; + friend class CSymbolHash; + }; -class CUtlSymbolTableMT : private CUtlSymbolTable +class CUtlSymbolTableMT : public CUtlSymbolTable { public: CUtlSymbolTableMT( int growSize = 0, int initSize = 32, bool caseInsensitive = false ) @@ -189,9 +215,9 @@ public: CUtlSymbol Find( const char* pString ) const { - m_lock.LockForRead(); + m_lock.LockForWrite(); CUtlSymbol result = CUtlSymbolTable::Find( pString ); - m_lock.UnlockRead(); + m_lock.UnlockWrite(); return result; } @@ -202,9 +228,24 @@ public: m_lock.UnlockRead(); return pszResult; } - + + const char * StringNoLock( CUtlSymbol id ) const + { + return CUtlSymbolTable::String( id ); + } + + void LockForRead() + { + m_lock.LockForRead(); + } + + void UnlockForRead() + { + m_lock.UnlockRead(); + } + private: -#if defined(WIN32) || defined(_WIN32) +#ifdef WIN32 mutable CThreadSpinRWLock m_lock; #else mutable CThreadRWLock m_lock; @@ -225,7 +266,6 @@ private: // The handle is a CUtlSymbol for the dirname and the same for the filename, the accessor // copies them into a static char buffer for return. typedef void* FileNameHandle_t; -#define FILENAMEHANDLE_INVALID 0 // Symbol table for more efficiently storing filenames by breaking paths and filenames apart. // Refactored from BaseFileSystem.h @@ -238,32 +278,104 @@ class CUtlFilenameSymbolTable { FileNameHandleInternal_t() { - path = 0; - file = 0; + COMPILE_TIME_ASSERT( sizeof( *this ) == sizeof( FileNameHandle_t ) ); + COMPILE_TIME_ASSERT( sizeof( value ) == 4 ); + value = 0; + +#ifdef PLATFORM_64BITS + pad = 0; +#endif } + // We pack the path and file values into a single 32 bit value. We were running + // out of space with the two 16 bit values (more than 64k files) so instead of increasing + // the total size we split the underlying pool into two (paths and files) and + // use a smaller path string pool and a larger file string pool. + unsigned int value; + +#ifdef PLATFORM_64BITS + // some padding to make sure we are the same size as FileNameHandle_t on 64 bit. + unsigned int pad; +#endif + + static const unsigned int cNumBitsInPath = 12; + static const unsigned int cNumBitsInFile = 32 - cNumBitsInPath; + + static const unsigned int cMaxPathValue = 1 << cNumBitsInPath; + static const unsigned int cMaxFileValue = 1 << cNumBitsInFile; + + static const unsigned int cPathBitMask = cMaxPathValue - 1; + static const unsigned int cFileBitMask = cMaxFileValue - 1; + // Part before the final '/' character - unsigned short path; + unsigned int GetPath() const { return ((value >> cNumBitsInFile) & cPathBitMask); } + void SetPath( unsigned int path ) { Assert( path < cMaxPathValue ); value = ((value & cFileBitMask) | ((path & cPathBitMask) << cNumBitsInFile)); } + // Part after the final '/', including extension - unsigned short file; + unsigned int GetFile() const { return (value & cFileBitMask); } + void SetFile( unsigned int file ) { Assert( file < cMaxFileValue ); value = ((value & (cPathBitMask << cNumBitsInFile)) | (file & cFileBitMask)); } }; - class HashTable; - public: - CUtlFilenameSymbolTable(); - ~CUtlFilenameSymbolTable(); FileNameHandle_t FindOrAddFileName( const char *pFileName ); FileNameHandle_t FindFileName( const char *pFileName ); - int PathIndex(const FileNameHandle_t &handle) { return (( const FileNameHandleInternal_t * )&handle)->path; } + int PathIndex( const FileNameHandle_t &handle ) { return (( const FileNameHandleInternal_t * )&handle)->GetPath(); } bool String( const FileNameHandle_t& handle, char *buf, int buflen ); void RemoveAll(); + void SpewStrings(); + bool SaveToBuffer( CUtlBuffer &buffer ); + bool RestoreFromBuffer( CUtlBuffer &buffer ); private: - //CCountedStringPool m_StringPool; - HashTable* m_Strings; + CCountedStringPoolBase m_PathStringPool; + CCountedStringPoolBase m_FileStringPool; mutable CThreadSpinRWLock m_lock; }; +// This creates a simple class that includes the underlying CUtlSymbol +// as a private member and then instances a private symbol table to +// manage those symbols. Avoids the possibility of the code polluting the +// 'global'/default symbol table, while letting the code look like +// it's just using = and .String() to look at CUtlSymbol type objects +// +// NOTE: You can't pass these objects between .dlls in an interface (also true of CUtlSymbol of course) +// +#define DECLARE_PRIVATE_SYMBOLTYPE( typename ) \ + class typename \ + { \ + public: \ + typename(); \ + typename( const char* pStr ); \ + typename& operator=( typename const& src ); \ + bool operator==( typename const& src ) const; \ + const char* String( ) const; \ + private: \ + CUtlSymbol m_SymbolId; \ + }; + +// Put this in the .cpp file that uses the above typename +#define IMPLEMENT_PRIVATE_SYMBOLTYPE( typename ) \ + static CUtlSymbolTable g_##typename##SymbolTable; \ + typename::typename() \ + { \ + m_SymbolId = UTL_INVAL_SYMBOL; \ + } \ + typename::typename( const char* pStr ) \ + { \ + m_SymbolId = g_##typename##SymbolTable.AddString( pStr ); \ + } \ + typename& typename::operator=( typename const& src ) \ + { \ + m_SymbolId = src.m_SymbolId; \ + return *this; \ + } \ + bool typename::operator==( typename const& src ) const \ + { \ + return ( m_SymbolId == src.m_SymbolId ); \ + } \ + const char* typename::String( ) const \ + { \ + return g_##typename##SymbolTable.String( m_SymbolId ); \ + } #endif // UTLSYMBOL_H diff --git a/public/vgui_controls/BuildGroup.h b/public/vgui_controls/BuildGroup.h index c6ce0f4e..a0fcf352 100644 --- a/public/vgui_controls/BuildGroup.h +++ b/public/vgui_controls/BuildGroup.h @@ -94,7 +94,6 @@ public: virtual const char *GetResourceName(void) { return m_pResourceName; } virtual void PanelAdded(Panel* panel); - virtual void PanelRemoved(Panel* panel); virtual bool MousePressed(MouseCode code,Panel* panel); virtual bool MouseReleased(MouseCode code,Panel* panel); diff --git a/public/vstdlib/jobthread.h b/public/vstdlib/jobthread.h index 306e1308..9b34efe9 100644 --- a/public/vstdlib/jobthread.h +++ b/public/vstdlib/jobthread.h @@ -191,7 +191,7 @@ public: // and execute or execute pFunctor right after completing current job and // before looking for another job. //----------------------------------------------------- - virtual void ExecuteHighPriorityFunctor( CFunctor *pFunctor ) = 0; + // virtual void ExecuteHighPriorityFunctor( CFunctor *pFunctor ) = 0; //----------------------------------------------------- // Add an function object to the queue (master thread) diff --git a/studiorender/r_studiodecal.cpp b/studiorender/r_studiodecal.cpp index 53524cde..c48702d0 100644 --- a/studiorender/r_studiodecal.cpp +++ b/studiorender/r_studiodecal.cpp @@ -115,7 +115,7 @@ StudioDecalHandle_t CStudioRender::CreateDecalList( studiohwdata_t *pHardwareDat // NOTE: This function is called directly without queueing m_DecalMutex.Lock(); - int handle = m_DecalList.AddToTail(); + intp handle = m_DecalList.AddToTail(); m_DecalMutex.Unlock(); m_DecalList[handle].m_pHardwareData = pHardwareData; diff --git a/tier0/cpu.cpp b/tier0/cpu.cpp index a8a0814c..9b0a9d6a 100644 --- a/tier0/cpu.cpp +++ b/tier0/cpu.cpp @@ -20,11 +20,23 @@ const tchar* GetProcessorVendorId(); -static bool cpuid(unsigned long function, unsigned long& out_eax, unsigned long& out_ebx, unsigned long& out_ecx, unsigned long& out_edx) +static bool cpuid(uint32 function, uint32& out_eax, uint32& out_ebx, uint32& out_ecx, uint32& out_edx) { #if defined (__arm__) || defined (__arm64__) || defined( _X360 ) return false; #elif defined(GNUC) + +#if defined(PLATFORM_64BITS) + asm("mov %%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchg %%rsi, %%rbx" + : "=a" (out_eax), + "=S" (out_ebx), + "=c" (out_ecx), + "=d" (out_edx) + : "a" (function) + ); +#else asm("mov %%ebx, %%esi\n\t" "cpuid\n\t" "xchg %%esi, %%ebx" @@ -34,7 +46,9 @@ static bool cpuid(unsigned long function, unsigned long& out_eax, unsigned long& "=d" (out_edx) : "a" (function) ); +#endif return true; + #elif defined(_WIN64) int pCPUInfo[4]; __cpuid( pCPUInfo, (int)function ); @@ -45,7 +59,7 @@ static bool cpuid(unsigned long function, unsigned long& out_eax, unsigned long& return true; #else bool retval = true; - unsigned long local_eax, local_ebx, local_ecx, local_edx; + uint32 local_eax, local_ebx, local_ecx, local_edx; _asm pushad; __try @@ -83,7 +97,7 @@ static bool CheckMMXTechnology(void) #if defined( _X360 ) || defined( _PS3 ) return true; #else - unsigned long eax,ebx,edx,unused; + uint32 eax,ebx,edx,unused; if ( !cpuid(1,eax,ebx,unused,edx) ) return false; @@ -151,7 +165,7 @@ static bool CheckSSETechnology(void) return false; } - unsigned long eax,ebx,edx,unused; + uint32 eax,ebx,edx,unused; if ( !cpuid(1,eax,ebx,unused,edx) ) { return false; } @@ -165,7 +179,7 @@ static bool CheckSSE2Technology(void) #if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) || defined (__arm__) return false; #else - unsigned long eax,ebx,edx,unused; + uint32 eax,ebx,edx,unused; if ( !cpuid(1,eax,ebx,unused,edx) ) return false; @@ -178,7 +192,7 @@ bool CheckSSE3Technology(void) #if defined( _X360 ) || defined( _PS3 ) || defined(__SANITIZE_ADDRESS__) || defined (__arm__) return false; #else - unsigned long eax,ebx,edx,ecx; + uint32 eax,ebx,edx,ecx; if( !cpuid(1,eax,ebx,ecx,edx) ) return false; @@ -193,7 +207,7 @@ bool CheckSSSE3Technology(void) #else // SSSE 3 is implemented by both Intel and AMD // detection is done the same way for both vendors - unsigned long eax,ebx,edx,ecx; + uint32 eax,ebx,edx,ecx; if( !cpuid(1,eax,ebx,ecx,edx) ) return false; @@ -209,7 +223,7 @@ bool CheckSSE41Technology(void) // SSE 4.1 is implemented by both Intel and AMD // detection is done the same way for both vendors - unsigned long eax,ebx,edx,ecx; + uint32 eax,ebx,edx,ecx; if( !cpuid(1,eax,ebx,ecx,edx) ) return false; @@ -228,7 +242,7 @@ bool CheckSSE42Technology(void) if ( 0 != V_tier0_stricmp( pchVendor, "GenuineIntel" ) ) return false; - unsigned long eax,ebx,edx,ecx; + uint32 eax,ebx,edx,ecx; if( !cpuid(1,eax,ebx,ecx,edx) ) return false; @@ -248,7 +262,7 @@ bool CheckSSE4aTechnology( void ) if ( 0 != V_tier0_stricmp( pchVendor, "AuthenticAMD" ) ) return false; - unsigned long eax,ebx,edx,ecx; + uint32 eax,ebx,edx,ecx; if( !cpuid( 0x80000001,eax,ebx,ecx,edx) ) return false; @@ -262,7 +276,7 @@ static bool Check3DNowTechnology(void) #if defined( _X360 ) || defined( _PS3 ) || defined (__arm__) || defined(__SANITIZE_ADDRESS__) return false; #else - unsigned long eax, unused; + uint32 eax, unused; if ( !cpuid(0x80000000,eax,unused,unused,unused) ) return false; @@ -282,7 +296,7 @@ static bool CheckCMOVTechnology() #if defined( _X360 ) || defined( _PS3 ) || defined (__arm__) || defined(__SANITIZE_ADDRESS__) return false; #else - unsigned long eax,ebx,edx,unused; + uint32 eax,ebx,edx,unused; if ( !cpuid(1,eax,ebx,unused,edx) ) return false; @@ -295,7 +309,7 @@ static bool CheckFCMOVTechnology(void) #if defined( _X360 ) || defined( _PS3 ) || defined (__arm__) || defined(__SANITIZE_ADDRESS__) return false; #else - unsigned long eax,ebx,edx,unused; + uint32 eax,ebx,edx,unused; if ( !cpuid(1,eax,ebx,unused,edx) ) return false; @@ -308,7 +322,7 @@ static bool CheckRDTSCTechnology(void) #if defined( _X360 ) || defined( _PS3 ) || defined (__arm__) || defined(__SANITIZE_ADDRESS__) return false; #else - unsigned long eax,ebx,edx,unused; + uint32 eax,ebx,edx,unused; if ( !cpuid(1,eax,ebx,unused,edx) ) return false; @@ -324,7 +338,7 @@ const tchar* GetProcessorVendorId() #elif defined ( __arm__ ) return "ARM"; #else - unsigned long unused, VendorIDRegisters[3]; + uint32 unused, VendorIDRegisters[3]; static tchar VendorID[13]; @@ -365,7 +379,7 @@ static bool HTSupported(void) const unsigned int EXT_FAMILY_ID = 0x0f00000; // EAX[23:20] - Bit 23 thru 20 contains extended family processor id const unsigned int PENTIUM4_ID = 0x0f00; // Pentium 4 family processor id - unsigned long unused, + uint32 unused, reg_eax = 0, reg_edx = 0, vendor_id[3] = {0, 0, 0}; @@ -393,7 +407,7 @@ static uint8 LogicalProcessorsPerPackage(void) // EBX[23:16] indicate number of logical processors per package const unsigned NUM_LOGICAL_BITS = 0x00FF0000; - unsigned long unused, reg_ebx = 0; + uint32 unused, reg_ebx = 0; if ( !HTSupported() ) return 1; @@ -582,7 +596,7 @@ const CPUInformation* GetCPUInformation() pi.m_szProcessorID = (tchar*)GetProcessorVendorId(); pi.m_bHT = HTSupported(); - unsigned long eax, ebx, edx, ecx; + uint32 eax, ebx, edx, ecx; if (cpuid(1, eax, ebx, ecx, edx)) { pi.m_nModel = eax; // full CPU model info diff --git a/tier0/dbg.cpp b/tier0/dbg.cpp index 2a64e77c..9d64da4a 100644 --- a/tier0/dbg.cpp +++ b/tier0/dbg.cpp @@ -49,7 +49,6 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" - //----------------------------------------------------------------------------- // internal structures //----------------------------------------------------------------------------- @@ -152,7 +151,7 @@ struct SpewInfo_t int m_nSpewOutputLevel; }; -CThreadLocalPtr g_pSpewInfo; +CTHREADLOCALPTR(SpewInfo_t) g_pSpewInfo; // Standard groups diff --git a/tier0/threadtools.cpp b/tier0/threadtools.cpp index 8f9ff285..2d00d706 100644 --- a/tier0/threadtools.cpp +++ b/tier0/threadtools.cpp @@ -1,35 +1,45 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========== Copyright 2005, Valve Corporation, All rights reserved. ======== // // Purpose: // //============================================================================= -#include "pch_tier0.h" +#include "tier0/platform.h" -#include "tier1/strtools.h" -#include "tier0/dynfunction.h" -#if defined( _WIN32 ) && !defined( _X360 ) +#if defined( PLATFORM_WINDOWS_PC ) #define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x0403 #include #endif -#ifdef _WIN32 + +#ifdef PLATFORM_WINDOWS #include - -#ifdef IS_WINDOWS_PC - #include - #pragma comment(lib, "winmm.lib") -#endif // IS_WINDOWS_PC - -#elif defined(POSIX) - -#if !defined(OSX) -#if defined(ANDROID) - #include + #ifdef PLATFORM_WINDOWS_PC + #include + #pragma comment(lib, "winmm.lib") + #endif +#elif PLATFORM_PS3 + #include #include -#else + #include + #include + #include + #include + #include + #define GetLastError() errno + typedef void *LPVOID; +#elif PLATFORM_POSIX + #include + #include + #include + #include + #include + #include + #define GetLastError() errno + typedef void *LPVOID; +#if !defined(OSX) #include #include -#endif #define sem_unlink( arg ) #define OS_TO_PTHREAD(x) (x) #else @@ -39,43 +49,39 @@ #define OS_TO_PTHREAD(x) pthread_from_mach_thread_np( x ) #endif // !OSX -#ifdef LINUX -#include // RTLD_NEXT #endif -typedef int (*PTHREAD_START_ROUTINE)( - void *lpThreadParameter - ); -typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; -#include -#include -#include -#include -#include -#include -#include -#define GetLastError() errno -typedef void *LPVOID; +#ifndef _PS3 +#include #endif - -#include "tier0/valve_minmax_off.h" -#include -#include "tier0/valve_minmax_on.h" - +#include "tier0/minidump.h" #include "tier0/threadtools.h" -#include "tier0/vcrmode.h" +#include "tier0/dynfunction.h" #ifdef _X360 #include "xbox/xbox_win32stubs.h" #endif -#include "tier0/vprof_telemetry.h" +#include // Must be last header... #include "tier0/memdbgon.h" +#ifdef _PS3 +#include "ps3/ps3_win32stubs.h" +#define NEW_WAIT_FOR_MULTIPLE_OBJECTS +bool gbCheckNotMultithreaded = true; + +extern "C" void(*g_pfnPushMarker)( const char * pName ); +extern "C" void(*g_pfnPopMarker)(); + + +#endif + #define THREADS_DEBUG 1 +#define DEBUG_ERROR(XX) Assert(0) + // Need to ensure initialized before other clients call in for main thread ID #ifdef _WIN32 #pragma warning(disable:4073) @@ -87,6 +93,50 @@ ASSERT_INVARIANT(TT_SIZEOF_CRITICALSECTION == sizeof(CRITICAL_SECTION)); ASSERT_INVARIANT(TT_INFINITE == INFINITE); #endif +// thread creation counter. +// this is used to provide a unique threadid for each running thread in g_nThreadID ( a thread local variable ). + +const int MAX_THREAD_IDS = 128; + +static volatile bool s_bThreadIDAllocated[MAX_THREAD_IDS]; + +#if defined(_LINUX) && defined(DEDICATED) + +DLL_CLASS_EXPORT __thread int g_nThreadID; + +#elif defined(_PS3) + #include "tls_ps3.h" +#else + DLL_CLASS_EXPORT CTHREADLOCALINT g_nThreadID; +#endif + + +static CThreadFastMutex s_ThreadIDMutex; + +PLATFORM_INTERFACE void AllocateThreadID( void ) +{ + AUTO_LOCK( s_ThreadIDMutex ); + for( int i = 1; i < MAX_THREAD_IDS; i++ ) + { + if ( ! s_bThreadIDAllocated[i] ) + { + g_nThreadID = i; + s_bThreadIDAllocated[i] = true; + return; + } + } + Error( "Out of thread ids. Decrease the number of threads or increase MAX_THREAD_IDS\n" ); +} + +PLATFORM_INTERFACE void FreeThreadID( void ) +{ + AUTO_LOCK( s_ThreadIDMutex ); + int nThread = g_nThreadID; + if ( nThread ) + s_bThreadIDAllocated[nThread] = false; +} + + //----------------------------------------------------------------------------- // Simple thread functions. // Because _beginthreadex uses stdcall, we need to convert to cdecl @@ -105,85 +155,330 @@ struct ThreadProcInfo_t //--------------------------------------------------------- -#ifdef _WIN32 -static unsigned __stdcall ThreadProcConvert( void *pParam ) -#elif defined(POSIX) -static void *ThreadProcConvert( void *pParam ) -#else -#error -#endif +#ifdef PLATFORM_WINDOWS +static DWORD WINAPI ThreadProcConvert( void *pParam ) { ThreadProcInfo_t info = *((ThreadProcInfo_t *)pParam); + AllocateThreadID(); delete ((ThreadProcInfo_t *)pParam); -#ifdef _WIN32 - return (*info.pfnThread)(info.pParam); -#elif defined(POSIX) - return (void *)(*info.pfnThread)(info.pParam); -#else -#error -#endif + unsigned nRet = (*info.pfnThread)(info.pParam); + FreeThreadID(); + return nRet; } +#elif defined( PLATFORM_PS3 ) +union ThreadProcInfoUnion_t +{ + struct Val_t + { + ThreadFunc_t pfnThread; + void * pParam; + } + val; + uint64_t val64; +}; +static void ThreadProcConvertUnion( uint64_t param ) +{ + COMPILE_TIME_ASSERT( sizeof( ThreadProcInfoUnion_t ) == 8 ); + ThreadProcInfoUnion_t info; + info.val64 = param; + AllocateThreadID(); + unsigned nRet = (*info.val.pfnThread)(info.val.pParam); + FreeThreadID(); + sys_ppu_thread_exit( nRet ); +} +static void* ThreadProcConvert( void *pParam ) +{ + ThreadProcInfo_t info = *((ThreadProcInfo_t *)pParam); + AllocateThreadID(); + delete ((ThreadProcInfo_t *)pParam); + unsigned nRet = (*info.pfnThread)(info.pParam); + FreeThreadID(); + return ( void * ) nRet; +} + +#else +static void* ThreadProcConvert( void *pParam ) +{ + ThreadProcInfo_t info = *((ThreadProcInfo_t *)pParam); + AllocateThreadID(); + delete ((ThreadProcInfo_t *)pParam); + unsigned nRet = (*info.pfnThread)(info.pParam); + FreeThreadID(); + return ( void * ) (uintp) nRet; +} +#endif + + + +#if defined( _PS3 ) + +/******************************************************************************* +* Thread Local Storage globals and functions +*******************************************************************************/ +#ifndef _PS3 +__thread void *gTLSValues[ MAX_TLS_VALUES ] = { NULL }; +__thread bool gTLSFlags[ MAX_TLS_VALUES ] = { false }; +__thread bool gbWaitObjectsCreated = false; +__thread sys_semaphore_t gWaitObjectsSemaphore; +#endif // !_PS3 + +static char gThreadName[28] = ""; + +// Simple TLS allocator. Linearly searches for a free slot. +uint32 TlsAlloc() +{ + for ( int i = 0; i < MAX_TLS_VALUES; ++i ) + { + if ( !gTLSFlags[i] ) + { + gTLSFlags[i] = true; + return i; + } + } + +#ifdef _PS3 + DEBUG_ERROR("TlsAlloc(): Out of TLS\n"); +#endif + + return 0xFFFFFFFF; +} + +void TlsFree( uint32 index ) +{ + gTLSValues[ index ] = NULL; + gTLSFlags[ index ] = false; +} + +void *TlsGetValue( uint32 index ) +{ + return gTLSValues[ index ]; +} + +void TlsSetValue( uint32 index, void *pValue ) +{ + gTLSValues[ index ] = pValue; +} +#endif //_PS3 + + + +#ifdef PLATFORM_WINDOWS +class CThreadHandleToIDMap +{ +public: + HANDLE m_hThread; + uint m_ThreadID; + CThreadHandleToIDMap *m_pNext; +}; +static CThreadHandleToIDMap *g_pThreadHandleToIDMaps = NULL; +static CThreadMutex g_ThreadHandleToIDMapMutex; +static volatile int g_nThreadHandleToIDMaps = 0; + +static void AddThreadHandleToIDMap( HANDLE hThread, uint threadID ) +{ + if ( !hThread ) + return; + + // Remember this handle/id combo. + CThreadHandleToIDMap *pMap = new CThreadHandleToIDMap; + pMap->m_hThread = hThread; + pMap->m_ThreadID = threadID; + + // Add it to the global list. + g_ThreadHandleToIDMapMutex.Lock(); + pMap->m_pNext = g_pThreadHandleToIDMaps; + g_pThreadHandleToIDMaps = pMap; + ++g_nThreadHandleToIDMaps; + + g_ThreadHandleToIDMapMutex.Unlock(); + + if ( g_nThreadHandleToIDMaps > 500 ) + Error( "ThreadHandleToIDMap overflow." ); +} + +// This assumes you've got g_ThreadHandleToIDMapMutex locked!! +static bool InternalLookupHandleToThreadIDMap( HANDLE hThread, CThreadHandleToIDMap* &pMap, CThreadHandleToIDMap** &ppPrev ) +{ + ppPrev = &g_pThreadHandleToIDMaps; + for ( pMap=g_pThreadHandleToIDMaps; pMap; pMap=pMap->m_pNext ) + { + if ( pMap->m_hThread == hThread ) + return true; + + ppPrev = &pMap->m_pNext; + } + + return false; +} + +static void RemoveThreadHandleToIDMap( HANDLE hThread ) +{ + if ( !hThread ) + return; + + CThreadHandleToIDMap *pMap, **ppPrev; + + g_ThreadHandleToIDMapMutex.Lock(); + + if ( g_nThreadHandleToIDMaps <= 0 ) + Error( "ThreadHandleToIDMap underflow." ); + + if ( InternalLookupHandleToThreadIDMap( hThread, pMap, ppPrev ) ) + { + *ppPrev = pMap->m_pNext; + delete pMap; + --g_nThreadHandleToIDMaps; + } + + g_ThreadHandleToIDMapMutex.Unlock(); +} + +static uint LookupThreadIDFromHandle( HANDLE hThread ) +{ + if ( hThread == NULL || hThread == GetCurrentThread() ) + return GetCurrentThreadId(); + + float flStartTime = Plat_FloatTime(); + while ( Plat_FloatTime() - flStartTime < 2 ) + { + CThreadHandleToIDMap *pMap, **ppPrev; + + g_ThreadHandleToIDMapMutex.Lock(); + bool bRet = InternalLookupHandleToThreadIDMap( hThread, pMap, ppPrev ); + g_ThreadHandleToIDMapMutex.Unlock(); + + if ( bRet ) + return pMap->m_ThreadID; + + // We should only get here if a thread that is just starting up is currently in AddThreadHandleToIDMap. + // Give up the timeslice and try again. + ThreadSleep( 1 ); + } + + Assert( !"LookupThreadIDFromHandle failed!" ); + Warning( "LookupThreadIDFromHandle couldn't find thread ID for handle." ); + return 0; +} +#endif //--------------------------------------------------------- -ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, ThreadId_t *pID, unsigned stackSize ) +ThreadHandle_t * CreateTestThreads( ThreadFunc_t fnThread, int numThreads, int nProcessorsToDistribute ) { -#ifdef _WIN32 - ThreadId_t idIgnored; - if ( !pID ) - pID = &idIgnored; - HANDLE h = VCRHook_CreateThread(NULL, stackSize, (LPTHREAD_START_ROUTINE)ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ), CREATE_SUSPENDED, pID); - if ( h != INVALID_HANDLE_VALUE ) + ThreadHandle_t *pHandles = (new ThreadHandle_t[numThreads+1]) + 1; + pHandles[-1] = (ThreadHandle_t)INT_TO_POINTER( numThreads ); + for( int i = 0; i < numThreads; ++i ) { - Plat_ApplyHardwareDataBreakpointsToNewThread( *pID ); - ResumeThread( h ); - } - return (ThreadHandle_t)h; -#elif defined(POSIX) - pthread_t tid; + //TestThreads(); + ThreadHandle_t hThread; + const unsigned int nDefaultStackSize = 64 * 1024; // this stack size is used in case stackSize == 0 + hThread = CreateSimpleThread( fnThread, INT_TO_POINTER( i ), nDefaultStackSize ); - // If we need to create threads that are detached right out of the gate, we would need to do something like this: - // pthread_attr_t attr; - // int rc = pthread_attr_init(&attr); - // rc = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - // ... pthread_create( &tid, &attr, ... ) ... - // rc = pthread_attr_destroy(&attr); - // ... pthread_join will now fail - - int ret = pthread_create( &tid, NULL, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ) ); - if ( ret ) - { - // There are only PTHREAD_THREADS_MAX number of threads, and we're probably leaking handles if ret == EAGAIN here? - Error( "CreateSimpleThread: pthread_create failed. Someone not calling pthread_detach() or pthread_join. Ret:%d\n", ret ); + if ( nProcessorsToDistribute ) + { + int32 mask = 1 << (i % nProcessorsToDistribute); + ThreadSetAffinity( hThread, mask ); + } + +/* + ThreadProcInfoUnion_t info; + info.val.pfnThread = fnThread; + info.val.pParam = (void*)(i); + if ( int nError = sys_ppu_thread_create( &hThread, ThreadProcConvertUnion, info.val64, 1001, nDefaultStackSize, SYS_PPU_THREAD_CREATE_JOINABLE, "SimpleThread" ) != CELL_OK ) + { + printf( "PROBLEM!\n" ); + Error( "Cannot create thread, error %d\n", nError ); + return 0; + } +*/ + //ThreadHandle_t hThread = CreateSimpleThread( fnThread, (void*)i ); + pHandles[i] = hThread; } - if ( pID ) - *pID = (ThreadId_t)tid; - Plat_ApplyHardwareDataBreakpointsToNewThread( (long unsigned int)tid ); - return (ThreadHandle_t)tid; -#endif +// printf("Finishinged CreateTestThreads(%p,%d)\n", (void*)fnThread, numThreads ); + return pHandles; } +void JoinTestThreads( ThreadHandle_t *pHandles ) +{ + int nCount = POINTER_TO_INT( (uintp)pHandles[-1] ); +// printf("Joining test threads @%p[%d]:\n", pHandles, nCount ); +// for( int i = 0; i < nCount; ++i ) +// { +// printf(" %p,\n", (void*)pHandles[i] ); +// } + for( int i = 0; i < nCount; ++i ) + { +// printf( "Joining %p", (void*) pHandles[i] ); +// if( !i ) sys_timer_usleep(100000); + ThreadJoin( pHandles[i] ); + ReleaseThreadHandle( pHandles[i] ); + } + delete[]( pHandles - 1 ); +} + + + ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, unsigned stackSize ) { - return CreateSimpleThread( pfnThread, pParam, NULL, stackSize ); -} - -PLATFORM_INTERFACE void ThreadDetach( ThreadHandle_t hThread ) -{ -#if defined( POSIX ) - // The resources of this thread will be freed immediately when it terminates, - // instead of waiting for another thread to perform PTHREAD_JOIN. - pthread_t tid = ( pthread_t )hThread; - - pthread_detach( tid ); +#ifdef PLATFORM_WINDOWS + DWORD threadID; + HANDLE hThread = (HANDLE)CreateThread( NULL, stackSize, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ), stackSize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0, &threadID ); + AddThreadHandleToIDMap( hThread, threadID ); + return (ThreadHandle_t)hThread; +#elif PLATFORM_PS3 + //TestThreads(); + ThreadHandle_t th; + ThreadProcInfoUnion_t info; + info.val.pfnThread = pfnThread; + info.val.pParam = pParam; + const unsigned int nDefaultStackSize = 64 * 1024; // this stack size is used in case stackSize == 0 + if ( sys_ppu_thread_create( &th, ThreadProcConvertUnion, info.val64, 1001, stackSize ? stackSize : nDefaultStackSize, SYS_PPU_THREAD_CREATE_JOINABLE, "SimpleThread" ) != CELL_OK ) + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", errno ); + return 0; + } + return th; +#elif PLATFORM_POSIX + pthread_t tid; + pthread_create( &tid, NULL, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ) ); + return ( ThreadHandle_t ) tid; +#else + Assert( 0 ); + DebuggerBreak(); + return 0; #endif } +ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, ThreadId_t *pID, unsigned stackSize ) +{ +#ifdef PLATFORM_WINDOWS + DWORD threadID; + HANDLE hThread = (HANDLE)CreateThread( NULL, stackSize, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ), stackSize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0, &threadID ); + if( pID ) + *pID = (ThreadId_t)threadID; + AddThreadHandleToIDMap( hThread, threadID ); + return (ThreadHandle_t)hThread; +#elif PLATFORM_POSIX + pthread_t tid; + pthread_create( &tid, NULL, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ) ); + if( pID ) + *pID = (ThreadId_t)tid; + return ( ThreadHandle_t ) tid; +#else + Assert( 0 ); + DebuggerBreak(); + return 0; +#endif +} + + bool ReleaseThreadHandle( ThreadHandle_t hThread ) { #ifdef _WIN32 - return ( CloseHandle( hThread ) != 0 ); + bool bRetVal = ( CloseHandle( hThread ) != 0 ); + RemoveThreadHandleToIDMap( (HANDLE)hThread ); + return bRetVal; #else return true; #endif @@ -199,7 +494,7 @@ void ThreadSleep(unsigned nMilliseconds) { #ifdef _WIN32 -#ifdef IS_WINDOWS_PC +#ifdef PLATFORM_WINDOWS_PC static bool bInitialized = false; if ( !bInitialized ) { @@ -210,14 +505,42 @@ void ThreadSleep(unsigned nMilliseconds) // rate. timeBeginPeriod( 1 ); } -#endif // IS_WINDOWS_PC +#endif Sleep( nMilliseconds ); +#elif PLATFORM_PS3 + if( nMilliseconds == 0 ) + { + // sys_ppu_thread_yield doesn't seem to function properly, so sleep instead. +// sys_timer_usleep( 60 ); + sys_ppu_thread_yield(); + } + else + { + sys_timer_usleep( nMilliseconds * 1000 ); + } #elif defined(POSIX) usleep( nMilliseconds * 1000 ); #endif } +//----------------------------------------------------------------------------- +void ThreadNanoSleep(unsigned ns) +{ +#ifdef _WIN32 + // ceil + Sleep( ( ns + 999 ) / 1000 ); +#elif PLATFORM_PS3 + sys_timer_usleep( ns ); +#elif defined(POSIX) + struct timespec tm; + tm.tv_sec = 0; + tm.tv_nsec = ns; + nanosleep( &tm, NULL ); +#endif +} + + //----------------------------------------------------------------------------- #ifndef ThreadGetCurrentId @@ -225,8 +548,16 @@ ThreadId_t ThreadGetCurrentId() { #ifdef _WIN32 return GetCurrentThreadId(); +#elif defined( _PS3 ) + sys_ppu_thread_t th = 0; + sys_ppu_thread_get_id( &th ); + return th; #elif defined(POSIX) return (ThreadId_t)pthread_self(); +#else + Assert(0); + DebuggerBreak(); + return 0; #endif } #endif @@ -236,8 +567,16 @@ ThreadHandle_t ThreadGetCurrentHandle() { #ifdef _WIN32 return (ThreadHandle_t)GetCurrentThread(); +#elif defined( _PS3 ) + sys_ppu_thread_t th = 0; + sys_ppu_thread_get_id( &th ); + return th; #elif defined(POSIX) return (ThreadHandle_t)pthread_self(); +#else + Assert(0); + DebuggerBreak(); + return 0; #endif } @@ -261,24 +600,15 @@ bool ThreadIsThreadIdRunning( ThreadId_t uThreadId ) } return bRunning; #elif defined( _PS3 ) - + // will return CELL_OK for zombie threads int priority; return (sys_ppu_thread_get_priority( uThreadId, &priority ) == CELL_OK ); #elif defined(POSIX) - pthread_t thread = OS_TO_PTHREAD(uThreadId); - if ( thread ) - { - int iResult = pthread_kill( thread, 0 ); - if ( iResult == 0 ) - return true; - } - else - { - // We really ought not to be passing NULL in to here - AssertMsg( false, "ThreadIsThreadIdRunning received a null thread ID" ); - } + int iResult = pthread_kill( OS_TO_PTHREAD(uThreadId), 0 ); + if ( iResult == 0 ) + return true; return false; #endif @@ -295,11 +625,12 @@ int ThreadGetPriority( ThreadHandle_t hThread ) #ifdef _WIN32 return ::GetThreadPriority( (HANDLE)hThread ); +#elif defined( _PS3 ) + int iPri = 0; + sys_ppu_thread_get_priority( hThread, &iPri ); + return iPri; #else - struct sched_param thread_param; - int policy; - pthread_getschedparam( (pthread_t)hThread, &policy, &thread_param ); - return thread_param.sched_priority; + return 0; #endif } @@ -314,10 +645,13 @@ bool ThreadSetPriority( ThreadHandle_t hThread, int priority ) #ifdef _WIN32 return ( SetThreadPriority(hThread, priority) != 0 ); +#elif defined( _PS3 ) + int retval = sys_ppu_thread_set_priority( hThread, priority ); + return retval >= CELL_OK; #elif defined(POSIX) struct sched_param thread_param; thread_param.sched_priority = priority; - pthread_setschedparam( (pthread_t)hThread, SCHED_OTHER, &thread_param ); + //pthread_setschedparam( (pthread_t ) hThread, SCHED_RR, &thread_param ); return true; #endif } @@ -346,32 +680,12 @@ void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinityMask ) //----------------------------------------------------------------------------- +#ifndef _X360 ThreadId_t InitMainThread() { -#ifndef LINUX - // Skip doing the setname on Linux for the main thread. Here is why... - - // From Pierre-Loup e-mail about why pthread_setname_np() on the main thread - // in Linux will cause some tools to display "MainThrd" as the executable name: - // - // You have two things in procfs, comm and cmdline. Each of the threads have - // a different `comm`, which is the value you set through pthread_setname_np - // or prctl(PR_SET_NAME). Top can either display cmdline or comm; it - // switched to display comm by default; htop still displays cmdline by - // default. Top -c will output cmdline rather than comm. - // - // If you press 'H' while top is running it will display each thread as a - // separate process, so you will have different entries for MainThrd, - // MatQueue0, etc with their own CPU usage. But when that mode isn't enabled - // it just displays the 'comm' name from the first thread. ThreadSetDebugName( "MainThrd" ); -#endif -#ifdef _WIN32 return ThreadGetCurrentId(); -#elif defined(POSIX) - return (ThreadId_t)pthread_self(); -#endif } ThreadId_t g_ThreadMainThreadID = InitMainThread(); @@ -381,24 +695,33 @@ bool ThreadInMainThread() return ( ThreadGetCurrentId() == g_ThreadMainThreadID ); } -//----------------------------------------------------------------------------- void DeclareCurrentThreadIsMainThread() { g_ThreadMainThreadID = ThreadGetCurrentId(); } +#else +byte *InitMainThread() +{ + byte b; + + return AlignValue( &b, 64*1024 ); +} +#define STACK_SIZE_360 327680 +byte *g_pBaseMainStack = InitMainThread(); +byte *g_pLimitMainStack = InitMainThread() - STACK_SIZE_360; +#endif + +//----------------------------------------------------------------------------- bool ThreadJoin( ThreadHandle_t hThread, unsigned timeout ) { - // You should really never be calling this with a NULL thread handle. If you - // are then that probably implies a race condition or threading misunderstanding. - Assert( hThread ); if ( !hThread ) { return false; } #ifdef _WIN32 - DWORD dwWait = VCRHook_WaitForSingleObject((HANDLE)hThread, timeout); + DWORD dwWait = WaitForSingleObject( (HANDLE)hThread, timeout ); if ( dwWait == WAIT_TIMEOUT) return false; if ( dwWait != WAIT_OBJECT_0 && ( dwWait != WAIT_FAILED && GetLastError() != 0 ) ) @@ -406,29 +729,24 @@ bool ThreadJoin( ThreadHandle_t hThread, unsigned timeout ) Assert( 0 ); return false; } +#elif defined( _PS3 ) + uint64 uiExitCode = 0; + int retval = sys_ppu_thread_join( hThread, &uiExitCode ); + return ( retval >= CELL_OK ); #elif defined(POSIX) if ( pthread_join( (pthread_t)hThread, NULL ) != 0 ) return false; +#else + Assert(0); + DebuggerBreak(); #endif return true; } -#ifdef RAD_TELEMETRY_ENABLED -void TelemetryThreadSetDebugName( ThreadId_t id, const char *pszName ); -#endif - //----------------------------------------------------------------------------- - -void ThreadSetDebugName( ThreadId_t id, const char *pszName ) +void ThreadSetDebugName( ThreadHandle_t hThread, const char *pszName ) { - if( !pszName ) - return; - -#ifdef RAD_TELEMETRY_ENABLED - TelemetryThreadSetDebugName( id, pszName ); -#endif - -#ifdef _WIN32 +#ifdef WIN32 if ( Plat_IsInDebugSession() ) { #define MS_VC_EXCEPTION 0x406d1388 @@ -444,59 +762,25 @@ void ThreadSetDebugName( ThreadId_t id, const char *pszName ) THREADNAME_INFO info; info.dwType = 0x1000; info.szName = pszName; - info.dwThreadID = id; - info.dwFlags = 0; + info.dwThreadID = LookupThreadIDFromHandle( hThread ); - __try + if ( info.dwThreadID != 0 ) { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info); - } - __except (EXCEPTION_CONTINUE_EXECUTION) - { - } - } -#elif defined( _LINUX ) - // As of glibc v2.12, we can use pthread_setname_np. - typedef int (pthread_setname_np_func)(pthread_t, const char *); - static pthread_setname_np_func *s_pthread_setname_np_func = (pthread_setname_np_func *)dlsym(RTLD_DEFAULT, "pthread_setname_np"); + info.dwFlags = 0; - if ( s_pthread_setname_np_func ) - { - if ( id == (uint32)-1 ) - id = pthread_self(); - - /* - pthread_setname_np() in phthread_setname.c has the following code: - - #define TASK_COMM_LEN 16 - size_t name_len = strlen (name); - if (name_len >= TASK_COMM_LEN) - return ERANGE; - - So we need to truncate the threadname to 16 or the call will just fail. - */ - char szThreadName[ 16 ]; - strncpy( szThreadName, pszName, ARRAYSIZE( szThreadName ) ); - szThreadName[ ARRAYSIZE( szThreadName ) - 1 ] = 0; - (*s_pthread_setname_np_func)( id, szThreadName ); + __try + { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info); + } + __except (EXCEPTION_CONTINUE_EXECUTION) + { + } + } } #endif } -//----------------------------------------------------------------------------- - -#ifdef _WIN32 -ASSERT_INVARIANT( TW_FAILED == WAIT_FAILED ); -ASSERT_INVARIANT( TW_TIMEOUT == WAIT_TIMEOUT ); -ASSERT_INVARIANT( WAIT_OBJECT_0 == 0 ); - -int ThreadWaitForObjects( int nEvents, const HANDLE *pHandles, bool bWaitAll, unsigned timeout ) -{ - return VCRHook_WaitForMultipleObjects( nEvents, pHandles, bWaitAll, timeout ); -} -#endif - //----------------------------------------------------------------------------- // Used to thread LoadLibrary on the 360 @@ -515,15 +799,50 @@ PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc() //----------------------------------------------------------------------------- // +// CThreadSyncObject (note nothing uses this directly (I think) ) +// //----------------------------------------------------------------------------- + +#ifdef _PS3 +uint32_t CThreadSyncObject::m_bstaticMutexInitialized = false; +uint32_t CThreadSyncObject::m_bstaticMutexInitializing = false; +sys_lwmutex_t CThreadSyncObject::m_staticMutex; +#endif + + CThreadSyncObject::CThreadSyncObject() #ifdef _WIN32 : m_hSyncObject( NULL ), m_bCreatedHandle(false) -#elif defined(POSIX) +#elif defined(POSIX) && !defined(PLATFORM_PS3) : m_bInitalized( false ) #endif { +#ifdef _PS3 + //Do we nee to initialise the staticMutex? + if (m_bstaticMutexInitialized) return; + + //If we are the first thread then create the mutex + if ( cellAtomicCompareAndSwap32(&m_bstaticMutexInitializing, false, true) == false ) + { + sys_lwmutex_attribute_t mutexAttr; + sys_lwmutex_attribute_initialize( mutexAttr ); + mutexAttr.attr_recursive = SYS_SYNC_RECURSIVE; + int err = sys_lwmutex_create( &m_staticMutex, &mutexAttr ); + Assert(err == CELL_OK); + m_bstaticMutexInitialized = true; + } + else + { + //Another thread is already in the process of initialising the mutex, wait for it + while ( !m_bstaticMutexInitialized ) + { + // sys_ppu_thread_yield doesn't seem to function properly, so sleep instead. +// sys_timer_usleep( 60 ); + sys_ppu_thread_yield(); + } + } +#endif } //--------------------------------------------------------- @@ -538,12 +857,12 @@ CThreadSyncObject::~CThreadSyncObject() Assert( 0 ); } } -#elif defined(POSIX) +#elif defined(POSIX) && !defined( PLATFORM_PS3 ) if ( m_bInitalized ) { - pthread_cond_destroy( &m_Condition ); + pthread_cond_destroy( &m_Condition ); pthread_mutex_destroy( &m_Mutex ); - m_bInitalized = false; + m_bInitalized = false; } #endif } @@ -552,7 +871,9 @@ CThreadSyncObject::~CThreadSyncObject() bool CThreadSyncObject::operator!() const { -#ifdef _WIN32 +#if PLATFORM_PS3 + return m_bstaticMutexInitialized; +#elif defined( _WIN32 ) return !m_hSyncObject; #elif defined(POSIX) return !m_bInitalized; @@ -564,7 +885,9 @@ bool CThreadSyncObject::operator!() const void CThreadSyncObject::AssertUseable() { #ifdef THREADS_DEBUG -#ifdef _WIN32 +#if PLATFORM_PS3 + AssertMsg( m_bstaticMutexInitialized, "Thread synchronization object is unuseable" ); +#elif defined( _WIN32 ) AssertMsg( m_hSyncObject, "Thread synchronization object is unuseable" ); #elif defined(POSIX) AssertMsg( m_bInitalized, "Thread synchronization object is unuseable" ); @@ -574,14 +897,15 @@ void CThreadSyncObject::AssertUseable() //--------------------------------------------------------- +#if defined(_WIN32) || ( defined(POSIX) && !defined( _PS3 ) ) bool CThreadSyncObject::Wait( uint32 dwTimeout ) { #ifdef THREADS_DEBUG AssertUseable(); #endif #ifdef _WIN32 - return ( VCRHook_WaitForSingleObject( m_hSyncObject, dwTimeout ) == WAIT_OBJECT_0 ); -#elif defined(POSIX) + return ( WaitForSingleObject( m_hSyncObject, dwTimeout ) == WAIT_OBJECT_0 ); +#elif defined( POSIX ) && !defined( PLATFORM_PS3 ) pthread_mutex_lock( &m_Mutex ); bool bRet = false; if ( m_cSet > 0 ) @@ -634,6 +958,147 @@ bool CThreadSyncObject::Wait( uint32 dwTimeout ) return bRet; #endif } +#endif + +uint32 CThreadSyncObject::WaitForMultiple( int nObjects, CThreadSyncObject **ppObjects, bool bWaitAll, uint32 dwTimeout ) +{ +#if defined( _WIN32 ) + + CThreadSyncObject *pHandles = (CThreadSyncObject*)stackalloc( sizeof(CThreadSyncObject) * nObjects ); + for ( int i=0; i < nObjects; i++ ) + { + pHandles[i].m_hSyncObject = ppObjects[i]->m_hSyncObject; + } + + return WaitForMultiple( nObjects, pHandles, bWaitAll, dwTimeout ); + +#else + + // TODO: Need a more efficient implementation of this. + uint32 dwStartTime = 0; + + if ( dwTimeout != TT_INFINITE ) + dwStartTime = Plat_MSTime(); + + // If bWaitAll = true, then we need to track which ones were triggered. + char *pWasTriggered = NULL; + int nTriggered = 0; + if ( bWaitAll ) + { + pWasTriggered = (char*)stackalloc( nObjects ); + memset( pWasTriggered, 0, nObjects ); + } + + while ( 1 ) + { + for ( int i=0; i < nObjects; i++ ) + { + if ( bWaitAll && pWasTriggered[i] ) + continue; + +#ifdef _PS3 + Assert( !"Not implemented!" ); + if ( false ) +#else + if ( ppObjects[i]->Wait( 0 ) ) +#endif + { + ++nTriggered; + if ( bWaitAll ) + { + if ( nTriggered == nObjects ) + return 0; + else + pWasTriggered[i] = 1; + } + else + { + return i; + } + } + } + + // Timeout? + if ( dwTimeout != TT_INFINITE ) + { + if ( Plat_MSTime() - dwStartTime >= dwTimeout ) + return TW_TIMEOUT; + } + + ThreadSleep( 0 ); + } + +#endif +} + +uint32 CThreadSyncObject::WaitForMultiple( int nObjects, CThreadSyncObject *pObjects, bool bWaitAll, uint32 dwTimeout ) +{ +#if defined(_WIN32 ) + + HANDLE *pHandles = (HANDLE*)stackalloc( sizeof(HANDLE) * nObjects ); + for ( int i=0; i < nObjects; i++ ) + { + pHandles[i] = pObjects[i].m_hSyncObject; + } + + DWORD ret = WaitForMultipleObjects( nObjects, pHandles, bWaitAll, dwTimeout ); + if ( ret == WAIT_TIMEOUT ) + return TW_TIMEOUT; + else if ( ret >= WAIT_OBJECT_0 && (ret-WAIT_OBJECT_0) < (uint32)nObjects ) + return (int)(ret - WAIT_OBJECT_0); + else if ( ret >= WAIT_ABANDONED_0 && (ret - WAIT_ABANDONED_0) < (uint32)nObjects ) + Error( "Unhandled WAIT_ABANDONED in WaitForMultipleObjects" ); + else if ( ret == WAIT_FAILED ) + return TW_FAILED; + else + Error( "Unknown return value (%lu) from WaitForMultipleObjects", ret ); + + // We'll never get here.. + return 0; + +#else + + CThreadSyncObject **ppObjects = (CThreadSyncObject**)stackalloc( sizeof( CThreadSyncObject* ) * nObjects ); + for ( int i=0; i < nObjects; i++ ) + { + ppObjects[i] = &pObjects[i]; + } + + return WaitForMultiple( nObjects, ppObjects, bWaitAll, dwTimeout ); + +#endif +} + +// To implement these, I need to check that casts are safe +uint32 CThreadEvent::WaitForMultiple( int nObjects, CThreadEvent *pObjects, bool bWaitAll, uint32 dwTimeout ) +{ + // If data ever gets added to CThreadEvent, then we need a different implementation. +#ifdef _PS3 + CThreadEvent **ppObjects = (CThreadEvent**)stackalloc( sizeof( CThreadEvent* ) * nObjects ); + for ( int i=0; i < nObjects; i++ ) + { + ppObjects[i] = &pObjects[i]; + } + return WaitForMultipleObjects( nObjects, ppObjects, bWaitAll, dwTimeout ); +#else + COMPILE_TIME_ASSERT( sizeof( CThreadSyncObject ) == 0 || sizeof( CThreadEvent ) == sizeof( CThreadSyncObject ) ); + return CThreadSyncObject::WaitForMultiple( nObjects, (CThreadSyncObject*)pObjects, bWaitAll, dwTimeout ); +#endif +} + + +uint32 CThreadEvent::WaitForMultiple( int nObjects, CThreadEvent **ppObjects, bool bWaitAll, uint32 dwTimeout ) +{ +#ifdef _PS3 + return WaitForMultipleObjects( nObjects, ppObjects, bWaitAll, dwTimeout ); +#else + // If data ever gets added to CThreadEvent, then we need a different implementation. + COMPILE_TIME_ASSERT( sizeof( CThreadSyncObject )== 0 || sizeof( CThreadEvent ) == sizeof( CThreadSyncObject ) ); + return CThreadSyncObject::WaitForMultiple( nObjects, (CThreadSyncObject**)ppObjects, bWaitAll, dwTimeout ); +#endif +} + + //----------------------------------------------------------------------------- // @@ -645,6 +1110,23 @@ CThreadEvent::CThreadEvent( bool bManualReset ) m_hSyncObject = CreateEvent( NULL, bManualReset, FALSE, NULL ); m_bCreatedHandle = true; AssertMsg1(m_hSyncObject, "Failed to create event (error 0x%x)", GetLastError() ); +#elif defined( _PS3 ) + + m_bManualReset = bManualReset; + m_bSet = 0; + m_bInitalized = false; + m_numWaitingThread = 0; + + // set up linked list of wait objects + + memset(&m_waitObjects[0], 0, sizeof(m_waitObjects)); + m_pWaitObjectsList = &m_waitObjects[0]; + m_pWaitObjectsPool = &m_waitObjects[1]; + + for (int i = 2; i < CTHREADEVENT_MAX_WAITING_THREADS + 2; i++) + { + LLLinkNode(m_pWaitObjectsPool, &m_waitObjects[i]); + } #elif defined( POSIX ) pthread_mutexattr_t Attr; pthread_mutexattr_init( &Attr ); @@ -660,14 +1142,146 @@ CThreadEvent::CThreadEvent( bool bManualReset ) #endif } -#ifdef _WIN32 -CThreadEvent::CThreadEvent( HANDLE hHandle ) + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +#ifdef _PS3 + +// +// linked list functionality +// + +//----------------------------------------------------------------------------- +// Purpose: Linked list implementation +//----------------------------------------------------------------------------- + +CThreadEventWaitObject* CThreadEvent::LLUnlinkNode(CThreadEventWaitObject *node) { - m_hSyncObject = hHandle; - m_bCreatedHandle = false; - AssertMsg(m_hSyncObject, "Null event passed into constructor" ); + // Note: if you have a null-access crash here, it may mean that CTHREADEVENT_MAX_WAITING_THREADS is not high enough + // and the linked list pool is simply exhausted + node->m_pPrev->m_pNext = node->m_pNext; + if (node->m_pNext) node->m_pNext->m_pPrev = node->m_pPrev; + node->m_pNext = node->m_pPrev = NULL; + + return node; } -#endif + +CThreadEventWaitObject* CThreadEvent::LLLinkNode(CThreadEventWaitObject* list, CThreadEventWaitObject *node) +{ + node->m_pNext = list->m_pNext; + if (node->m_pNext) + { + node->m_pNext->m_pPrev = node; + } + + list->m_pNext = node; + node->m_pPrev = list; + + return node; +} + +//----------------------------------------------------------------------------- +// Helper function to atomically write index into destination and set semaphore +// This is used by WaitForMultipleObjects(WAIT_ANY) because once the semaphore +// is set, the waiting thread also needs to know which event triggered it +// We do NOT need this to be atomic because if a number of events fire it doesn't +// matter which one of these we pick +//----------------------------------------------------------------------------- +void CThreadEventWaitObject::Set() +{ + *m_pFlag = m_index; + sys_semaphore_post(*m_pSemaphore, 1); +} + +// +// CThreadEvent::RegisterWaitingThread +// +void CThreadEvent::RegisterWaitingThread(sys_semaphore_t *pSemaphore, int index, int *flag) +{ + sys_lwmutex_lock(&m_staticMutex, 0); + + // if we are already set, then signal this semaphore + if (m_bSet) + { + CThreadEventWaitObject waitObject; + waitObject.Init(pSemaphore, index, flag); + waitObject.Set(); + + if (!m_bManualReset) + { + m_bSet = false; + } + } + else + { + if (!m_pWaitObjectsPool->m_pNext) + { + DEBUG_ERROR("CThreadEvent: Ran out of events; cannot register waiting thread\n"); + } + + // add this semaphore to linked list - can be added more than once it doesn't matter + + CThreadEventWaitObject *pWaitObject = LLUnlinkNode(m_pWaitObjectsPool->m_pNext); + + pWaitObject->Init(pSemaphore, index, flag); + + LLLinkNode(m_pWaitObjectsList, pWaitObject); + } + + sys_lwmutex_unlock(&m_staticMutex); +} + +// +// CThreadEvent::UnregisterWaitingThread +// +void CThreadEvent::UnregisterWaitingThread(sys_semaphore_t *pSemaphore) +{ + // remove all instances of this semaphore from linked list + + sys_lwmutex_lock(&m_staticMutex, 0); + + CThreadEventWaitObject *pWaitObject = m_pWaitObjectsList->m_pNext; + + while (pWaitObject) + { + CThreadEventWaitObject *pNext = pWaitObject->m_pNext; + + if (pWaitObject->m_pSemaphore == pSemaphore) + { + LLUnlinkNode(pWaitObject); + LLLinkNode(m_pWaitObjectsPool, pWaitObject); + } + + pWaitObject = pNext; + } + + sys_lwmutex_unlock(&m_staticMutex); +} + +#endif // _PS3 + + +#ifdef PLATFORM_WINDOWS + CThreadEvent::CThreadEvent( const char *name, bool initialState, bool bManualReset ) + { + m_hSyncObject = CreateEvent( NULL, bManualReset, (BOOL) initialState, name ); + AssertMsg1( m_hSyncObject, "Failed to create event (error 0x%x)", GetLastError() ); + } + + + NamedEventResult_t CThreadEvent::CheckNamedEvent( const char *name, uint32 dwTimeout ) + { + HANDLE eHandle = OpenEvent( SYNCHRONIZE, FALSE, name ); + + if ( eHandle == NULL ) return TT_EventDoesntExist; + + DWORD result = WaitForSingleObject( eHandle, dwTimeout ); + + return ( result == WAIT_OBJECT_0 ) ? TT_EventSignaled : TT_EventNotSignaled; + } +#endif //----------------------------------------------------------------------------- // @@ -678,17 +1292,92 @@ CThreadEvent::CThreadEvent( HANDLE hHandle ) bool CThreadEvent::Set() { +////////////////////////////////////////////////////////////// +#ifndef NEW_WAIT_FOR_MULTIPLE_OBJECTS +////////////////////////////////////////////////////////////// AssertUseable(); #ifdef _WIN32 return ( SetEvent( m_hSyncObject ) != 0 ); +#elif defined( _PS3 ) + + sys_lwmutex_lock(&m_staticMutex, 0); + + if (m_bManualReset) + { + //Mark event as set + m_bSet = true; + + //If any threads are already waiting then signal them to run + if (m_bInitalized) + { + int err = sys_semaphore_post( m_Semaphore, m_numWaitingThread); + Assert(err == CELL_OK); + } + } + else + { + //If any threads are already waiting then signal ONE to run, else signal next to run + + if (m_numWaitingThread>0) + { + int err = sys_semaphore_post( m_Semaphore, 1); + Assert(err == CELL_OK); + } + else + { + m_bSet=true; + } + } + + sys_lwmutex_unlock(&m_staticMutex); + + return true; + + #elif defined(POSIX) - pthread_mutex_lock( &m_Mutex ); - m_cSet = 1; + pthread_mutex_lock( &m_Mutex ); + m_cSet = 1; m_bWakeForEvent = true; int ret = pthread_cond_signal( &m_Condition ); - pthread_mutex_unlock( &m_Mutex ); - return ret == 0; + pthread_mutex_unlock( &m_Mutex ); + return ret == 0; #endif + + +////////////////////////////////////////////////////////////// +#else // NEW_WAIT_FOR_MULTIPLE_OBJECTS +////////////////////////////////////////////////////////////// + + sys_lwmutex_lock(&m_staticMutex, 0); + + //Mark event as set + m_bSet = true; + + // signal registered semaphores + while (m_pWaitObjectsList->m_pNext) + { + CThreadEventWaitObject *pWaitObject = LLUnlinkNode(m_pWaitObjectsList->m_pNext); + + pWaitObject->Set(); + + LLLinkNode(m_pWaitObjectsPool, pWaitObject); + + g_pfnPopMarker(); + + if (!m_bManualReset) + { + m_bSet = false; + break; + } + } + + sys_lwmutex_unlock(&m_staticMutex); + + return true; + +////////////////////////////////////////////////////////////// +#endif // NEW_WAIT_FOR_MULTIPLE_OBJECTS +////////////////////////////////////////////////////////////// } //--------------------------------------------------------- @@ -700,6 +1389,12 @@ bool CThreadEvent::Reset() #endif #ifdef _WIN32 return ( ResetEvent( m_hSyncObject ) != 0 ); +#elif defined( _PS3 ) + + //Just mark us as no longer signaled + m_bSet = 0; + + return true; #elif defined(POSIX) pthread_mutex_lock( &m_Mutex ); m_cSet = 0; @@ -713,6 +1408,9 @@ bool CThreadEvent::Reset() bool CThreadEvent::Check() { + #ifdef _PS3 + return m_bSet; // Please, use for debugging only! + #endif #ifdef THREADS_DEBUG AssertUseable(); #endif @@ -723,7 +1421,79 @@ bool CThreadEvent::Check() bool CThreadEvent::Wait( uint32 dwTimeout ) { +////////////////////////////////////////////////////////////// +#ifndef NEW_WAIT_FOR_MULTIPLE_OBJECTS +////////////////////////////////////////////////////////////// + + +#if defined( _WIN32 ) || ( defined( POSIX ) && !defined( _PS3 ) ) return CThreadSyncObject::Wait( dwTimeout ); +#elif defined( _PS3 ) + + { + + if (dwTimeout == 0) + { + //If timeout is 0 then just test it now (and reset it if manual ) + if (m_bSet) + { + if ( !m_bManualReset ) m_bSet=false; + return true; + } + return false; + } + + if (!AddWaitingThread()) + { + //Waiting thread NOT added because m_bSet was already set + if ( !m_bManualReset ) m_bSet=false; + return true; + } + + uint32 timeout; + int countTimeout = 0; + int ret = ETIMEDOUT; + while ( timeout=MIN(1, dwTimeout) ) + { + // on the PS3, "infinite timeout" is specified by zero, not + // 0xFFFFFFFF, so we need to perform that ternary here. +//#error Untested code: + ret = sys_semaphore_wait( m_Semaphore, timeout == TT_INFINITE ? 0 : timeout * 1000 ); + Assert( (ret == CELL_OK) || (ret == ETIMEDOUT) ); + + if ( ret == CELL_OK ) + break; + + dwTimeout -= timeout; + countTimeout++; + if (countTimeout > 30) + { + // printf("WARNING: possible deadlock in CThreadEvent::Wait() !!!\n"); + } + } + + RemoveWaitingThread(); + + if ( !m_bManualReset ) m_bSet=false; + + return ret == CELL_OK; + } + +#endif + +////////////////////////////////////////////////////////////// +#else // NEW_WAIT_FOR_MULTIPLE_OBJECTS +////////////////////////////////////////////////////////////// + + + CThreadEvent *pThis = this; + DWORD res = WaitForMultipleObjects(1, &pThis, true, dwTimeout); + return res == WAIT_OBJECT_0; + + +////////////////////////////////////////////////////////////// +#endif // NEW_WAIT_FOR_MULTIPLE_OBJECTS +////////////////////////////////////////////////////////////// } #ifdef _WIN32 @@ -735,8 +1505,9 @@ bool CThreadEvent::Wait( uint32 dwTimeout ) // //----------------------------------------------------------------------------- -CThreadSemaphore::CThreadSemaphore( long initialValue, long maxValue ) +CThreadSemaphore::CThreadSemaphore( int32 initialValue, int32 maxValue ) { +#ifdef _WIN32 if ( maxValue ) { AssertMsg( maxValue > 0, "Invalid max value for semaphore" ); @@ -750,16 +1521,135 @@ CThreadSemaphore::CThreadSemaphore( long initialValue, long maxValue ) { m_hSyncObject = NULL; } +#elif defined( _PS3 ) + if ( maxValue ) + { + m_sema_max_val = maxValue; + m_semaCount = initialValue; + } +#endif } + +#ifdef _PS3 +//--------------------------------------------------------- + +bool CThreadSemaphore::AddWaitingThread() +{ + bool result; + + sys_lwmutex_lock(&m_staticMutex, 0); + + if (cellAtomicTestAndDecr32(&m_semaCount) > 0) + { + result=false; + } + else + { + result=true; + m_numWaitingThread++; + + if ( m_numWaitingThread == 1 ) + { + sys_semaphore_attribute_t semAttr; + sys_semaphore_attribute_initialize( semAttr ); + Assert(m_semaCount == 0); + int err = sys_semaphore_create( &m_Semaphore, &semAttr, 0, m_sema_max_val ); + Assert( err == CELL_OK ); + m_bInitalized = true; + } + } + + sys_lwmutex_unlock(&m_staticMutex); + return result; +} + +void CThreadSemaphore::RemoveWaitingThread() +{ + sys_lwmutex_lock(&m_staticMutex, 0); + + m_numWaitingThread--; + + if ( m_numWaitingThread == 0) + { + int err = sys_semaphore_destroy( m_Semaphore ); + Assert( err == CELL_OK ); + m_bInitalized = false; + } + + sys_lwmutex_unlock(&m_staticMutex); +} + +#endif + +#ifdef _PS3 + +bool CThreadSemaphore::Wait( uint32 dwTimeout ) +{ +#ifdef THREADS_DEBUG + AssertUseable(); +#endif + + +#ifndef NO_THREAD_SYNC + if (!AddWaitingThread()) + { + //Waiting thread NOT added because semaphore was already in a signaled state + return true; + } + + int ret = sys_semaphore_wait( m_Semaphore, dwTimeout == TT_INFINITE ? 0 : dwTimeout * 1000 ); + Assert( (ret == CELL_OK) || (ret == ETIMEDOUT) ); + + RemoveWaitingThread(); + + int old = cellAtomicDecr32(&m_semaCount); + Assert(old>0); +#else + int ret = CELL_OK; +#endif + + // sys_ppu_thread_yield doesn't seem to function properly, so sleep instead. +// sys_timer_usleep( 60 ); + sys_ppu_thread_yield(); + + + + return ret == CELL_OK; +} + +#endif + //--------------------------------------------------------- -bool CThreadSemaphore::Release( long releaseCount, long *pPreviousCount ) +bool CThreadSemaphore::Release( int32 releaseCount, int32 *pPreviousCount ) { #ifdef THRDTOOL_DEBUG AssertUseable(); #endif - return ( ReleaseSemaphore( m_hSyncObject, releaseCount, pPreviousCount ) != 0 ); +#ifdef _WIN32 + return ( ReleaseSemaphore( m_hSyncObject, releaseCount, (LPLONG)pPreviousCount ) != 0 ); +#elif defined( _PS3 ) + +#ifndef NO_THREAD_SYNC + + if (m_bInitalized) + { + sys_semaphore_value_t previousVal; + sys_semaphore_get_value( m_Semaphore, &previousVal ); + + cellAtomicAdd32(&m_semaCount, releaseCount); + + *pPreviousCount = previousVal; + + int err = sys_semaphore_post( m_Semaphore, releaseCount ); + Assert(err == CELL_OK); + } + +#endif + + return true; +#endif } //----------------------------------------------------------------------------- @@ -789,15 +1679,20 @@ bool CThreadFullMutex::Release() // //----------------------------------------------------------------------------- +#if defined( WIN32 ) || defined( _PS3 ) || defined( _OSX ) || ( defined (_LINUX) && !defined(DEDICATED) ) +#if !defined(_PS3) +namespace GenericThreadLocals +{ +#endif CThreadLocalBase::CThreadLocalBase() { -#ifdef _WIN32 +#if defined(_WIN32) || defined(_PS3) m_index = TlsAlloc(); AssertMsg( m_index != 0xFFFFFFFF, "Bad thread local" ); if ( m_index == 0xFFFFFFFF ) Error( "Out of thread local storage!\n" ); #elif defined(POSIX) - if ( pthread_key_create( &m_index, NULL ) != 0 ) + if ( pthread_key_create( (pthread_key_t *)&m_index, NULL ) != 0 ) Error( "Out of thread local storage!\n" ); #endif } @@ -806,7 +1701,7 @@ CThreadLocalBase::CThreadLocalBase() CThreadLocalBase::~CThreadLocalBase() { -#ifdef _WIN32 +#if defined(_WIN32) || defined(_PS3) if ( m_index != 0xFFFFFFFF ) TlsFree( m_index ); m_index = 0xFFFFFFFF; @@ -819,7 +1714,7 @@ CThreadLocalBase::~CThreadLocalBase() void * CThreadLocalBase::Get() const { -#ifdef _WIN32 +#if defined(_WIN32) || defined(_PS3) if ( m_index != 0xFFFFFFFF ) return TlsGetValue( m_index ); AssertMsg( 0, "Bad thread local" ); @@ -834,7 +1729,7 @@ void * CThreadLocalBase::Get() const void CThreadLocalBase::Set( void *value ) { -#ifdef _WIN32 +#if defined(_WIN32) || defined(_PS3) if (m_index != 0xFFFFFFFF) TlsSetValue(m_index, value); else @@ -844,22 +1739,25 @@ void CThreadLocalBase::Set( void *value ) AssertMsg( 0, "Bad thread local" ); #endif } - -//----------------------------------------------------------------------------- - - -//----------------------------------------------------------------------------- - -#ifdef _WIN32 -#ifdef _X360 -#define TO_INTERLOCK_PARAM(p) ((long *)p) -#define TO_INTERLOCK_PTR_PARAM(p) ((void **)p) -#else -#define TO_INTERLOCK_PARAM(p) (p) -#define TO_INTERLOCK_PTR_PARAM(p) (p) +#if !defined(_PS3) +} // namespace GenericThreadLocals #endif +#endif // ( defined(WIN32) ) +//----------------------------------------------------------------------------- -#ifndef USE_INTRINSIC_INTERLOCKED + +//----------------------------------------------------------------------------- + +#ifdef MSVC +//#ifdef _X360 +#define TO_INTERLOCK_PARAM(p) ((volatile long *)p) +#define TO_INTERLOCK_PTR_PARAM(p) ((void **)p) +//#else +//#define TO_INTERLOCK_PARAM(p) (p) +//#define TO_INTERLOCK_PTR_PARAM(p) (p) +//#endif + +#if !defined(USE_INTRINSIC_INTERLOCKED) && !defined(_X360) int32 ThreadInterlockedIncrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); @@ -915,7 +1813,7 @@ bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comper void *ThreadInterlockedExchangePointer( void * volatile *pDest, void *value ) { Assert( (size_t)pDest % 4 == 0 ); - return InterlockedExchangePointer( TO_INTERLOCK_PARAM(pDest), value ); + return InterlockedExchangePointer( TO_INTERLOCK_PTR_PARAM(pDest), value ); } void *ThreadInterlockedCompareExchangePointer( void * volatile *pDest, void *value, void *comperand ) @@ -943,13 +1841,11 @@ bool ThreadInterlockedAssignPointerIf( void * volatile *pDest, void *value, void } #endif +#ifdef COMPILER_MSVC32 int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand ) { Assert( (size_t)pDest % 8 == 0 ); -#if defined(_WIN64) || defined (_X360) - return InterlockedCompareExchange64( pDest, value, comperand ); -#else __asm { lea esi,comperand; @@ -962,14 +1858,16 @@ int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, in mov esi,pDest; lock CMPXCHG8B [esi]; } -#endif } +#endif bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand ) { Assert( (size_t)pDest % 8 == 0 ); -#if defined(PLATFORM_WINDOWS_PC32 ) +#if defined(_X360) || defined(_WIN64) + return ( ThreadInterlockedCompareExchange64( pDest, value, comperand ) == comperand ); +#else __asm { lea esi,comperand; @@ -984,25 +1882,15 @@ bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 compe mov eax,0; setz al; } -#else - return ( ThreadInterlockedCompareExchange64( pDest, value, comperand ) == comperand ); #endif } -#if defined( PLATFORM_64BITS ) - -#if _MSC_VER < 1500 -// This intrinsic isn't supported on VS2005. -extern "C" unsigned char _InterlockedCompareExchange128( int64 volatile * Destination, int64 ExchangeHigh, int64 ExchangeLow, int64 * ComparandResult ); -#endif - +#ifdef _WIN64 bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand ) { - Assert( ( (size_t)pDest % 16 ) == 0 ); - - volatile int64 *pDest64 = ( volatile int64 * )pDest; - int64 *pValue64 = ( int64 * )&value; - int64 *pComperand64 = ( int64 * )&comperand; + DbgAssert( ( (size_t)pDest % 16 ) == 0 ); + // Must copy comperand to stack because the intrinsic uses it as an in/out param + int64 comperandInOut[2] = { comperand.m128i_i64[0], comperand.m128i_i64[1] }; // Description: // The CMPXCHG16B instruction compares the 128-bit value in the RDX:RAX and RCX:RBX registers @@ -1011,120 +1899,50 @@ bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, // Otherwise, the ZF flag is cleared, and the memory value is copied to RDX:RAX. // _InterlockedCompareExchange128: http://msdn.microsoft.com/en-us/library/bb514094.aspx - return _InterlockedCompareExchange128( pDest64, pValue64[1], pValue64[0], pComperand64 ) == 1; -} - -#endif // PLATFORM_64BITS - -int64 ThreadInterlockedIncrement64( int64 volatile *pDest ) -{ - Assert( (size_t)pDest % 8 == 0 ); - - int64 Old; - - do - { - Old = *pDest; - } while (ThreadInterlockedCompareExchange64(pDest, Old + 1, Old) != Old); - - return Old + 1; -} - -int64 ThreadInterlockedDecrement64( int64 volatile *pDest ) -{ - Assert( (size_t)pDest % 8 == 0 ); - int64 Old; - - do - { - Old = *pDest; - } while (ThreadInterlockedCompareExchange64(pDest, Old - 1, Old) != Old); - - return Old - 1; -} - -int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value ) -{ - Assert( (size_t)pDest % 8 == 0 ); - int64 Old; - - do - { - Old = *pDest; - } while (ThreadInterlockedCompareExchange64(pDest, value, Old) != Old); - - return Old; -} - -int64 ThreadInterlockedExchangeAdd64( int64 volatile *pDest, int64 value ) -{ - Assert( (size_t)pDest % 8 == 0 ); - int64 Old; - - do - { - Old = *pDest; - } while (ThreadInterlockedCompareExchange64(pDest, Old + value, Old) != Old); - - return Old; + if ( _InterlockedCompareExchange128( ( volatile int64 * )pDest, value.m128i_i64[1], value.m128i_i64[0], comperandInOut ) ) + return true; + return false; } +#endif #elif defined(GNUC) -int32 ThreadInterlockedIncrement( int32 volatile *pDest ) +#ifdef OSX +#include +#endif + + +long ThreadInterlockedIncrement( long volatile *pDest ) { return __sync_fetch_and_add( pDest, 1 ) + 1; } -int64 ThreadInterlockedIncrement64( int64 volatile *pDest ) -{ - return __sync_fetch_and_add( pDest, 1 ) + 1; -} - -int32 ThreadInterlockedDecrement( int32 volatile *pDest ) +long ThreadInterlockedDecrement( long volatile *pDest ) { return __sync_fetch_and_sub( pDest, 1 ) - 1; } -int64 ThreadInterlockedDecrement64( int64 volatile *pDest ) -{ - return __sync_fetch_and_sub( pDest, 1 ) - 1; -} - -int32 ThreadInterlockedExchange( int32 volatile *pDest, int32 value ) +long ThreadInterlockedExchange( long volatile *pDest, long value ) { return __sync_lock_test_and_set( pDest, value ); } -int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value ) -{ - return __sync_lock_test_and_set( pDest, value ); -} - -int32 ThreadInterlockedExchangeAdd( int32 volatile *pDest, int32 value ) +long ThreadInterlockedExchangeAdd( long volatile *pDest, long value ) { return __sync_fetch_and_add( pDest, value ); } -int64 ThreadInterlockedExchangeAdd64( int64 volatile *pDest, int64 value ) -{ - return __sync_fetch_and_add( pDest, value ); -} - -int32 ThreadInterlockedCompareExchange( int32 volatile *pDest, int32 value, int32 comperand ) +long ThreadInterlockedCompareExchange( long volatile *pDest, long value, long comperand ) { return __sync_val_compare_and_swap( pDest, comperand, value ); } -bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comperand ) +bool ThreadInterlockedAssignIf( long volatile *pDest, long value, long comperand ) { return __sync_bool_compare_and_swap( pDest, comperand, value ); } -void *ThreadInterlockedExchangePointer( void * volatile *pDest, void *value ) -{ - return __sync_lock_test_and_set( pDest, value ); -} +#if !defined( USE_INTRINSIC_INTERLOCKED ) void *ThreadInterlockedCompareExchangePointer( void *volatile *pDest, void *value, void *comperand ) { @@ -1136,6 +1954,18 @@ bool ThreadInterlockedAssignPointerIf( void * volatile *pDest, void *value, void return __sync_bool_compare_and_swap( pDest, comperand, value ); } +#elif defined( PLATFORM_64BITS ) + +void *ThreadInterlockedExchangePointer( void * volatile *pDest, void *value ) +{ + return __sync_lock_test_and_set( pDest, value ); +} + +void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comparand ) { + return (void *)( ( intp )ThreadInterlockedCompareExchange64( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comparand) ) ); +} +#endif + int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand ) { return __sync_val_compare_and_swap( pDest, comperand, value ); @@ -1146,35 +1976,32 @@ bool ThreadInterlockedAssignIf64( int64 volatile * pDest, int64 value, int64 com return __sync_bool_compare_and_swap( pDest, comperand, value ); } -#ifdef PLATFORM_64BITS -bool ThreadInterlockedAssignIf128( int128 volatile *pDest, const int128 &value, const int128 &comperand ) -{ - return __sync_bool_compare_and_swap( pDest, comperand, value ); -} -#endif +#elif defined( _PS3 ) + +// This is defined in the header! #else // This will perform horribly, #error "Falling back to mutexed interlocked operations, you really don't have intrinsics you can use?"ß CThreadMutex g_InterlockedMutex; -int32 ThreadInterlockedIncrement( int32 volatile *pDest ) +long ThreadInterlockedIncrement( long volatile *pDest ) { AUTO_LOCK( g_InterlockedMutex ); return ++(*pDest); } -int32 ThreadInterlockedDecrement( int32 volatile *pDest ) +long ThreadInterlockedDecrement( long volatile *pDest ) { AUTO_LOCK( g_InterlockedMutex ); return --(*pDest); } -int32 ThreadInterlockedExchange( int32 volatile *pDest, int32 value ) +long ThreadInterlockedExchange( long volatile *pDest, long value ) { AUTO_LOCK( g_InterlockedMutex ); - int32 retVal = *pDest; + long retVal = *pDest; *pDest = value; return retVal; } @@ -1187,18 +2014,18 @@ void *ThreadInterlockedExchangePointer( void * volatile *pDest, void *value ) return retVal; } -int32 ThreadInterlockedExchangeAdd( int32 volatile *pDest, int32 value ) +long ThreadInterlockedExchangeAdd( long volatile *pDest, long value ) { AUTO_LOCK( g_InterlockedMutex ); - int32 retVal = *pDest; + long retVal = *pDest; *pDest += value; return retVal; } -int32 ThreadInterlockedCompareExchange( int32 volatile *pDest, int32 value, int32 comperand ) +long ThreadInterlockedCompareExchange( long volatile *pDest, long value, long comperand ) { AUTO_LOCK( g_InterlockedMutex ); - int32 retVal = *pDest; + long retVal = *pDest; if ( *pDest == comperand ) *pDest = value; return retVal; @@ -1224,6 +2051,74 @@ int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, in return retVal; } +#endif + +#ifdef COMPILER_MSVC32 + +PLATFORM_INTERFACE int64 ThreadInterlockedOr64( int64 volatile *pDest, int64 value ) +{ + int64 Old; + + do + { + Old = *pDest; + } while ( ThreadInterlockedCompareExchange64( pDest, Old | value, Old ) != Old ); + + return Old; +} + +PLATFORM_INTERFACE int64 ThreadInterlockedAnd64( int64 volatile *pDest, int64 value ) +{ + int64 Old; + + do + { + Old = *pDest; + } while ( ThreadInterlockedCompareExchange64( pDest, Old & value, Old ) != Old ); + + return Old; +} + +PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile *pDest ) +{ + int64 Old; + + do + { + Old = *pDest; + } while ( ThreadInterlockedCompareExchange64( pDest, Old + 1, Old ) != Old ); + + return Old + 1; +} + +PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile *pDest ) +{ + int64 Old; + + + do + { + Old = *pDest; + } while ( ThreadInterlockedCompareExchange64( pDest, Old - 1, Old ) != Old ); + + return Old - 1; +} + +PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *pDest, int64 value ) +{ + int64 Old; + + do + { + Old = *pDest; + } while ( ThreadInterlockedCompareExchange64( pDest, Old + value, Old ) != Old ); + + return Old; +} + + +#endif + int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value ) { Assert( (size_t)pDest % 8 == 0 ); @@ -1237,19 +2132,6 @@ int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value ) return Old; } -bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand ) -{ - Assert( (size_t)pDest % 8 == 0 ); - return ( ThreadInterlockedCompareExchange64( pDest, value, comperand ) == comperand ); -} - -bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comperand ) -{ - Assert( (size_t)pDest % 4 == 0 ); - return ( ThreadInterlockedCompareExchange( pDest, value, comperand ) == comperand ); -} - -#endif //----------------------------------------------------------------------------- @@ -1276,7 +2158,20 @@ MAP_THREAD_PROFILER_CALL( ThreadNotifySyncReleasing, __itt_notify_sync_releasing // //----------------------------------------------------------------------------- -#ifndef POSIX +#ifdef _PS3 +CThreadMutex::CThreadMutex() +{ + // sys_mutex with recursion enabled is like a win32 critical section + sys_mutex_attribute_t mutexAttr; + sys_mutex_attribute_initialize( mutexAttr ); + mutexAttr.attr_recursive = SYS_SYNC_RECURSIVE; + sys_mutex_create( &m_Mutex, &mutexAttr ); +} +CThreadMutex::~CThreadMutex() +{ + sys_mutex_destroy( m_Mutex ); +} +#elif !defined( POSIX ) CThreadMutex::CThreadMutex() { #ifdef THREAD_MUTEX_TRACING_ENABLED @@ -1297,7 +2192,7 @@ CThreadMutex::~CThreadMutex() } #endif // !POSIX -#if defined( _WIN32 ) && !defined( _X360 ) +#ifdef IS_WINDOWS_PC typedef BOOL (WINAPI*TryEnterCriticalSectionFunc_t)(LPCRITICAL_SECTION); static CDynamicFunction DynTryEnterCriticalSection( "Kernel32.dll", "TryEnterCriticalSection" ); #elif defined( _X360 ) @@ -1306,8 +2201,7 @@ static CDynamicFunction DynTryEnterCriticalSectio bool CThreadMutex::TryLock() { - -#if defined( _WIN32 ) +#if defined( MSVC ) #ifdef THREAD_MUTEX_TRACING_ENABLED uint thisThreadID = ThreadGetCurrentId(); if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) ) @@ -1323,7 +2217,7 @@ bool CThreadMutex::TryLock() // we now own it for the first time. Set owner information m_currentOwnerID = thisThreadID; if ( m_bTrace ) - Msg( "Thread %u now owns lock 0x%p\n", m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); + Msg( "Thread %u now owns lock %p\n", m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); } m_lockCount++; #endif @@ -1333,8 +2227,18 @@ bool CThreadMutex::TryLock() } Lock(); return true; +#elif defined( _PS3 ) + +#ifndef NO_THREAD_SYNC + if ( sys_mutex_trylock( m_Mutex ) == CELL_OK ) +#endif + + return true; + + return false; // ?? moved from EA code + #elif defined( POSIX ) - return pthread_mutex_trylock( &m_Mutex ) == 0; + return pthread_mutex_trylock( &m_Mutex ) == 0; #else #error "Implement me!" return true; @@ -1347,10 +2251,59 @@ bool CThreadMutex::TryLock() // //----------------------------------------------------------------------------- +#ifdef THREAD_FAST_MUTEX_TIMINGS +// This is meant to be used in combination with breakpoints and in-debugee, so we turn the optimizer off +#pragma optimize( "", off ) +CThreadFastMutex *g_pIgnoredMutexes[256]; // Ignore noisy non-problem mutex. Probably could be an array. Right now needed only for sound thread +float g_MutexTimingTolerance = 5; +bool g_bMutexTimingOutput; + +void TrapMutexTimings( uint32 probableBlocker, uint32 thisThread, volatile CThreadFastMutex *pMutex, CFastTimer &spikeTimer, CAverageCycleCounter &sleepTimer ) +{ + spikeTimer.End(); + if ( spikeTimer.GetDuration().GetMillisecondsF() > g_MutexTimingTolerance ) + { + bool bIgnore = false; + for ( int j = 0; j < ARRAYSIZE( g_pIgnoredMutexes ) && g_pIgnoredMutexes[j]; j++ ) + { + if ( g_pIgnoredMutexes[j] == pMutex ) + { + bIgnore = true; + break; + } + } + + if ( !bIgnore && spikeTimer.GetDuration().GetMillisecondsF() < 100 ) + { + volatile float FastMutexDuration = spikeTimer.GetDuration().GetMillisecondsF(); + volatile float average = sleepTimer.GetAverageMilliseconds(); + volatile float peak = sleepTimer.GetPeakMilliseconds(); volatile int xx = 6; + if ( g_bMutexTimingOutput ) + { + char szBuf[256]; + Msg( "M (%.8x): [%.8x <-- %.8x] (%f,%f,%f)\n", pMutex, probableBlocker, thisThread, FastMutexDuration, average, peak ); + } + } + } +} + +#else +#define TrapMutexTimings( a, b, c, d, e ) ((void)0) +#endif + +//------------------------------------- + #define THREAD_SPIN (8*1024) -void CThreadFastMutex::Lock( const uintp threadId, unsigned nSpinSleepTime ) volatile +void CThreadFastMutex::Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile { +#ifdef THREAD_FAST_MUTEX_TIMINGS + CAverageCycleCounter sleepTimer; + CFastTimer spikeTimer; + uint32 currentOwner = m_ownerID; + spikeTimer.Start(); + sleepTimer.Init(); +#endif int i; if ( nSpinSleepTime != TT_INFINITE ) { @@ -1358,6 +2311,7 @@ void CThreadFastMutex::Lock( const uintp threadId, unsigned nSpinSleepTime ) vol { if ( TryLock( threadId ) ) { + TrapMutexTimings( currentOwner, threadId, this, spikeTimer, sleepTimer ); return; } ThreadPause(); @@ -1367,11 +2321,15 @@ void CThreadFastMutex::Lock( const uintp threadId, unsigned nSpinSleepTime ) vol { if ( TryLock( threadId ) ) { + TrapMutexTimings( currentOwner, threadId, this, spikeTimer, sleepTimer ); return; } ThreadPause(); if ( i % 1024 == 0 ) { +#ifdef THREAD_FAST_MUTEX_TIMINGS + CAverageTimeMarker marker( &sleepTimer ); +#endif ThreadSleep( 0 ); } } @@ -1381,15 +2339,18 @@ void CThreadFastMutex::Lock( const uintp threadId, unsigned nSpinSleepTime ) vol { nSpinSleepTime = 1; } - else #endif if ( nSpinSleepTime ) { for ( i = THREAD_SPIN; i != 0; --i ) { +#ifdef THREAD_FAST_MUTEX_TIMINGS + CAverageTimeMarker marker( &sleepTimer ); +#endif if ( TryLock( threadId ) ) { + TrapMutexTimings( currentOwner, threadId, this, spikeTimer, sleepTimer ); return; } @@ -1399,10 +2360,14 @@ void CThreadFastMutex::Lock( const uintp threadId, unsigned nSpinSleepTime ) vol } - for ( ;; ) // coded as for instead of while to make easy to breakpoint success + for ( ;; ) { +#ifdef THREAD_FAST_MUTEX_TIMINGS + CAverageTimeMarker marker( &sleepTimer ); +#endif if ( TryLock( threadId ) ) { + TrapMutexTimings( currentOwner, threadId, this, spikeTimer, sleepTimer ); return; } @@ -1412,10 +2377,11 @@ void CThreadFastMutex::Lock( const uintp threadId, unsigned nSpinSleepTime ) vol } else { - for ( ;; ) // coded as for instead of while to make easy to breakpoint success + for ( ;; ) { if ( TryLock( threadId ) ) { + TrapMutexTimings( currentOwner, threadId, this, spikeTimer, sleepTimer ); return; } @@ -1424,6 +2390,10 @@ void CThreadFastMutex::Lock( const uintp threadId, unsigned nSpinSleepTime ) vol } } +#ifdef THREAD_FAST_MUTEX_TIMINGS +#pragma optimize( "", on ) +#endif + //----------------------------------------------------------------------------- // // CThreadRWLock @@ -1483,12 +2453,122 @@ void CThreadRWLock::UnlockWrite() // CThreadSpinRWLock // //----------------------------------------------------------------------------- +#ifndef OLD_SPINRWLOCK -void CThreadSpinRWLock::SpinLockForWrite( const uintp threadId ) +void CThreadSpinRWLock::SpinLockForWrite() { int i; - for ( i = 1000; i != 0; --i ) + if ( TryLockForWrite_UnforcedInline() ) + { + return; + } + + for ( i = THREAD_SPIN; i != 0; --i ) + { + if ( TryLockForWrite_UnforcedInline() ) + { + return; + } + ThreadPause(); + } + + for ( i = THREAD_SPIN; i != 0; --i ) + { + if ( TryLockForWrite_UnforcedInline() ) + { + return; + } + ThreadPause(); + if ( i % 1024 == 0 ) + { + ThreadSleep( 0 ); + } + } + + for ( i = THREAD_SPIN * 4; i != 0; --i ) + { + if ( TryLockForWrite_UnforcedInline() ) + { + return; + } + + ThreadPause(); + ThreadSleep( 0 ); + } + + for ( ;; ) // coded as for instead of while to make easy to breakpoint success + { + if ( TryLockForWrite_UnforcedInline() ) + { + return; + } + + ThreadPause(); + ThreadSleep( 1 ); + } +} + +void CThreadSpinRWLock::SpinLockForRead() +{ + int i; + for ( i = THREAD_SPIN; i != 0; --i ) + { + if ( TryLockForRead_UnforcedInline() ) + { + return; + } + ThreadPause(); + } + + for ( i = THREAD_SPIN; i != 0; --i ) + { + if ( TryLockForRead_UnforcedInline() ) + { + return; + } + ThreadPause(); + if ( i % 1024 == 0 ) + { + ThreadSleep( 0 ); + } + } + + for ( i = THREAD_SPIN * 4; i != 0; --i ) + { + if ( TryLockForRead_UnforcedInline() ) + { + return; + } + + ThreadPause(); + ThreadSleep( 0 ); + } + + for ( ;; ) // coded as for instead of while to make easy to breakpoint success + { + if ( TryLockForRead_UnforcedInline() ) + { + return; + } + + ThreadPause(); + ThreadSleep( 1 ); + } +} + +#else +/* (commented out to reduce distraction in colorized editor, remove entirely when new implementation settles) +void CThreadSpinRWLock::SpinLockForWrite( const uint32 threadId ) +{ + int i; + + if ( TryLockForWrite( threadId ) ) + { + return; + } + + for ( i = THREAD_SPIN; i != 0; --i ) { if ( TryLockForWrite( threadId ) ) { @@ -1497,7 +2577,20 @@ void CThreadSpinRWLock::SpinLockForWrite( const uintp threadId ) ThreadPause(); } - for ( i = 20000; i != 0; --i ) + for ( i = THREAD_SPIN; i != 0; --i ) + { + if ( TryLockForWrite( threadId ) ) + { + return; + } + ThreadPause(); + if ( i % 1024 == 0 ) + { + ThreadSleep( 0 ); + } + } + + for ( i = THREAD_SPIN * 4; i != 0; --i ) { if ( TryLockForWrite( threadId ) ) { @@ -1523,49 +2616,53 @@ void CThreadSpinRWLock::SpinLockForWrite( const uintp threadId ) void CThreadSpinRWLock::LockForRead() { int i; - - // In order to grab a read lock, the number of readers must not change and no thread can own the write lock - LockInfo_t oldValue; - LockInfo_t newValue; - - oldValue.m_nReaders = m_lockInfo.m_nReaders; - oldValue.m_writerId = 0; - newValue.m_nReaders = oldValue.m_nReaders + 1; - newValue.m_writerId = 0; - - if( m_nWriters == 0 && AssignIf( newValue, oldValue ) ) - return; - ThreadPause(); - oldValue.m_nReaders = m_lockInfo.m_nReaders; - newValue.m_nReaders = oldValue.m_nReaders + 1; - - for ( i = 1000; i != 0; --i ) + if ( TryLockForRead() ) { - if( m_nWriters == 0 && AssignIf( newValue, oldValue ) ) - return; - ThreadPause(); - oldValue.m_nReaders = m_lockInfo.m_nReaders; - newValue.m_nReaders = oldValue.m_nReaders + 1; + return; } - for ( i = 20000; i != 0; --i ) + for ( i = THREAD_SPIN; i != 0; --i ) { - if( m_nWriters == 0 && AssignIf( newValue, oldValue ) ) + if ( TryLockForRead() ) + { return; + } + ThreadPause(); + } + + for ( i = THREAD_SPIN; i != 0; --i ) + { + if ( TryLockForRead() ) + { + return; + } + ThreadPause(); + if ( i % 1024 == 0 ) + { + ThreadSleep( 0 ); + } + } + + for ( i = THREAD_SPIN * 4; i != 0; --i ) + { + if ( TryLockForRead() ) + { + return; + } + ThreadPause(); ThreadSleep( 0 ); - oldValue.m_nReaders = m_lockInfo.m_nReaders; - newValue.m_nReaders = oldValue.m_nReaders + 1; } for ( ;; ) // coded as for instead of while to make easy to breakpoint success { - if( m_nWriters == 0 && AssignIf( newValue, oldValue ) ) + if ( TryLockForRead() ) + { return; + } + ThreadPause(); ThreadSleep( 1 ); - oldValue.m_nReaders = m_lockInfo.m_nReaders; - newValue.m_nReaders = oldValue.m_nReaders + 1; } } @@ -1574,21 +2671,35 @@ void CThreadSpinRWLock::UnlockRead() int i; Assert( m_lockInfo.m_nReaders > 0 && m_lockInfo.m_writerId == 0 ); + + //uint32 nLockInfoReaders = m_lockInfo.m_nReaders; LockInfo_t oldValue; LockInfo_t newValue; - - oldValue.m_nReaders = m_lockInfo.m_nReaders; - oldValue.m_writerId = 0; - newValue.m_nReaders = oldValue.m_nReaders - 1; - newValue.m_writerId = 0; - + + if( IsX360() ) + { + // this is the code equivalent to original code (see below) that doesn't cause LHS on Xbox360 + // WARNING: This code assumes BIG Endian CPU + oldValue.m_i64 = uint32( m_lockInfo.m_nReaders ); + newValue.m_i64 = oldValue.m_i64 - 1; // NOTE: when we have -1 (or 0xFFFFFFFF) readers, this will result in non-equivalent code + } + else + { + // this is the original code that worked here for a while + oldValue.m_nReaders = m_lockInfo.m_nReaders; + oldValue.m_writerId = 0; + newValue.m_nReaders = oldValue.m_nReaders - 1; + newValue.m_writerId = 0; + } + ThreadMemoryBarrier(); if( AssignIf( newValue, oldValue ) ) return; + ThreadPause(); oldValue.m_nReaders = m_lockInfo.m_nReaders; newValue.m_nReaders = oldValue.m_nReaders - 1; - for ( i = 500; i != 0; --i ) + for ( i = THREAD_SPIN; i != 0; --i ) { if( AssignIf( newValue, oldValue ) ) return; @@ -1597,7 +2708,20 @@ void CThreadSpinRWLock::UnlockRead() newValue.m_nReaders = oldValue.m_nReaders - 1; } - for ( i = 20000; i != 0; --i ) + for ( i = THREAD_SPIN; i != 0; --i ) + { + if( AssignIf( newValue, oldValue ) ) + return; + ThreadPause(); + if ( i % 512 == 0 ) + { + ThreadSleep( 0 ); + } + oldValue.m_nReaders = m_lockInfo.m_nReaders; + newValue.m_nReaders = oldValue.m_nReaders - 1; + } + + for ( i = THREAD_SPIN * 4; i != 0; --i ) { if( AssignIf( newValue, oldValue ) ) return; @@ -1621,563 +2745,33 @@ void CThreadSpinRWLock::UnlockRead() void CThreadSpinRWLock::UnlockWrite() { Assert( m_lockInfo.m_writerId == ThreadGetCurrentId() && m_lockInfo.m_nReaders == 0 ); - static const LockInfo_t newValue = { 0, 0 }; -#if defined(_X360) - // X360TBD: Serious Perf implications, not yet. __sync(); -#endif - int64 val; memcpy( &val, &newValue, sizeof( val ) ); - ThreadInterlockedExchange64( (int64 *)&m_lockInfo, val ); + static const LockInfo_t newValue = { { 0, 0 } }; + ThreadMemoryBarrier(); + ThreadInterlockedExchange64( (int64 *)&m_lockInfo, *((int64 *)&newValue) ); m_nWriters--; } - - - -//----------------------------------------------------------------------------- -// -// CThread -// -//----------------------------------------------------------------------------- - -CThreadLocalPtr g_pCurThread; - -//--------------------------------------------------------- - -CThread::CThread() -: -#ifdef _WIN32 - m_hThread( NULL ), -#endif - m_threadId( 0 ), - m_result( 0 ), - m_flags( 0 ) -{ - m_szName[0] = 0; -} - -//--------------------------------------------------------- - -CThread::~CThread() -{ -#ifdef _WIN32 - if (m_hThread) -#elif defined(POSIX) - if ( m_threadId ) -#endif - { - if ( IsAlive() ) - { - Msg( "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" ); -#ifdef _WIN32 - - DoNewAssertDialog( __FILE__, __LINE__, "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" ); -#endif - if ( GetCurrentCThread() == this ) - { - Stop(); // BUGBUG: Alfred - this doesn't make sense, this destructor fires from the hosting thread not the thread itself!! - } - } - -#ifdef _WIN32 - // Now that the worker thread has exited (which we know because we presumably waited - // on the thread handle for it to exit) we can finally close the thread handle. We - // cannot do this any earlier, and certainly not in CThread::ThreadProc(). - CloseHandle( m_hThread ); -#endif - } -} - - -//--------------------------------------------------------- - -const char *CThread::GetName() -{ - AUTO_LOCK( m_Lock ); - if ( !m_szName[0] ) - { -#ifdef _WIN32 - _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/%p)", this, m_hThread ); -#elif defined(POSIX) - _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(0x" PRIxPTR "/0x" PRIxPTR ")", (ThreadId_t)this, (ThreadId_t)m_threadId ); -#endif - m_szName[sizeof(m_szName) - 1] = 0; - } - return m_szName; -} - -//--------------------------------------------------------- - -void CThread::SetName(const char *pszName) -{ - AUTO_LOCK( m_Lock ); - strncpy( m_szName, pszName, sizeof(m_szName) - 1 ); - m_szName[sizeof(m_szName) - 1] = 0; -} - -//--------------------------------------------------------- - -bool CThread::Start( unsigned nBytesStack ) -{ - AUTO_LOCK( m_Lock ); - - if ( IsAlive() ) - { - AssertMsg( 0, "Tried to create a thread that has already been created!" ); - return false; - } - - bool bInitSuccess = false; - CThreadEvent createComplete; - ThreadInit_t init = { this, &createComplete, &bInitSuccess }; - -#ifdef _WIN32 - HANDLE hThread; - m_hThread = hThread = (HANDLE)VCRHook_CreateThread( NULL, - nBytesStack, - (LPTHREAD_START_ROUTINE)GetThreadProc(), - new ThreadInit_t(init), - CREATE_SUSPENDED, - &m_threadId ); - if ( !hThread ) - { - AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() ); - return false; - } - Plat_ApplyHardwareDataBreakpointsToNewThread( m_threadId ); - ResumeThread( hThread ); - -#elif defined(POSIX) - pthread_attr_t attr; - pthread_attr_init( &attr ); - // From http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_attr_setstacksize.3.html - // A thread's stack size is fixed at the time of thread creation. Only the main thread can dynamically grow its stack. - pthread_attr_setstacksize( &attr, MAX( nBytesStack, 1024u*1024 ) ); - if ( pthread_create( &m_threadId, &attr, (void *(*)(void *))GetThreadProc(), new ThreadInit_t( init ) ) != 0 ) - { - AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() ); - return false; - } - Plat_ApplyHardwareDataBreakpointsToNewThread( (long unsigned int)m_threadId ); - bInitSuccess = true; +*/ #endif -#if !defined( OSX ) - ThreadSetDebugName( m_threadId, m_szName ); -#endif +#if defined( _PS3 ) +// All CThread code is inline in the header for PS3 - if ( !WaitForCreateComplete( &createComplete ) ) - { - Msg( "Thread failed to initialize\n" ); -#ifdef _WIN32 - CloseHandle( m_hThread ); - m_hThread = NULL; - m_threadId = 0; -#elif defined(POSIX) - m_threadId = 0; -#endif - return false; - } - - if ( !bInitSuccess ) - { - Msg( "Thread failed to initialize\n" ); -#ifdef _WIN32 - CloseHandle( m_hThread ); - m_hThread = NULL; - m_threadId = 0; -#elif defined(POSIX) - m_threadId = 0; -#endif - return false; - } - -#ifdef _WIN32 - if ( !m_hThread ) - { - Msg( "Thread exited immediately\n" ); - } -#endif - -#ifdef _WIN32 - return !!m_hThread; -#elif defined(POSIX) - return !!m_threadId; -#endif +// This function is implemented here rather than the header because g_pCurThread resolves to GetCurThread() on PS3 +// and we don't want to create a dependency on the ELF stub for everyone who includes the header. +PLATFORM_INTERFACE CThread *GetCurThreadPS3() +{ + return (CThread*)g_pCurThread; } -//--------------------------------------------------------- -// -// Return true if the thread exists. false otherwise -// - -bool CThread::IsAlive() +PLATFORM_INTERFACE void SetCurThreadPS3( CThread *pThread ) { -#ifdef _WIN32 - DWORD dwExitCode; - - return ( m_hThread && - GetExitCodeThread( m_hThread, &dwExitCode ) && - dwExitCode == STILL_ACTIVE ); -#elif defined(POSIX) - return m_threadId; -#endif -} - -//--------------------------------------------------------- - -bool CThread::Join(unsigned timeout) -{ -#ifdef _WIN32 - if ( m_hThread ) -#elif defined(POSIX) - if ( m_threadId ) -#endif - { - AssertMsg(GetCurrentCThread() != this, _T("Thread cannot be joined with self")); - -#ifdef _WIN32 - return ThreadJoin( (ThreadHandle_t)m_hThread ); -#elif defined(POSIX) - return ThreadJoin( (ThreadHandle_t)m_threadId ); -#endif - } - return true; -} - -//--------------------------------------------------------- - -#ifdef _WIN32 - -HANDLE CThread::GetThreadHandle() -{ - return m_hThread; -} - -#endif - -#if defined( _WIN32 ) || defined( LINUX ) - -//--------------------------------------------------------- - -uint CThread::GetThreadId() -{ - return m_threadId; -} - -#endif - -//--------------------------------------------------------- - -int CThread::GetResult() -{ - return m_result; -} - -//--------------------------------------------------------- -// -// Forcibly, abnormally, but relatively cleanly stop the thread -// - -void CThread::Stop(int exitCode) -{ - if ( !IsAlive() ) - return; - - if ( GetCurrentCThread() == this ) - { - m_result = exitCode; - if ( !( m_flags & SUPPORT_STOP_PROTOCOL ) ) - { - OnExit(); - g_pCurThread = NULL; - -#ifdef _WIN32 - CloseHandle( m_hThread ); - m_hThread = NULL; -#endif - Cleanup(); - } - throw exitCode; - } - else - AssertMsg( 0, "Only thread can stop self: Use a higher-level protocol"); -} - -//--------------------------------------------------------- - -int CThread::GetPriority() const -{ -#ifdef _WIN32 - return GetThreadPriority(m_hThread); -#elif defined(POSIX) - struct sched_param thread_param; - int policy; - pthread_getschedparam( m_threadId, &policy, &thread_param ); - return thread_param.sched_priority; -#endif -} - -//--------------------------------------------------------- - -bool CThread::SetPriority(int priority) -{ -#ifdef _WIN32 - return ThreadSetPriority( (ThreadHandle_t)m_hThread, priority ); -#else - return ThreadSetPriority( (ThreadHandle_t)m_threadId, priority ); -#endif -} - - -//--------------------------------------------------------- - -void CThread::SuspendCooperative() -{ - if ( ThreadGetCurrentId() == (ThreadId_t)m_threadId ) - { - m_SuspendEventSignal.Set(); - m_nSuspendCount = 1; - m_SuspendEvent.Wait(); - m_nSuspendCount = 0; - } - else - { - Assert( !"Suspend not called from worker thread, this would be a bug" ); - } -} - -//--------------------------------------------------------- - -void CThread::ResumeCooperative() -{ - //Assert( m_nSuspendCount == 1 ); - m_SuspendEvent.Set(); -} - - -void CThread::BWaitForThreadSuspendCooperative() -{ - m_SuspendEventSignal.Wait(); -} - - -#ifndef LINUX -//--------------------------------------------------------- - -unsigned int CThread::Suspend() -{ -#ifdef _WIN32 - return ( SuspendThread(m_hThread) != 0 ); -#elif defined(OSX) - int susCount = m_nSuspendCount++; - while ( thread_suspend( pthread_mach_thread_np(m_threadId) ) != KERN_SUCCESS ) - { - }; - return ( susCount) != 0; -#else -#error -#endif -} - -//--------------------------------------------------------- - -unsigned int CThread::Resume() -{ -#ifdef _WIN32 - return ( ResumeThread(m_hThread) != 0 ); -#elif defined(OSX) - int susCount = m_nSuspendCount++; - while ( thread_resume( pthread_mach_thread_np(m_threadId) ) != KERN_SUCCESS ) - { - }; - return ( susCount - 1) != 0; -#else -#error -#endif -} -#endif - - -//--------------------------------------------------------- - -bool CThread::Terminate(int exitCode) -{ -#ifndef _X360 -#ifdef _WIN32 - // I hope you know what you're doing! - if (!TerminateThread(m_hThread, exitCode)) - return false; - CloseHandle( m_hThread ); - m_hThread = NULL; - Cleanup(); -#elif defined(POSIX) - pthread_kill( m_threadId, SIGKILL ); - Cleanup(); -#endif - - return true; -#else - AssertMsg( 0, "Cannot terminate a thread on the Xbox!" ); - return false; -#endif -} - -//--------------------------------------------------------- -// -// Get the Thread object that represents the current thread, if any. -// Can return NULL if the current thread was not created using -// CThread -// - -CThread *CThread::GetCurrentCThread() -{ - return g_pCurThread; -} - -//--------------------------------------------------------- -// -// Offer a context switch. Under Win32, equivalent to Sleep(0) -// - -void CThread::Yield() -{ -#ifdef _WIN32 - ::Sleep(0); -#elif defined(ANDROID) - sched_yield(); -#elif defined(POSIX) - pthread_yield(); -#endif -} - -//--------------------------------------------------------- -// -// This method causes the current thread to yield and not to be -// scheduled for further execution until a certain amount of real -// time has elapsed, more or less. -// - -void CThread::Sleep(unsigned duration) -{ -#ifdef _WIN32 - ::Sleep(duration); -#elif defined(POSIX) - usleep( duration * 1000 ); -#endif -} - -//--------------------------------------------------------- - -bool CThread::Init() -{ - return true; -} - -//--------------------------------------------------------- - -void CThread::OnExit() -{ -} - -//--------------------------------------------------------- - -void CThread::Cleanup() -{ - m_threadId = 0; -} - -//--------------------------------------------------------- -bool CThread::WaitForCreateComplete(CThreadEvent * pEvent) -{ - // Force serialized thread creation... - if (!pEvent->Wait(60000)) - { - AssertMsg( 0, "Probably deadlock or failure waiting for thread to initialize." ); - return false; - } - return true; -} - -//--------------------------------------------------------- - -bool CThread::IsThreadRunning() -{ -#ifdef _PS3 - // ThreadIsThreadIdRunning() doesn't work on PS3 if the thread is in a zombie state - return m_eventTheadExit.Check(); -#else - return ThreadIsThreadIdRunning( (ThreadId_t)m_threadId ); -#endif -} - -//--------------------------------------------------------- - -CThread::ThreadProc_t CThread::GetThreadProc() -{ - return ThreadProc; -} - -//--------------------------------------------------------- - -unsigned __stdcall CThread::ThreadProc(LPVOID pv) -{ - std::unique_ptr pInit((ThreadInit_t *)pv); - -#ifdef _X360 - // Make sure all threads are consistent w.r.t floating-point math - SetupFPUControlWord(); -#endif - - CThread *pThread = pInit->pThread; g_pCurThread = pThread; - - g_pCurThread->m_pStackBase = AlignValue( &pThread, 4096 ); - - pInit->pThread->m_result = -1; - - bool bInitSuccess = true; - if ( pInit->pfInitSuccess ) - *(pInit->pfInitSuccess) = false; - - try - { - bInitSuccess = pInit->pThread->Init(); - } - - catch (...) - { - pInit->pInitCompleteEvent->Set(); - throw; - } - - if ( pInit->pfInitSuccess ) - *(pInit->pfInitSuccess) = bInitSuccess; - pInit->pInitCompleteEvent->Set(); - if (!bInitSuccess) - return 0; - - if ( pInit->pThread->m_flags & SUPPORT_STOP_PROTOCOL ) - { - try - { - pInit->pThread->m_result = pInit->pThread->Run(); - } - - catch (...) - { - } - } - else - { - pInit->pThread->m_result = pInit->pThread->Run(); - } - - pInit->pThread->OnExit(); - g_pCurThread = NULL; - pInit->pThread->Cleanup(); - - return pInit->pThread->m_result; } - +#else +// The CThread implementation needs to be inlined for performance on the PS3 - It makes a difference of more than 1ms/frame +// for other platforms, we include the .inl in the .cpp file where it existed before +#include "../public/tier0/threadtools.inl" +#endif //----------------------------------------------------------------------------- // @@ -2186,16 +2780,15 @@ CWorkerThread::CWorkerThread() : m_EventSend(true), // must be manual-reset for PeekCall() m_EventComplete(true), // must be manual-reset to handle multiple wait with thread properly m_Param(0), - m_pParamFunctor(NULL), m_ReturnVal(0) { } //--------------------------------------------------------- -int CWorkerThread::CallWorker(unsigned dw, unsigned timeout, bool fBoostWorkerPriorityToMaster, CFunctor *pParamFunctor) +int CWorkerThread::CallWorker(unsigned dw, unsigned timeout, bool fBoostWorkerPriorityToMaster) { - return Call(dw, timeout, fBoostWorkerPriorityToMaster, NULL, pParamFunctor); + return Call(dw, timeout, fBoostWorkerPriorityToMaster); } //--------------------------------------------------------- @@ -2214,10 +2807,8 @@ CThreadEvent &CWorkerThread::GetCallHandle() //--------------------------------------------------------- -unsigned CWorkerThread::GetCallParam( CFunctor **ppParamFunctor ) const +unsigned CWorkerThread::GetCallParam() const { - if( ppParamFunctor ) - *ppParamFunctor = m_pParamFunctor; return m_Param; } @@ -2226,22 +2817,28 @@ unsigned CWorkerThread::GetCallParam( CFunctor **ppParamFunctor ) const int CWorkerThread::BoostPriority() { int iInitialPriority = GetPriority(); + +#ifdef WIN32 + const int iNewPriority = ThreadGetPriority( GetThreadHandle() ); + if (iNewPriority > iInitialPriority) + ThreadSetPriority( GetThreadHandle(), iNewPriority); +#elif !defined( _PS3 ) const int iNewPriority = ThreadGetPriority( (ThreadHandle_t)GetThreadID() ); if (iNewPriority > iInitialPriority) ThreadSetPriority( (ThreadHandle_t)GetThreadID(), iNewPriority); +#endif + return iInitialPriority; } //--------------------------------------------------------- - -static uint32 __stdcall DefaultWaitFunc( int nEvents, CThreadEvent * const *pEvents, int bWaitAll, uint32 timeout ) +static uint32 DefaultWaitFunc( uint32 nHandles, CThreadEvent** ppHandles, int bWaitAll, uint32 timeout ) { - return ThreadWaitForEvents( nEvents, pEvents, bWaitAll!=0, timeout ); -// return VCRHook_WaitForMultipleObjects( nHandles, (const void **)pHandles, bWaitAll, timeout ); + return CThreadEvent::WaitForMultiple( nHandles, ppHandles, bWaitAll!=0, timeout ) ; } -int CWorkerThread::Call(unsigned dwParam, unsigned timeout, bool fBoostPriority, WaitFunc_t pfnWait, CFunctor *pParamFunctor) +int CWorkerThread::Call(unsigned dwParam, unsigned timeout, bool fBoostPriority, WaitFunc_t waitFunc) { AssertMsg(!m_EventSend.Check(), "Cannot perform call if there's an existing call pending" ); @@ -2258,18 +2855,14 @@ int CWorkerThread::Call(unsigned dwParam, unsigned timeout, bool fBoostPriority, // set the parameter, signal the worker thread, wait for the completion to be signaled m_Param = dwParam; - m_pParamFunctor = pParamFunctor; m_EventComplete.Reset(); m_EventSend.Set(); - WaitForReply( timeout, pfnWait ); + WaitForReply( timeout, waitFunc ); - // MWD: Investigate why setting thread priorities is killing the 360 -#ifndef _X360 if (fBoostPriority) SetPriority(iInitialPriority); -#endif return m_ReturnVal; } @@ -2288,47 +2881,44 @@ int CWorkerThread::WaitForReply( unsigned timeout, WaitFunc_t pfnWait ) { if (!pfnWait) { - pfnWait = DefaultWaitFunc; + pfnWait = &DefaultWaitFunc; } -#ifdef WIN32 - CThreadEvent threadEvent( GetThreadHandle() ); -#endif - CThreadEvent *waits[] = { -#ifdef WIN32 - &threadEvent, -#endif - &m_EventComplete + &m_EventComplete, + &m_ExitEvent }; - unsigned result; bool bInDebugger = Plat_IsInDebugSession(); + uint32 dwActualTimeout = ( (timeout==TT_INFINITE) ? 30000 : timeout ); + do { #ifdef WIN32 // Make sure the thread handle hasn't been closed if ( !GetThreadHandle() ) { - result = WAIT_OBJECT_0 + 1; + result = 1; break; } #endif - result = (*pfnWait)((sizeof(waits) / sizeof(waits[0])), waits, false, - (timeout != TT_INFINITE) ? timeout : 30000); - AssertMsg(timeout != TT_INFINITE || result != WAIT_TIMEOUT, "Possible hung thread, call to thread timed out"); + result = (*pfnWait)( ARRAYSIZE( waits ), waits, false, dwActualTimeout ); - } while ( bInDebugger && ( timeout == TT_INFINITE && result == WAIT_TIMEOUT ) ); + AssertMsg(timeout != TT_INFINITE || result != TW_TIMEOUT, "Possible hung thread, call to thread timed out"); - if ( result != WAIT_OBJECT_0 + 1 ) + } while ( bInDebugger && ( timeout == TT_INFINITE && result == TW_TIMEOUT ) ); + + if ( result != 0 ) { - if (result == WAIT_TIMEOUT) + if (result == TW_TIMEOUT) + { m_ReturnVal = WTCR_TIMEOUT; - else if (result == WAIT_OBJECT_0) + } + else if (result == 1) { DevMsg( 2, "Thread failed to respond, probably exited\n"); m_EventSend.Reset(); @@ -2371,7 +2961,7 @@ bool CWorkerThread::WaitForCall(unsigned dwTimeout, unsigned * pResult) // is there a request? // -bool CWorkerThread::PeekCall(unsigned * pParam, CFunctor **ppParamFunctor) +bool CWorkerThread::PeekCall(unsigned * pParam) { if (!m_EventSend.Check()) { @@ -2383,10 +2973,6 @@ bool CWorkerThread::PeekCall(unsigned * pParam, CFunctor **ppParamFunctor) { *pParam = m_Param; } - if( ppParamFunctor ) - { - *ppParamFunctor = m_pParamFunctor; - } return true; } } @@ -2411,4 +2997,267 @@ void CWorkerThread::Reply(unsigned dw) m_EventComplete.Set(); } + //----------------------------------------------------------------------------- + + +#if defined( _PS3 ) + +/******************************************************************************* +* PS3 equivalent to Win32 function for setting events +*******************************************************************************/ +BOOL SetEvent( CThreadEvent *pEvent ) +{ + bool bRetVal = pEvent->Set(); + if ( !bRetVal ) + Assert(0); + + return bRetVal; +} + +/******************************************************************************* +* PS3 equivalent to Win32 function for resetting events +*******************************************************************************/ +BOOL ResetEvent( CThreadEvent *pEvent ) +{ + return pEvent->Reset(); +} + +#define MAXIMUM_WAIT_OBJECTS 64 + +/******************************************************************************* +* Wait for a selection of events to terminate +*******************************************************************************/ +DWORD WaitForMultipleObjects( DWORD nCount, CThreadEvent **lppHandles, BOOL bWaitAll, DWORD dwMilliseconds ) +{ + ////////////////////////////////////////////////////////////// +#ifndef NEW_WAIT_FOR_MULTIPLE_OBJECTS + ////////////////////////////////////////////////////////////// + + + // Support for a limited amount of events + if ( nCount >= MAXIMUM_WAIT_OBJECTS ) + { + Assert(0); + return false; + } + + bool bRunning = true; + unsigned int result = TW_FAILED; + + // For bWaitAll + int numEvent = 0; + int eventComplete[ MAXIMUM_WAIT_OBJECTS ] = {0}; + + uint64_t timeDiffMS = 0; + uint64_t startTimeMS = Plat_MSTime(); + uint64_t endTimeMS = 0; + + while ( bRunning ) + { + // Check for a timeout + if ( bRunning && ( dwMilliseconds != INFINITE ) && ( timeDiffMS > dwMilliseconds ) ) + { + result = TW_TIMEOUT; + bRunning = false; + } + + // Wait for all the events to be set + if ( bWaitAll ) + { + for ( int event = 0; event < nCount; ++event ) + { + if ( lppHandles[event]->Wait(1) ) + { + // If an event is complete, mark it as complete in our list + if ( eventComplete[ event ] == 0 ) + { + numEvent++; + eventComplete[ event ] = 1; + } + } + } + + // If all the events have been set, terminate the function + if ( numEvent >= nCount ) + { + result = WAIT_OBJECT_0; + bRunning = false; + } + } + + // Wait for one event to be set + else + { + for ( int event = 0; event < nCount; ++event ) + { + if ( lppHandles[event]->Wait(1) ) + { + result = WAIT_OBJECT_0 + event; + bRunning = false; + break; + } + } + } + + endTimeMS = Plat_MSTime(); + timeDiffMS = endTimeMS - startTimeMS; + } + + return result; + + + + ////////////////////////////////////////////////////////////// +#else // NEW_WAIT_FOR_MULTIPLE_OBJECTS // (expected PS3 only) + ////////////////////////////////////////////////////////////// +#ifndef _PS3 +#error This code was written expecting to be run on PS3. +#endif + + // check if we have a wait objects semaphore + if (!gbWaitObjectsCreated) + { + sys_semaphore_attribute_t semAttr; + sys_semaphore_attribute_initialize(semAttr); + sys_semaphore_create(&gWaitObjectsSemaphore, &semAttr, 0, 0xFFFF); + + gbWaitObjectsCreated = true; + } + + // Support for a limited amount of events + if ( nCount >= MAXIMUM_WAIT_OBJECTS ) + { + Assert(0); + return false; + } + + unsigned int result = WAIT_FAILED; + int res = CELL_OK; + int event = -1; + int numEvent = 0; + + // run through events registering this thread with each one + for (int i = 0; i < nCount; i++) + { + lppHandles[i]->RegisterWaitingThread(&gWaitObjectsSemaphore, i, &event); + } + + + // in the Source API, a timeOut of 0 means very short timeOut, not (as in the PS3 spec) an infinite timeout. + // TT_INFINITE is #defined to 2^31-1, which means "infinite timeout" on PC and "72 minutes, 35 seconds" on PS3. + // conversely, the code below (around deltaTime) expects to be able to compare against the timeout + // value given here, so we cannot just replace 0 with 1 and TT_INFINITE with 0. + // So, we replace 0 with 1, meaning "a very short time", and test for the special value TT_INFINITE + // at the moment of calling sys_semaphore_wait, where we replace it with the real "infinite timeout" + // value. It isn't safe to simply increase the declaration size of TT_INFINITE, because as you can + // see it is often assigned to uint32s. + // Also, Source timeouts are specified in milliseconds, and PS3 timeouts are in microseconds, + // so we need to multiply by one thousand. + uint32 timeOut = dwMilliseconds; + if ( timeOut == 0 ) + { + timeOut = 1; + } + else if ( timeOut != TT_INFINITE ) + { + timeOut *= 1000; + // note that it's impossible for dwMilliseconds * 1000 + // to coincidentally equal TT_INFINITE since TT_INFINITE + // is not divisible by 1000. + COMPILE_TIME_ASSERT( TT_INFINITE % 1000 != 0 ); + } + + COMPILE_TIME_ASSERT( TT_INFINITE != 0 ); // The code here was written expecting (working around) that TT_INFINITE is + // MAXINT, so if you changed this number, please read the comment above and + // carefully examine the code here to make sure that timeouts still work + // correctly on PS3. Be aware that in many places in Source, a timeout of + // 0 has some special meaning other than "infinite timeout", so track those + // down too. + + + // Wait for all the events to be set + if ( bWaitAll ) + { + while (numEvent < nCount) + { + uint64_t deltaTime = Plat_USTime(); + + res = sys_semaphore_wait(gWaitObjectsSemaphore, timeOut == TT_INFINITE ? 0 : timeOut ); + + deltaTime = Plat_USTime() - deltaTime; + + if (res == ETIMEDOUT) + { + result = TW_TIMEOUT; + break; + } + else if (res == CELL_OK) + { + numEvent++; + + if (deltaTime >= timeOut) + { + // note - if this is not truly a time out + // then it will be set to WAIT_OBJECT_0 + // after this loop + result = TW_TIMEOUT; + break; + } + else + { + timeOut -= deltaTime; + } + } + else + { + result = TW_FAILED; + break; + } + } + + if (numEvent >= nCount) + { + result = WAIT_OBJECT_0; + } + } + else // Wait for one event to be set + { + // no event fired yet, wait on semaphore + res = sys_semaphore_wait( gWaitObjectsSemaphore, timeOut == TT_INFINITE ? 0 : timeOut ); + + if (res == ETIMEDOUT) + { + result = TW_TIMEOUT; + } + else if (res == CELL_OK) + { + if ((event < 0) || (event >= nCount)) + { + DEBUG_ERROR("Bad event\n"); + } + + result = WAIT_OBJECT_0 + event; + } + } + + // run through events unregistering this thread, for benefit + // of those events that did not fire, or fired before semaphore + // was registered + for (int i = 0; i < nCount; i++) + { + lppHandles[i]->UnregisterWaitingThread(&gWaitObjectsSemaphore); + } + + // reset semaphore + while (sys_semaphore_trywait(gWaitObjectsSemaphore) != EBUSY); + + return result; + + + ////////////////////////////////////////////////////////////// +#endif // NEW_WAIT_FOR_MULTIPLE_OBJECTS + ////////////////////////////////////////////////////////////// +} + +#endif diff --git a/tier1/KeyValues.cpp b/tier1/KeyValues.cpp index a86cc530..ebf4d937 100644 --- a/tier1/KeyValues.cpp +++ b/tier1/KeyValues.cpp @@ -1425,7 +1425,7 @@ const char *KeyValues::GetString( const char *keyName, const char *defaultValue SetString( keyName, buf ); break; case TYPE_PTR: - Q_snprintf( buf, sizeof( buf ), "%lld", (int64)(size_t)dat->m_pValue ); + Q_snprintf( buf, sizeof( buf ), "%lld", (int64)dat->m_pValue ); SetString( keyName, buf ); break; case TYPE_INT: @@ -1478,7 +1478,7 @@ const wchar_t *KeyValues::GetWString( const char *keyName, const wchar_t *defaul SetWString( keyName, wbuf); break; case TYPE_PTR: - swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%lld", (int64)(size_t)dat->m_pValue ); + swprintf( wbuf, Q_ARRAYSIZE(wbuf), L"%lld", (int64)dat->m_pValue ); SetWString( keyName, wbuf ); break; case TYPE_INT: diff --git a/tier1/stringpool.cpp b/tier1/stringpool.cpp index 6b6b0ff9..2f0fbf6c 100644 --- a/tier1/stringpool.cpp +++ b/tier1/stringpool.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -18,16 +18,21 @@ // Purpose: Comparison function for string sorted associative data structures //----------------------------------------------------------------------------- -bool StrLess( const char * const &pszLeft, const char * const &pszRight ) +bool StrLessInsensitive( const char * const &pszLeft, const char * const &pszRight ) { return ( Q_stricmp( pszLeft, pszRight) < 0 ); } +bool StrLessSensitive( const char * const &pszLeft, const char * const &pszRight ) +{ + return ( Q_strcmp( pszLeft, pszRight) < 0 ); +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -CStringPool::CStringPool() - : m_Strings( 32, 256, StrLess ) +CStringPool::CStringPool( StringPoolCase_t caseSensitivity ) + : m_Strings( 32, 256, caseSensitivity == StringPoolCaseInsensitive ? StrLessInsensitive : StrLessSensitive ) { } @@ -69,9 +74,7 @@ const char * CStringPool::Allocate( const char *pszValue ) return m_Strings[i]; pszNew = strdup( pszValue ); - - if ( bNew ) - m_Strings.Insert( pszNew ); + m_Strings.Insert( pszNew ); return pszNew; } @@ -94,217 +97,6 @@ void CStringPool::FreeAll() //----------------------------------------------------------------------------- -CCountedStringPool::CCountedStringPool() -{ - MEM_ALLOC_CREDIT(); - m_HashTable.EnsureCount(HASH_TABLE_SIZE); - - for( int i = 0; i < m_HashTable.Count(); i++ ) - { - m_HashTable[i] = INVALID_ELEMENT; - } - - m_FreeListStart = INVALID_ELEMENT; - m_Elements.AddToTail(); - m_Elements[0].pString = NULL; - m_Elements[0].nReferenceCount = 0; - m_Elements[0].nNextElement = INVALID_ELEMENT; -} - -CCountedStringPool::~CCountedStringPool() -{ - FreeAll(); -} - -void CCountedStringPool::FreeAll() -{ - int i; - - // Reset the hash table: - for( i = 0; i < m_HashTable.Count(); i++ ) - { - m_HashTable[i] = INVALID_ELEMENT; - } - - // Blow away the free list: - m_FreeListStart = INVALID_ELEMENT; - - for( i = 0; i < m_Elements.Count(); i++ ) - { - if( m_Elements[i].pString ) - { - delete [] m_Elements[i].pString; - m_Elements[i].pString = NULL; - m_Elements[i].nReferenceCount = 0; - m_Elements[i].nNextElement = INVALID_ELEMENT; - } - } - - // Remove all but the invalid element: - m_Elements.RemoveAll(); - m_Elements.AddToTail(); - m_Elements[0].pString = NULL; - m_Elements[0].nReferenceCount = 0; - m_Elements[0].nNextElement = INVALID_ELEMENT; -} - - -unsigned short CCountedStringPool::FindStringHandle( const char* pIntrinsic ) -{ - if( pIntrinsic == NULL ) - return INVALID_ELEMENT; - - unsigned short nHashBucketIndex = (HashStringCaseless(pIntrinsic ) %HASH_TABLE_SIZE); - unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ]; - - // Does the bucket already exist? - if( nCurrentBucket != INVALID_ELEMENT ) - { - for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement ) - { - if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) ) - { - return nCurrentBucket; - } - } - } - - return 0; - -} - -char* CCountedStringPool::FindString( const char* pIntrinsic ) -{ - if( pIntrinsic == NULL ) - return NULL; - - // Yes, this will be NULL on failure. - return m_Elements[FindStringHandle(pIntrinsic)].pString; -} - -unsigned short CCountedStringPool::ReferenceStringHandle( const char* pIntrinsic ) -{ - if( pIntrinsic == NULL ) - return INVALID_ELEMENT; - - unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % HASH_TABLE_SIZE); - unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ]; - - // Does the bucket already exist? - if( nCurrentBucket != INVALID_ELEMENT ) - { - for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement ) - { - if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) ) - { - // Anyone who hits 65k references is permanant - if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE ) - { - m_Elements[nCurrentBucket].nReferenceCount ++ ; - } - return nCurrentBucket; - } - } - } - - if( m_FreeListStart != INVALID_ELEMENT ) - { - nCurrentBucket = m_FreeListStart; - m_FreeListStart = m_Elements[nCurrentBucket].nNextElement; - } - else - { - nCurrentBucket = m_Elements.AddToTail(); - } - - m_Elements[nCurrentBucket].nReferenceCount = 1; - - // Insert at the beginning of the bucket: - m_Elements[nCurrentBucket].nNextElement = m_HashTable[ nHashBucketIndex ]; - m_HashTable[ nHashBucketIndex ] = nCurrentBucket; - - m_Elements[nCurrentBucket].pString = new char[Q_strlen( pIntrinsic ) + 1]; - Q_strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic ); - - return nCurrentBucket; -} - - -char* CCountedStringPool::ReferenceString( const char* pIntrinsic ) -{ - if(!pIntrinsic) - return NULL; - - return m_Elements[ReferenceStringHandle( pIntrinsic)].pString; -} - -void CCountedStringPool::DereferenceString( const char* pIntrinsic ) -{ - // If we get a NULL pointer, just return - if (!pIntrinsic) - return; - - unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % m_HashTable.Count()); - unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ]; - - // If there isn't anything in the bucket, just return. - if ( nCurrentBucket == INVALID_ELEMENT ) - return; - - for( unsigned short previous = INVALID_ELEMENT; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement ) - { - if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) ) - { - // Anyone who hits 65k references is permanant - if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE ) - { - m_Elements[nCurrentBucket].nReferenceCount --; - } - - if( m_Elements[nCurrentBucket].nReferenceCount == 0 ) - { - if( previous == INVALID_ELEMENT ) - { - m_HashTable[nHashBucketIndex] = m_Elements[nCurrentBucket].nNextElement; - } - else - { - m_Elements[previous].nNextElement = m_Elements[nCurrentBucket].nNextElement; - } - - delete [] m_Elements[nCurrentBucket].pString; - m_Elements[nCurrentBucket].pString = NULL; - m_Elements[nCurrentBucket].nReferenceCount = 0; - - m_Elements[nCurrentBucket].nNextElement = m_FreeListStart; - m_FreeListStart = nCurrentBucket; - break; - - } - } - - previous = nCurrentBucket; - } -} - -char* CCountedStringPool::HandleToString( unsigned short handle ) -{ - return m_Elements[handle].pString; -} - -void CCountedStringPool::SpewStrings() -{ - int i; - for ( i = 0; i < m_Elements.Count(); i++ ) - { - char* string = m_Elements[i].pString; - - Msg("String %d: ref:%d %s", i, m_Elements[i].nReferenceCount, string == NULL? "EMPTY - ok for slot zero only!" : string); - } - - Msg("\n%d total counted strings.", m_Elements.Count()); -} - #ifdef _DEBUG CON_COMMAND( test_stringpool, "Tests the class CStringPool" ) { diff --git a/tier1/utlbuffer.cpp b/tier1/utlbuffer.cpp index ff03da06..ae29160f 100644 --- a/tier1/utlbuffer.cpp +++ b/tier1/utlbuffer.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // $Header: $ // $NoKeywords: $ @@ -92,14 +92,14 @@ CUtlCStringConversion::CUtlCStringConversion( char nEscapeChar, const char *pDel memset( m_pConversion, 0x0, sizeof(m_pConversion) ); for ( int i = 0; i < nCount; ++i ) { - m_pConversion[ (unsigned char) pArray[i].m_pReplacementString[0] ] = pArray[i].m_nActualChar; + m_pConversion[ (unsigned char)(pArray[i].m_pReplacementString[0]) ] = pArray[i].m_nActualChar; } } // Finds a conversion for the passed-in string, returns length char CUtlCStringConversion::FindConversion( const char *pString, int *pLength ) { - char c = m_pConversion[ (unsigned char) pString[0] ]; + char c = m_pConversion[ (unsigned char)( pString[0] ) ]; *pLength = (c != '\0') ? 1 : 0; return c; } @@ -114,7 +114,7 @@ CUtlCharConversion::CUtlCharConversion( char nEscapeChar, const char *pDelimiter m_nEscapeChar = nEscapeChar; m_pDelimiter = pDelimiter; m_nCount = nCount; - m_nDelimiterLength = Q_strlen( pDelimiter ); + m_nDelimiterLength = V_strlen( pDelimiter ); m_nMaxConversionLength = 0; memset( m_pReplacements, 0, sizeof(m_pReplacements) ); @@ -122,10 +122,10 @@ CUtlCharConversion::CUtlCharConversion( char nEscapeChar, const char *pDelimiter for ( int i = 0; i < nCount; ++i ) { m_pList[i] = pArray[i].m_nActualChar; - ConversionInfo_t &info = m_pReplacements[ (unsigned char) m_pList[i] ]; + ConversionInfo_t &info = m_pReplacements[ (unsigned char)( m_pList[i] ) ]; Assert( info.m_pReplacementString == 0 ); info.m_pReplacementString = pArray[i].m_pReplacementString; - info.m_nLength = Q_strlen( info.m_pReplacementString ); + info.m_nLength = V_strlen( info.m_pReplacementString ); if ( info.m_nLength > m_nMaxConversionLength ) { m_nMaxConversionLength = info.m_nLength; @@ -158,12 +158,12 @@ int CUtlCharConversion::GetDelimiterLength() const //----------------------------------------------------------------------------- const char *CUtlCharConversion::GetConversionString( char c ) const { - return m_pReplacements[ (unsigned char) c ].m_pReplacementString; + return m_pReplacements[ (unsigned char)c ].m_pReplacementString; } int CUtlCharConversion::GetConversionLength( char c ) const { - return m_pReplacements[ (unsigned char) c ].m_nLength; + return m_pReplacements[ (unsigned char)c ].m_nLength; } int CUtlCharConversion::MaxConversionLength() const @@ -179,9 +179,9 @@ char CUtlCharConversion::FindConversion( const char *pString, int *pLength ) { for ( int i = 0; i < m_nCount; ++i ) { - if ( !Q_strcmp( pString, m_pReplacements[ (unsigned char) m_pList[i] ].m_pReplacementString ) ) + if ( !V_strcmp( pString, m_pReplacements[ (unsigned char)( m_pList[i] ) ].m_pReplacementString ) ) { - *pLength = m_pReplacements[ (unsigned char) m_pList[i] ].m_nLength; + *pLength = m_pReplacements[ (unsigned char)( m_pList[i] ) ].m_nLength; return m_pList[i]; } } @@ -207,7 +207,7 @@ CUtlBuffer::CUtlBuffer( int growSize, int initSize, int nFlags ) : if ( (initSize != 0) && !IsReadOnly() ) { m_nMaxPut = -1; - AddNullTermination(); + AddNullTermination( m_Put ); } else { @@ -228,17 +228,115 @@ CUtlBuffer::CUtlBuffer( const void *pBuffer, int nSize, int nFlags ) : m_Flags = nFlags; if ( IsReadOnly() ) { - m_nMaxPut = nSize; + m_nMaxPut = m_Put = nSize; } else { m_nMaxPut = -1; - AddNullTermination(); + AddNullTermination( m_Put ); } SetOverflowFuncs( &CUtlBuffer::GetOverflow, &CUtlBuffer::PutOverflow ); } +CUtlBuffer::CUtlBuffer( const CUtlBuffer& copyFrom ) +: m_Get( copyFrom.m_Get ) +, m_Put( copyFrom.m_Put ) +, m_Error( copyFrom.m_Error ) +, m_Flags( copyFrom.m_Flags ) +, m_Reserved( copyFrom.m_Reserved ) +#if defined( _GAMECONSOLE ) +, pad( copyFrom.pad ) +#endif +, m_nTab( copyFrom.m_nTab ) +, m_nMaxPut( copyFrom.m_nMaxPut ) +, m_nOffset( copyFrom.m_nOffset ) +, m_GetOverflowFunc( copyFrom.m_GetOverflowFunc ) +, m_PutOverflowFunc( copyFrom.m_PutOverflowFunc ) +, m_Byteswap( copyFrom.m_Byteswap ) +{ + if(copyFrom.m_Memory.Count() > 0) + { + Assert( false ); // This is a slow path, don't do this. + + // copy memory + m_Memory.EnsureCapacity( copyFrom.m_Memory.Count() ); + memcpy( m_Memory.Base(), copyFrom.m_Memory.Base(), copyFrom.m_Memory.Count() ); + } +} + + +CUtlBuffer& CUtlBuffer::operator=( const CUtlBuffer& copyFrom ) +{ + if ( copyFrom.m_Memory.Count() > 0 ) + { + Assert( false ); // This is a slow path, don't do this. + if(this != ©From) + { + m_Memory.Purge(); + m_Memory.EnsureCapacity( copyFrom.m_Memory.Count() ); + memcpy( m_Memory.Base(), copyFrom.m_Memory.Base(), copyFrom.m_Memory.Count() ); + } + } + m_Get = copyFrom.m_Get; + m_Put = copyFrom.m_Put; + m_Error = copyFrom.m_Error; + m_Flags = copyFrom.m_Flags; + m_Reserved = copyFrom.m_Reserved; +#if defined( _GAMECONSOLE ) + pad = copyFrom.pad; +#endif + m_nTab = copyFrom.m_nTab; + m_nMaxPut = copyFrom.m_nMaxPut; + m_nOffset = copyFrom.m_nOffset; + m_GetOverflowFunc = copyFrom.m_GetOverflowFunc; + m_PutOverflowFunc = copyFrom.m_PutOverflowFunc; + m_Byteswap = copyFrom.m_Byteswap; + + return *this; +} + +#if VALVE_CPP11 +CUtlBuffer::CUtlBuffer( CUtlBuffer&& moveFrom ) // = default +: m_Memory( Move( moveFrom.m_Memory ) ) +, m_Get( Move( moveFrom.m_Get ) ) +, m_Put( Move( moveFrom.m_Put ) ) +, m_Error( Move( moveFrom.m_Error ) ) +, m_Flags( Move( moveFrom.m_Flags ) ) +, m_Reserved( Move( moveFrom.m_Reserved ) ) +#if defined( _GAMECONSOLE ) +, pad( Move( moveFrom.pad ) ) +#endif +, m_nTab( Move( moveFrom.m_nTab ) ) +, m_nMaxPut( Move( moveFrom.m_nMaxPut ) ) +, m_nOffset( Move( moveFrom.m_nOffset ) ) +, m_GetOverflowFunc( Move( moveFrom.m_GetOverflowFunc ) ) +, m_PutOverflowFunc( Move( moveFrom.m_PutOverflowFunc ) ) +, m_Byteswap( Move( moveFrom.m_Byteswap ) ) +{} + +CUtlBuffer& CUtlBuffer::operator=( CUtlBuffer&& moveFrom ) // = default +{ + m_Memory = Move( moveFrom.m_Memory ); + m_Get = Move( moveFrom.m_Get ); + m_Put = Move( moveFrom.m_Put ); + m_Error = Move( moveFrom.m_Error ); + m_Flags = Move( moveFrom.m_Flags ); + m_Reserved = Move( moveFrom.m_Reserved ); +#if defined( _GAMECONSOLE ) + pad = Move( moveFrom.pad ); +#endif + m_nTab = Move( moveFrom.m_nTab ); + m_nMaxPut = Move( moveFrom.m_nMaxPut ); + m_nOffset = Move( moveFrom.m_nOffset ); + m_GetOverflowFunc = Move( moveFrom.m_GetOverflowFunc ); + m_PutOverflowFunc = Move( moveFrom.m_PutOverflowFunc ); + m_Byteswap = Move( moveFrom.m_Byteswap ); + + return *this; +} +#endif + //----------------------------------------------------------------------------- // Modifies the buffer to be binary or text; Blows away the buffer and the CONTAINS_CRLF value. //----------------------------------------------------------------------------- @@ -303,7 +401,7 @@ void CUtlBuffer::SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, i m_nOffset = 0; m_Flags = nFlags; m_nMaxPut = -1; - AddNullTermination(); + AddNullTermination( m_Put ); } //----------------------------------------------------------------------------- @@ -321,9 +419,25 @@ void CUtlBuffer::AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nF m_nOffset = 0; m_Flags = nFlags; m_nMaxPut = -1; - AddNullTermination(); + AddNullTermination( m_Put ); } + +//----------------------------------------------------------------------------- +// Allows the caller to control memory +//----------------------------------------------------------------------------- +void* CUtlBuffer::DetachMemory() +{ + // Reset all indices; we just changed memory + m_Get = 0; + m_Put = 0; + m_nTab = 0; + m_Error = 0; + m_nOffset = 0; + return m_Memory.DetachMemory( ); +} + + //----------------------------------------------------------------------------- // Makes sure we've got at least this much memory //----------------------------------------------------------------------------- @@ -351,16 +465,15 @@ void CUtlBuffer::EnsureCapacity( int num ) //----------------------------------------------------------------------------- // Base get method from which all others derive //----------------------------------------------------------------------------- -void CUtlBuffer::Get( void* pMem, int size ) +bool CUtlBuffer::Get( void* pMem, int size ) { if ( size > 0 && CheckGet( size ) ) { - int Index = m_Get - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) ); - - memcpy( pMem, &m_Memory[ Index ], size ); + memcpy( pMem, &m_Memory[m_Get - m_nOffset], size ); m_Get += size; + return true; } + return false; } @@ -372,10 +485,7 @@ int CUtlBuffer::GetUpTo( void *pMem, int nSize ) { if ( CheckArbitraryPeekGet( 0, nSize ) ) { - int Index = m_Get - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nSize - 1 ) ); - - memcpy( pMem, &m_Memory[ Index ], nSize ); + memcpy( pMem, &m_Memory[m_Get - m_nOffset], nSize ); m_Get += nSize; return nSize; } @@ -392,7 +502,7 @@ void CUtlBuffer::EatWhiteSpace() { while ( CheckGet( sizeof(char) ) ) { - if ( !isspace( *(const unsigned char*)PeekGet() ) ) + if ( !V_isspace( *(const unsigned char*)PeekGet() ) ) break; m_Get += sizeof(char); } @@ -437,7 +547,7 @@ int CUtlBuffer::PeekWhiteSpace( int nOffset ) while ( CheckPeekGet( nOffset, sizeof(char) ) ) { - if ( !isspace( *(unsigned char*)PeekGet( nOffset ) ) ) + if ( !V_isspace( *(unsigned char*)PeekGet( nOffset ) ) ) break; nOffset += sizeof(char); } @@ -491,7 +601,7 @@ int CUtlBuffer::PeekStringLength() for ( int i = 0; i < nPeekAmount; ++i ) { // The +1 here is so we eat the terminating 0 - if ( isspace((unsigned char)pTest[i]) || (pTest[i] == 0) ) + if ( V_isspace((unsigned char)pTest[i]) || (pTest[i] == 0) ) return (i + nOffset - nStartingOffset + 1); } } @@ -550,7 +660,7 @@ bool CUtlBuffer::PeekStringMatch( int nOffset, const char *pString, int nLen ) { if ( !CheckPeekGet( nOffset, nLen ) ) return false; - return !Q_strncmp( (const char*)PeekGet(nOffset), pString, nLen ); + return !V_strncmp( (const char*)PeekGet(nOffset), pString, nLen ); } @@ -607,19 +717,16 @@ int CUtlBuffer::PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActu //----------------------------------------------------------------------------- // Reads a null-terminated string //----------------------------------------------------------------------------- -void CUtlBuffer::GetStringInternal( char *pString, size_t maxLenInChars ) +void CUtlBuffer::GetString( char* pString, int nMaxChars ) { - if ( !IsValid() ) + if (!IsValid()) { *pString = 0; return; } - // This can legitimately be zero if we were told that the buffer is zero length, and - // we're asking to duplicate the buffer, so let that pass, too. - Assert( maxLenInChars != 0 || PeekStringLength() == 0 ); - - if ( maxLenInChars == 0 ) + Assert( nMaxChars > 0 ); + if ( nMaxChars <= 0 ) { return; } @@ -640,14 +747,14 @@ void CUtlBuffer::GetStringInternal( char *pString, size_t maxLenInChars ) return; } - const size_t nCharsToRead = min( (size_t)nLen, maxLenInChars ) - 1; - + const int nCharsToRead = Min( nLen, nMaxChars ) - 1; + Get( pString, nCharsToRead ); - pString[nCharsToRead] = 0; + pString[ nCharsToRead ] = 0; - if ( (size_t)nLen > (nCharsToRead + 1) ) + if ( nLen > ( nCharsToRead + 1 ) ) { - SeekGet( SEEK_CURRENT, nLen - (nCharsToRead + 1) ); + SeekGet( SEEK_CURRENT, nLen - ( nCharsToRead + 1 ) ); } // Read the terminating NULL in binary formats @@ -663,7 +770,7 @@ void CUtlBuffer::GetStringInternal( char *pString, size_t maxLenInChars ) //----------------------------------------------------------------------------- void CUtlBuffer::GetLine( char* pLine, int nMaxChars ) { - Assert( IsText() && !ContainsCRLF() ); + //Assert( IsText() && !ContainsCRLF() ); if ( !IsValid() ) { @@ -732,7 +839,7 @@ void CUtlBuffer::GetDelimitedString( CUtlCharConversion *pConv, char *pString, i { if ( !IsText() || !pConv ) { - GetStringInternal( pString, nMaxChars ); + GetString( pString, nMaxChars ); return; } @@ -858,11 +965,7 @@ const void* CUtlBuffer::PeekGet( int nMaxSize, int nOffset ) { if ( !CheckPeekGet( nOffset, nMaxSize ) ) return NULL; - - int Index = m_Get + nOffset - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + nMaxSize - 1 ) ); - - return &m_Memory[ Index ]; + return &m_Memory[ m_Get + nOffset - m_nOffset ]; } @@ -914,10 +1017,8 @@ int CUtlBuffer::VaScanf( const char* pFmt, va_list list ) return 0; int numScanned = 0; - int nLength; char c; - char* pEnd; - while ( (c = *pFmt++) ) + while ( c = *pFmt++ ) { // Stop if we hit the end of the buffer if ( m_Get >= TellMaxPut() ) @@ -956,93 +1057,105 @@ int CUtlBuffer::VaScanf( const char* pFmt, va_list list ) return numScanned; } } - break; + break; + + case 'h': + { + if ( *pFmt == 'd' || *pFmt == 'i' ) + { + if ( !GetTypeText( *va_arg( list, int16 * ) ) ) + return numScanned; // only support short ints, don't bother with hex + } + else if ( *pFmt == 'u' ) + { + if ( !GetTypeText( *va_arg( list, uint16 * ) ) ) + return numScanned; + } + else + return numScanned; + ++pFmt; + } + break; + + case 'I': + { + if ( *pFmt++ != '6' || *pFmt++ != '4' ) + return numScanned; // only support "I64d" and "I64u" + + if ( *pFmt == 'd' ) + { + if ( !GetTypeText( *va_arg( list, int64 * ) ) ) + return numScanned; + } + else if ( *pFmt == 'u' ) + { + if ( !GetTypeText( *va_arg( list, uint64 * ) ) ) + return numScanned; + } + else + { + return numScanned; + } + + ++pFmt; + } + break; case 'i': case 'd': { - int* i = va_arg( list, int * ); - - // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters - nLength = 128; - if ( !CheckArbitraryPeekGet( 0, nLength ) ) - { - *i = 0; + int32 *pArg = va_arg( list, int32 * ); + if ( !GetTypeText( *pArg ) ) return numScanned; - } - - *i = strtol( (char*)PeekGet(), &pEnd, 10 ); - int nBytesRead = (int)( pEnd - (char*)PeekGet() ); - if ( nBytesRead == 0 ) - return numScanned; - m_Get += nBytesRead; } break; - + case 'x': { - int* i = va_arg( list, int * ); - - // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters - nLength = 128; - if ( !CheckArbitraryPeekGet( 0, nLength ) ) - { - *i = 0; + uint32 *pArg = va_arg( list, uint32 * ); + if ( !GetTypeText( *pArg, 16 ) ) return numScanned; - } - - *i = strtol( (char*)PeekGet(), &pEnd, 16 ); - int nBytesRead = (int)( pEnd - (char*)PeekGet() ); - if ( nBytesRead == 0 ) - return numScanned; - m_Get += nBytesRead; } break; - + case 'u': { - unsigned int* u = va_arg( list, unsigned int *); - - // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters - nLength = 128; - if ( !CheckArbitraryPeekGet( 0, nLength ) ) - { - *u = 0; + uint32 *pArg = va_arg( list, uint32 * ); + if ( !GetTypeText( *pArg ) ) return numScanned; - } - - *u = strtoul( (char*)PeekGet(), &pEnd, 10 ); - int nBytesRead = (int)( pEnd - (char*)PeekGet() ); - if ( nBytesRead == 0 ) - return numScanned; - m_Get += nBytesRead; } break; - + + case 'l': + { + // we currently support %lf and %lld + if ( *pFmt == 'f' ) + { + if ( !GetTypeText( *va_arg( list, double * ) ) ) + return numScanned; + } + else if ( *pFmt == 'l' && *++pFmt == 'd' ) + { + if ( !GetTypeText( *va_arg( list, int64 * ) ) ) + return numScanned; + } + else + return numScanned; + } + break; + case 'f': { - float* f = va_arg( list, float *); - - // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters - nLength = 128; - if ( !CheckArbitraryPeekGet( 0, nLength ) ) - { - *f = 0.0f; + float *pArg = va_arg( list, float * ); + if ( !GetTypeText( *pArg ) ) return numScanned; - } - - *f = (float)strtod( (char*)PeekGet(), &pEnd ); - int nBytesRead = (int)( pEnd - (char*)PeekGet() ); - if ( nBytesRead == 0 ) - return numScanned; - m_Get += nBytesRead; } break; - + case 's': { char* s = va_arg( list, char * ); - GetStringInternal( s, 256 ); + GetString( s, 64 ); // [SECURITY EXPLOIT: Scanf %s should be deprecated as malicious data can overrun stack buffers! Here we'd assume that at least 64 bytes are available on the stack, and even if not this shouldn't give attracker much room for code execution] } break; @@ -1099,38 +1212,55 @@ bool CUtlBuffer::GetToken( const char *pToken ) Assert( pToken ); // Look for the token - int nLen = Q_strlen( pToken ); + int nLen = V_strlen( pToken ); - int nSizeToCheck = Size() - TellGet() - m_nOffset; + // First time through on streaming, check what we already have loaded + // if we have enough loaded to do the check + int nMaxSize = Size() - ( TellGet() - m_nOffset ); + if ( nMaxSize <= nLen ) + { + nMaxSize = Size(); + } + int nSizeRemaining = TellMaxPut() - TellGet(); int nGet = TellGet(); - do + while ( nSizeRemaining >= nLen ) { - int nMaxSize = TellMaxPut() - TellGet(); - if ( nMaxSize < nSizeToCheck ) - { - nSizeToCheck = nMaxSize; - } - if ( nLen > nSizeToCheck ) - break; - + bool bOverFlow = ( nSizeRemaining > nMaxSize ); + int nSizeToCheck = bOverFlow ? nMaxSize : nSizeRemaining; if ( !CheckPeekGet( 0, nSizeToCheck ) ) break; const char *pBufStart = (const char*)PeekGet(); - const char *pFoundEnd = Q_strnistr( pBufStart, pToken, nSizeToCheck ); - if ( pFoundEnd ) + const char *pFoundEnd = V_strnistr( pBufStart, pToken, nSizeToCheck ); + + // Time to be careful: if we are in a state of overflow + // (namely, there's more of the buffer beyond the current window) + // we could be looking for 'foo' for example, and find 'foobar' + // if 'foo' happens to be the last 3 characters of the current window + size_t nOffset = (size_t)pFoundEnd - (size_t)pBufStart; + bool bPotentialMismatch = ( bOverFlow && ( (int)nOffset == Size() - nLen ) ); + if ( !pFoundEnd || bPotentialMismatch ) { - size_t nOffset = (size_t)pFoundEnd - (size_t)pBufStart; - SeekGet( CUtlBuffer::SEEK_CURRENT, nOffset + nLen ); - return true; + nSizeRemaining -= nSizeToCheck; + if ( !pFoundEnd && ( nSizeRemaining < nLen ) ) + break; + + // Second time through, stream as much in as possible + // But keep the last portion of the current buffer + // since we couldn't check it against stuff outside the window + nSizeRemaining += nLen; + nMaxSize = Size(); + SeekGet( CUtlBuffer::SEEK_CURRENT, nSizeToCheck - nLen ); + continue; } - SeekGet( CUtlBuffer::SEEK_CURRENT, nSizeToCheck - nLen - 1 ); - nSizeToCheck = Size() - (nLen-1); - - } while ( true ); + // Seek past the end of the found string + SeekGet( CUtlBuffer::SEEK_CURRENT, (int)( nOffset + nLen ) ); + return true; + } + // Didn't find a match, leave the get index where it was to start with SeekGet( CUtlBuffer::SEEK_HEAD, nGet ); return false; } @@ -1161,7 +1291,7 @@ bool CUtlBuffer::ParseToken( const char *pStartingDelim, const char *pEndingDeli // Ending delimiter is not Assert( pEndingDelim && pEndingDelim[0] ); - nEndingDelimLen = Q_strlen( pEndingDelim ); + nEndingDelimLen = V_strlen( pEndingDelim ); int nStartGet = TellGet(); char nCurrChar; @@ -1170,7 +1300,7 @@ bool CUtlBuffer::ParseToken( const char *pStartingDelim, const char *pEndingDeli while ( *pStartingDelim ) { nCurrChar = *pStartingDelim++; - if ( !isspace((unsigned char)nCurrChar) ) + if ( !V_isspace((unsigned char)nCurrChar) ) { if ( tolower( GetChar() ) != tolower( nCurrChar ) ) goto parseFailed; @@ -1187,7 +1317,7 @@ bool CUtlBuffer::ParseToken( const char *pStartingDelim, const char *pEndingDeli goto parseFailed; nCurrentGet = TellGet(); - nCharsToCopy = (nCurrentGet - nEndingDelimLen) - nTokenStart; + nCharsToCopy = (int)( (nCurrentGet - nEndingDelimLen) - nTokenStart ); if ( nCharsToCopy >= nMaxLen ) { nCharsToCopy = nMaxLen - 1; @@ -1203,7 +1333,7 @@ bool CUtlBuffer::ParseToken( const char *pStartingDelim, const char *pEndingDeli // Eat trailing whitespace for ( ; nCharsToCopy > 0; --nCharsToCopy ) { - if ( !isspace( (unsigned char)pString[ nCharsToCopy-1 ] ) ) + if ( !V_isspace( (unsigned char)pString[ nCharsToCopy-1 ] ) ) break; } } @@ -1319,15 +1449,10 @@ void CUtlBuffer::Put( const void *pMem, int size ) { if ( size && CheckPut( size ) ) { - int Index = m_Put - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) && m_Memory.IsIdxValid( Index + size - 1 ) ); - if( Index >= 0 ) - { - memcpy( &m_Memory[ Index ], pMem, size ); - m_Put += size; + memcpy( &m_Memory[m_Put - m_nOffset], pMem, size ); + m_Put += size; - AddNullTermination(); - } + AddNullTermination( m_Put ); } } @@ -1342,7 +1467,7 @@ void CUtlBuffer::PutString( const char* pString ) if ( pString ) { // Not text? append a null at the end. - size_t nLen = Q_strlen( pString ) + 1; + int nLen = (int)V_strlen( pString ) + 1; Put( pString, nLen * sizeof(char) ); return; } @@ -1365,7 +1490,7 @@ void CUtlBuffer::PutString( const char* pString ) while ( pEndl ) { size_t nSize = (size_t)pEndl - (size_t)pString + sizeof(char); - Put( pString, nSize ); + Put( pString, (int)nSize ); pString = pEndl + 1; if ( *pString ) { @@ -1378,7 +1503,7 @@ void CUtlBuffer::PutString( const char* pString ) } } } - size_t nLen = Q_strlen( pString ); + int nLen = (int)V_strlen( pString ); if ( nLen ) { Put( pString, nLen * sizeof(char) ); @@ -1430,7 +1555,7 @@ void CUtlBuffer::PutDelimitedString( CUtlCharConversion *pConv, const char *pStr } Put( pConv->GetDelimiter(), pConv->GetDelimiterLength() ); - int nLen = pString ? Q_strlen( pString ) : 0; + int nLen = pString ? V_strlen( pString ) : 0; for ( int i = 0; i < nLen; ++i ) { PutDelimitedCharInternal( pConv, pString[i] ); @@ -1446,12 +1571,9 @@ void CUtlBuffer::PutDelimitedString( CUtlCharConversion *pConv, const char *pStr void CUtlBuffer::VaPrintf( const char* pFmt, va_list list ) { - char temp[2048]; -#ifdef DBGFLAG_ASSERT - int nLen = -#endif - Q_vsnprintf( temp, sizeof( temp ), pFmt, list ); - Assert( nLen < 2048 ); + char temp[8192]; + int nLen = V_vsnprintf( temp, sizeof( temp ), pFmt, list ); + ErrorIfNot( nLen < sizeof( temp ), ( "CUtlBuffer::VaPrintf: String overflowed buffer [%d]\n", sizeof( temp ) ) ); PutString( temp ); } @@ -1563,7 +1685,7 @@ void CUtlBuffer::SeekPut( SeekType_t type, int offset ) OnPutOverflow( -nNextPut-1 ); m_Put = nNextPut; - AddNullTermination(); + AddNullTermination( m_Put ); } @@ -1585,8 +1707,10 @@ bool CUtlBuffer::IsBigEndian( void ) //----------------------------------------------------------------------------- // null terminate the buffer +// NOTE: Pass in nPut here even though it is just a copy of m_Put. This is almost always called immediately +// after modifying m_Put and this lets it stay in a register and avoid LHS on PPC. //----------------------------------------------------------------------------- -void CUtlBuffer::AddNullTermination( void ) +void CUtlBuffer::AddNullTermination( ) { if ( m_Put > m_nMaxPut ) { @@ -1595,12 +1719,7 @@ void CUtlBuffer::AddNullTermination( void ) // Add null termination value if ( CheckPut( 1 ) ) { - int Index = m_Put - m_nOffset; - Assert( m_Memory.IsIdxValid( Index ) ); - if( Index >= 0 ) - { - m_Memory[ Index ] = 0; - } + m_Memory[m_Put - m_nOffset] = 0; } else { @@ -1613,6 +1732,29 @@ void CUtlBuffer::AddNullTermination( void ) } +void CUtlBuffer::AddNullTermination( int nPut ) +{ + if ( nPut > m_nMaxPut ) + { + if ( !IsReadOnly() && ((m_Error & PUT_OVERFLOW) == 0) ) + { + // Add null termination value + if ( CheckPut( 1 ) ) + { + m_Memory[nPut - m_nOffset] = 0; + } + else + { + // Restore the overflow state, it was valid before... + m_Error &= ~PUT_OVERFLOW; + } + } + m_nMaxPut = nPut; + } +} + + + //----------------------------------------------------------------------------- // Converts a buffer from a CRLF buffer to a CR buffer (and back) // Returns false if no conversion was necessary (and outBuf is left untouched) @@ -1640,21 +1782,21 @@ bool CUtlBuffer::ConvertCRLF( CUtlBuffer &outBuf ) int nPutDelta = 0; const char *pBase = (const char*)Base(); - int nCurrGet = 0; + intp nCurrGet = 0; while ( nCurrGet < nInCount ) { const char *pCurr = &pBase[nCurrGet]; if ( bFromCRLF ) { - const char *pNext = Q_strnistr( pCurr, "\r\n", nInCount - nCurrGet ); + const char *pNext = V_strnistr( pCurr, "\r\n", nInCount - nCurrGet ); if ( !pNext ) { outBuf.Put( pCurr, nInCount - nCurrGet ); break; } - int nBytes = (size_t)pNext - (size_t)pCurr; - outBuf.Put( pCurr, nBytes ); + intp nBytes = (intp)pNext - (intp)pCurr; + outBuf.Put( pCurr, (int)nBytes ); outBuf.PutChar( '\n' ); nCurrGet += nBytes + 2; if ( nGet >= nCurrGet - 1 ) @@ -1668,15 +1810,15 @@ bool CUtlBuffer::ConvertCRLF( CUtlBuffer &outBuf ) } else { - const char *pNext = Q_strnchr( pCurr, '\n', nInCount - nCurrGet ); + const char *pNext = V_strnchr( pCurr, '\n', nInCount - nCurrGet ); if ( !pNext ) { outBuf.Put( pCurr, nInCount - nCurrGet ); break; } - int nBytes = (size_t)pNext - (size_t)pCurr; - outBuf.Put( pCurr, nBytes ); + intp nBytes = (intp)pNext - (intp)pCurr; + outBuf.Put( pCurr, (int)nBytes ); outBuf.PutChar( '\r' ); outBuf.PutChar( '\n' ); nCurrGet += nBytes + 1; @@ -1793,4 +1935,3 @@ char * CUtlInplaceBuffer::InplaceGetLinePtr( void ) return pszLine; } - diff --git a/tier1/utlsymbol.cpp b/tier1/utlsymbol.cpp index d75eaa52..2f3e32cc 100644 --- a/tier1/utlsymbol.cpp +++ b/tier1/utlsymbol.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Defines a symbol table // @@ -9,29 +9,11 @@ #pragma warning (disable:4514) #include "utlsymbol.h" -#include "KeyValues.h" #include "tier0/threadtools.h" -#include "tier0/memdbgon.h" #include "stringpool.h" -#include "utlhashtable.h" -#include "utlstring.h" - -// Ensure that everybody has the right compiler version installed. The version -// number can be obtained by looking at the compiler output when you type 'cl' -// and removing the last two digits and the periods: 16.00.40219.01 becomes 160040219 -#ifdef _MSC_FULL_VER - #if _MSC_FULL_VER > 160000000 - // VS 2010 - #if _MSC_FULL_VER < 160040219 - #error You must install VS 2010 SP1 - #endif - #else - // VS 2005 - #if _MSC_FULL_VER < 140050727 - #error You must install VS 2005 SP1 - #endif - #endif -#endif +#include "generichash.h" +#include "tier0/vprof.h" +#include // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -68,6 +50,17 @@ void CUtlSymbol::Initialize() } } +void CUtlSymbol::LockTableForRead() +{ + Initialize(); + s_pSymbolTable->LockForRead(); +} + +void CUtlSymbol::UnlockTableForRead() +{ + s_pSymbolTable->UnlockForRead(); +} + //----------------------------------------------------------------------------- // Purpose: Singleton to delete table on exit from module //----------------------------------------------------------------------------- @@ -104,6 +97,11 @@ const char* CUtlSymbol::String( ) const return CurrTable()->String(m_Id); } +const char* CUtlSymbol::StringNoLock( ) const +{ + return CurrTable()->StringNoLock(m_Id); +} + void CUtlSymbol::DisableStaticSymbolTable() { s_bAllowStaticSymbolTable = false; @@ -125,16 +123,25 @@ bool CUtlSymbol::operator==( const char* pStr ) const //----------------------------------------------------------------------------- // symbol table stuff //----------------------------------------------------------------------------- - -inline const char* CUtlSymbolTable::StringFromIndex( const CStringPoolIndex &index ) const +inline const char* CUtlSymbolTable::DecoratedStringFromIndex( const CStringPoolIndex &index ) const { Assert( index.m_iPool < m_StringPools.Count() ); Assert( index.m_iOffset < m_StringPools[index.m_iPool]->m_TotalLen ); - return &m_StringPools[index.m_iPool]->m_Data[index.m_iOffset]; + // step over the hash decorating the beginning of the string + return (&m_StringPools[index.m_iPool]->m_Data[index.m_iOffset]); } +inline const char* CUtlSymbolTable::StringFromIndex( const CStringPoolIndex &index ) const +{ + // step over the hash decorating the beginning of the string + return DecoratedStringFromIndex(index)+sizeof(hashDecoration_t); +} +// The first two bytes of each string in the pool are actually the hash for that string. +// Thus we compare hashes rather than entire strings for a significant perf benefit. +// However since there is a high rate of hash collision we must still compare strings +// if the hashes match. bool CUtlSymbolTable::CLess::operator()( const CStringPoolIndex &i1, const CStringPoolIndex &i2 ) const { // Need to do pointer math because CUtlSymbolTable is used in CUtlVectors, and hence @@ -142,21 +149,79 @@ bool CUtlSymbolTable::CLess::operator()( const CStringPoolIndex &i1, const CStri // right now at least, because m_LessFunc is the first member of CUtlRBTree, and m_Lookup // is the first member of CUtlSymbolTabke, this == pTable CUtlSymbolTable *pTable = (CUtlSymbolTable *)( (byte *)this - offsetof(CUtlSymbolTable::CTree, m_LessFunc) ) - offsetof(CUtlSymbolTable, m_Lookup ); + +#if 1 // using the hashes + const char *str1, *str2; + hashDecoration_t hash1, hash2; + + if (i1 == INVALID_STRING_INDEX) + { + str1 = pTable->m_pUserSearchString; + hash1 = pTable->m_nUserSearchStringHash; + } + else + { + str1 = pTable->DecoratedStringFromIndex( i1 ); + hashDecoration_t storedHash = *reinterpret_cast(str1); + str1 += sizeof(hashDecoration_t); + AssertMsg2( storedHash == ( !pTable->m_bInsensitive ? HashString(str1) : HashStringCaseless(str1) ), + "The stored hash (%d) for symbol %s is not correct.", storedHash, str1 ); + hash1 = storedHash; + } + + if (i2 == INVALID_STRING_INDEX) + { + str2 = pTable->m_pUserSearchString; + hash2 = pTable->m_nUserSearchStringHash; + } + else + { + str2 = pTable->DecoratedStringFromIndex( i2 ); + hashDecoration_t storedHash = *reinterpret_cast(str2); + str2 += sizeof(hashDecoration_t); + AssertMsg2( storedHash == ( !pTable->m_bInsensitive ? HashString(str2) : HashStringCaseless(str2) ), + "The stored hash (%d) for symbol '%s' is not correct.", storedHash, str2 ); + hash2 = storedHash; + } + + // compare the hashes + if ( hash1 == hash2 ) + { + if ( !str1 && str2 ) + return 1; + if ( !str2 && str1 ) + return -1; + if ( !str1 && !str2 ) + return 0; + + // if the hashes match compare the strings + if ( !pTable->m_bInsensitive ) + return strcmp( str1, str2 ) < 0; + else + return V_stricmp( str1, str2 ) < 0; + } + else + { + return hash1 < hash2; + } + +#else // not using the hashes, just comparing strings const char* str1 = (i1 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString : - pTable->StringFromIndex( i1 ); + pTable->StringFromIndex( i1 ); const char* str2 = (i2 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString : - pTable->StringFromIndex( i2 ); + pTable->StringFromIndex( i2 ); if ( !str1 && str2 ) - return false; + return 1; if ( !str2 && str1 ) - return true; + return -1; if ( !str1 && !str2 ) - return false; + return 0; if ( !pTable->m_bInsensitive ) - return V_strcmp( str1, str2 ) < 0; + return strcmp( str1, str2 ) < 0; else - return V_stricmp( str1, str2 ) < 0; + return strcmpi( str1, str2 ) < 0; +#endif } @@ -177,11 +242,13 @@ CUtlSymbolTable::~CUtlSymbolTable() CUtlSymbol CUtlSymbolTable::Find( const char* pString ) const { + VPROF( "CUtlSymbol::Find" ); if (!pString) return CUtlSymbol(); // Store a special context used to help with insertion m_pUserSearchString = pString; + m_nUserSearchStringHash = m_bInsensitive ? HashStringCaseless(pString) : HashString(pString) ; // Passing this special invalid symbol makes the comparison function // use the string passed in the context @@ -189,6 +256,7 @@ CUtlSymbol CUtlSymbolTable::Find( const char* pString ) const #ifdef _DEBUG m_pUserSearchString = NULL; + m_nUserSearchStringHash = 0; #endif return CUtlSymbol( idx ); @@ -217,6 +285,7 @@ int CUtlSymbolTable::FindPoolWithSpace( int len ) const CUtlSymbol CUtlSymbolTable::AddString( const char* pString ) { + VPROF("CUtlSymbol::AddString"); if (!pString) return CUtlSymbol( UTL_INVAL_SYMBOL ); @@ -225,35 +294,47 @@ CUtlSymbol CUtlSymbolTable::AddString( const char* pString ) if (id.IsValid()) return id; - int len = V_strlen(pString) + 1; + int lenString = strlen(pString) + 1; // length of just the string + int lenDecorated = lenString + sizeof(hashDecoration_t); // and with its hash decoration + // make sure that all strings are aligned on 2-byte boundaries so the hashes will read correctly + COMPILE_TIME_ASSERT(sizeof(hashDecoration_t) == 2); + lenDecorated = (lenDecorated + 1) & (~0x01); // round up to nearest multiple of 2 // Find a pool with space for this string, or allocate a new one. - int iPool = FindPoolWithSpace( len ); + int iPool = FindPoolWithSpace( lenDecorated ); if ( iPool == -1 ) { // Add a new pool. - int newPoolSize = max( len, MIN_STRING_POOL_SIZE ); - StringPool_t *pPool = (StringPool_t*)malloc( sizeof( StringPool_t ) + newPoolSize - 1 ); - pPool->m_TotalLen = newPoolSize; + int newPoolSize = MAX( lenDecorated + sizeof( StringPool_t ), MIN_STRING_POOL_SIZE ); + StringPool_t *pPool = (StringPool_t*)malloc( newPoolSize ); + pPool->m_TotalLen = newPoolSize - sizeof( StringPool_t ); pPool->m_SpaceUsed = 0; iPool = m_StringPools.AddToTail( pPool ); } + // Compute a hash + hashDecoration_t hash = m_bInsensitive ? HashStringCaseless(pString) : HashString(pString) ; + // Copy the string in. StringPool_t *pPool = m_StringPools[iPool]; Assert( pPool->m_SpaceUsed < 0xFFFF ); // This should never happen, because if we had a string > 64k, it // would have been given its entire own pool. unsigned short iStringOffset = pPool->m_SpaceUsed; + const char *startingAddr = &pPool->m_Data[pPool->m_SpaceUsed]; - memcpy( &pPool->m_Data[pPool->m_SpaceUsed], pString, len ); - pPool->m_SpaceUsed += len; + // store the hash at the head of the string + *((hashDecoration_t *)(startingAddr)) = hash; + // and then the string's data + memcpy( (void *)(startingAddr + sizeof(hashDecoration_t)), pString, lenString ); + pPool->m_SpaceUsed += lenDecorated; - // didn't find, insert the string into the vector. + // insert the string into the vector. CStringPoolIndex index; index.m_iPool = iPool; index.m_iOffset = iStringOffset; + MEM_ALLOC_CREDIT(); UtlSymId_t idx = m_Lookup.Insert( index ); return CUtlSymbol( idx ); } @@ -288,22 +369,6 @@ void CUtlSymbolTable::RemoveAll() } - -class CUtlFilenameSymbolTable::HashTable : public CUtlStableHashtable -{ -}; - -CUtlFilenameSymbolTable::CUtlFilenameSymbolTable() -{ - m_Strings = new HashTable; -} - -CUtlFilenameSymbolTable::~CUtlFilenameSymbolTable() -{ - delete m_Strings; -} - - //----------------------------------------------------------------------------- // Purpose: // Input : *pFileName - @@ -328,7 +393,7 @@ FileNameHandle_t CUtlFilenameSymbolTable::FindOrAddFileName( const char *pFileNa Q_strncpy( fn, pFileName, sizeof( fn ) ); Q_RemoveDotSlashes( fn ); #ifdef _WIN32 - Q_strlower( fn ); + strlwr( fn ); #endif // Split the filename into constituent parts @@ -340,20 +405,18 @@ FileNameHandle_t CUtlFilenameSymbolTable::FindOrAddFileName( const char *pFileNa // not found, lock and look again FileNameHandleInternal_t handle; m_lock.LockForWrite(); - handle.path = m_Strings->Insert( basepath ) + 1; - handle.file = m_Strings->Insert( filename ) + 1; - //handle.path = m_StringPool.FindStringHandle( basepath ); - //handle.file = m_StringPool.FindStringHandle( filename ); - //if ( handle.path != m_Strings.InvalidHandle() && handle.file ) - //{ + handle.SetPath( m_PathStringPool.FindStringHandle( basepath ) ); + handle.SetFile( m_FileStringPool.FindStringHandle( filename ) ); + if ( handle.GetPath() && handle.GetFile() ) + { // found - // m_lock.UnlockWrite(); - // return *( FileNameHandle_t * )( &handle ); - //} + m_lock.UnlockWrite(); + return *( FileNameHandle_t * )( &handle ); + } // safely add it - //handle.path = m_StringPool.ReferenceStringHandle( basepath ); - //handle.file = m_StringPool.ReferenceStringHandle( filename ); + handle.SetPath( m_PathStringPool.ReferenceStringHandle( basepath ) ); + handle.SetFile( m_FileStringPool.ReferenceStringHandle( filename ) ); m_lock.UnlockWrite(); return *( FileNameHandle_t * )( &handle ); @@ -371,7 +434,7 @@ FileNameHandle_t CUtlFilenameSymbolTable::FindFileName( const char *pFileName ) Q_strncpy( fn, pFileName, sizeof( fn ) ); Q_RemoveDotSlashes( fn ); #ifdef _WIN32 - Q_strlower( fn ); + strlwr( fn ); #endif // Split the filename into constituent parts @@ -382,16 +445,13 @@ FileNameHandle_t CUtlFilenameSymbolTable::FindFileName( const char *pFileName ) FileNameHandleInternal_t handle; - Assert( (uint16)(m_Strings->InvalidHandle() + 1) == 0 ); - m_lock.LockForRead(); - handle.path = m_Strings->Find(basepath) + 1; - handle.file = m_Strings->Find(filename) + 1; - //handle.path = m_StringPool.FindStringHandle(basepath); - //handle.file = m_StringPool.FindStringHandle(filename); + handle.SetPath( m_PathStringPool.FindStringHandle( basepath ) ); + handle.SetFile( m_FileStringPool.FindStringHandle( filename ) ); m_lock.UnlockRead(); - if ( handle.path == 0 || handle.file == 0 ) + + if ( ( handle.GetPath() == 0 ) || ( handle.GetFile() == 0 ) ) return NULL; return *( FileNameHandle_t * )( &handle ); @@ -406,17 +466,15 @@ bool CUtlFilenameSymbolTable::String( const FileNameHandle_t& handle, char *buf, { buf[ 0 ] = 0; - FileNameHandleInternal_t *internal = ( FileNameHandleInternal_t * )&handle; - if ( !internal || !internal->file || !internal->path ) + FileNameHandleInternal_t *internalFileHandle = ( FileNameHandleInternal_t * )&handle; + if ( !internalFileHandle ) { return false; } m_lock.LockForRead(); - //const char *path = m_StringPool.HandleToString(internal->path); - //const char *fn = m_StringPool.HandleToString(internal->file); - const char *path = (*m_Strings)[ internal->path - 1 ].Get(); - const char *fn = (*m_Strings)[ internal->file - 1].Get(); + const char *path = m_PathStringPool.HandleToString( internalFileHandle->GetPath() ); + const char *fn = m_FileStringPool.HandleToString( internalFileHandle->GetFile() ); m_lock.UnlockRead(); if ( !path || !fn ) @@ -432,5 +490,34 @@ bool CUtlFilenameSymbolTable::String( const FileNameHandle_t& handle, char *buf, void CUtlFilenameSymbolTable::RemoveAll() { - m_Strings->Purge(); + m_PathStringPool.FreeAll(); + m_FileStringPool.FreeAll(); +} + +void CUtlFilenameSymbolTable::SpewStrings() +{ + m_lock.LockForRead(); + m_PathStringPool.SpewStrings(); + m_FileStringPool.SpewStrings(); + m_lock.UnlockRead(); +} + +bool CUtlFilenameSymbolTable::SaveToBuffer( CUtlBuffer &buffer ) +{ + m_lock.LockForRead(); + bool bResult = m_PathStringPool.SaveToBuffer( buffer ); + bResult = bResult && m_FileStringPool.SaveToBuffer( buffer ); + m_lock.UnlockRead(); + + return bResult; +} + +bool CUtlFilenameSymbolTable::RestoreFromBuffer( CUtlBuffer &buffer ) +{ + m_lock.LockForWrite(); + bool bResult = m_PathStringPool.RestoreFromBuffer( buffer ); + bResult = bResult && m_FileStringPool.RestoreFromBuffer( buffer ); + m_lock.UnlockWrite(); + + return bResult; } diff --git a/vgui2/vgui_controls/BuildGroup.cpp b/vgui2/vgui_controls/BuildGroup.cpp index a5001cbe..1905f7b1 100644 --- a/vgui2/vgui_controls/BuildGroup.cpp +++ b/vgui2/vgui_controls/BuildGroup.cpp @@ -41,6 +41,7 @@ #include "filesystem.h" #include "tier0/icommandline.h" #include "const.h" +#include "vprof.h" #if defined( _X360 ) #include "xbox/xbox_win32stubs.h" @@ -869,18 +870,6 @@ void BuildGroup::PanelAdded(Panel *panel) _panelDar.AddToTail(temp); } -//----------------------------------------------------------------------------- -// Purpose: Add panel the list of panels that are in the build group -//----------------------------------------------------------------------------- -void BuildGroup::PanelRemoved(Panel *panel) -{ - Assert(panel); - - PHandle temp; - temp = panel; - _panelDar.FindAndRemove(temp); -} - //----------------------------------------------------------------------------- // Purpose: loads the control settings from file //----------------------------------------------------------------------------- @@ -1553,4 +1542,4 @@ void BuildGroup::ClearResFileCache() nIndex = m_dictCachedResFiles.Next( nIndex ); } m_dictCachedResFiles.Purge(); -} \ No newline at end of file +} diff --git a/vgui2/vgui_controls/Panel.cpp b/vgui2/vgui_controls/Panel.cpp index 3c53f350..3adbf7ed 100644 --- a/vgui2/vgui_controls/Panel.cpp +++ b/vgui2/vgui_controls/Panel.cpp @@ -3800,17 +3800,11 @@ void Panel::SetTall(int tall) void Panel::SetBuildGroup(BuildGroup* buildGroup) { - if ( _buildGroup == buildGroup ) - return; - if ( _buildGroup.Get() ) - { - _buildGroup->PanelRemoved( this ); - } - _buildGroup = buildGroup; - if ( _buildGroup.Get() ) - { + //TODO: remove from old group + + Assert(buildGroup != NULL); + _buildGroup = buildGroup; _buildGroup->PanelAdded(this); - } } bool Panel::IsBuildGroupEnabled() @@ -5142,7 +5136,7 @@ void Panel::OnMessage(const KeyValues *params, VPANEL ifromPanel) { typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, VPANEL); VPANEL vp1 = ivgui()->HandleToPanel( param1->GetInt() ); - VPANEL vp2 = ivgui()->HandleToPanel( param1->GetInt() ); + VPANEL vp2 = ivgui()->HandleToPanel( param2->GetInt() ); (this->*((MessageFunc_HandleConstCharPtr_t)pMap->func))( vp1, vp2 ); } else diff --git a/vphysics/physics_virtualmesh.cpp b/vphysics/physics_virtualmesh.cpp index 7f447a80..f3c7bd4c 100644 --- a/vphysics/physics_virtualmesh.cpp +++ b/vphysics/physics_virtualmesh.cpp @@ -27,7 +27,7 @@ class CPhysCollideVirtualMesh; CTSPool< CUtlVector > g_MeshFrameLocksPool; -CThreadLocalPtr< CUtlVector > g_pMeshFrameLocks; +CTHREADLOCALPTR(CUtlVector) g_pMeshFrameLocks; // This is the surfacemanager class for IVP that implements the required functions by layering CPhysCollideVirtualMesh class IVP_SurfaceManager_VirtualMesh : public IVP_SurfaceManager diff --git a/vphysics/vphysics_saverestore.cpp b/vphysics/vphysics_saverestore.cpp index 4908f807..7cdff13e 100644 --- a/vphysics/vphysics_saverestore.cpp +++ b/vphysics/vphysics_saverestore.cpp @@ -57,7 +57,7 @@ bool CPhysicsEnvironment::Save( const physsaveparams_t ¶ms ) if ( type >= 0 && type < PIID_NUM_TYPES ) { - params.pSave->WriteInt( (int *)¶ms.pObject ); + params.pSave->WriteData( (char *)¶ms.pObject, sizeof(void*) ); return (*saveFuncs[type])( params, params.pObject ); } return false; @@ -105,7 +105,7 @@ bool CPhysicsEnvironment::Restore( const physrestoreparams_t ¶ms ) if ( type >= 0 && type < PIID_NUM_TYPES ) { void *pOldObject; - params.pRestore->ReadInt( (int *)&pOldObject ); + params.pRestore->ReadData( (char *)&pOldObject, sizeof(void*), 0 ); if ( (*restoreFuncs[type])( params, params.ppObject ) ) { AddPtrAssociation( pOldObject, *params.ppObject ); @@ -131,11 +131,11 @@ void CPhysicsEnvironment::PostRestore() void CVPhysPtrSaveRestoreOps::Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) { - int *pField = (int *)fieldInfo.pField; + void *pField = (void *)fieldInfo.pField; int nObjects = fieldInfo.pTypeDesc->fieldSize; for ( int i = 0; i < nObjects; i++ ) { - pSave->WriteInt( pField ); + pSave->WriteData( (char*)pField, sizeof(void*) ); ++pField; } } @@ -153,9 +153,10 @@ void CVPhysPtrSaveRestoreOps::Restore( const SaveRestoreFieldInfo_t &fieldInfo, { void **ppField = (void **)fieldInfo.pField; int nObjects = fieldInfo.pTypeDesc->fieldSize; + for ( int i = 0; i < nObjects; i++ ) { - pRestore->ReadInt( (int *)ppField ); + pRestore->ReadData( (char *)ppField, sizeof(void*), 0 ); int iNewVal = s_VPhysPtrMap.Find( *ppField ); if ( iNewVal != s_VPhysPtrMap.InvalidIndex() ) @@ -188,10 +189,11 @@ void CVPhysPtrUtlVectorSaveRestoreOps::Save( const SaveRestoreFieldInfo_t &field VPhysPtrVector *pUtlVector = (VPhysPtrVector*)fieldInfo.pField; int nObjects = pUtlVector->Count(); + pSave->WriteInt( &nObjects ); for ( int i = 0; i < nObjects; i++ ) { - pSave->WriteInt( &pUtlVector->Element(i) ); + pSave->WriteData( (char*)&pUtlVector->Element(i), sizeof(void*) ); } } @@ -207,7 +209,8 @@ void CVPhysPtrUtlVectorSaveRestoreOps::Restore( const SaveRestoreFieldInfo_t &fi for ( int i = 0; i < nObjects; i++ ) { void **ppElem = (void**)(&pUtlVector->Element(i)); - pRestore->ReadInt( (int*)ppElem ); + + pRestore->ReadData( (char *)ppElem, sizeof(void*), 0 ); int iNewVal = s_VPhysPtrMap.Find( *ppElem ); if ( iNewVal != s_VPhysPtrMap.InvalidIndex() ) diff --git a/vstdlib/coroutine.cpp b/vstdlib/coroutine.cpp index a1bcfc1d..dc148a8c 100644 --- a/vstdlib/coroutine.cpp +++ b/vstdlib/coroutine.cpp @@ -585,7 +585,7 @@ private: CUtlVector m_VecCoroutineStack; }; -CThreadLocalPtr< CCoroutineMgr > g_ThreadLocalCoroutineMgr; +CTHREADLOCALPTR(CCoroutineMgr) g_ThreadLocalCoroutineMgr; CUtlVector< CCoroutineMgr * > g_VecPCoroutineMgr; CThreadMutex g_ThreadMutexCoroutineMgr; @@ -610,7 +610,7 @@ void Coroutine_ReleaseThreadMemory() { AUTO_LOCK( g_ThreadMutexCoroutineMgr ); - if ( g_ThreadLocalCoroutineMgr != NULL ) + if ( g_ThreadLocalCoroutineMgr != static_cast( nullptr ) ) { int iCoroutineMgr = g_VecPCoroutineMgr.Find( g_ThreadLocalCoroutineMgr ); delete g_VecPCoroutineMgr[iCoroutineMgr]; diff --git a/vstdlib/jobthread.cpp b/vstdlib/jobthread.cpp index 46d843e0..922b770f 100644 --- a/vstdlib/jobthread.cpp +++ b/vstdlib/jobthread.cpp @@ -227,7 +227,7 @@ public: // and execute or execute pFunctor right after completing current job and // before looking for another job. //----------------------------------------------------- - void ExecuteHighPriorityFunctor( CFunctor *pFunctor ); + // void ExecuteHighPriorityFunctor( CFunctor *pFunctor ); //----------------------------------------------------- // Add an function object to the queue (master thread) @@ -247,8 +247,6 @@ public: virtual void Reserved1() {} - void WaitForIdle( bool bAll = true ); - private: enum { @@ -418,7 +416,7 @@ private: CFunctor *pFunctor = NULL; tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s PeekCall():%d", __FUNCTION__, GetCallParam() ); - switch ( GetCallParam( &pFunctor ) ) + switch ( GetCallParam() ) { case TPM_EXIT: Reply( true ); @@ -427,10 +425,10 @@ private: case TPM_SUSPEND: Reply( true ); - SuspendCooperative(); + Suspend(); break; - case TPM_RUNFUNCTOR: +/* case TPM_RUNFUNCTOR: if( pFunctor ) { ( *pFunctor )(); @@ -441,7 +439,7 @@ private: Assert( pFunctor ); Reply( false ); } - break; + break;*/ default: AssertMsg( 0, "Unknown call to thread" ); @@ -535,7 +533,7 @@ int CThreadPool::NumIdleThreads() return m_nIdleThreads; } -void CThreadPool::ExecuteHighPriorityFunctor( CFunctor *pFunctor ) +/*void CThreadPool::ExecuteHighPriorityFunctor( CFunctor *pFunctor ) { int i; for ( i = 0; i < m_Threads.Count(); i++ ) @@ -547,7 +545,7 @@ void CThreadPool::ExecuteHighPriorityFunctor( CFunctor *pFunctor ) { m_Threads[i]->WaitForReply(); } -} +}*/ //--------------------------------------------------------- // Pause/resume processing jobs @@ -575,7 +573,10 @@ int CThreadPool::SuspendExecution() // here with the thread not actually suspended for ( i = 0; i < m_Threads.Count(); i++ ) { - m_Threads[i]->BWaitForThreadSuspendCooperative(); + while ( !m_Threads[i]->IsSuspended() ) + { + ThreadSleep(); + } } } @@ -593,7 +594,7 @@ int CThreadPool::ResumeExecution() { for ( int i = 0; i < m_Threads.Count(); i++ ) { - m_Threads[i]->ResumeCooperative(); + m_Threads[i]->Resume(); } } return result; @@ -601,13 +602,6 @@ int CThreadPool::ResumeExecution() //--------------------------------------------------------- -void CThreadPool::WaitForIdle( bool bAll ) -{ - ThreadWaitForEvents( m_IdleEvents.Count(), m_IdleEvents.Base(), bAll, 60000 ); -} - -//--------------------------------------------------------- - int CThreadPool::YieldWait( CThreadEvent **pEvents, int nEvents, bool bWaitAll, unsigned timeout ) { tmZone( TELEMETRY_LEVEL0, TMZF_IDLE, "%s(%d) SPINNING %t", __FUNCTION__, timeout, tmSendCallStack( TELEMETRY_LEVEL0, 0 ) ); @@ -618,7 +612,7 @@ int CThreadPool::YieldWait( CThreadEvent **pEvents, int nEvents, bool bWaitAll, CJob *pJob; // Always wait for zero milliseconds initially, to let us process jobs on this thread. timeout = 0; - while ( ( result = ThreadWaitForEvents( nEvents, pEvents, bWaitAll, timeout ) ) == WAIT_TIMEOUT ) + while ( ( result = CThreadEvent::WaitForMultiple( nEvents, pEvents, bWaitAll, timeout ) ) == TW_TIMEOUT ) { if ( !m_bExecOnThreadPoolThreadsOnly && m_SharedQueue.Pop( &pJob ) ) { diff --git a/wscript b/wscript index b3b87b0d..bdaab19a 100644 --- a/wscript +++ b/wscript @@ -158,11 +158,14 @@ def define_platform(conf): if conf.options.SDL: conf.define('USE_SDL', 1) + if conf.options.ALLOW64: + conf.define('PLATFORM_64BITS', 1) + if conf.env.DEST_OS == 'linux': conf.define('_GLIBCXX_USE_CXX11_ABI',0) conf.env.append_unique('DEFINES', [ 'LINUX=1', '_LINUX=1', - 'POSIX=1', '_POSIX=1', + 'POSIX=1', '_POSIX=1', 'PLATFORM_POSIX=1', 'GNUC', 'NO_HOOK_MALLOC', '_DLL_EXT=.so' @@ -265,6 +268,12 @@ def configure(conf): '-Wuninitialized', '-Winit-self', '-Wstrict-aliasing', + '-Wno-reorder', + '-Wno-unknown-pragmas', + '-Wno-unused-function', + '-Wno-unused-but-set-variable', + '-Wno-unused-value', + '-Wno-unused-variable', '-faligned-new', ] @@ -274,7 +283,7 @@ def configure(conf): cflags, linkflags = conf.get_optimization_flags() - flags = ['-fPIC', '-pipe'] #, '-fsanitize=undefined', '-fno-sanitize=vptr'] #, '-fno-sanitize=vptr,shift,shift-exponent,shift-base,signed-integer-overflow'] + flags = ['-pipe', '-fPIC'] #, '-fsanitize=undefined'] #, '-fsanitize=undefined'] #, '-fno-sanitize=vptr'] #, '-fno-sanitize=vptr,shift,shift-exponent,shift-base,signed-integer-overflow'] if conf.env.COMPILER_CC != 'msvc': flags += ['-pthread'] From d59e0ffa595c1fea63b7a2b5b3bb9a25c35fbfbd Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 5 Jun 2022 01:53:59 +0300 Subject: [PATCH 26/34] update ivp submodule --- ivp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivp b/ivp index 88cca3a5..929777cc 160000 --- a/ivp +++ b/ivp @@ -1 +1 @@ -Subproject commit 88cca3a543744868ea0903ceff7ed920dc88bd56 +Subproject commit 929777ccc85887e2374e9a73bd04c3215720436d From 363f4774f1cd0f1d52ad2b8d81526fd313fef742 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 5 Jun 2022 02:21:39 +0300 Subject: [PATCH 27/34] togl: replace long with int --- togl/linuxwin/glmgr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/togl/linuxwin/glmgr.cpp b/togl/linuxwin/glmgr.cpp index b97e6cf2..a573210c 100644 --- a/togl/linuxwin/glmgr.cpp +++ b/togl/linuxwin/glmgr.cpp @@ -4654,14 +4654,14 @@ void GLMContext::GenDebugFontTex( void ) //----------------------------------------------------- // fetch elements of font data and make texels... we're doing the whole slab so we don't really need the stride info - unsigned long *destTexelPtr = (unsigned long *)lockAddress; + uint32 *destTexelPtr = (uint32 *)lockAddress; for( int index = 0; index < 16384; index++ ) { if (g_glmDebugFontMap[index] == ' ') { // clear - *destTexelPtr = 0x00000000; + *destTexelPtr = 0; } else { From b84ad6417102fde60161a5bc310543d9dccb5ac7 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 5 Jun 2022 03:30:44 +0300 Subject: [PATCH 28/34] game/server: fix AI_TaskFailureCode_t size --- game/server/ai_component.h | 2 +- game/server/ai_navigator.h | 2 +- game/server/ai_task.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/game/server/ai_component.h b/game/server/ai_component.h index 62a7ab09..7722f66a 100644 --- a/game/server/ai_component.h +++ b/game/server/ai_component.h @@ -14,7 +14,7 @@ class CAI_BaseNPC; class CAI_Enemies; -typedef intp AI_TaskFailureCode_t; +typedef int AI_TaskFailureCode_t; struct Task_t; //----------------------------------------------------------------------------- diff --git a/game/server/ai_navigator.h b/game/server/ai_navigator.h index 67b0a83d..a2100943 100644 --- a/game/server/ai_navigator.h +++ b/game/server/ai_navigator.h @@ -29,7 +29,7 @@ class CAI_WaypointList; class CAI_Network; struct AIMoveTrace_t; struct AILocalMoveGoal_t; -typedef intp AI_TaskFailureCode_t; +typedef int AI_TaskFailureCode_t; //----------------------------------------------------------------------------- // Debugging tools diff --git a/game/server/ai_task.h b/game/server/ai_task.h index a49c9797..15152ea6 100644 --- a/game/server/ai_task.h +++ b/game/server/ai_task.h @@ -21,7 +21,7 @@ class CStringRegistry; // ---------------------------------------------------------------------- // Codes are either one of the enumerated types below, or a string (similar to Windows resource IDs) -typedef intp AI_TaskFailureCode_t; +typedef int AI_TaskFailureCode_t; enum AI_BaseTaskFailureCodes_t : AI_TaskFailureCode_t { From 94916a20cecea1a93f21fde1c67c7bb686f5a6d5 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Tue, 14 Jun 2022 13:09:10 +0300 Subject: [PATCH 29/34] vphysics: fix saverestore --- public/datamap.h | 2 +- public/tier0/platform.h | 10 ++ public/tier1/datamanager.h | 29 +++- public/tier1/mempool.h | 232 +++++++++++++++++++++--------- tier1/datamanager.cpp | 61 +++++--- tier1/mempool.cpp | 77 +++++++--- vphysics/physics_virtualmesh.cpp | 4 +- vphysics/vphysics_saverestore.cpp | 1 - vphysics/vphysics_saverestore.h | 2 +- vstdlib/KeyValuesSystem.cpp | 4 +- 10 files changed, 300 insertions(+), 122 deletions(-) diff --git a/public/datamap.h b/public/datamap.h index d4eee4ee..2f4edbf5 100644 --- a/public/datamap.h +++ b/public/datamap.h @@ -110,7 +110,7 @@ DECLARE_FIELD_SIZE( FIELD_MODELNAME, sizeof(void*)) DECLARE_FIELD_SIZE( FIELD_SOUNDNAME, sizeof(void*)) DECLARE_FIELD_SIZE( FIELD_EHANDLE, sizeof(void*)) DECLARE_FIELD_SIZE( FIELD_CLASSPTR, sizeof(void*)) -DECLARE_FIELD_SIZE( FIELD_EDICT, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_EDICT, sizeof(void*)) DECLARE_FIELD_SIZE( FIELD_POSITION_VECTOR, 3 * sizeof(float)) DECLARE_FIELD_SIZE( FIELD_TIME, sizeof(float)) DECLARE_FIELD_SIZE( FIELD_TICK, sizeof(int)) diff --git a/public/tier0/platform.h b/public/tier0/platform.h index 0e46b970..701c62ff 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -525,6 +525,16 @@ typedef void * HINSTANCE; #error #endif +// !!! NOTE: if you get a compile error here, you are using VALIGNOF on an abstract type :NOTE !!! +#define VALIGNOF_PORTABLE( type ) ( sizeof( AlignOf_t ) - sizeof( type ) ) + +#if defined( COMPILER_GCC ) || defined( COMPILER_MSVC ) +#define VALIGNOF( type ) __alignof( type ) +#define VALIGNOF_TEMPLATE_SAFE( type ) VALIGNOF_PORTABLE( type ) +#else +#error "PORT: Code only tested with MSVC! Must validate with new compiler, and use built-in keyword if available." +#endif + // Pull in the /analyze code annotations. #include "annotations.h" diff --git a/public/tier1/datamanager.h b/public/tier1/datamanager.h index 19342a39..03403248 100644 --- a/public/tier1/datamanager.h +++ b/public/tier1/datamanager.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -65,6 +65,8 @@ public: // ----------------------------------------------------------------------------- + void SetFreeOnDestruct( bool value ) { m_freeOnDestruct = value; } + // Debugging only!!!! void GetLRUHandleList( CUtlVector< memhandle_t >& list ); void GetLockHandleList( CUtlVector< memhandle_t >& list ); @@ -77,6 +79,7 @@ protected: void *GetResource_NoLock( memhandle_t handle ); void *GetResource_NoLockNoLRUTouch( memhandle_t handle ); void *LockResource( memhandle_t handle ); + void *LockResourceReturnCount( int *pCount, memhandle_t handle ); // NOTE: you must call this from the destructor of the derived class! (will assert otherwise) void FreeAllLists() { FlushAll(); m_listsAreFreed = true; } @@ -123,7 +126,8 @@ protected: unsigned short m_lockList; unsigned short m_freeList; unsigned short m_listsAreFreed : 1; - unsigned short m_unused : 15; + unsigned short m_freeOnDestruct : 1; + unsigned short m_unused : 14; }; @@ -139,7 +143,10 @@ public: ~CDataManager() { // NOTE: This must be called in all implementations of CDataManager - FreeAllLists(); + if ( m_freeOnDestruct ) + { + FreeAllLists(); + } } // Use GetData() to translate pointer to LOCK_TYPE @@ -154,6 +161,17 @@ public: return NULL; } + LOCK_TYPE LockResourceReturnCount( int *pCount, memhandle_t hMem ) + { + void *pLock = BaseClass::LockResourceReturnCount( pCount, hMem ); + if ( pLock ) + { + return StoragePointer(pLock)->GetData(); + } + + return NULL; + } + // Use GetData() to translate pointer to LOCK_TYPE LOCK_TYPE GetResource_NoLock( memhandle_t hMem ) { @@ -181,8 +199,9 @@ public: memhandle_t CreateResource( const CREATE_PARAMS &createParams, bool bCreateLocked = false ) { BaseClass::EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams)); - unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked ); STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams ); + AUTO_LOCK_( CDataManagerBase, *this ); + unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked ); return BaseClass::StoreResourceInHandle( memoryIndex, pStore, pStore->Size() ); } @@ -251,7 +270,7 @@ private: inline unsigned short CDataManagerBase::FromHandle( memhandle_t handle ) { - uintp fullWord = (uintp)handle; + unsigned int fullWord = (unsigned int)reinterpret_cast( handle ); unsigned short serial = fullWord>>16; unsigned short index = fullWord & 0xFFFF; index--; diff --git a/public/tier1/mempool.h b/public/tier1/mempool.h index 26b9ea23..e01bc9ef 100644 --- a/public/tier1/mempool.h +++ b/public/tier1/mempool.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -30,27 +30,19 @@ typedef void (*MemoryPoolReportFunc_t)( PRINTF_FORMAT_STRING char const* pMsg, ... ); -// Ways a memory pool can grow when it needs to make a new blob: -enum MemoryPoolGrowType_t -{ - UTLMEMORYPOOL_GROW_NONE=0, // Don't allow new blobs. - UTLMEMORYPOOL_GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates - // get larger and larger each time it allocates one). - UTLMEMORYPOOL_GROW_SLOW=2 // New blob size is numElements. -}; - class CUtlMemoryPool { public: - // !KLUDGE! For legacy code support, import the global enum into this scope + // Ways the memory pool can grow when it needs to make a new blob. enum MemoryPoolGrowType_t { - GROW_NONE=UTLMEMORYPOOL_GROW_NONE, - GROW_FAST=UTLMEMORYPOOL_GROW_FAST, - GROW_SLOW=UTLMEMORYPOOL_GROW_SLOW + GROW_NONE=0, // Don't allow new blobs. + GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates + // get larger and larger each time it allocates one). + GROW_SLOW=2 // New blob size is numElements. }; - CUtlMemoryPool( int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 ); + CUtlMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 ); ~CUtlMemoryPool(); void* Alloc(); // Allocate the element size you specified in the constructor. @@ -66,8 +58,12 @@ public: static void SetErrorReportFunc( MemoryPoolReportFunc_t func ); // returns number of allocated blocks - int Count() { return m_BlocksAllocated; } - int PeakCount() { return m_PeakAlloc; } + int Count() const { return m_BlocksAllocated; } + int PeakCount() const { return m_PeakAlloc; } + int BlockSize() const { return m_BlockSize; } + int Size() const; + + bool IsAllocationWithinPool( void *pMem ) const; protected: class CBlob @@ -89,14 +85,13 @@ protected: int m_GrowMode; // GROW_ enum. - // Put m_BlocksAllocated in front of m_pHeadOfFreeList for better - // packing on 64-bit where pointers are 8-byte aligned. int m_BlocksAllocated; - // FIXME: Change m_ppMemBlob into a growable array? - void *m_pHeadOfFreeList; int m_PeakAlloc; unsigned short m_nAlignment; unsigned short m_NumBlobs; + // Group up pointers at the end of the class to avoid padding bloat + // FIXME: Change m_ppMemBlob into a growable array? + void *m_pHeadOfFreeList; const char * m_pszAllocOwner; // CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned CBlob m_BlobHead; @@ -106,13 +101,12 @@ protected: //----------------------------------------------------------------------------- -// +// Multi-thread/Thread Safe Memory Class //----------------------------------------------------------------------------- class CMemoryPoolMT : public CUtlMemoryPool { public: - // MoeMod : add alignment - CMemoryPoolMT(int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment) {} + CMemoryPoolMT( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment ) {} void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); } @@ -136,15 +130,8 @@ template< class T > class CClassMemoryPool : public CUtlMemoryPool { public: - // MoeMod : bad default align here, should be alignof(T) - CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = alignof(T) ) : - CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) { - #ifdef PLATFORM_64BITS - COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 64 ); - #else - COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 48 ); - #endif - } + CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) : + CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {} T* Alloc(); T* AllocZero(); @@ -153,16 +140,15 @@ public: void Clear(); }; - //----------------------------------------------------------------------------- -// Specialized pool for aligned data management (e.g., Xbox cubemaps) +// Specialized pool for aligned data management (e.g., Xbox textures) //----------------------------------------------------------------------------- -template +template class CAlignedMemPool { enum { - BLOCK_SIZE = ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) > 8 ? ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) : 8 + BLOCK_SIZE = COMPILETIME_MAX( ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ), 8 ), }; public: @@ -174,13 +160,13 @@ public: static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight ); void Compact(); - int NumTotal() { return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); } - int NumAllocated() { return NumTotal() - m_nFree; } - int NumFree() { return m_nFree; } + int NumTotal() { AUTO_LOCK( m_mutex ); return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); } + int NumAllocated() { AUTO_LOCK( m_mutex ); return NumTotal() - m_nFree; } + int NumFree() { AUTO_LOCK( m_mutex ); return m_nFree; } - int BytesTotal() { return NumTotal() * BLOCK_SIZE; } - int BytesAllocated() { return NumAllocated() * BLOCK_SIZE; } - int BytesFree() { return NumFree() * BLOCK_SIZE; } + int BytesTotal() { AUTO_LOCK( m_mutex ); return NumTotal() * BLOCK_SIZE; } + int BytesAllocated() { AUTO_LOCK( m_mutex ); return NumAllocated() * BLOCK_SIZE; } + int BytesFree() { AUTO_LOCK( m_mutex ); return NumFree() * BLOCK_SIZE; } int ItemSize() { return ITEM_SIZE; } int BlockSize() { return BLOCK_SIZE; } @@ -197,7 +183,9 @@ private: FreeBlock_t * m_pFirstFree; int m_nFree; CAllocator m_Allocator; - float m_TimeLastCompact; + double m_TimeLastCompact; + + CThreadFastMutex m_mutex; }; //----------------------------------------------------------------------------- @@ -228,7 +216,7 @@ public: void Purge() { - T *p; + T *p = NULL; while ( m_AvailableObjects.PopItem( &p ) ) { delete p; @@ -237,7 +225,7 @@ public: T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty ) { - T *p; + T *p = NULL; if ( !m_AvailableObjects.PopItem( &p ) ) { p = ( bCreateNewIfEmpty ) ? new T : NULL; @@ -255,6 +243,98 @@ private: }; //----------------------------------------------------------------------------- +// Fixed budget pool with overflow to malloc +//----------------------------------------------------------------------------- +template +class CFixedBudgetMemoryPool +{ +public: + CFixedBudgetMemoryPool() + { + m_pBase = m_pLimit = 0; + COMPILE_TIME_ASSERT( ITEM_SIZE % 4 == 0 ); + } + + bool Owns( void *p ) + { + return ( p >= m_pBase && p < m_pLimit ); + } + + void *Alloc() + { + MEM_ALLOC_CREDIT_CLASS(); +#ifndef USE_MEM_DEBUG + if ( !m_pBase ) + { + LOCAL_THREAD_LOCK(); + if ( !m_pBase ) + { + byte *pMemory = m_pBase = (byte *)malloc( ITEM_COUNT * ITEM_SIZE ); + m_pLimit = m_pBase + ( ITEM_COUNT * ITEM_SIZE ); + + for ( int i = 0; i < ITEM_COUNT; i++ ) + { + m_freeList.Push( (TSLNodeBase_t *)pMemory ); + pMemory += ITEM_SIZE; + } + } + } + + void *p = m_freeList.Pop(); + if ( p ) + return p; +#endif + return malloc( ITEM_SIZE ); + } + + void Free( void *p ) + { +#ifndef USE_MEM_DEBUG + if ( Owns( p ) ) + m_freeList.Push( (TSLNodeBase_t *)p ); + else +#endif + free( p ); + } + + void Clear() + { +#ifndef USE_MEM_DEBUG + if ( m_pBase ) + { + free( m_pBase ); + } + m_pBase = m_pLimit = 0; + Construct( &m_freeList ); +#endif + } + + bool IsEmpty() + { +#ifndef USE_MEM_DEBUG + if ( m_pBase && m_freeList.Count() != ITEM_COUNT ) + return false; +#endif + return true; + } + + enum + { + ITEM_SIZE = ALIGN_VALUE( PROVIDED_ITEM_SIZE, TSLIST_NODE_ALIGNMENT ) + }; + + CTSListBase m_freeList; + byte *m_pBase; + byte *m_pLimit; +}; + +#define BIND_TO_FIXED_BUDGET_POOL( poolName ) \ + inline void* operator new( size_t size ) { return poolName.Alloc(); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { return poolName.Alloc(); } \ + inline void operator delete( void* p ) { poolName.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { poolName.Free(p); } + +//----------------------------------------------------------------------------- template< class T > @@ -263,7 +343,7 @@ inline T* CClassMemoryPool::Alloc() T *pRet; { - MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); + MEM_ALLOC_CREDIT_CLASS(); pRet = (T*)CUtlMemoryPool::Alloc(); } @@ -280,7 +360,7 @@ inline T* CClassMemoryPool::AllocZero() T *pRet; { - MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); + MEM_ALLOC_CREDIT_CLASS(); pRet = (T*)CUtlMemoryPool::AllocZero(); } @@ -305,7 +385,7 @@ inline void CClassMemoryPool::Free(T *pMem) template< class T > inline void CClassMemoryPool::Clear() { - CUtlRBTree freeBlocks; + CUtlRBTree freeBlocks; SetDefLessFunc( freeBlocks ); void *pCurFree = m_pHeadOfFreeList; @@ -317,9 +397,9 @@ inline void CClassMemoryPool::Clear() for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) { - // MoeMod : should realign to real data. - T *p = (T *)AlignValue( pCur->m_Data, m_nAlignment ); - T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes); + int nElements = pCur->m_NumBytes / this->m_BlockSize; + T *p = ( T * ) AlignValue( pCur->m_Data, this->m_nAlignment ); + T *pLimit = p + nElements; while ( p < pLimit ) { if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() ) @@ -334,6 +414,9 @@ inline void CClassMemoryPool::Clear() } + + + //----------------------------------------------------------------------------- // Macros that make it simple to make a class use a fixed-size allocator // Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class, @@ -364,7 +447,7 @@ inline void CClassMemoryPool::Clear() static CMemoryPoolMT s_Allocator #define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \ - CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", alignof(_class)) + CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") //----------------------------------------------------------------------------- // Macros that make it simple to make a class use a fixed-size allocator @@ -385,21 +468,30 @@ inline void CClassMemoryPool::Clear() CUtlMemoryPool* _class::s_pAllocator = _allocator -template -inline CAlignedMemPool::CAlignedMemPool() +template +inline CAlignedMemPool::CAlignedMemPool() : m_pFirstFree( 0 ), m_nFree( 0 ), m_TimeLastCompact( 0 ) { - COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); - COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); + // These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks + // on MacOS and Linux due to a gcc bug. + { COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); } + { COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); } } -template -inline void *CAlignedMemPool::Alloc() +template +inline void *CAlignedMemPool::Alloc() { + AUTO_LOCK( m_mutex ); + if ( !m_pFirstFree ) { + if ( !GROWMODE && m_Chunks.Count() ) + { + return NULL; + } + FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE ); Assert( (unsigned)pNew % ALIGNMENT == 0 ); m_Chunks.AddToTail( pNew ); @@ -420,9 +512,11 @@ inline void *CAlignedMemPool -inline void CAlignedMemPool::Free( void *p ) +template +inline void CAlignedMemPool::Free( void *p ) { + AUTO_LOCK( m_mutex ); + // Insertion sort to encourage allocation clusters in chunks FreeBlock_t *pFree = ((FreeBlock_t *)p); FreeBlock_t *pCur = m_pFirstFree; @@ -448,9 +542,9 @@ inline void CAlignedMemPool= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD ) { - float time = Plat_FloatTime(); - float compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0; - if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < Plat_FloatTime() ) + double time = Plat_FloatTime(); + double compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0; + if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < time ) { Compact(); m_TimeLastCompact = time; @@ -458,14 +552,14 @@ inline void CAlignedMemPool -inline int __cdecl CAlignedMemPool::CompareChunk( void * const *ppLeft, void * const *ppRight ) +template +inline int __cdecl CAlignedMemPool::CompareChunk( void * const *ppLeft, void * const *ppRight ) { - return (int)(((uintp)*ppLeft) - ((uintp)*ppRight)); + return static_cast( (intp)*ppLeft - (intp)*ppRight ); } -template -inline void CAlignedMemPool::Compact() +template +inline void CAlignedMemPool::Compact() { FreeBlock_t *pCur = m_pFirstFree; FreeBlock_t *pPrev = NULL; diff --git a/tier1/datamanager.cpp b/tier1/datamanager.cpp index 1fe33f32..922a1262 100644 --- a/tier1/datamanager.cpp +++ b/tier1/datamanager.cpp @@ -1,4 +1,4 @@ - +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -9,8 +9,14 @@ #include "basetypes.h" #include "datamanager.h" +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + DECLARE_POINTER_HANDLE( memhandle_t ); +#define AUTO_LOCK_DM() AUTO_LOCK_( CDataManagerBase, *this ) + CDataManagerBase::CDataManagerBase( unsigned int maxSize ) { m_targetMemorySize = maxSize; @@ -19,11 +25,12 @@ CDataManagerBase::CDataManagerBase( unsigned int maxSize ) m_lockList = m_memoryLists.CreateList(); m_freeList = m_memoryLists.CreateList(); m_listsAreFreed = 0; + m_freeOnDestruct = 1; } CDataManagerBase::~CDataManagerBase() { - Assert( m_listsAreFreed ); + Assert( !m_freeOnDestruct || m_listsAreFreed ); } void CDataManagerBase::NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize ) @@ -43,7 +50,7 @@ unsigned int CDataManagerBase::FlushAllUnlocked() Lock(); int nFlush = m_memoryLists.Count( m_lruList ); - void **pScratch = (void **)_alloca( nFlush * sizeof(void *) ); + void **pScratch = (void **)stackalloc( nFlush * sizeof(void *) ); CUtlVector destroyList( pScratch, nFlush ); unsigned nBytesInitial = MemUsed_Inline(); @@ -80,7 +87,7 @@ unsigned int CDataManagerBase::FlushAll() Lock(); int nFlush = m_memoryLists.Count( m_lruList ) + m_memoryLists.Count( m_lockList ); - void **pScratch = (void **)_alloca( nFlush * sizeof(void *) ); + void **pScratch = (void **) stackalloc( nFlush * sizeof(void *) ); CUtlVector destroyList( pScratch, nFlush ); unsigned result = MemUsed_Inline(); @@ -120,8 +127,7 @@ unsigned int CDataManagerBase::FlushAll() unsigned int CDataManagerBase::Purge( unsigned int nBytesToPurge ) { unsigned int nTargetSize = MemUsed_Inline() - nBytesToPurge; - // Check for underflow - if ( MemUsed_Inline() < nBytesToPurge ) + if ( nBytesToPurge > MemUsed_Inline() ) nTargetSize = 0; unsigned int nImpliedCapacity = MemTotal_Inline() - nTargetSize; return EnsureCapacity( nImpliedCapacity ); @@ -151,8 +157,7 @@ void CDataManagerBase::DestroyResource( memhandle_t handle ) void *CDataManagerBase::LockResource( memhandle_t handle ) { - AUTO_LOCK( *this ); - + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -169,9 +174,29 @@ void *CDataManagerBase::LockResource( memhandle_t handle ) return NULL; } +void *CDataManagerBase::LockResourceReturnCount( int *pCount, memhandle_t handle ) +{ + AUTO_LOCK_DM(); + unsigned short memoryIndex = FromHandle(handle); + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + if ( m_memoryLists[memoryIndex].lockCount == 0 ) + { + m_memoryLists.Unlink( m_lruList, memoryIndex ); + m_memoryLists.LinkToTail( m_lockList, memoryIndex ); + } + Assert(m_memoryLists[memoryIndex].lockCount != (unsigned short)-1); + *pCount = ++m_memoryLists[memoryIndex].lockCount; + return m_memoryLists[memoryIndex].pStore; + } + + *pCount = 0; + return NULL; +} + int CDataManagerBase::UnlockResource( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -193,7 +218,7 @@ int CDataManagerBase::UnlockResource( memhandle_t handle ) void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -205,7 +230,7 @@ void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle ) void *CDataManagerBase::GetResource_NoLock( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -217,13 +242,13 @@ void *CDataManagerBase::GetResource_NoLock( memhandle_t handle ) void CDataManagerBase::TouchResource( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); TouchByIndex( FromHandle(handle) ); } void CDataManagerBase::MarkAsStale( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -237,7 +262,7 @@ void CDataManagerBase::MarkAsStale( memhandle_t handle ) int CDataManagerBase::BreakLock( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() && m_memoryLists[memoryIndex].lockCount ) { @@ -253,7 +278,7 @@ int CDataManagerBase::BreakLock( memhandle_t handle ) int CDataManagerBase::BreakAllLocks() { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); int nBroken = 0; int node; int nextNode; @@ -275,7 +300,7 @@ int CDataManagerBase::BreakAllLocks() unsigned short CDataManagerBase::CreateHandle( bool bCreateLocked ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); int memoryIndex = m_memoryLists.Head(m_freeList); unsigned short list = ( bCreateLocked ) ? m_lockList : m_lruList; if ( memoryIndex != m_memoryLists.InvalidIndex() ) @@ -298,7 +323,7 @@ unsigned short CDataManagerBase::CreateHandle( bool bCreateLocked ) memhandle_t CDataManagerBase::StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); resource_lru_element_t &mem = m_memoryLists[memoryIndex]; mem.pStore = pStore; m_memUsed += realSize; @@ -322,7 +347,7 @@ memhandle_t CDataManagerBase::ToHandle( unsigned short index ) unsigned int hiword = m_memoryLists.Element(index).serial; hiword <<= 16; index++; - return (memhandle_t)( hiword|index ); + return reinterpret_cast< memhandle_t >( (uintp)( hiword|index ) ); } unsigned int CDataManagerBase::TargetSize() diff --git a/tier1/mempool.cpp b/tier1/mempool.cpp index fc3fb9b1..9cb9e223 100644 --- a/tier1/mempool.cpp +++ b/tier1/mempool.cpp @@ -1,24 +1,23 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // //===========================================================================// -#include "mempool.h" +#include "tier1/mempool.h" #include -#ifdef OSX -#include -#else -#include -#endif #include #include "tier0/dbg.h" #include #include "tier1/strtools.h" +#ifndef _PS3 +#include +#endif + // Should be last include #include "tier0/memdbgon.h" - + MemoryPoolReportFunc_t CUtlMemoryPool::g_ReportFunc = 0; //----------------------------------------------------------------------------- @@ -36,7 +35,7 @@ void CUtlMemoryPool::SetErrorReportFunc( MemoryPoolReportFunc_t func ) CUtlMemoryPool::CUtlMemoryPool( int blockSize, int numElements, int growMode, const char *pszAllocOwner, int nAlignment ) { #ifdef _X360 - if( numElements > 0 && growMode != UTLMEMORYPOOL_GROW_NONE ) + if( numElements > 0 && growMode != GROW_NONE ) { numElements = 1; } @@ -100,18 +99,40 @@ void CUtlMemoryPool::Clear() Init(); } + +//----------------------------------------------------------------------------- +// Is an allocation within the pool? +//----------------------------------------------------------------------------- +bool CUtlMemoryPool::IsAllocationWithinPool( void *pMem ) const +{ + for( CBlob *pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pCur->m_pNext ) + { + // Is the allocation within the blob? + if ( ( pMem < pCur->m_Data ) || ( pMem >= pCur->m_Data + pCur->m_NumBytes ) ) + continue; + + // Make sure the allocation is on a block boundary + intp pFirstAllocation = AlignValue( ( intp ) pCur->m_Data, m_nAlignment ); + + intp nOffset = (intp)pMem - pFirstAllocation; + return ( nOffset % m_BlockSize ) == 0; + } + + return false; +} + + //----------------------------------------------------------------------------- // Purpose: Reports memory leaks //----------------------------------------------------------------------------- - void CUtlMemoryPool::ReportLeaks() { +#ifdef _DEBUG if (!g_ReportFunc) return; g_ReportFunc("Memory leak: mempool blocks left in memory: %d\n", m_BlocksAllocated); -#ifdef _DEBUG // walk and destroy the free list so it doesn't intefere in the scan while (m_pHeadOfFreeList != NULL) { @@ -132,7 +153,7 @@ void CUtlMemoryPool::ReportLeaks() while (scanPoint < scanEnd) { // search for and dump any strings - if ((unsigned)(*scanPoint + 1) <= 256 && isprint(*scanPoint)) + if ((unsigned)(*scanPoint + 1) <= 256 && V_isprint(*scanPoint)) { g_ReportFunc("%c", *scanPoint); needSpace = true; @@ -161,18 +182,18 @@ void CUtlMemoryPool::AddNewBlob() int sizeMultiplier; - if( m_GrowMode == UTLMEMORYPOOL_GROW_SLOW ) + if( m_GrowMode == GROW_SLOW ) { sizeMultiplier = 1; } else { - if ( m_GrowMode == UTLMEMORYPOOL_GROW_NONE ) + if ( m_GrowMode == GROW_NONE ) { // Can only have one allocation when we're in this mode if( m_NumBlobs != 0 ) { - Assert( !"CUtlMemoryPool::AddNewBlob: mode == UTLMEMORYPOOL_GROW_NONE" ); + Assert( !"CUtlMemoryPool::AddNewBlob: mode == GROW_NONE" ); return; } } @@ -230,15 +251,15 @@ void *CUtlMemoryPool::Alloc( size_t amount ) { void *returnBlock; - if ( amount > (unsigned int)m_BlockSize ) + if ( amount > (size_t)m_BlockSize ) return NULL; - if( !m_pHeadOfFreeList ) + if ( !m_pHeadOfFreeList ) { - // returning NULL is fine in UTLMEMORYPOOL_GROW_NONE - if( m_GrowMode == UTLMEMORYPOOL_GROW_NONE ) + // returning NULL is fine in GROW_NONE + if ( m_GrowMode == GROW_NONE && m_NumBlobs > 0 ) { - //Assert( !"CUtlMemoryPool::Alloc: tried to make new blob with UTLMEMORYPOOL_GROW_NONE" ); + //Assert( !"CUtlMemoryPool::Alloc: tried to make new blob with GROW_NONE" ); return NULL; } @@ -246,14 +267,14 @@ void *CUtlMemoryPool::Alloc( size_t amount ) AddNewBlob(); // still failure, error out - if( !m_pHeadOfFreeList ) + if ( !m_pHeadOfFreeList ) { Assert( !"CUtlMemoryPool::Alloc: ran out of memory" ); return NULL; } } m_BlocksAllocated++; - m_PeakAlloc = max(m_PeakAlloc, m_BlocksAllocated); + m_PeakAlloc = MAX(m_PeakAlloc, m_BlocksAllocated); returnBlock = m_pHeadOfFreeList; @@ -272,7 +293,7 @@ void *CUtlMemoryPool::AllocZero( size_t amount ) void *mem = Alloc( amount ); if ( mem ) { - V_memset( mem, 0x00, amount ); + V_memset( mem, 0x00, ( int )amount ); } return mem; } @@ -313,4 +334,14 @@ void CUtlMemoryPool::Free( void *memBlock ) m_pHeadOfFreeList = memBlock; } +int CUtlMemoryPool::Size() const +{ + uint32 size = 0; + + for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) + { + size += pCur->m_NumBytes; + } + return size; +} diff --git a/vphysics/physics_virtualmesh.cpp b/vphysics/physics_virtualmesh.cpp index f3c7bd4c..0242478e 100644 --- a/vphysics/physics_virtualmesh.cpp +++ b/vphysics/physics_virtualmesh.cpp @@ -443,7 +443,7 @@ CMeshInstance *CPhysCollideVirtualMesh::BuildLedges() { list.pHull = (byte *)m_pHull; } - + if ( list.triangleCount ) { m_hMemory = g_MeshManager.CreateResource( list ); @@ -532,7 +532,6 @@ CPhysCollide *CreateVirtualMesh( const virtualmeshparams_t ¶ms ) void DestroyVirtualMesh( CPhysCollide *pMesh ) { - FlushFrameLocks(); delete pMesh; } @@ -547,6 +546,7 @@ IVP_SurfaceManager_VirtualMesh::IVP_SurfaceManager_VirtualMesh( CPhysCollideVirt IVP_SurfaceManager_VirtualMesh::~IVP_SurfaceManager_VirtualMesh() { + FlushFrameLocks(); } void IVP_SurfaceManager_VirtualMesh::add_reference_to_ledge(const IVP_Compact_Ledge *ledge) diff --git a/vphysics/vphysics_saverestore.cpp b/vphysics/vphysics_saverestore.cpp index 7cdff13e..dc4b8434 100644 --- a/vphysics/vphysics_saverestore.cpp +++ b/vphysics/vphysics_saverestore.cpp @@ -209,7 +209,6 @@ void CVPhysPtrUtlVectorSaveRestoreOps::Restore( const SaveRestoreFieldInfo_t &fi for ( int i = 0; i < nObjects; i++ ) { void **ppElem = (void**)(&pUtlVector->Element(i)); - pRestore->ReadData( (char *)ppElem, sizeof(void*), 0 ); int iNewVal = s_VPhysPtrMap.Find( *ppElem ); diff --git a/vphysics/vphysics_saverestore.h b/vphysics/vphysics_saverestore.h index c18df61f..8dc5c2d4 100644 --- a/vphysics/vphysics_saverestore.h +++ b/vphysics/vphysics_saverestore.h @@ -69,7 +69,7 @@ public: void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ); private: - typedef CUtlVector VPhysPtrVector; + typedef CUtlVector VPhysPtrVector; }; extern CVPhysPtrUtlVectorSaveRestoreOps g_VPhysPtrUtlVectorSaveRestoreOps; diff --git a/vstdlib/KeyValuesSystem.cpp b/vstdlib/KeyValuesSystem.cpp index 8bd4035f..986ccae0 100644 --- a/vstdlib/KeyValuesSystem.cpp +++ b/vstdlib/KeyValuesSystem.cpp @@ -108,8 +108,8 @@ IKeyValuesSystem *KeyValuesSystem() //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- -CKeyValuesSystem::CKeyValuesSystem() -: m_HashItemMemPool(sizeof(hash_item_t), 64, UTLMEMORYPOOL_GROW_FAST, "CKeyValuesSystem::m_HashItemMemPool") +CKeyValuesSystem::CKeyValuesSystem() +: m_HashItemMemPool(sizeof(hash_item_t), 64, CUtlMemoryPool::GROW_FAST, "CKeyValuesSystem::m_HashItemMemPool") , m_KeyValuesTrackingList(0, 0, MemoryLeakTrackerLessFunc) , m_KeyValueCache( UtlStringLessFunc ) { From a0e05d885a09fae7159cfeb48b8956866b3aef4d Mon Sep 17 00:00:00 2001 From: nillerusr Date: Tue, 14 Jun 2022 13:11:14 +0300 Subject: [PATCH 30/34] amd64: fix model loading issues --- common/studiobyteswap.cpp | 26 ++----- datacache/mdlcache.cpp | 37 +++++++++- public/studio.h | 141 ++++++++++++++++---------------------- 3 files changed, 97 insertions(+), 107 deletions(-) diff --git a/common/studiobyteswap.cpp b/common/studiobyteswap.cpp index 63e7ce37..9462bdbd 100644 --- a/common/studiobyteswap.cpp +++ b/common/studiobyteswap.cpp @@ -2522,27 +2522,14 @@ BEGIN_BYTESWAP_DATADESC( studiohdr_t ) DEFINE_FIELD( contents, FIELD_INTEGER ), DEFINE_FIELD( numincludemodels, FIELD_INTEGER ), DEFINE_INDEX( includemodelindex, FIELD_INTEGER ), -#ifdef PLATFORM_64BITS - DEFINE_FIELD( index_ptr_virtualModel, FIELD_INTEGER ), // void* -#else - DEFINE_FIELD( virtualModel, FIELD_INTEGER ), // void* -#endif + DEFINE_FIELD( unused_virtualModel, FIELD_INTEGER ), // void* DEFINE_INDEX( szanimblocknameindex, FIELD_INTEGER ), DEFINE_FIELD( numanimblocks, FIELD_INTEGER ), DEFINE_INDEX( animblockindex, FIELD_INTEGER ), -#ifdef PLATFORM_64BITS - DEFINE_FIELD( index_ptr_virtualModel, FIELD_INTEGER ), // void* -#else - DEFINE_FIELD( animblockModel, FIELD_INTEGER ), // void* -#endif + DEFINE_FIELD( unused_animblockModel, FIELD_INTEGER ), // void* DEFINE_INDEX( bonetablebynameindex, FIELD_INTEGER ), -#ifdef PLATFORM_64BITS - DEFINE_FIELD( index_ptr_pVertexBase, FIELD_INTEGER ), // void* - DEFINE_FIELD( index_ptr_pVertexBase, FIELD_INTEGER ), // void* -#else - DEFINE_FIELD( pVertexBase, FIELD_INTEGER ), // void* - DEFINE_FIELD( pIndexBase, FIELD_INTEGER ), // void* -#endif + DEFINE_FIELD( unused_pVertexBase, FIELD_INTEGER ), // void* + DEFINE_FIELD( unused_pIndexBase, FIELD_INTEGER ), // void* DEFINE_FIELD( constdirectionallightdot, FIELD_CHARACTER ), // byte DEFINE_FIELD( rootLOD, FIELD_CHARACTER ), // byte DEFINE_FIELD( numAllowedRootLODs, FIELD_CHARACTER ), // byte @@ -2918,13 +2905,8 @@ BEGIN_BYTESWAP_DATADESC( mstudiomodel_t ) END_BYTESWAP_DATADESC() BEGIN_BYTESWAP_DATADESC( mstudio_modelvertexdata_t ) -#ifdef PLATFORM_64BITS - DEFINE_FIELD( index_ptr_pVertexData, FIELD_INTEGER ), // void* - DEFINE_FIELD( index_ptr_pTangentData, FIELD_INTEGER ), // void* -#else DEFINE_FIELD( pVertexData, FIELD_INTEGER ), // void* DEFINE_FIELD( pTangentData, FIELD_INTEGER ), // void* -#endif END_BYTESWAP_DATADESC() BEGIN_BYTESWAP_DATADESC( mstudioflexdesc_t ) diff --git a/datacache/mdlcache.cpp b/datacache/mdlcache.cpp index 11e88ca5..4719c4d8 100644 --- a/datacache/mdlcache.cpp +++ b/datacache/mdlcache.cpp @@ -523,7 +523,7 @@ private: int UpdateOrCreate( studiohdr_t *pHdr, const char *pFilename, char *pX360Filename, int maxLen, const char *pPathID, bool bForce = false ); // Attempts to read the platform native file - on 360 it can read and swap Win32 file as a fallback - bool ReadFileNative( char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes = 0 ); + bool ReadFileNative( char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes = 0, MDLCacheDataType_t type = MDLCACHE_NONE ); // Creates a thin cache entry (to be used for model decals) from fat vertex data vertexFileHeader_t * CreateThinVertexes( vertexFileHeader_t * originalData, const studiohdr_t * pStudioHdr, int * cacheLength ); @@ -1913,7 +1913,7 @@ int CMDLCache::UpdateOrCreate( studiohdr_t *pHdr, const char *pSourceName, char //----------------------------------------------------------------------------- // Purpose: Attempts to read a file native to the current platform //----------------------------------------------------------------------------- -bool CMDLCache::ReadFileNative( char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes ) +bool CMDLCache::ReadFileNative( char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes, MDLCacheDataType_t type ) { bool bOk = false; @@ -1928,6 +1928,32 @@ bool CMDLCache::ReadFileNative( char *pFileName, const char *pPath, CUtlBuffer & { // Read the PC version bOk = g_pFullFileSystem->ReadFile( pFileName, pPath, buf, nMaxBytes ); + + if( bOk && type == MDLCACHE_STUDIOHDR ) + { + studiohdr_t* pStudioHdr = ( studiohdr_t* ) buf.PeekGet(); + + if ( pStudioHdr->studiohdr2index == 0 ) + { + // We always need this now, so make room for it in the buffer now. + int bufferContentsEnd = buf.TellMaxPut(); + int maskBits = VALIGNOF( studiohdr2_t ) - 1; + int offsetStudiohdr2 = ( bufferContentsEnd + maskBits ) & ~maskBits; + int sizeIncrease = ( offsetStudiohdr2 - bufferContentsEnd ) + sizeof( studiohdr2_t ); + buf.SeekPut( CUtlBuffer::SEEK_CURRENT, sizeIncrease ); + + // Re-get the pointer after resizing, because it has probably moved. + pStudioHdr = ( studiohdr_t* ) buf.Base(); + studiohdr2_t* pStudioHdr2 = ( studiohdr2_t* ) ( ( byte * ) pStudioHdr + offsetStudiohdr2 ); + memset( pStudioHdr2, 0, sizeof( studiohdr2_t ) ); + pStudioHdr2->flMaxEyeDeflection = 0.866f; // Matches studio.h. + + pStudioHdr->studiohdr2index = offsetStudiohdr2; + // Also make sure the structure knows about the extra bytes + // we've added so they get copied around. + pStudioHdr->length += sizeIncrease; + } + } } return bOk; @@ -2033,7 +2059,7 @@ bool CMDLCache::ReadMDLFile( MDLHandle_t handle, const char *pMDLFileName, CUtlB MEM_ALLOC_CREDIT(); - bool bOk = ReadFileNative( pFileName, "GAME", buf ); + bool bOk = ReadFileNative( pFileName, "GAME", buf, 0, MDLCACHE_STUDIOHDR ); if ( !bOk ) { DevWarning( "Failed to load %s!\n", pMDLFileName ); @@ -2147,6 +2173,11 @@ studiohdr_t *CMDLCache::GetStudioHdr( MDLHandle_t handle ) // Assert( m_pModelCacheSection->IsFrameLocking() ); // Assert( m_pMeshCacheSection->IsFrameLocking() ); + studiodata_t *pStudioData = m_MDLDict[handle]; + + if( !pStudioData ) + return NULL; + #if _DEBUG VPROF_INCREMENT_COUNTER( "GetStudioHdr", 1 ); #endif diff --git a/public/studio.h b/public/studio.h index cf489807..80a4a874 100644 --- a/public/studio.h +++ b/public/studio.h @@ -106,6 +106,39 @@ struct mstudiodata_t #define STUDIO_PROC_AIMATATTACH 4 #define STUDIO_PROC_JIGGLE 5 +// If you want to embed a pointer into one of the structures that is serialized, use this class! It will ensure that the pointers consume the +// right amount of space and work correctly across 32 and 64 bit. It also makes sure that there is no surprise about how large the structure +// is when placed in the middle of another structure, and supports Intel's desired behavior on 64-bit that pointers are always 8-byte aligned. +#pragma pack( push, 4 ) +template < class T > +struct ALIGN4 serializedstudioptr_t +{ + T* m_pData; +#ifndef PLATFORM_64BITS + int32 padding; +#endif + + serializedstudioptr_t() + { + m_pData = nullptr; + #if _DEBUG && !defined( PLATFORM_64BITS ) + padding = 0; + #endif + } + + inline operator T*() { return m_pData; } + inline operator const T*() const { return m_pData; } + + inline T* operator->( ) { return m_pData; } + inline const T* operator->( ) const { return m_pData; } + + inline T* operator=( T* ptr ) { return m_pData = ptr; } + +} ALIGN4_POST; + +#pragma pack( pop ) + + struct mstudioaxisinterpbone_t { DECLARE_BYTESWAP_DATADESC(); @@ -1292,26 +1325,14 @@ struct mstudio_modelvertexdata_t int GetGlobalTangentIndex( int i ) const; // base of external vertex data stores -#ifdef PLATFORM_64BITS - int index_ptr_pVertexData; - int index_ptr_pTangentData; -#else - const void *pVertexData; - const void *pTangentData; -#endif + serializedstudioptr_t pVertexData; + serializedstudioptr_t pTangentData; + const void *GetVertexData() const { -#ifdef PLATFORM_64BITS - return *(const void **)((byte *)this + index_ptr_pVertexData); -#else return pVertexData; -#endif } const void *GetTangentData() const { -#ifdef PLATFORM_64BITS - return *(const void **)((byte *)this + index_ptr_pTangentData); -#else return pTangentData; -#endif } }; @@ -1431,13 +1452,8 @@ struct mstudiomodel_t inline mstudioeyeball_t *pEyeball( int i ) { return (mstudioeyeball_t *)(((byte *)this) + eyeballindex) + i; }; mstudio_modelvertexdata_t vertexdata; // sizeof(mstudio_modelvertexdata_t) == 16 -#ifdef PLATFORM_64BITS - int unused[4]; // remove as appropriate - const void *real_pVertexData; - const void *real_pTangentData; -#else - int unused[8]; // remove as appropriate -#endif + + int unused[6]; // remove as appropriate }; #ifdef PLATFORM_64BITS @@ -1514,8 +1530,8 @@ inline const mstudio_meshvertexdata_t *mstudiomesh_t::GetVertexData( void *pMode // returning NULL if the data has been converted to 'thin' vertices) this->pModel()->GetVertexData( pModelData ); #ifdef PLATFORM_64BITS - real_modelvertexdata = &( this->pModel()->vertexdata ); - vertexdata.index_ptr_modelvertexdata = (byte *)&real_modelvertexdata - (byte *)&vertexdata; + real_modelvertexdata = &( this->pModel()->vertexdata ); + vertexdata.index_ptr_modelvertexdata = (byte *)&real_modelvertexdata - (byte *)&vertexdata; #else vertexdata.modelvertexdata = &( this->pModel()->vertexdata ); #endif @@ -1991,27 +2007,13 @@ inline const mstudio_modelvertexdata_t * mstudiomodel_t::GetVertexData( void *pM const vertexFileHeader_t * pVertexHdr = CacheVertexData( pModelData ); if ( !pVertexHdr ) { -#ifdef PLATFORM_64BITS - this->real_pVertexData = NULL; - this->real_pTangentData = NULL; - vertexdata.index_ptr_pVertexData = (byte *)&real_pVertexData - (byte *)&vertexdata; - vertexdata.index_ptr_pTangentData = (byte *)&real_pTangentData - (byte *)&vertexdata; -#else vertexdata.pVertexData = NULL; vertexdata.pTangentData = NULL; -#endif return NULL; } -#ifdef PLATFORM_64BITS - this->real_pVertexData = pVertexHdr->GetVertexData(); - this->real_pTangentData = pVertexHdr->GetTangentData(); - vertexdata.index_ptr_pVertexData = (byte *)&real_pVertexData - (byte *)&vertexdata; - vertexdata.index_ptr_pTangentData = (byte *)&real_pTangentData - (byte *)&vertexdata; -#else vertexdata.pVertexData = pVertexHdr->GetVertexData(); vertexdata.pTangentData = pVertexHdr->GetTangentData(); -#endif if ( !vertexdata.GetVertexData() ) return NULL; @@ -2136,7 +2138,13 @@ struct studiohdr2_t int m_nBoneFlexDriverIndex; inline mstudioboneflexdriver_t *pBoneFlexDriver( int i ) const { Assert( i >= 0 && i < m_nBoneFlexDriverCount ); return (mstudioboneflexdriver_t *)(((byte *)this) + m_nBoneFlexDriverIndex) + i; } - int reserved[56]; + mutable serializedstudioptr_t< void > virtualModel; + mutable serializedstudioptr_t< void > animblockModel; + + serializedstudioptr_t< void> pVertexBase; + serializedstudioptr_t< void> pIndexBase; + + int reserved[48]; }; struct studiohdr_t @@ -2341,11 +2349,7 @@ struct studiohdr_t const studiohdr_t *FindModel( void **cache, char const *modelname ) const; // implementation specific back pointer to virtual data -#ifdef PLATFORM_64BITS - int index_ptr_virtualModel; -#else - mutable void *virtualModel; -#endif + int unused_virtualModel; virtualmodel_t *GetVirtualModel( void ) const; // for demand loaded animation blocks @@ -2354,11 +2358,8 @@ struct studiohdr_t int numanimblocks; int animblockindex; inline mstudioanimblock_t *pAnimBlock( int i ) const { Assert( i > 0 && i < numanimblocks); return (mstudioanimblock_t *)(((byte *)this) + animblockindex) + i; }; -#ifdef PLATFORM_64BITS - int index_ptr_animblockModel; -#else - mutable void *animblockModel; -#endif + + int unused_animblockModel; byte * GetAnimBlock( int i ) const; int bonetablebynameindex; @@ -2366,13 +2367,8 @@ struct studiohdr_t // used by tools only that don't cache, but persist mdl's peer data // engine uses virtualModel to back link to cache pointers -#ifdef PLATFORM_64BITS - int index_ptr_pVertexBase; - int index_ptr_pIndexBase; -#else - void *pVertexBase; - void *pIndexBase; -#endif + int unused_pVertexBase; + int unused_pIndexBase; // if STUDIOHDR_FLAGS_CONSTANT_DIRECTIONAL_LIGHT_DOT is set, // this value is used to calculate directional components of lighting @@ -2420,21 +2416,12 @@ struct studiohdr_t inline int BoneFlexDriverCount() const { return studiohdr2index ? pStudioHdr2()->m_nBoneFlexDriverCount : 0; } inline const mstudioboneflexdriver_t* BoneFlexDriver( int i ) const { Assert( i >= 0 && i < BoneFlexDriverCount() ); return studiohdr2index > 0 ? pStudioHdr2()->pBoneFlexDriver( i ) : NULL; } -#ifdef PLATFORM_64BITS - void* VirtualModel() const { return *(void **)(((byte *)this) + index_ptr_virtualModel); } - void SetVirtualModel( void* ptr ) const { *(void **)(((byte *)this) + index_ptr_virtualModel) = ptr; } - void* VertexBase() const { return *(void **)(((byte *)this) + index_ptr_pVertexBase); } - void SetVertexBase( void* ptr ) { *(void **)(((byte *)this) + index_ptr_pVertexBase) = ptr; } - void* IndexBase() const { return *(void **)(((byte *)this) + index_ptr_pIndexBase); } - void SetIndexBase( void* ptr ) { *(void **)(((byte *)this) + index_ptr_pIndexBase) = ptr; } -#else - void* VirtualModel() const { return virtualModel; } - void SetVirtualModel( void* ptr ) const { virtualModel = ptr; } - void* VertexBase() const { return pVertexBase; } - void SetVertexBase( void* ptr ) { pVertexBase = ptr; } - void* IndexBase() const { return pIndexBase; } - void SetIndexBase( void* ptr ) { pIndexBase = ptr; } -#endif + void* VirtualModel() const { return studiohdr2index ? (void *)( pStudioHdr2()->virtualModel ) : nullptr; } + void SetVirtualModel( void* ptr ) { Assert( studiohdr2index ); if ( studiohdr2index ) { pStudioHdr2()->virtualModel = ptr; } else { Msg("go fuck urself!\n"); } } + void* VertexBase() const { return studiohdr2index ? (void *)( pStudioHdr2()->pVertexBase ) : nullptr; } + void SetVertexBase( void* pVertexBase ) const { Assert( studiohdr2index ); if ( studiohdr2index ) { pStudioHdr2()->pVertexBase = pVertexBase; } } + void* IndexBase() const { return studiohdr2index ? ( void * ) ( pStudioHdr2()->pIndexBase ) : nullptr; } + void SetIndexBase( void* pIndexBase ) const { Assert( studiohdr2index ); if ( studiohdr2index ) { pStudioHdr2()->pIndexBase = pIndexBase; } } // NOTE: No room to add stuff? Up the .mdl file format version // [and move all fields in studiohdr2_t into studiohdr_t and kill studiohdr2_t], @@ -2447,17 +2434,6 @@ private: friend struct virtualmodel_t; }; -#ifdef PLATFORM_64BITS -struct studiohdr_shim64_index -{ - mutable void *virtualModel; - mutable void *animblockModel; - void *pVertexBase; - void *pIndexBase; -}; -#endif - - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -3131,6 +3107,7 @@ inline bool Studio_ConvertStudioHdrToNewVersion( studiohdr_t *pStudioHdr ) return true; bool bResult = true; + if (version < 46) { // some of the anim index data is incompatible From 29db778997a4db7ddc1b18b9762f17d113f37329 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Tue, 14 Jun 2022 13:16:08 +0300 Subject: [PATCH 31/34] fix some AddressSanitizer issues --- engine/cmd.cpp | 2 +- game/client/hud_closecaption.cpp | 5 +++-- game/client/particlemgr.cpp | 2 +- game/server/ai_behavior_follow.cpp | 17 ++++++++--------- game/server/ai_behavior_follow.h | 2 +- game/server/hl2/npc_antlion.cpp | 4 ++-- game/shared/props_shared.cpp | 10 +++++----- game/shared/props_shared.h | 10 +++++----- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/engine/cmd.cpp b/engine/cmd.cpp index 689832b1..b9567271 100644 --- a/engine/cmd.cpp +++ b/engine/cmd.cpp @@ -624,7 +624,7 @@ void Cmd_Exec_f( const CCommand &args ) } } - char buf[16384] = { 0 }; + static char buf[16384] = { 0 }; int len = 0; char *f = (char *)COM_LoadStackFile( fileName, buf, sizeof( buf ), len ); if ( !f ) diff --git a/game/client/hud_closecaption.cpp b/game/client/hud_closecaption.cpp index f72b9fc1..0e25341b 100644 --- a/game/client/hud_closecaption.cpp +++ b/game/client/hud_closecaption.cpp @@ -543,7 +543,7 @@ struct AsyncCaptionData_t data->m_nBlockNum = params.blocktoload; data->m_nFileIndex = params.fileindex; data->m_nBlockSize = params.blocksize; - data->m_pBlockData = new byte[ data->m_nBlockSize ]; + data->m_pBlockData = new byte[ data->m_nBlockSize * sizeof(ucs2) ]; return data; } @@ -2027,6 +2027,7 @@ public: if ( entry.blockNum != nBlockNum ) continue; + #ifdef WIN32 const wchar_t *pIn = ( const wchar_t *)&pData->m_pBlockData[ entry.offset ]; caption->stream = new wchar_t[ entry.length >> 1 ]; @@ -2034,7 +2035,7 @@ public: #else // we persist to disk as ucs2 so convert back to real unicode here caption->stream = new wchar_t[ entry.length ]; - V_UCS2ToUnicode( (ucs2 *)&pData->m_pBlockData[ entry.offset ], caption->stream, entry.length*sizeof(wchar_t) ); + V_UCS2ToUnicode( (ucs2 *)&pData->m_pBlockData[ entry.offset ], caption->stream, entry.length << 1 ); #endif } } diff --git a/game/client/particlemgr.cpp b/game/client/particlemgr.cpp index d62c6e73..792711ed 100644 --- a/game/client/particlemgr.cpp +++ b/game/client/particlemgr.cpp @@ -1014,7 +1014,7 @@ bool CParticleEffectBinding::RecalculateBoundingBox() CEffectMaterial* CParticleEffectBinding::GetEffectMaterial( CParticleSubTexture *pSubTexture ) { // Hash the IMaterial pointer. - unsigned long index = (((unsigned long)pSubTexture->m_pGroup) >> 6) % EFFECT_MATERIAL_HASH_SIZE; + unsigned int index = (((unsigned int)pSubTexture->m_pGroup) >> 6) % EFFECT_MATERIAL_HASH_SIZE; for ( CEffectMaterial *pCur=m_EffectMaterialHash[index]; pCur; pCur = pCur->m_pHashedNext ) { if ( pCur->m_pGroup == pSubTexture->m_pGroup ) diff --git a/game/server/ai_behavior_follow.cpp b/game/server/ai_behavior_follow.cpp index 4c77972c..40f66583 100644 --- a/game/server/ai_behavior_follow.cpp +++ b/game/server/ai_behavior_follow.cpp @@ -53,7 +53,7 @@ struct AI_Follower_t } AIHANDLE hFollower; - int slot; + intp slot; AI_FollowNavInfo_t navInfo; AI_FollowGroup_t * pGroup; // backpointer for efficiency }; @@ -2561,7 +2561,7 @@ bool CAI_FollowManager::AddFollower( CBaseEntity *pTarget, CAI_BaseNPC *pFollowe AI_FollowSlot_t *pSlot = &pGroup->pFormation->pSlots[slot]; - int i = pGroup->followers.AddToTail( ); + intp i = pGroup->followers.AddToTail( ); AI_Follower_t *iterNode = &pGroup->followers[i]; iterNode->hFollower = pFollower; @@ -2569,9 +2569,8 @@ bool CAI_FollowManager::AddFollower( CBaseEntity *pTarget, CAI_BaseNPC *pFollowe iterNode->pGroup = pGroup; pGroup->slotUsage.Set( slot ); - CalculateFieldsFromSlot( pSlot, &iterNode->navInfo ); - + pHandle->m_hFollower = i; pHandle->m_pGroup = pGroup; return true; @@ -2641,10 +2640,10 @@ bool CAI_FollowManager::RedistributeSlots( AI_FollowGroup_t *pGroup ) { AI_FollowSlot_t * pSlot = &pGroup->pFormation->pSlots[bestSlot]; Vector slotPos = originFollowed + pSlot->position; - int h = pGroup->followers.Head(); - int hBest = pGroup->followers.InvalidIndex(); + intp h = pGroup->followers.Head(); + intp hBest = pGroup->followers.InvalidIndex(); float distSqBest = FLT_MAX; - + while ( h != pGroup->followers.InvalidIndex() ) { AI_Follower_t *p = &pGroup->followers[h]; @@ -2691,7 +2690,7 @@ void CAI_FollowManager::ChangeFormation( AI_FollowManagerInfoHandle_t& hInfo, AI if ( pNewFormation == pGroup->pFormation ) return; - int h = pGroup->followers.Head(); + intp h = pGroup->followers.Head(); while ( h != pGroup->followers.InvalidIndex() ) { @@ -2738,7 +2737,7 @@ void CAI_FollowManager::RemoveFollower( AI_FollowManagerInfoHandle_t& hInfo ) AI_FollowGroup_t *pGroup = hInfo.m_pGroup; AI_Follower_t* iterNode = &pGroup->followers[hInfo.m_hFollower]; - int slot = iterNode->slot; + intp slot = iterNode->slot; pGroup->slotUsage.Clear( slot ); pGroup->followers.Remove( hInfo.m_hFollower ); if ( pGroup->followers.Count() == 0 ) diff --git a/game/server/ai_behavior_follow.h b/game/server/ai_behavior_follow.h index a0e43837..ad734f53 100644 --- a/game/server/ai_behavior_follow.h +++ b/game/server/ai_behavior_follow.h @@ -100,7 +100,7 @@ struct AI_FollowGroup_t; struct AI_FollowManagerInfoHandle_t { AI_FollowGroup_t *m_pGroup; - int m_hFollower; + intp m_hFollower; }; //------------------------------------- diff --git a/game/server/hl2/npc_antlion.cpp b/game/server/hl2/npc_antlion.cpp index 8cb7f789..eaaaa31d 100644 --- a/game/server/hl2/npc_antlion.cpp +++ b/game/server/hl2/npc_antlion.cpp @@ -4015,8 +4015,8 @@ bool CNPC_Antlion::CorpseGib( const CTakeDamageInfo &info ) } Vector velocity = vec3_origin; - AngularImpulse angVelocity = RandomAngularImpulse( -150, 150 ); - breakablepropparams_t params( EyePosition(), GetAbsAngles(), velocity, angVelocity ); + AngularImpulse angVelocity = RandomAngularImpulse( -150, 150 ); + static breakablepropparams_t params( EyePosition(), GetAbsAngles(), velocity, angVelocity ); params.impactEnergyScale = 1.0f; params.defBurstScale = 150.0f; params.defCollisionGroup = COLLISION_GROUP_DEBRIS; diff --git a/game/shared/props_shared.cpp b/game/shared/props_shared.cpp index 6d0f9209..80ab39b7 100644 --- a/game/shared/props_shared.cpp +++ b/game/shared/props_shared.cpp @@ -951,7 +951,7 @@ void PropBreakableCreateAll( int modelindex, IPhysicsObject *pPhysics, const bre nSkin = pOwnerAnim->m_nSkin; } } - matrix3x4_t localToWorld; + static matrix3x4_t localToWorld; CStudioHdr studioHdr; const model_t *model = modelinfo->GetModel( modelindex ); @@ -1009,7 +1009,7 @@ void PropBreakableCreateAll( int modelindex, IPhysicsObject *pPhysics, const bre if ( ( iPrecomputedBreakableCount != -1 ) && ( i >= iPrecomputedBreakableCount ) ) break; - matrix3x4_t matrix; + static matrix3x4_t matrix; AngleMatrix( params.angles, params.origin, matrix ); CStudioHdr studioHdr; @@ -1188,7 +1188,7 @@ void PropBreakableCreateAll( int modelindex, IPhysicsObject *pPhysics, const bre Vector vecBreakableObbSize = pBreakable->CollisionProp()->OBBSize(); // Try to align the gibs along the original axis - matrix3x4_t matrix; + static matrix3x4_t matrix; AngleMatrix( vecAngles, matrix ); AlignBoxes( &matrix, vecObbSize, vecBreakableObbSize ); MatrixAngles( matrix, vecAngles ); @@ -1397,7 +1397,7 @@ CBaseEntity *CreateGibsFromList( CUtlVector &list, int modelindex, if ( ( iPrecomputedBreakableCount != -1 ) && ( i >= iPrecomputedBreakableCount ) ) break; - matrix3x4_t matrix; + static matrix3x4_t matrix; AngleMatrix( params.angles, params.origin, matrix ); CStudioHdr studioHdr; @@ -1596,7 +1596,7 @@ CBaseEntity *CreateGibsFromList( CUtlVector &list, int modelindex, Vector vecBreakableObbSize = pBreakable->CollisionProp()->OBBSize(); // Try to align the gibs along the original axis - matrix3x4_t matrix; + static matrix3x4_t matrix; AngleMatrix( vecAngles, matrix ); AlignBoxes( &matrix, vecObbSize, vecBreakableObbSize ); MatrixAngles( matrix, vecAngles ); diff --git a/game/shared/props_shared.h b/game/shared/props_shared.h index c63cb212..03dcb169 100644 --- a/game/shared/props_shared.h +++ b/game/shared/props_shared.h @@ -221,7 +221,7 @@ struct breakmodel_t struct breakablepropparams_t { - breakablepropparams_t( const Vector &_origin, const QAngle &_angles, const Vector &_velocity, const AngularImpulse &_angularVelocity ) + breakablepropparams_t( const Vector _origin, const QAngle _angles, const Vector _velocity, const AngularImpulse _angularVelocity ) : origin(_origin), angles(_angles), velocity(_velocity), angularVelocity(_angularVelocity) { impactEnergyScale = 0; @@ -230,10 +230,10 @@ struct breakablepropparams_t nDefaultSkin = 0; } - const Vector &origin; - const QAngle &angles; - const Vector &velocity; - const AngularImpulse &angularVelocity; + const Vector origin; + const QAngle angles; + const Vector velocity; + const AngularImpulse angularVelocity; float impactEnergyScale; float defBurstScale; int defCollisionGroup; From b06620b8c9741b0c98bc57bc17b9500c7e69209b Mon Sep 17 00:00:00 2001 From: nillerusr Date: Wed, 15 Jun 2022 21:59:06 +0300 Subject: [PATCH 32/34] fpersmissive fixes --- bitmap/float_bm.cpp | 246 ++++++++++++++---------- datacache/mdlcache.cpp | 3 - engine/baseclient.cpp | 6 +- engine/cmodel_disp.cpp | 2 +- engine/dt_encode.cpp | 8 +- engine/saverestore_filesystem.cpp | 8 +- engine/sv_main.cpp | 1 + engine/sys_dll2.cpp | 1 + filesystem/QueuedLoader.cpp | 2 +- filesystem/filesystem_async.cpp | 4 +- filesystem/linux_support.cpp | 2 +- game/client/c_particle_smokegrenade.cpp | 2 +- game/client/c_smoke_trail.cpp | 6 +- game/client/c_te_effect_dispatch.cpp | 4 +- game/client/c_te_playerdecal.cpp | 2 +- game/client/fx.cpp | 2 +- game/client/hud_lcd.cpp | 2 +- game/client/particlemgr.cpp | 2 +- game/server/ai_behavior_follow.cpp | 2 +- game/server/ai_hint.cpp | 6 +- game/server/ai_memory.cpp | 4 +- game/server/ai_navigator.cpp | 2 +- game/server/ai_senses.cpp | 4 +- game/server/ai_squad.cpp | 2 +- game/server/ai_task.cpp | 2 +- game/server/hl2/npc_metropolice.cpp | 4 +- game/server/physics.cpp | 4 +- game/shared/choreoevent.cpp | 4 +- game/shared/sceneimage.cpp | 2 +- public/XUnzip.cpp | 6 +- public/bitmap/float_bm.h | 14 +- public/filesystem_helpers.h | 1 - public/tier0/threadtools.inl | 2 +- public/tier1/utllinkedlist.h | 9 - public/togl/linuxwin/glmgr.h | 4 +- public/vgui_controls/BuildGroup.h | 2 +- public/vstdlib/jobthread.h | 2 +- tier1/utlbuffer.cpp | 2 +- togl/linuxwin/glmgr.cpp | 4 +- vgui2/matsys_controls/QCGenerator.cpp | 8 +- vguimatsurface/Input.cpp | 2 +- vphysics/main.cpp | 6 +- vphysics/physics_environment.cpp | 4 +- 43 files changed, 220 insertions(+), 185 deletions(-) diff --git a/bitmap/float_bm.cpp b/bitmap/float_bm.cpp index 33ab8c1f..f10264ec 100644 --- a/bitmap/float_bm.cpp +++ b/bitmap/float_bm.cpp @@ -311,13 +311,16 @@ FloatBitMap_t *FloatBitMap_t::QuarterSize(void) const FloatBitMap_t *newbm=new FloatBitMap_t(Width/2,Height/2); for(int y=0;yPixel(x,y,c)=((Pixel(x*2,y*2,c)+Pixel(x*2+1,y*2,c)+ Pixel(x*2,y*2+1,c)+Pixel(x*2+1,y*2+1,c))/4); } - return newbm; + } + + return newbm; } FloatBitMap_t *FloatBitMap_t::QuarterSizeBlocky(void) const @@ -326,12 +329,14 @@ FloatBitMap_t *FloatBitMap_t::QuarterSizeBlocky(void) const FloatBitMap_t *newbm=new FloatBitMap_t(Width/2,Height/2); for(int y=0;yPixel(x,y,c)=Pixel(x*2,y*2,c); } - return newbm; + } + return newbm; } Vector FloatBitMap_t::AverageColor(void) @@ -349,12 +354,15 @@ float FloatBitMap_t::BrightestColor(void) { float ret=0.0; for(int y=0;y static inline void SWAP(T & a, T & b) @@ -394,6 +402,7 @@ void FloatBitMap_t::UnLogize(void) void FloatBitMap_t::Clear(float r, float g, float b, float alpha) { for(int y=0;yPixel(x,y,c)=dx1; + for (int i = 0; i < NDELTAS; i++) + { + int x1 = x + dx[i]; + int y1 = y + dy[i]; + x1 = MAX(0, x1); + x1 = MIN(Width - 1, x1); + y1 = MAX(0, y1); + y1 = MIN(Height - 1, y1); + float dx1 = Pixel(x, y, c) - Pixel(x1, y1, c); + deltas[i]->Pixel(x, y, c) = dx1; + } } } - for(int x=1;xPixel(x + xofs, y + yofs, c) = diff; + if (Flags & SPFLAGS_MAXGRADIENT) { - float diff=b.Pixel(x,y,c)-b.Pixel(x+dx[i],y+dy[i],c); - deltas[i]->Pixel(x+xofs,y+yofs,c)=diff; - if (Flags & SPFLAGS_MAXGRADIENT) - { - float dx1=Pixel(x+xofs,y+yofs,c)-Pixel(x+dx[i]+xofs,y+dy[i]+yofs,c); - if (fabs(dx1)>fabs(diff)) - deltas[i]->Pixel(x+xofs,y+yofs,c)=dx1; - } + float dx1 = Pixel(x + xofs, y + yofs, c) - Pixel(x + dx[i] + xofs, y + dy[i] + yofs, c); + if (fabs(dx1) > fabs(diff)) + deltas[i]->Pixel(x + xofs, y + yofs, c) = dx1; } } + } + } + } - // now, calculate modifiability - for(int x=0;xxofs+1) && (x<=xofs+b.Width-2) && - (y>yofs+1) && (y<=yofs+b.Height-2)) - modify=1; - Alpha(x,y)=modify; - } - - // // now, force a fex pixels in center to be constant - // int midx=xofs+b.Width/2; - // int midy=yofs+b.Height/2; - // for(x=midx-10;x xofs + 1) && (x <= xofs + b.Width - 2) && + (y > yofs + 1) && (y <= yofs + b.Height - 2)) + modify = 1; + Alpha(x, y) = modify; + } + } + // // now, force a fex pixels in center to be constant + // int midx=xofs+b.Width/2; + // int midy=yofs+b.Height/2; + // for(x=midx-10;xPixel(x,y,c)=dx1; - gsum+=fabs(dx1); + int x1 = x + dx[i]; + int y1 = y + dy[i]; + x1 = MAX(0, x1); + x1 = MIN(Width - 1, x1); + y1 = MAX(0, y1); + y1 = MIN(Height - 1, y1); + float dx1 = Pixel(x, y, c) - Pixel(x1, y1, c); + deltas[i]->Pixel(x, y, c) = dx1; + gsum += fabs(dx1); + } + } + // now, reduce gradient changes + // float gavg=gsum/(Width*Height); + for (int x = 0; x < Width; x++) + for (int y = 0; y < Height; y++) + for (int c = 0; c < 3; c++) + { + for (int i = 0; i < NDELTAS; i++) + { + float norml = 1.1 *deltas[i]->Pixel(x, y, c); + // if (norml < 0.0) + // norml=-pow(-norml,1.2); + // else + // norml=pow(norml,1.2); + deltas[i]->Pixel(x, y, c) = norml; } } - // now, reduce gradient changes - // float gavg=gsum/(Width*Height); - for(int x=0;xPixel(x,y,c); - // if (norml<0.0) - // norml=-pow(-norml,1.2); - // else - // norml=pow(norml,1.2); - deltas[i]->Pixel(x,y,c)=norml; - } - } - // now, calculate modifiability - for(int x=0;x0) && (x 0) && (x < Width - 1) && + (y) && (y < Height - 1)) + { + modify = 1; + Alpha(x, y) = modify; + } + } - Poisson(deltas,2200,0); + Poisson(deltas, 2200, 0); } @@ -553,7 +572,9 @@ void FloatBitMap_t::MakeTileable(void) // set each pixel=avg-pixel FloatBitMap_t *cursrc=&rslta; for(int x=1;xPixel(x+1,y,c); @@ -596,12 +619,16 @@ void FloatBitMap_t::MakeTileable(void) error+=SQ(desired-cursrc->Pixel(x,y,c)); } SWAP(cursrc,curdst); + } + } } // paste result for(int x=0;xPixel(x,y,c); + } + } } @@ -613,15 +640,18 @@ void FloatBitMap_t::GetAlphaBounds(int &minx, int &miny, int &maxx,int &maxy) for(y=0;y=0;maxx--) { int y; for(y=0;yPoisson(lowdeltas,n_iters*4,flags); // now, propagate results from tmp to us for(int x=0;xWidth;x++) + { for(int y=0;yHeight;y++) + { for(int xi=0;xi<2;xi++) + { for(int yi=0;yi<2;yi++) + { if (Alpha(x*2+xi,y*2+yi)) { for(int c=0;c<3;c++) @@ -683,6 +719,10 @@ void FloatBitMap_t::Poisson(FloatBitMap_t *deltas[4], delete tmp; for(int i=0;iPixel(x,y,c)+cursrc->Pixel(x+dx[i],y+dy[i],c); desired*=(1.0/NDELTAS); - // desired=FLerp(Pixel(x,y,c),desired,Alpha(x,y)); + // desired=FLerp(Pixel(x,y,c),desired,Alpha(x,y)); curdst->Pixel(x,y,c)=FLerp(cursrc->Pixel(x,y,c),desired,0.5); error+=SQ(desired-cursrc->Pixel(x,y,c)); } diff --git a/datacache/mdlcache.cpp b/datacache/mdlcache.cpp index 4719c4d8..57ea4006 100644 --- a/datacache/mdlcache.cpp +++ b/datacache/mdlcache.cpp @@ -1450,9 +1450,6 @@ virtualmodel_t *CMDLCache::GetVirtualModelFast( const studiohdr_t *pStudioHdr, M AllocateVirtualModel( handle ); - // MoeMod : added - pStudioHdr->SetVirtualModel( MDLHandleToVirtual( handle ) ); - // Group has to be zero to ensure refcounting is correct int nGroup = pStudioData->m_pVirtualModel->m_group.AddToTail( ); Assert( nGroup == 0 ); diff --git a/engine/baseclient.cpp b/engine/baseclient.cpp index 9e501e33..ed81068f 100644 --- a/engine/baseclient.cpp +++ b/engine/baseclient.cpp @@ -1098,10 +1098,10 @@ void CBaseClient::EndTrace( bf_write &msg ) } if ( sv_netspike_output.GetInt() & 1 ) - COM_LogString( SERVER_PACKETS_LOG, logData.String() ); + COM_LogString( SERVER_PACKETS_LOG, (const char*)logData.String() ); if ( sv_netspike_output.GetInt() & 2 ) - Log( "%s", logData.String() ); - ETWMark1S( "netspike", logData.String() ); + Log( "%s", (const char*)logData.String() ); + ETWMark1S( "netspike", (const char*)logData.String() ); m_Trace.m_Records.RemoveAll(); m_iTracing = 0; } diff --git a/engine/cmodel_disp.cpp b/engine/cmodel_disp.cpp index 3b71a765..5090600f 100644 --- a/engine/cmodel_disp.cpp +++ b/engine/cmodel_disp.cpp @@ -318,7 +318,7 @@ void CM_CreateDispPhysCollide( dphysdisp_t *pDispLump, int dispLumpSize ) { g_VirtualTerrain.LevelInit(pDispLump, dispLumpSize); g_TerrainList.SetCount( g_DispCollTreeCount ); - for ( int i = 0; i < g_DispCollTreeCount; i++ ) + for ( intp i = 0; i < g_DispCollTreeCount; i++ ) { // Don't create a physics collision model for displacements that have been tagged as such. CDispCollTree *pDispTree = &g_pDispCollTrees[i]; diff --git a/engine/dt_encode.cpp b/engine/dt_encode.cpp index fdd0639a..8bebd113 100644 --- a/engine/dt_encode.cpp +++ b/engine/dt_encode.cpp @@ -39,7 +39,7 @@ void EncodeFloat( const SendProp *pProp, float fVal, bf_write *pOut, int objectI } else // standard clamped-range float { - unsigned long ulVal; + unsigned int ulVal; int nBits = pProp->m_nBits; if ( flags & SPROP_NOSCALE ) { @@ -109,7 +109,7 @@ static float DecodeFloat(SendProp const *pProp, bf_read *pIn) } else // standard clamped-range float { - unsigned long dwInterp = pIn->ReadUBitLong(pProp->m_nBits); + unsigned int dwInterp = pIn->ReadUBitLong(pProp->m_nBits); float fVal = (float)dwInterp / ((1 << pProp->m_nBits) - 1); fVal = pProp->m_fLowValue + (pProp->m_fHighValue - pProp->m_fLowValue) * fVal; return fVal; @@ -281,7 +281,7 @@ void Int_Decode( DecodeInfo *pInfo ) { if ( flags & SPROP_UNSIGNED ) { - pInfo->m_Value.m_Int = (long)pInfo->m_pIn->ReadVarInt32(); + pInfo->m_Value.m_Int = (int)pInfo->m_pIn->ReadVarInt32(); } else { @@ -295,7 +295,7 @@ void Int_Decode( DecodeInfo *pInfo ) if( bits != 32 && (flags & SPROP_UNSIGNED) == 0 ) { - unsigned long highbit = 1ul << (pProp->m_nBits - 1); + unsigned int highbit = 1ul << (pProp->m_nBits - 1); if ( pInfo->m_Value.m_Int & highbit ) { pInfo->m_Value.m_Int -= highbit; // strip high bit... diff --git a/engine/saverestore_filesystem.cpp b/engine/saverestore_filesystem.cpp index 0fde4082..a58bab50 100644 --- a/engine/saverestore_filesystem.cpp +++ b/engine/saverestore_filesystem.cpp @@ -310,12 +310,12 @@ int CSaveRestoreFileSystem::GetFileIndex( const char *filename ) FileHandle_t CSaveRestoreFileSystem::GetFileHandle( const char *filename ) { - int idx = GetFileIndex( filename ); + intp idx = GetFileIndex( filename ); if ( idx == INVALID_INDEX ) { idx = 0; } - return (void*)idx; + return (FileHandle_t)idx; } //----------------------------------------------------------------------------- @@ -339,7 +339,7 @@ bool CSaveRestoreFileSystem::HandleIsValid( FileHandle_t hFile ) //----------------------------------------------------------------------------- void CSaveRestoreFileSystem::RenameFile( char const *pOldPath, char const *pNewPath, const char *pathID ) { - int idx = GetFileIndex( pOldPath ); + intp idx = GetFileIndex( pOldPath ); if ( idx != INVALID_INDEX ) { CUtlSymbol newID = AddString( Q_UnqualifiedFileName( pNewPath ) ); @@ -369,7 +369,7 @@ FileHandle_t CSaveRestoreFileSystem::Open( const char *pFullName, const char *pO { SaveFile_t *pFile = NULL; CUtlSymbol id = AddString( Q_UnqualifiedFileName( pFullName ) ); - int idx = GetDirectory().Find( id ); + intp idx = GetDirectory().Find( id ); if ( idx == INVALID_INDEX ) { // Don't create a read-only file diff --git a/engine/sv_main.cpp b/engine/sv_main.cpp index 66fadb3c..1628c881 100644 --- a/engine/sv_main.cpp +++ b/engine/sv_main.cpp @@ -75,6 +75,7 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +#include "tier0/memalloc.h" extern CNetworkStringTableContainer *networkStringTableContainerServer; extern CNetworkStringTableContainer *networkStringTableContainerClient; diff --git a/engine/sys_dll2.cpp b/engine/sys_dll2.cpp index 59b66b8c..6bcc2af8 100644 --- a/engine/sys_dll2.cpp +++ b/engine/sys_dll2.cpp @@ -100,6 +100,7 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +#include "tier0/memalloc.h" //----------------------------------------------------------------------------- // Globals diff --git a/filesystem/QueuedLoader.cpp b/filesystem/QueuedLoader.cpp index 0fe235a6..dce2bd63 100644 --- a/filesystem/QueuedLoader.cpp +++ b/filesystem/QueuedLoader.cpp @@ -306,7 +306,7 @@ CQueuedLoader::CQueuedLoader() : BaseClass( false ) V_memset( m_pLoaders, 0, sizeof( m_pLoaders ) ); // set resource dictionaries sort context - for ( int i = 0; i < RESOURCEPRELOAD_COUNT; i++ ) + for ( intp i = 0; i < RESOURCEPRELOAD_COUNT; i++ ) { m_ResourceNames[i].SetLessContext( (void *)i ); } diff --git a/filesystem/filesystem_async.cpp b/filesystem/filesystem_async.cpp index e8ad047e..adce661c 100644 --- a/filesystem/filesystem_async.cpp +++ b/filesystem/filesystem_async.cpp @@ -126,7 +126,7 @@ public: AUTO_LOCK( m_mutex ); - int iEntry = m_map.Find( szFixedName ); + intp iEntry = m_map.Find( szFixedName ); if ( iEntry == m_map.InvalidIndex() ) { iEntry = m_map.Insert( strdup( szFixedName ), new AsyncOpenedFile_t ); @@ -146,7 +146,7 @@ public: AUTO_LOCK( m_mutex ); - int iEntry = m_map.Find( szFixedName ); + intp iEntry = m_map.Find( szFixedName ); if ( iEntry != m_map.InvalidIndex() ) { m_map[iEntry]->AddRef(); diff --git a/filesystem/linux_support.cpp b/filesystem/linux_support.cpp index c68967c4..81988846 100644 --- a/filesystem/linux_support.cpp +++ b/filesystem/linux_support.cpp @@ -102,7 +102,7 @@ HANDLE FindFirstFile( const char *fileName, FIND_DATA *dat) { char nameStore[PATH_MAX]; char *dir=NULL; - int n,iret=-1; + intp n,iret=-1; Q_strncpy(nameStore,fileName, sizeof( nameStore ) ); diff --git a/game/client/c_particle_smokegrenade.cpp b/game/client/c_particle_smokegrenade.cpp index f2fad7c7..da44878a 100644 --- a/game/client/c_particle_smokegrenade.cpp +++ b/game/client/c_particle_smokegrenade.cpp @@ -968,7 +968,7 @@ void C_ParticleSmokeGrenade::CleanupToolRecordingState( KeyValues *msg ) pLifetime->SetFloat( "maxLifetime", m_FadeEndTime ); KeyValues *pVelocity = pInitializers->FindKey( "DmeAttachmentVelocityInitializer", true ); - pVelocity->SetPtr( "entindex", (void*)entindex() ); + pVelocity->SetPtr( "entindex", (void*)(intp)entindex() ); pVelocity->SetFloat( "minRandomSpeed", 10 ); pVelocity->SetFloat( "maxRandomSpeed", 20 ); diff --git a/game/client/c_smoke_trail.cpp b/game/client/c_smoke_trail.cpp index f3d71adb..7f4b6078 100644 --- a/game/client/c_smoke_trail.cpp +++ b/game/client/c_smoke_trail.cpp @@ -418,7 +418,7 @@ void C_SmokeTrail::CleanupToolRecordingState( KeyValues *msg ) // FIXME: Until we can interpolate ent logs during emission, this can't work KeyValues *pPosition = pInitializers->FindKey( "DmePositionPointToEntityInitializer", true ); - pPosition->SetPtr( "entindex", (void*)pEnt->entindex() ); + pPosition->SetPtr( "entindex", (void*)(intp)pEnt->entindex() ); pPosition->SetInt( "attachmentIndex", m_nAttachment ); pPosition->SetFloat( "randomDist", m_SpawnRadius ); pPosition->SetFloat( "startx", pEnt->GetAbsOrigin().x ); @@ -430,7 +430,7 @@ void C_SmokeTrail::CleanupToolRecordingState( KeyValues *msg ) pLifetime->SetFloat( "maxLifetime", m_ParticleLifetime ); KeyValues *pVelocity = pInitializers->FindKey( "DmeAttachmentVelocityInitializer", true ); - pVelocity->SetPtr( "entindex", (void*)entindex() ); + pVelocity->SetPtr( "entindex", (void*)(intp)entindex() ); pVelocity->SetFloat( "minAttachmentSpeed", m_MinDirectedSpeed ); pVelocity->SetFloat( "maxAttachmentSpeed", m_MaxDirectedSpeed ); pVelocity->SetFloat( "minRandomSpeed", m_MinSpeed ); @@ -1933,7 +1933,7 @@ void C_DustTrail::CleanupToolRecordingState( KeyValues *msg ) // FIXME: Until we can interpolate ent logs during emission, this can't work KeyValues *pPosition = pInitializers->FindKey( "DmePositionPointToEntityInitializer", true ); - pPosition->SetPtr( "entindex", (void*)pEnt->entindex() ); + pPosition->SetPtr( "entindex", (void*)(intp)pEnt->entindex() ); pPosition->SetInt( "attachmentIndex", GetParentAttachment() ); pPosition->SetFloat( "randomDist", m_SpawnRadius ); pPosition->SetFloat( "startx", pEnt->GetAbsOrigin().x ); diff --git a/game/client/c_te_effect_dispatch.cpp b/game/client/c_te_effect_dispatch.cpp index b586df97..9c2557fe 100644 --- a/game/client/c_te_effect_dispatch.cpp +++ b/game/client/c_te_effect_dispatch.cpp @@ -132,7 +132,7 @@ static void RecordEffect( const char *pEffectName, const CEffectData &data ) msg->SetInt( "attachmentindex", data.m_nAttachmentIndex ); // NOTE: Ptrs are our way of indicating it's an entindex - msg->SetPtr( "entindex", (void*)data.entindex() ); + msg->SetPtr( "entindex", (void*)(intp)data.entindex() ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->deleteThis(); @@ -213,7 +213,7 @@ void TE_DispatchEffect( IRecipientFilter& filter, float delay, KeyValues *pKeyVa // NOTE: Ptrs are our way of indicating it's an entindex ClientEntityHandle_t hWorld = ClientEntityList().EntIndexToHandle( 0 ); - data.m_hEntity = (intp)pKeyValues->GetPtr( "entindex", (void*)hWorld.ToInt() ); + data.m_hEntity = (intp)pKeyValues->GetPtr( "entindex", (void*)(intp)hWorld.ToInt() ); const char *pEffectName = pKeyValues->GetString( "effectname" ); diff --git a/game/client/c_te_playerdecal.cpp b/game/client/c_te_playerdecal.cpp index 9620484f..f8d503b6 100644 --- a/game/client/c_te_playerdecal.cpp +++ b/game/client/c_te_playerdecal.cpp @@ -240,7 +240,7 @@ void TE_PlayerDecal( IRecipientFilter& filter, float delay, color32 rgbaColor = { 255, 255, 255, 255 }; effects->PlayerDecalShoot( logo, - (void *)player, + (void *)(intp)player, entity, ent->GetModel(), ent->GetAbsOrigin(), diff --git a/game/client/fx.cpp b/game/client/fx.cpp index b7f12cbd..3615aa0d 100644 --- a/game/client/fx.cpp +++ b/game/client/fx.cpp @@ -403,7 +403,7 @@ void FX_MuzzleEffectAttached( KeyValues *pInitializers = pEmitter->FindKey( "initializers", true ); KeyValues *pPosition = pInitializers->FindKey( "DmeLinearAttachedPositionInitializer", true ); - pPosition->SetPtr( "entindex", (void*)pEnt->entindex() ); + pPosition->SetPtr( "entindex", (void*)(intp)pEnt->entindex() ); pPosition->SetInt( "attachmentIndex", attachmentIndex ); pPosition->SetFloat( "linearOffsetX", 2.0f * scale ); diff --git a/game/client/hud_lcd.cpp b/game/client/hud_lcd.cpp index 0f0609d6..e2919bbc 100644 --- a/game/client/hud_lcd.cpp +++ b/game/client/hud_lcd.cpp @@ -11,7 +11,7 @@ #include "cbase.h" #ifdef POSIX -#define HICON int +#define HICON intp const int DT_LEFT = 1; const int DT_CENTER = 2; const int DT_RIGHT = 3; diff --git a/game/client/particlemgr.cpp b/game/client/particlemgr.cpp index 792711ed..a82ff1f5 100644 --- a/game/client/particlemgr.cpp +++ b/game/client/particlemgr.cpp @@ -1014,7 +1014,7 @@ bool CParticleEffectBinding::RecalculateBoundingBox() CEffectMaterial* CParticleEffectBinding::GetEffectMaterial( CParticleSubTexture *pSubTexture ) { // Hash the IMaterial pointer. - unsigned int index = (((unsigned int)pSubTexture->m_pGroup) >> 6) % EFFECT_MATERIAL_HASH_SIZE; + unsigned int index = (((intp)pSubTexture->m_pGroup) >> 6) % EFFECT_MATERIAL_HASH_SIZE; for ( CEffectMaterial *pCur=m_EffectMaterialHash[index]; pCur; pCur = pCur->m_pHashedNext ) { if ( pCur->m_pGroup == pSubTexture->m_pGroup ) diff --git a/game/server/ai_behavior_follow.cpp b/game/server/ai_behavior_follow.cpp index 40f66583..0cedd2fa 100644 --- a/game/server/ai_behavior_follow.cpp +++ b/game/server/ai_behavior_follow.cpp @@ -2845,7 +2845,7 @@ AI_FollowGroup_t *CAI_FollowManager::FindFollowerGroup( CBaseEntity *pFollower ) { for ( int i = 0; i < m_groups.Count(); i++ ) { - int h = m_groups[i]->followers.Head(); + intp h = m_groups[i]->followers.Head(); while( h != m_groups[i]->followers.InvalidIndex() ) { AI_Follower_t *p = &m_groups[i]->followers[h]; diff --git a/game/server/ai_hint.cpp b/game/server/ai_hint.cpp index 5d541887..04b8dca8 100644 --- a/game/server/ai_hint.cpp +++ b/game/server/ai_hint.cpp @@ -729,7 +729,7 @@ CAI_Hint *CAI_HintManager::GetFirstHint( AIHintIter_t *pIter ) { if ( !gm_AllHints.Count() ) { - *pIter = (AIHintIter_t)gm_AllHints.InvalidIndex(); + *pIter = (AIHintIter_t)(intp)gm_AllHints.InvalidIndex(); return NULL; } *pIter = (AIHintIter_t)0; @@ -743,10 +743,10 @@ CAI_Hint *CAI_HintManager::GetNextHint( AIHintIter_t *pIter ) { if ( (intp)*pIter != gm_AllHints.InvalidIndex() ) { - int i = ( (intp)*pIter ) + 1; + intp i = ( (intp)*pIter ) + 1; if ( gm_AllHints.Count() <= i ) { - *pIter = (AIHintIter_t)gm_AllHints.InvalidIndex(); + *pIter = (AIHintIter_t)(intp)gm_AllHints.InvalidIndex(); return NULL; } *pIter = (AIHintIter_t)i; diff --git a/game/server/ai_memory.cpp b/game/server/ai_memory.cpp index ca4fe573..c0784e4f 100644 --- a/game/server/ai_memory.cpp +++ b/game/server/ai_memory.cpp @@ -176,7 +176,7 @@ CAI_Enemies::~CAI_Enemies() AI_EnemyInfo_t *CAI_Enemies::GetFirst( AIEnemiesIter_t *pIter ) { CMemMap::IndexType_t i = m_Map.FirstInorder(); - *pIter = (AIEnemiesIter_t)(unsigned)i; + *pIter = (AIEnemiesIter_t)(uintp)i; if ( i == m_Map.InvalidIndex() ) return NULL; @@ -197,7 +197,7 @@ AI_EnemyInfo_t *CAI_Enemies::GetNext( AIEnemiesIter_t *pIter ) return NULL; i = m_Map.NextInorder( i ); - *pIter = (AIEnemiesIter_t)(unsigned)i; + *pIter = (AIEnemiesIter_t)(uintp)i; if ( i == m_Map.InvalidIndex() ) return NULL; diff --git a/game/server/ai_navigator.cpp b/game/server/ai_navigator.cpp index 005ecec7..2825744c 100644 --- a/game/server/ai_navigator.cpp +++ b/game/server/ai_navigator.cpp @@ -1224,7 +1224,7 @@ AI_PathNode_t CAI_Navigator::GetNearestNode() #ifdef WIN32 COMPILE_TIME_ASSERT( (int)AIN_NO_NODE == NO_NODE ); #endif - return (AI_PathNode_t)( GetPathfinder()->NearestNodeToNPC() ); + return (AI_PathNode_t)(intp)( GetPathfinder()->NearestNodeToNPC() ); } //----------------------------------------------------------------------------- diff --git a/game/server/ai_senses.cpp b/game/server/ai_senses.cpp index 3c056f0e..9104b195 100644 --- a/game/server/ai_senses.cpp +++ b/game/server/ai_senses.cpp @@ -573,7 +573,7 @@ CSound* CAI_Senses::GetFirstHeardSound( AISoundIter_t *pIter ) return NULL; } - *pIter = (AISoundIter_t)iFirst; + *pIter = (AISoundIter_t)(intp)iFirst; return CSoundEnt::SoundPointerForIndex( iFirst ); } @@ -584,7 +584,7 @@ CSound* CAI_Senses::GetNextHeardSound( AISoundIter_t *pIter ) if ( !*pIter ) return NULL; - int iCurrent = (intp)*pIter; + intp iCurrent = (intp)*pIter; Assert( iCurrent != SOUNDLIST_EMPTY ); if ( iCurrent == SOUNDLIST_EMPTY ) diff --git a/game/server/ai_squad.cpp b/game/server/ai_squad.cpp index 9ad4b6bb..f8bee51a 100644 --- a/game/server/ai_squad.cpp +++ b/game/server/ai_squad.cpp @@ -420,7 +420,7 @@ CAI_BaseNPC *CAI_Squad::GetLeader( void ) //----------------------------------------------------------------------------- CAI_BaseNPC *CAI_Squad::GetFirstMember( AISquadIter_t *pIter, bool bIgnoreSilentMembers ) { - int i = 0; + intp i = 0; if ( bIgnoreSilentMembers ) { for ( ; i < m_SquadMembers.Count(); i++ ) diff --git a/game/server/ai_task.cpp b/game/server/ai_task.cpp index a2cf6be6..7c05f834 100644 --- a/game/server/ai_task.cpp +++ b/game/server/ai_task.cpp @@ -49,7 +49,7 @@ const char *TaskFailureToString( AI_TaskFailureCode_t code ) { const char *pszResult; if ( code < 0 || code >= NUM_FAIL_CODES ) - pszResult = (const char *)code; + pszResult = (const char *)(intp)code; else pszResult = g_ppszTaskFailureText[code]; return pszResult; diff --git a/game/server/hl2/npc_metropolice.cpp b/game/server/hl2/npc_metropolice.cpp index 833318d4..cb58f1fe 100644 --- a/game/server/hl2/npc_metropolice.cpp +++ b/game/server/hl2/npc_metropolice.cpp @@ -2612,7 +2612,7 @@ void CNPC_MetroPolice::IdleSound( void ) if ( m_Sentences.Speak( pQuestion[bIsCriminal][nQuestionType] ) >= 0 ) { - GetSquad()->BroadcastInteraction( g_interactionMetrocopIdleChatter, (void*)(METROPOLICE_CHATTER_RESPONSE + nQuestionType), this ); + GetSquad()->BroadcastInteraction( g_interactionMetrocopIdleChatter, (void*)(intp)(METROPOLICE_CHATTER_RESPONSE + nQuestionType), this ); m_nIdleChatterType = METROPOLICE_CHATTER_WAIT_FOR_RESPONSE; } } @@ -2983,7 +2983,7 @@ bool CNPC_MetroPolice::HandleInteraction(int interactionType, void *data, CBaseC if ( interactionType == g_interactionMetrocopIdleChatter ) { - m_nIdleChatterType = (int)data; + m_nIdleChatterType = (intp)data; return true; } diff --git a/game/server/physics.cpp b/game/server/physics.cpp index bec86f5f..2adc5587 100644 --- a/game/server/physics.cpp +++ b/game/server/physics.cpp @@ -1068,7 +1068,7 @@ void CCollisionEvent::FluidStartTouch( IPhysicsObject *pObject, IPhysicsFluidCon return; pEntity->AddEFlags( EFL_TOUCHING_FLUID ); - pEntity->OnEntityEvent( ENTITY_EVENT_WATER_TOUCH, (void*)pFluid->GetContents() ); + pEntity->OnEntityEvent( ENTITY_EVENT_WATER_TOUCH, (void*)(intp)pFluid->GetContents() ); float timeSinceLastCollision = DeltaTimeSinceLastFluid( pEntity ); if ( timeSinceLastCollision < 0.5f ) @@ -1124,7 +1124,7 @@ void CCollisionEvent::FluidEndTouch( IPhysicsObject *pObject, IPhysicsFluidContr } pEntity->RemoveEFlags( EFL_TOUCHING_FLUID ); - pEntity->OnEntityEvent( ENTITY_EVENT_WATER_UNTOUCH, (void*)pFluid->GetContents() ); + pEntity->OnEntityEvent( ENTITY_EVENT_WATER_UNTOUCH, (void*)(intp)pFluid->GetContents() ); } class CSkipKeys : public IVPhysicsKeyHandler diff --git a/game/shared/choreoevent.cpp b/game/shared/choreoevent.cpp index 50755f04..7e61cbb1 100644 --- a/game/shared/choreoevent.cpp +++ b/game/shared/choreoevent.cpp @@ -2076,7 +2076,7 @@ public: { if ( ARRAYSIZE( g_NameMap ) != CChoreoEvent::NUM_TYPES ) { - Error( "g_NameMap contains %i entries, CChoreoEvent::NUM_TYPES == %i!", + Error( "g_NameMap contains %zd entries, CChoreoEvent::NUM_TYPES == %i!", ARRAYSIZE( g_NameMap ), CChoreoEvent::NUM_TYPES ); } for ( int i = 0; i < CChoreoEvent::NUM_TYPES; ++i ) @@ -2158,7 +2158,7 @@ public: { if ( ARRAYSIZE( g_CCNameMap ) != CChoreoEvent::NUM_CC_TYPES ) { - Error( "g_CCNameMap contains %i entries, CChoreoEvent::NUM_CC_TYPES == %i!", + Error( "g_CCNameMap contains %zd entries, CChoreoEvent::NUM_CC_TYPES == %i!", ARRAYSIZE( g_CCNameMap ), CChoreoEvent::NUM_CC_TYPES ); } for ( int i = 0; i < CChoreoEvent::NUM_CC_TYPES; ++i ) diff --git a/game/shared/sceneimage.cpp b/game/shared/sceneimage.cpp index 55426008..5283eda9 100644 --- a/game/shared/sceneimage.cpp +++ b/game/shared/sceneimage.cpp @@ -368,7 +368,7 @@ bool CSceneImage::CreateSceneImageFile( CUtlBuffer &targetBuffer, char const *pc if ( !bQuiet ) { - Msg( "Scenes: String Table: %d bytes\n", stringOffsets.Count() * sizeof( int ) ); + Msg( "Scenes: String Table: %zd bytes\n", stringOffsets.Count() * sizeof( int ) ); Msg( "Scenes: String Pool: %d bytes\n", stringPool.TellMaxPut() ); } diff --git a/public/XUnzip.cpp b/public/XUnzip.cpp index 650a932a..9d7c4362 100644 --- a/public/XUnzip.cpp +++ b/public/XUnzip.cpp @@ -2778,7 +2778,7 @@ LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err) #ifdef _WIN32 res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&h,0,FALSE,DUPLICATE_SAME_ACCESS) == TRUE; #else - h = (void*) dup( (intptr_t)hf ); + h = (void*)(intptr_t) dup( (intptr_t)hf ); res = (intptr_t) dup >= 0; #endif if (!res) @@ -2793,7 +2793,7 @@ LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err) h = CreateFile((const TCHAR *)z, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); #else - h = (void*) open( (const TCHAR *)z, O_RDONLY ); + h = (void*)(intptr_t) open( (const TCHAR *)z, O_RDONLY ); #endif if (h == INVALID_HANDLE_VALUE) { @@ -4198,7 +4198,7 @@ ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) h = ::CreateFile((const TCHAR*)dst, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, ze.attr, NULL); #else - h = (void*) open( (const TCHAR*)dst, O_WRONLY | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO ); + h = (void*)(intptr_t)open( (const TCHAR*)dst, O_WRONLY | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO ); #endif } diff --git a/public/bitmap/float_bm.h b/public/bitmap/float_bm.h index a80722dd..ec538b0c 100644 --- a/public/bitmap/float_bm.h +++ b/public/bitmap/float_bm.h @@ -278,14 +278,18 @@ public: Vector ret(0,0,0); int nfaces=0; for(int f=0;f<6;f++) + { if (face_maps[f].RGBAData) { nfaces++; ret+=face_maps[f].AverageColor(); } - if (nfaces) - ret*=(1.0/nfaces); - return ret; + } + + if (nfaces) + ret*=(1.0/nfaces); + + return ret; } float BrightestColor(void) @@ -293,12 +297,14 @@ public: float ret=0.0; int nfaces=0; for(int f=0;f<6;f++) + { if (face_maps[f].RGBAData) { nfaces++; ret=max(ret,face_maps[f].BrightestColor()); } - return ret; + } + return ret; } diff --git a/public/filesystem_helpers.h b/public/filesystem_helpers.h index 070e779a..cc0b43c9 100644 --- a/public/filesystem_helpers.h +++ b/public/filesystem_helpers.h @@ -23,7 +23,6 @@ const char* ParseFileInternal( const char* pFileBytes, OUT_Z_CAP(nMaxTokenLen) c template const char* ParseFile( const char* pFileBytes, OUT_Z_ARRAY char (&pTokenOut)[count], bool* pWasQuoted, characterset_t *pCharSet = NULL, unsigned int nMaxTokenLen = (unsigned int)-1 ) { - (void*)nMaxTokenLen; // Avoid unreferenced variable warnings. return ParseFileInternal( pFileBytes, pTokenOut, pWasQuoted, pCharSet, count ); } diff --git a/public/tier0/threadtools.inl b/public/tier0/threadtools.inl index 037a64ed..dda4b5f5 100644 --- a/public/tier0/threadtools.inl +++ b/public/tier0/threadtools.inl @@ -75,7 +75,7 @@ INLINE_ON_PS3 const char *CThread::GetName() #elif defined( _PS3 ) snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p)", this ); #elif defined( POSIX ) - _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/0x%p)", this, m_threadId ); + _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/0x%p)", this, (void*)m_threadId ); #endif m_szName[sizeof(m_szName) - 1] = 0; } diff --git a/public/tier1/utllinkedlist.h b/public/tier1/utllinkedlist.h index d0f4249b..3717aab2 100644 --- a/public/tier1/utllinkedlist.h +++ b/public/tier1/utllinkedlist.h @@ -121,9 +121,6 @@ public: I Alloc( bool multilist = false ); void Free( I elem ); - // Identify the owner of this linked list's memory: - void SetAllocOwner( const char *pszAllocOwner ); - // list modification void LinkBefore( I before, I elem ); void LinkAfter( I after, I elem ); @@ -618,12 +615,6 @@ void CUtlLinkedList::SetGrowSize( int growSize ) ResetDbgInfo(); } -template< class T, class S, bool ML, class I, class M > -void CUtlLinkedList::SetAllocOwner( const char *pszAllocOwner ) -{ - m_Memory.SetAllocOwner( pszAllocOwner ); -} - //----------------------------------------------------------------------------- // Deallocate memory diff --git a/public/togl/linuxwin/glmgr.h b/public/togl/linuxwin/glmgr.h index b9e5d0d8..8cde5a92 100644 --- a/public/togl/linuxwin/glmgr.h +++ b/public/togl/linuxwin/glmgr.h @@ -1934,11 +1934,11 @@ FORCEINLINE void GLMContext::DrawRangeElements( GLenum mode, GLuint start, GLuin if ( pIndexBuf->m_bPseudo ) { // you have to pass actual address, not offset - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_pPseudoBuf ); } if (pIndexBuf->m_bUsingPersistentBuffer) { - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_nPersistentBufferStartOffset ); } //#if GLMDEBUG diff --git a/public/vgui_controls/BuildGroup.h b/public/vgui_controls/BuildGroup.h index a0fcf352..d6b0ea04 100644 --- a/public/vgui_controls/BuildGroup.h +++ b/public/vgui_controls/BuildGroup.h @@ -38,7 +38,7 @@ class BuildGroup public: BuildGroup(Panel *parentPanel, Panel *contextPanel); - ~BuildGroup(); + virtual ~BuildGroup(); // Toggle build mode on/off virtual void SetEnabled(bool state); diff --git a/public/vstdlib/jobthread.h b/public/vstdlib/jobthread.h index 9b34efe9..05798a2c 100644 --- a/public/vstdlib/jobthread.h +++ b/public/vstdlib/jobthread.h @@ -1162,7 +1162,7 @@ inline ThreadHandle_t ThreadExecuteSoloImpl( CFunctor *pFunctor, const char *psz hThread = CreateSimpleThread( FunctorExecuteThread, pFunctor, &threadId ); if ( pszName ) { - ThreadSetDebugName( threadId, pszName ); + ThreadSetDebugName( (ThreadHandle_t)threadId, pszName ); } return hThread; } diff --git a/tier1/utlbuffer.cpp b/tier1/utlbuffer.cpp index ae29160f..604059f1 100644 --- a/tier1/utlbuffer.cpp +++ b/tier1/utlbuffer.cpp @@ -1573,7 +1573,7 @@ void CUtlBuffer::VaPrintf( const char* pFmt, va_list list ) { char temp[8192]; int nLen = V_vsnprintf( temp, sizeof( temp ), pFmt, list ); - ErrorIfNot( nLen < sizeof( temp ), ( "CUtlBuffer::VaPrintf: String overflowed buffer [%d]\n", sizeof( temp ) ) ); + ErrorIfNot( nLen < sizeof( temp ), ( "CUtlBuffer::VaPrintf: String overflowed buffer [%zd]\n", sizeof( temp ) ) ); PutString( temp ); } diff --git a/togl/linuxwin/glmgr.cpp b/togl/linuxwin/glmgr.cpp index a573210c..7e7d0dc4 100644 --- a/togl/linuxwin/glmgr.cpp +++ b/togl/linuxwin/glmgr.cpp @@ -5098,11 +5098,11 @@ void GLMContext::DrawRangeElementsNonInline( GLenum mode, GLuint start, GLuint e if ( pIndexBuf->m_bPseudo ) { // you have to pass actual address, not offset - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_pPseudoBuf ); } if (pIndexBuf->m_bUsingPersistentBuffer) { - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_nPersistentBufferStartOffset ); } #if GL_ENABLE_INDEX_VERIFICATION diff --git a/vgui2/matsys_controls/QCGenerator.cpp b/vgui2/matsys_controls/QCGenerator.cpp index 89f01732..78ad4404 100644 --- a/vgui2/matsys_controls/QCGenerator.cpp +++ b/vgui2/matsys_controls/QCGenerator.cpp @@ -320,13 +320,13 @@ CQCGenerator::CQCGenerator( vgui::Panel *pParent, const char *pszPath, const cha SetParent( pParent ); char szGamePath[1024] = "\0"; - char szSearchPath[1024] = "\0"; + char szSearchPath[2048] = "\0"; // Get the currently set game configuration GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGamePath, sizeof( szGamePath ) ); static const char *pSurfacePropFilename = "\\scripts\\surfaceproperties.txt"; - sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename ); + snprintf( szSearchPath, sizeof(szSearchPath), "%s%s", szGamePath, pSurfacePropFilename ); FileHandle_t fp = g_pFullFileSystem->Open( szSearchPath, "rb" ); @@ -338,7 +338,7 @@ CQCGenerator::CQCGenerator( vgui::Panel *pParent, const char *pszPath, const cha char *pszEndGamePath = Q_strrchr( szGamePath, '\\' ); pszEndGamePath[0] = 0; V_strcat_safe( szGamePath, "\\hl2" ); - sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename ); + snprintf( szSearchPath, sizeof(szSearchPath), "%s%s", szGamePath, pSurfacePropFilename ); fp = g_pFullFileSystem->Open( szSearchPath, "rb" ); } @@ -720,4 +720,4 @@ void CQCGenerator::OnNewLODText() m_pLODPanel->LeaveEditMode(); m_pLODPanel->InvalidateLayout(); return; -} \ No newline at end of file +} diff --git a/vguimatsurface/Input.cpp b/vguimatsurface/Input.cpp index 03df13d5..744aafbb 100644 --- a/vguimatsurface/Input.cpp +++ b/vguimatsurface/Input.cpp @@ -509,7 +509,7 @@ bool InputHandleInputEvent( const InputEvent_t &event ) return true; case IE_IMESetWindow: - g_pIInput->SetIMEWindow( (void *)event.m_nData ); + g_pIInput->SetIMEWindow( (void *)(intp)event.m_nData ); return true; case IE_LocateMouseClick: diff --git a/vphysics/main.cpp b/vphysics/main.cpp index cb8424e4..03bdeb63 100644 --- a/vphysics/main.cpp +++ b/vphysics/main.cpp @@ -189,8 +189,8 @@ IPhysicsCollisionSet *CPhysicsInterface::FindOrCreateCollisionSet( unsigned int IPhysicsCollisionSet *pSet = FindCollisionSet( id ); if ( pSet ) return pSet; - int index = m_collisionSets.AddToTail(); - m_pCollisionSetHash->add_elem( (void *)id, (void *)(index+1) ); + intp index = m_collisionSets.AddToTail(); + m_pCollisionSetHash->add_elem( (void *)(intp)id, (void *)(intp)(index+1) ); return &m_collisionSets[index]; } @@ -198,7 +198,7 @@ IPhysicsCollisionSet *CPhysicsInterface::FindCollisionSet( unsigned int id ) { if ( m_pCollisionSetHash ) { - intp index = (intp)m_pCollisionSetHash->find_elem( (void *)id ); + intp index = (intp)m_pCollisionSetHash->find_elem( (void *)(intp)id ); if ( index > 0 ) { Assert( index <= m_collisionSets.Count() ); diff --git a/vphysics/physics_environment.cpp b/vphysics/physics_environment.cpp index a22670f7..9d3a8e34 100644 --- a/vphysics/physics_environment.cpp +++ b/vphysics/physics_environment.cpp @@ -2051,10 +2051,10 @@ public: void *ListIndexToHash( unsigned short listIndex ) { unsigned int hash = (unsigned int)listIndex; - + // set the high bit, so zero means "not there" hash |= 0x80000000; - return (void *)hash; + return (void *)(intp)hash; } // Lookup this object and get a multilist entry From 57bb27e4439a856ebd1757c8df60189b6c790765 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Wed, 15 Jun 2022 21:59:40 +0300 Subject: [PATCH 33/34] engine: add spatialpartition from cs:go engine --- engine/spatialpartition.cpp | 737 +++++++++++++++++++++++++----------- 1 file changed, 513 insertions(+), 224 deletions(-) diff --git a/engine/spatialpartition.cpp b/engine/spatialpartition.cpp index 68a51a13..29689d03 100644 --- a/engine/spatialpartition.cpp +++ b/engine/spatialpartition.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -30,8 +30,13 @@ #include "datacache/imdlcache.h" #include "tier2/renderutils.h" #include "bitvec.h" +#include "host.h" #include "tier1/mempool.h" +#ifdef _PS3 +#include "tls_ps3.h" +#endif + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -63,6 +68,9 @@ class CPartitionVisitor; #if defined( _X360 ) #pragma bitfield_order( push, lsb_to_msb ) +#elif defined( _PS3 ) +#pragma ms_struct on +#pragma reverse_bitfields on #endif union Voxel_t { @@ -76,6 +84,9 @@ union Voxel_t }; #if defined( _X360 ) #pragma bitfield_order( pop ) +#elif defined( _PS3 ) +#pragma ms_struct off +#pragma reverse_bitfields off #endif enum EntityInfoFlags_t @@ -89,7 +100,9 @@ enum EntityInfoFlags_t struct EntityInfo_t { Vector m_vecMin; // Min/Max of entity + Voxel_t m_voxelMin; Vector m_vecMax; + Voxel_t m_voxelMax; IHandleEntity * m_pHandleEntity; // Entity handle. unsigned short m_fList; // Which lists is it in? uint8 m_flags; @@ -101,7 +114,7 @@ struct EntityInfo_t struct LeafListData_t { - UtlHashFastHandle_t m_hVoxel; // Voxel handle the entity is in. + UtlHashFixedHandle_t m_hVoxel; // Voxel handle the entity is in. intp m_iEntity; // Entity list index for voxel }; @@ -142,7 +155,12 @@ inline Voxel_t ConvertToNextLevel( Voxel_t v ) return res; } - +class CSpatialEntry +{ +public: + SpatialPartitionHandle_t m_handle; + uint16 m_nListMask; +}; //----------------------------------------------------------------------------- // A single voxel hash //----------------------------------------------------------------------------- @@ -164,8 +182,9 @@ public: bool EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask, Voxel_t v, const Vector& pt, IPartitionEnumerator* pIterator ); // Inserts/Removes a handle from the tree. - void InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector &vecMin, const Vector &vecMax ); + void InsertIntoTree( SpatialPartitionHandle_t hPartition, Voxel_t voxelMin, Voxel_t voxelMax ); void RemoveFromTree( SpatialPartitionHandle_t hPartition ); + void UpdateListMask( SpatialPartitionHandle_t hPartition ); // Debug! void RenderAllObjectsInTree( float flTime ); @@ -179,6 +198,7 @@ public: // Gets the voxel size for this hash int VoxelSize( ) const; + inline float VoxelSizeF( ) const { return m_flVoxelSize; } int EntityCount(); @@ -189,6 +209,11 @@ public: inline Voxel_t VoxelIndexFromPoint( const Vector &vecWorldPoint ); inline void VoxelIndexFromPoint( const Vector &vecWorldPoint, int pPoint[3] ); +#if defined(_X360) || defined(_PS3) + inline Voxel_t VoxelIndexFromPoint( const fltx4 &vecWorldPoint ); + inline void VoxelIndexFromPoint( const fltx4 &vecWorldPoint, int pPoint[3] ); +#endif + // Setup ray for iteration void LeafListRaySetup( const Ray_t &ray, const Vector &vecEnd, const Vector &vecInvDelta, Voxel_t voxel, int *pStep, float *pMax, float *pDelta ); void LeafListExtrudedRaySetup( const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecMin, const Vector &vecMax, int iVoxelMin[3], int iVoxelMax[3], int *pStep, float *pMin, float *pMax, float *pDelta ); @@ -206,14 +231,16 @@ private: inline void PackVoxel( int iX, int iY, int iZ, Voxel_t &voxel ); - typedef CUtlHashFixed > CHashTable; + typedef CUtlHashFixed > CHashTable; Vector m_vecVoxelOrigin; // Voxel space (hash) origin. CHashTable m_aVoxelHash; // Voxel tree (hash) - data = entity list head handle (m_aEntityList) int m_nVoxelDelta[3]; // Voxel world - width(Dx), height(Dy), depth(Dz) - CUtlFixedLinkedList m_aEntityList; // Pool - Linked list(multilist) of entities per leaf. + CUtlFixedLinkedList m_aEntityList; // Pool - Linked list(multilist) of entities per leaf. CVoxelTree *m_pTree; int m_nLevel; + float m_flVoxelSize; + uint m_nLevelShift; }; class CSpatialPartition; @@ -257,10 +284,11 @@ public: void Shutdown( void ); // Insert into the appropriate tree - void InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs ); + void InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs, bool bReinsert ); // Remove from appropriate tree void RemoveFromTree( SpatialPartitionHandle_t hPartition ); + void UpdateListMask( SpatialPartitionHandle_t hPartition ); void LockForWrite() { m_lock.LockForWrite(); } void UnlockWrite() { m_lock.UnlockWrite(); } @@ -273,6 +301,8 @@ public: bool EnumerateElementsAlongRay_ExtrudedRay( SpatialPartitionListMask_t listMask, const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator *pIterator ); + bool EnumerateRayStartVoxels( SpatialPartitionListMask_t listMask, IPartitionEnumerator *pIterator, CIntersectSweptBox &intersectSweptBox, int voxelBounds[4][2][3] ); + // Purpose: void ComputeSweptRayBounds( const Ray_t &ray, const Vector &vecStartMin, const Vector &vecStartMax, Vector *pVecMin, Vector *pVecMax ); @@ -282,15 +312,11 @@ private: CVoxelHash* m_pVoxelHash; CLeafList m_aLeafList; // Pool - Linked list(multilist) of leaves per entity. int m_TreeId; - CTHREADLOCALPTR(CPartitionVisits) m_pVisits; + CPartitionVisits * m_pVisits[MAX_THREADS_SUPPORTED]; CSpatialPartition * m_pOwner; CUtlVector m_AvailableVisitBits; unsigned short m_nNextVisitBit; -#if TEST_TRACE_POOL CTSPool m_FreeVisits; -#else - CObjectPool m_FreeVisits; -#endif CThreadSpinRWLock m_lock; }; @@ -326,7 +352,7 @@ public: virtual void UnhideElement( SpatialPartitionHandle_t handle, SpatialTempHandle_t tempHandle ); virtual void InstallQueryCallback( IPartitionQueryCallback *pCallback ); - virtual void InstallQueryCallback_V1( IPartitionQueryCallback *pCallback ); + virtual void InstallQueryCallback_V1( IPartitionQueryCallback *pCallback ) { Error("Use InstallQueryCallback instead of InstallQueryCallback_V1\n"); } virtual void RemoveQueryCallback( IPartitionQueryCallback *pCallback ); virtual void SuppressLists( SpatialPartitionListMask_t nListMask, bool bSuppress ); @@ -366,6 +392,7 @@ public: CVoxelTree * VoxelTreeForHandle( SpatialPartitionHandle_t handle ); protected: + void UpdateListMask( SpatialPartitionHandle_t hPartition, uint16 nListMask ); // Invokes the pre-query callbacks. void InvokeQueryCallbacks( SpatialPartitionListMask_t listMask, bool = false ); @@ -378,7 +405,6 @@ private: CVoxelTree m_VoxelTrees[NUM_TREES]; IPartitionQueryCallback *m_pQueryCallback[MAX_QUERY_CALLBACK]; // Query callbacks. - bool m_bUseOldQueryCallback[MAX_QUERY_CALLBACK]; int m_nQueryCallbackCount; // Number of query callbacks. // Debug! @@ -411,22 +437,32 @@ inline int CVoxelTree::GetTreeId() const inline CPartitionVisits *CVoxelTree::GetVisits() { - return m_pVisits; + int nThread = g_nThreadID; + return m_pVisits[nThread]; } inline CPartitionVisits *CVoxelTree::BeginVisit() { - CPartitionVisits *pPrev = m_pVisits; + int nThread = g_nThreadID; + CPartitionVisits *pPrev = m_pVisits[nThread]; CPartitionVisits *pVisits = m_FreeVisits.GetObject(); - pVisits->Resize( m_nNextVisitBit, true ); - m_pVisits = pVisits; + if ( pVisits->GetNumBits() < m_nNextVisitBit ) + { + pVisits->Resize( m_nNextVisitBit, true ); + } + else + { + pVisits->ClearAll(); + } + m_pVisits[g_nThreadID] = pVisits; return pPrev; } inline void CVoxelTree::EndVisit( CPartitionVisits *pPrev ) { - m_FreeVisits.PutObject( m_pVisits ); - m_pVisits = pPrev; + int nThread = g_nThreadID; + m_FreeVisits.PutObject( m_pVisits[nThread] ); + m_pVisits[nThread] = pPrev; } inline CVoxelTree *CSpatialPartition::VoxelTree( SpatialPartitionListMask_t listMask ) @@ -460,13 +496,6 @@ CVoxelHash::~CVoxelHash() // Input: vecWorldPoint - world point to get voxel index for // Output: voxel index //----------------------------------------------------------------------------- -inline void CVoxelHash::VoxelIndexFromPoint( const Vector &vecWorldPoint, int pPoint[3] ) -{ - pPoint[0] = static_cast( vecWorldPoint.x - m_vecVoxelOrigin.x ) >> ( SPHASH_VOXEL_SHIFT + SPHASH_LEVEL_SKIP * m_nLevel ); - pPoint[1] = static_cast( vecWorldPoint.y - m_vecVoxelOrigin.y ) >> ( SPHASH_VOXEL_SHIFT + SPHASH_LEVEL_SKIP * m_nLevel ); - pPoint[2] = static_cast( vecWorldPoint.z - m_vecVoxelOrigin.z ) >> ( SPHASH_VOXEL_SHIFT + SPHASH_LEVEL_SKIP * m_nLevel ); -} - inline void CVoxelHash::PackVoxel( int iX, int iY, int iZ, Voxel_t &voxel ) { Assert( ( iX >= -( 1 << 10 ) ) && ( iX <= ( 1 << 10 ) ) ); @@ -477,17 +506,125 @@ inline void CVoxelHash::PackVoxel( int iX, int iY, int iZ, Voxel_t &voxel ) voxel.bitsVoxel.z = iZ; } + +#if defined(_X360) || defined(_PS3) + +// NOTE: This isn't supportable on SSE but it isn't necessary either +inline double FloatConvertToIntegerFormat( double flVal ) +{ +#if defined( _PS3 ) + return __builtin_fctiwz( flVal ); +#else + return __fctiwz( flVal ); +#endif +} + +inline fltx4 ConvertToSignedIntegerSIMD( fltx4 fl4Data ) +{ +#if defined(_X360) + return __vctsxs( fl4Data, 0 ); // NOTE: 0 is power of 2 to scale by +#else + return (fltx4)vec_cts( fl4Data, 0 ); +#endif +} + +inline fltx4 ShiftRightSIMD( const fltx4 &fl4Data, const fltx4 &fl4Shift ) +{ +#if defined(_X360) + return __vsrw( fl4Data, fl4Shift ); +#else + return (fltx4)vec_sr( (u32x4)fl4Data, (u32x4)fl4Shift ); +#endif +} + +union doublecnv_t +{ + double m_flConverted; + int32 m_nConverted[2]; +}; + +// SIMD Versions - need more code changes to fully support this but there are enough benefits to use it on some of the code +inline void CVoxelHash::VoxelIndexFromPoint( const fltx4 &fl4WorldPoint, int pPoint[3] ) +{ + fltx4 fl4Shift = (fltx4)ReplicateIX4( m_nLevelShift ); + fltx4 fl4VoxelOrigin = LoadUnaligned3SIMD( m_vecVoxelOrigin.Base() ); + fltx4 fl4LocalOrigin = SubSIMD( fl4WorldPoint, fl4VoxelOrigin ); + fltx4 fl4OriginInt = ConvertToSignedIntegerSIMD( fl4LocalOrigin ); + fl4OriginInt = ShiftRightSIMD( fl4OriginInt, fl4Shift ); + StoreUnaligned3SIMD( (float *)pPoint, fl4OriginInt ); +} + +inline void CVoxelHash::VoxelIndexFromPoint( const Vector &vecWorldPoint, int pPoint[3] ) +{ + return VoxelIndexFromPoint( LoadUnaligned3SIMD( vecWorldPoint.Base() ), pPoint ); +} + + inline Voxel_t CVoxelHash::VoxelIndexFromPoint( const Vector &vecWorldPoint ) { Voxel_t voxel; - voxel.bitsVoxel.x = static_cast( vecWorldPoint.x - m_vecVoxelOrigin.x ) >> ( SPHASH_VOXEL_SHIFT + SPHASH_LEVEL_SKIP * m_nLevel ); - voxel.bitsVoxel.y = static_cast( vecWorldPoint.y - m_vecVoxelOrigin.y ) >> ( SPHASH_VOXEL_SHIFT + SPHASH_LEVEL_SKIP * m_nLevel ); - voxel.bitsVoxel.z = static_cast( vecWorldPoint.z - m_vecVoxelOrigin.z ) >> ( SPHASH_VOXEL_SHIFT + SPHASH_LEVEL_SKIP * m_nLevel ); + // This code manually schedules the float->int conversion to avoid LHS on PPC + // First we convert the float to int format within a float register + // then we write it back to memory + volatile union doublecnv_t cnvX, cnvY, cnvZ; + cnvX.m_flConverted = FloatConvertToIntegerFormat( vecWorldPoint.x - m_vecVoxelOrigin.x ); + cnvY.m_flConverted = FloatConvertToIntegerFormat( vecWorldPoint.y - m_vecVoxelOrigin.y ); + cnvZ.m_flConverted = FloatConvertToIntegerFormat( vecWorldPoint.z - m_vecVoxelOrigin.z ); + // now we load that value back into an integer register. This will LHS if there aren't enough + // cycles between the stores and the loads but this will allow the compiler to reorder the operations + // and when the conversions are implicit they don't get reordered (load instruction immediately follows the store) + int nX = cnvX.m_nConverted[1]; + int nY = cnvY.m_nConverted[1]; + int nZ = cnvZ.m_nConverted[1]; + voxel.bitsVoxel.x = nX >> m_nLevelShift; + voxel.bitsVoxel.y = nY >> m_nLevelShift; + voxel.bitsVoxel.z = nZ >> m_nLevelShift; return voxel; } +inline Voxel_t CVoxelHash::VoxelIndexFromPoint( const fltx4 &fl4WorldPoint ) +{ + Voxel_t voxel; + + fltx4 fl4Shift = (fltx4)ReplicateIX4( m_nLevelShift ); + fltx4 fl4VoxelOrigin = LoadUnaligned3SIMD( m_vecVoxelOrigin.Base() ); + fltx4 fl4LocalOrigin = SubSIMD( fl4WorldPoint, fl4VoxelOrigin ); + fltx4 fl4OriginInt = ConvertToSignedIntegerSIMD( fl4LocalOrigin ); + fl4OriginInt = ShiftRightSIMD( fl4OriginInt, fl4Shift ); + + // UNDONE: Can probably pack these with shift, permute, or + int32 ALIGN16 tmp[4]; + StoreAlignedIntSIMD( tmp, fl4OriginInt ); + voxel.bitsVoxel.x = tmp[0]; + voxel.bitsVoxel.y = tmp[1]; + voxel.bitsVoxel.z = tmp[2]; + + return voxel; +} + +#else + +inline void CVoxelHash::VoxelIndexFromPoint( const Vector &vecWorldPoint, int pPoint[3] ) +{ + pPoint[0] = static_cast( vecWorldPoint.x - m_vecVoxelOrigin.x ) >> m_nLevelShift; + pPoint[1] = static_cast( vecWorldPoint.y - m_vecVoxelOrigin.y ) >> m_nLevelShift; + pPoint[2] = static_cast( vecWorldPoint.z - m_vecVoxelOrigin.z ) >> m_nLevelShift; +} + + +inline Voxel_t CVoxelHash::VoxelIndexFromPoint( const Vector &vecWorldPoint ) +{ + Voxel_t voxel; + + voxel.bitsVoxel.x = static_cast( vecWorldPoint.x - m_vecVoxelOrigin.x ) >> m_nLevelShift; + voxel.bitsVoxel.y = static_cast( vecWorldPoint.y - m_vecVoxelOrigin.y ) >> m_nLevelShift; + voxel.bitsVoxel.z = static_cast( vecWorldPoint.z - m_vecVoxelOrigin.z ) >> m_nLevelShift; + + return voxel; +} +#endif //----------------------------------------------------------------------------- // Purpose: Computes the voxel count at a particular level of the tree @@ -518,6 +655,8 @@ void CVoxelHash::Init( CVoxelTree *pPartition, const Vector &worldmin, const Vec { m_pTree = pPartition; m_nLevel = nLevel; + m_flVoxelSize = VoxelSize(); + m_nLevelShift = ( SPHASH_VOXEL_SHIFT + SPHASH_LEVEL_SKIP * nLevel ); // Setup the hash. MEM_ALLOC_CREDIT(); @@ -562,27 +701,21 @@ void CVoxelHash::Shutdown( void ) //----------------------------------------------------------------------------- // Purpose: Insert the object into the voxel hash. //----------------------------------------------------------------------------- -void CVoxelHash::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector &vecMin, const Vector &vecMax ) +void CVoxelHash::InsertIntoTree( SpatialPartitionHandle_t hPartition, Voxel_t voxelMin, Voxel_t voxelMax ) { EntityInfo_t &info = m_pTree->EntityInfo( hPartition ); CLeafList &leafList = m_pTree->LeafList(); int treeId = m_pTree->GetTreeId(); - // Set the entity bounding box. - info.m_vecMin = vecMin; - info.m_vecMax = vecMax; + uint16 nListMask = m_pTree->EntityInfo( hPartition ).m_fList; // Set the voxel level info.m_nLevel[m_pTree->GetTreeId()] = m_nLevel; - // Add the object to the tree. - Voxel_t voxelMin, voxelMax; - voxelMin = VoxelIndexFromPoint( vecMin ); - voxelMax = VoxelIndexFromPoint( vecMax ); Assert( (m_nLevel == 4) || - ( (voxelMax.bitsVoxel.x - voxelMin.bitsVoxel.x <= 1) && + (voxelMax.bitsVoxel.x - voxelMin.bitsVoxel.x <= 1) && (voxelMax.bitsVoxel.y - voxelMin.bitsVoxel.y <= 1) && - (voxelMax.bitsVoxel.z - voxelMin.bitsVoxel.z <= 1) ) ); + (voxelMax.bitsVoxel.z - voxelMin.bitsVoxel.z <= 1) ); // Add the object to all the voxels it intersects. Voxel_t voxel; @@ -604,9 +737,10 @@ void CVoxelHash::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vect // Entity list. intp iEntity = m_aEntityList.Alloc( true ); - m_aEntityList[iEntity] = hPartition; + m_aEntityList[iEntity].m_handle = hPartition; + m_aEntityList[iEntity].m_nListMask = nListMask; - UtlHashFastHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); + UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); if ( hHash == m_aVoxelHash.InvalidHandle() ) { // Add voxel(leaf) to hash. @@ -650,13 +784,13 @@ void CVoxelHash::RemoveFromTree( SpatialPartitionHandle_t hPartition ) int treeId = m_pTree->GetTreeId(); intp iLeaf = data.m_iLeafList[treeId]; - intp iNext; + intp iNext; while ( iLeaf != leafList.InvalidIndex() ) { // Get the next voxel - if any. iNext = leafList.Next( iLeaf ); - UtlHashFastHandle_t hHash = leafList[iLeaf].m_hVoxel; + UtlHashFixedHandle_t hHash = leafList[iLeaf].m_hVoxel; if ( hHash == m_aVoxelHash.InvalidHandle() ) { iLeaf = iNext; @@ -691,6 +825,64 @@ void CVoxelHash::RemoveFromTree( SpatialPartitionHandle_t hPartition ) data.m_iLeafList[treeId] = leafList.InvalidIndex(); } +void CVoxelHash::UpdateListMask( SpatialPartitionHandle_t hPartition ) +{ + EntityInfo_t &data = m_pTree->EntityInfo( hPartition ); + uint16 nListMask = data.m_fList; + + Voxel_t vmin = data.m_voxelMin; + Voxel_t vmax = data.m_voxelMax; + + // single voxel + if ( vmin.uiVoxel == vmax.uiVoxel ) + { + UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( vmin.uiVoxel ); + if ( hHash != m_aVoxelHash.InvalidHandle() ) + { + for ( intp i = m_aVoxelHash.Element( hHash ); i != m_aEntityList.InvalidIndex(); i = m_aEntityList.Next(i) ) + { + SpatialPartitionHandle_t handle = m_aEntityList[i].m_handle; + if ( handle != hPartition ) + continue; + + m_aEntityList[i].m_nListMask = nListMask; + break; + } + } + } + + // spans voxels + Voxel_t vdelta; + vdelta.uiVoxel = vmax.uiVoxel - vmin.uiVoxel; + int cx = vdelta.bitsVoxel.x; + int cy = vdelta.bitsVoxel.y; + int cz = vdelta.bitsVoxel.z; + Voxel_t voxel; + voxel.bitsVoxel.x = vmin.bitsVoxel.x; + for ( int iX = 0; iX <= cx; ++iX, ++voxel.bitsVoxel.x ) + { + voxel.bitsVoxel.y = vmin.bitsVoxel.y; + for ( int iY = 0; iY <= cy; ++iY, ++voxel.bitsVoxel.y ) + { + voxel.bitsVoxel.z = vmin.bitsVoxel.z; + for ( int iZ = 0; iZ <= cz; ++iZ, ++voxel.bitsVoxel.z ) + { + UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); + if ( hHash != m_aVoxelHash.InvalidHandle() ) + { + for ( intp i = m_aVoxelHash.Element( hHash ); i != m_aEntityList.InvalidIndex(); i = m_aEntityList.Next(i) ) + { + if ( m_aEntityList[i].m_handle != hPartition ) + continue; + + m_aEntityList[i].m_nListMask = nListMask; + break; + } + } + } + } + } +} //----------------------------------------------------------------------------- // Purpose: @@ -803,23 +995,23 @@ private: class CIntersectPoint : public CPartitionVisitor { public: - CIntersectPoint( CVoxelTree *pPartition, const Vector &pt ) : CPartitionVisitor( pPartition ), m_vecPoint( pt ) + CIntersectPoint( CVoxelTree *pPartition, const Vector &pt ) : CPartitionVisitor( pPartition ) { + m_f4Point = LoadUnaligned3SIMD( pt.Base() ); } - bool Intersects( const Vector &vecMins, const Vector &vecMaxs ) const + bool Intersects( const float *pMins, const float *pMaxs ) const { // Ray intersection test - Assert( vecMins.x <= vecMaxs.x ); - Assert( vecMins.y <= vecMaxs.y ); - Assert( vecMins.z <= vecMaxs.z ); + Assert( pMins[0] <= pMaxs[0] ); + Assert( pMins[1] <= pMaxs[1] ); + Assert( pMins[2] <= pMaxs[2] ); - // Does the ray intersect the box? - return IsPointInBox( m_vecPoint, vecMins, vecMaxs ); + return IsPointInBox( m_f4Point, LoadUnaligned3SIMD( pMins ), LoadUnaligned3SIMD(pMaxs) ); } private: - const Vector &m_vecPoint; + fltx4 m_f4Point; }; @@ -830,16 +1022,16 @@ public: { } - bool Intersects( const Vector &vecMins, const Vector &vecMaxs ) const + bool Intersects( const float *pMins, const float *pMaxs ) const { // Box intersection test - Assert( vecMins.x <= vecMaxs.x ); - Assert( vecMins.y <= vecMaxs.y ); - Assert( vecMins.z <= vecMaxs.z ); + Assert( pMins[0] <= pMaxs[0] ); + Assert( pMins[1] <= pMaxs[1] ); + Assert( pMins[2] <= pMaxs[2] ); - return ( vecMins.x <= m_vecMaxs.x ) && ( vecMaxs.x >= m_vecMins.x ) && - ( vecMins.y <= m_vecMaxs.y ) && ( vecMaxs.y >= m_vecMins.y ) && - ( vecMins.z <= m_vecMaxs.z ) && ( vecMaxs.z >= m_vecMins.z ); + return ( pMins[0] <= m_vecMaxs.x ) && ( pMaxs[0] >= m_vecMins.x ) && + ( pMins[1] <= m_vecMaxs.y ) && ( pMaxs[1] >= m_vecMins.y ) && + ( pMins[2] <= m_vecMaxs.z ) && ( pMaxs[2] >= m_vecMins.z ); } private: @@ -850,55 +1042,64 @@ private: class CIntersectRay : public CPartitionVisitor { public: - CIntersectRay( CVoxelTree *pPartition, const Ray_t &ray, const Vector &vecInvDelta ) : CPartitionVisitor( pPartition ), m_Ray( ray ), m_vecInvDelta( vecInvDelta ) + CIntersectRay( CVoxelTree *pPartition, const Ray_t &ray, const Vector &vecInvDelta ) : CPartitionVisitor( pPartition ) { + m_f4Start = LoadUnaligned3SIMD( ray.m_Start.Base() ); + m_f4Delta = LoadUnaligned3SIMD( ray.m_Delta.Base() ); + m_f4InvDelta = LoadUnaligned3SIMD( vecInvDelta.Base() ); } - bool Intersects( const Vector &vecMins, const Vector &vecMaxs ) const + bool Intersects( const float *pMins, const float *pMaxs ) const { // Ray intersection test - Assert( vecMins.x <= vecMaxs.x ); - Assert( vecMins.y <= vecMaxs.y ); - Assert( vecMins.z <= vecMaxs.z ); + Assert( pMins[0] <= pMaxs[0] ); + Assert( pMins[1] <= pMaxs[1] ); + Assert( pMins[2] <= pMaxs[2] ); - // Does the ray intersect the box? - return IsBoxIntersectingRay( vecMins, vecMaxs, m_Ray.m_Start, m_Ray.m_Delta, m_vecInvDelta ); + fltx4 f4Mins = LoadUnaligned3SIMD( pMins ); + fltx4 f4Maxs = LoadUnaligned3SIMD( pMaxs ); + return IsBoxIntersectingRay( f4Mins, f4Maxs, m_f4Start, m_f4Delta, m_f4InvDelta ); } private: - const Ray_t &m_Ray; - const Vector &m_vecInvDelta; + fltx4 m_f4Start; + fltx4 m_f4Delta; + fltx4 m_f4InvDelta; }; class CIntersectSweptBox : public CPartitionVisitor { public: - CIntersectSweptBox( CVoxelTree *pPartition, const Ray_t &ray, const Vector &vecInvDelta ) : CPartitionVisitor( pPartition ), m_Ray( ray ), m_vecInvDelta( vecInvDelta ) + CIntersectSweptBox( CVoxelTree *pPartition, const Ray_t &ray, const Vector &vecInvDelta ) : CPartitionVisitor( pPartition ) { + m_f4Start = LoadUnaligned3SIMD( ray.m_Start.Base() ); + m_f4Delta = LoadUnaligned3SIMD( ray.m_Delta.Base() ); + m_f4InvDelta = LoadUnaligned3SIMD( vecInvDelta.Base() ); + m_f4Extents = LoadUnaligned3SIMD( ray.m_Extents.Base() ); } - bool Intersects( const Vector &vecMins, const Vector &vecMaxs ) const + bool Intersects( const float *pMins, const float *pMaxs ) const { // Swept box intersection test - Assert( vecMins.x <= vecMaxs.x ); - Assert( vecMins.y <= vecMaxs.y ); - Assert( vecMins.z <= vecMaxs.z ); + Assert( pMins[0] <= pMaxs[0] ); + Assert( pMins[1] <= pMaxs[1] ); + Assert( pMins[2] <= pMaxs[2] ); - Vector vecTestMin, vecTestMax; - VectorSubtract( vecMins, m_Ray.m_Extents, vecTestMin ); - VectorAdd( vecMaxs, m_Ray.m_Extents, vecTestMax ); + fltx4 f4Mins = LoadUnaligned3SIMD( pMins ); + fltx4 f4Maxs = LoadUnaligned3SIMD( pMaxs ); // Does the ray intersect the box? - return IsBoxIntersectingRay( vecTestMin, vecTestMax, m_Ray.m_Start, m_Ray.m_Delta, m_vecInvDelta ); + return IsBoxIntersectingRay( SubSIMD(f4Mins, m_f4Extents), AddSIMD(f4Maxs, m_f4Extents), m_f4Start, m_f4Delta, m_f4InvDelta ); } private: - const Ray_t &m_Ray; - const Vector &m_vecInvDelta; + fltx4 m_f4Start; + fltx4 m_f4Delta; + fltx4 m_f4InvDelta; + fltx4 m_f4Extents; }; - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -906,32 +1107,33 @@ template bool CVoxelHash::EnumerateElementsInVoxel( Voxel_t voxel, const T &intersectTest, SpatialPartitionListMask_t listMask, IPartitionEnumerator* pIterator ) { // If the voxel doesn't exist, nothing to iterate over - UtlHashFastHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); + UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); if ( hHash == m_aVoxelHash.InvalidHandle() ) return true; - SpatialPartitionHandle_t hPartition; for ( intp i = m_aVoxelHash.Element( hHash ); i != m_aEntityList.InvalidIndex(); i = m_aEntityList.Next(i) ) { - hPartition = m_aEntityList[i]; - if ( hPartition == PARTITION_INVALID_HANDLE ) + SpatialPartitionHandle_t handle = m_aEntityList[i].m_handle; + SpatialPartitionListMask_t nListMask = m_aEntityList[i].m_nListMask; + if ( handle == PARTITION_INVALID_HANDLE ) continue; - EntityInfo_t &hInfo = m_pTree->EntityInfo( hPartition ); - // Keep going if this dude isn't in the list - if ( !( listMask & hInfo.m_fList ) ) + if ( !( listMask & nListMask ) ) continue; + EntityInfo_t &hInfo = m_pTree->EntityInfo( handle ); + Assert( hInfo.m_fList == nListMask ); + if ( hInfo.m_flags & ENTITY_HIDDEN ) continue; // Has this handle already been visited? - if ( !intersectTest.Visit( hPartition, hInfo ) ) + if ( !intersectTest.Visit( handle, hInfo ) ) continue; // Intersection test - if ( !intersectTest.Intersects( hInfo.m_vecMin, hInfo.m_vecMax ) ) + if ( !intersectTest.Intersects( hInfo.m_vecMin.Base(), hInfo.m_vecMax.Base() ) ) continue; // Okay, this one is good... @@ -953,28 +1155,28 @@ bool CVoxelHash::EnumerateElementsInSingleVoxel( Voxel_t voxel, const T &interse // NOTE: We don't have to do the enum id checking, nor do we have to up the // nesting level, since this only visits 1 voxel. intp iEntityList; - UtlHashFastHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); + UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); if ( hHash != m_aVoxelHash.InvalidHandle() ) { iEntityList = m_aVoxelHash.Element( hHash ); while ( iEntityList != m_aEntityList.InvalidIndex() ) { - SpatialPartitionHandle_t hPartition = m_aEntityList[iEntityList]; + SpatialPartitionHandle_t handle = m_aEntityList[iEntityList].m_handle; + SpatialPartitionListMask_t nListMask = m_aEntityList[iEntityList].m_nListMask; iEntityList = m_aEntityList.Next( iEntityList ); - if ( hPartition == PARTITION_INVALID_HANDLE ) + if ( handle == PARTITION_INVALID_HANDLE ) continue; - EntityInfo_t &hInfo = m_pTree->EntityInfo( hPartition ); - // Keep going if this dude isn't in the list - if ( !( listMask & hInfo.m_fList ) ) + if ( !( listMask & nListMask ) ) continue; + EntityInfo_t &hInfo = m_pTree->EntityInfo( handle ); if ( hInfo.m_flags & ENTITY_HIDDEN ) continue; // Keep going if there's no collision - if ( !intersectTest.Intersects( hInfo.m_vecMin, hInfo.m_vecMax ) ) + if ( !intersectTest.Intersects( hInfo.m_vecMin.Base(), hInfo.m_vecMax.Base() ) ) continue; // Okay, this one is good... @@ -1013,6 +1215,15 @@ bool CVoxelHash::EnumerateElementsInBox( SpatialPartitionListMask_t listMask, int cy = vdelta.bitsVoxel.y; int cz = vdelta.bitsVoxel.z; + // Hijack what can feel like infinite iteration over voxels +#if defined( _GAMECONSOLE ) && defined( _DEBUG ) + if ( uint64( cx ) * uint64( cy ) * uint64( cz ) > 10000ull ) + { + Assert( !"CVoxelHash::EnumerateElementsInBox: box too large" ); + return true; + } +#endif + Voxel_t voxel; voxel.bitsVoxel.x = vmin.bitsVoxel.x; for ( int iX = 0; iX <= cx; ++iX, ++voxel.bitsVoxel.x ) @@ -1395,23 +1606,23 @@ bool CVoxelHash::EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask, // NOTE: We don't have to do the enum id checking, nor do we have to up the // nesting level, since this only visits 1 voxel. intp iEntityList; - UtlHashFastHandle_t hHash = m_aVoxelHash.Find( v.uiVoxel ); + UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( v.uiVoxel ); if ( hHash != m_aVoxelHash.InvalidHandle() ) { iEntityList = m_aVoxelHash.Element( hHash ); while ( iEntityList != m_aEntityList.InvalidIndex() ) { - SpatialPartitionHandle_t hPartition = m_aEntityList[iEntityList]; + SpatialPartitionHandle_t handle = m_aEntityList[iEntityList].m_handle; + SpatialPartitionListMask_t nListMask = m_aEntityList[iEntityList].m_nListMask; iEntityList = m_aEntityList.Next( iEntityList ); - if ( hPartition == PARTITION_INVALID_HANDLE ) + if ( handle == PARTITION_INVALID_HANDLE ) continue; - EntityInfo_t &hInfo = m_pTree->EntityInfo( hPartition ); - // Keep going if this dude isn't in the list - if ( !( listMask & hInfo.m_fList ) ) + if ( !( listMask & nListMask ) ) continue; + EntityInfo_t &hInfo = m_pTree->EntityInfo( handle ); if ( hInfo.m_flags & ENTITY_HIDDEN ) continue; @@ -1433,7 +1644,7 @@ bool CVoxelHash::EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask, //----------------------------------------------------------------------------- void CVoxelHash::RenderVoxel( Voxel_t voxel, float flTime ) { -#ifndef SWDS +#ifndef DEDICATED Vector vecMin, vecMax; vecMin.x = ( voxel.bitsVoxel.x * VoxelSize() ) + m_vecVoxelOrigin.x; vecMin.y = ( voxel.bitsVoxel.y * VoxelSize() ) + m_vecVoxelOrigin.y; @@ -1479,7 +1690,7 @@ void CVoxelHash::RenderVoxel( Voxel_t voxel, float flTime ) //----------------------------------------------------------------------------- void CVoxelHash::RenderObjectInVoxel( SpatialPartitionHandle_t hPartition, CPartitionVisitor *pVisitor, float flTime ) { -#ifndef SWDS +#ifndef DEDICATED // Add outline. if ( hPartition == PARTITION_INVALID_HANDLE ) return; @@ -1529,14 +1740,14 @@ void CVoxelHash::RenderObjectInVoxel( SpatialPartitionHandle_t hPartition, CPart //----------------------------------------------------------------------------- void CVoxelHash::RenderObjectsInVoxel( Voxel_t voxel, CPartitionVisitor *pVisitor, bool bRenderVoxel, float flTime ) { - UtlHashFastHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); + UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel ); if ( hHash == m_aVoxelHash.InvalidHandle() ) return; intp iEntityList = m_aVoxelHash.Element( hHash ); while ( iEntityList != m_aEntityList.InvalidIndex() ) { - SpatialPartitionHandle_t hPartition = m_aEntityList[iEntityList]; + SpatialPartitionHandle_t hPartition = m_aEntityList[iEntityList].m_handle; RenderObjectInVoxel( hPartition, pVisitor, flTime ); iEntityList = m_aEntityList.Next( iEntityList ); } @@ -1583,7 +1794,7 @@ int CVoxelHash::EntityCount() //----------------------------------------------------------------------------- void CVoxelHash::RenderGrid() { -#ifndef SWDS +#ifndef DEDICATED Vector vecStart, vecEnd; for ( int i = 0; i < m_nVoxelDelta[0]; ++i ) { @@ -1648,7 +1859,7 @@ void CVoxelHash::RenderAllObjectsInTree( float flTime ) intp iEntity = m_aVoxelHash.m_aBuckets[iBucket][hHash].m_Data; while ( iEntity!= m_aEntityList.InvalidIndex() ) { - SpatialPartitionHandle_t hPartition = m_aEntityList[iEntity]; + SpatialPartitionHandle_t hPartition = m_aEntityList[iEntity].m_handle; RenderObjectInVoxel( hPartition, &visitor, flTime ); iEntity = m_aEntityList.Next( iEntity ); } @@ -1744,7 +1955,7 @@ void CVoxelTree::Init( CSpatialPartition *pOwner, int iTree, const Vector &world m_TreeId = iTree; // Reset the enumeration id. - m_pVisits = NULL; + memset( m_pVisits, 0, sizeof( m_pVisits ) ); for ( int i = 0; i < m_nLevelCount; ++i ) { @@ -1769,32 +1980,14 @@ void CVoxelTree::Shutdown( void ) } } - //----------------------------------------------------------------------------- // Insert into the appropriate tree //----------------------------------------------------------------------------- -void CVoxelTree::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs ) +void CVoxelTree::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs, bool bReinsert ) { - bool bWasReading = ( m_pVisits != static_cast(nullptr) ); - if ( bWasReading ) - { - // If we're recursing in this thread, need to release our read lock to allow ourselves to write - UnlockRead(); - } - - m_lock.LockForWrite(); Assert( hPartition != PARTITION_INVALID_HANDLE ); EntityInfo_t &info = EntityInfo( hPartition ); - if ( m_AvailableVisitBits.Count() ) - { - info.m_nVisitBit[m_TreeId] = m_AvailableVisitBits.Tail(); - m_AvailableVisitBits.Remove( m_AvailableVisitBits.Count() - 1 ); - } - else - { - info.m_nVisitBit[m_TreeId] = m_nNextVisitBit++; - } // Bloat by an eps before inserting the object into the tree. Vector vecMin( mins.x - SPHASH_EPS, mins.y - SPHASH_EPS, mins.z - SPHASH_EPS ); @@ -1808,16 +2001,63 @@ void CVoxelTree::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vect int nLevel; for ( nLevel = 0; nLevel < m_nLevelCount - 1; ++nLevel ) { - int nVoxelSize = m_pVoxelHash[nLevel].VoxelSize(); - if ( (nVoxelSize > vecSize.x) && (nVoxelSize > vecSize.y) && (nVoxelSize > vecSize.z) ) + float flVoxelSize = m_pVoxelHash[nLevel].VoxelSizeF(); + if ( (flVoxelSize > vecSize.x) && (flVoxelSize > vecSize.y) && (flVoxelSize > vecSize.z) ) break; } - m_pVoxelHash[nLevel].InsertIntoTree( hPartition, vecMin, vecMax ); - m_lock.UnlockWrite(); - if ( bWasReading ) + // Add the object to the tree. + Voxel_t voxelMin, voxelMax; + voxelMin = m_pVoxelHash[nLevel].VoxelIndexFromPoint( vecMin ); + voxelMax = m_pVoxelHash[nLevel].VoxelIndexFromPoint( vecMax ); + + bool bDoInsert = true; + if ( bReinsert ) { - LockForRead(); + // on reinsert we need to either remove/insert or not do anything + // if the entity spans the same bounding box of voxels no remove/insert is necessary + if ( info.m_voxelMin.uiVoxel == voxelMin.uiVoxel && info.m_voxelMax.uiVoxel == voxelMax.uiVoxel ) + { + bDoInsert = false; + } + else + { + // Remove entity from voxel hash. + RemoveFromTree( hPartition ); + } + } + // Set/update the entity bounding box. + info.m_vecMin = vecMin; + info.m_vecMax = vecMax; + + if ( bDoInsert ) + { + bool bWasReading = ( m_pVisits[g_nThreadID] != NULL ); + if ( bWasReading ) + { + // If we're recursing in this thread, need to release our read lock to allow ourselves to write + UnlockRead(); + } + m_lock.LockForWrite(); + + // if these have changed we need to insert + info.m_voxelMin = voxelMin; + info.m_voxelMax = voxelMax; + if ( m_AvailableVisitBits.Count() ) + { + info.m_nVisitBit[m_TreeId] = m_AvailableVisitBits.Tail(); + m_AvailableVisitBits.Remove( m_AvailableVisitBits.Count() - 1 ); + } + else + { + info.m_nVisitBit[m_TreeId] = m_nNextVisitBit++; + } + m_pVoxelHash[nLevel].InsertIntoTree( hPartition, voxelMin, voxelMax ); + m_lock.UnlockWrite(); + if ( bWasReading ) + { + LockForRead(); + } } } @@ -1832,7 +2072,7 @@ void CVoxelTree::RemoveFromTree( SpatialPartitionHandle_t hPartition ) int nLevel = info.m_nLevel[GetTreeId()]; if ( nLevel >= 0 ) { - bool bWasReading = ( m_pVisits != static_cast(nullptr) ); + bool bWasReading = ( m_pVisits[g_nThreadID] != NULL ); if ( bWasReading ) { // If we're recursing in this thread, need to release our read lock to allow ourselves to write @@ -1852,6 +2092,18 @@ void CVoxelTree::RemoveFromTree( SpatialPartitionHandle_t hPartition ) } } +void CVoxelTree::UpdateListMask( SpatialPartitionHandle_t hPartition ) +{ + EntityInfo_t &info = EntityInfo( hPartition ); + int nLevel = info.m_nLevel[GetTreeId()]; + if ( nLevel >= 0 ) + { + m_lock.LockForRead(); + m_pVoxelHash[nLevel].UpdateListMask( hPartition ); + m_lock.UnlockRead(); + } +} + //----------------------------------------------------------------------------- // Called when an element moves @@ -1864,25 +2116,12 @@ void CVoxelTree::ElementMoved( SpatialPartitionHandle_t hPartition, const Vector EntityInfo_t &info = EntityInfo( hPartition ); if ( info.m_iLeafList[GetTreeId()] == CLeafList::InvalidIndex() ) { - InsertIntoTree( hPartition, mins, maxs ); + InsertIntoTree( hPartition, mins, maxs, false ); return; } - // Bloat by an eps before inserting the object into the tree. - // Need to do this here to get the test to work - Vector vecEpsMin( mins.x - SPHASH_EPS, mins.y - SPHASH_EPS, mins.z - SPHASH_EPS ); - Vector vecEpsMax( maxs.x + SPHASH_EPS, maxs.y + SPHASH_EPS, maxs.z + SPHASH_EPS ); - - if ( (info.m_vecMin == vecEpsMin) && (info.m_vecMax == vecEpsMax) ) - { - return; - } - - // Remove entity from voxel hash. - RemoveFromTree( hPartition ); - // Re-insert entity into voxel hash. - InsertIntoTree( hPartition, mins, maxs ); + InsertIntoTree( hPartition, mins, maxs, true ); } } @@ -2114,6 +2353,56 @@ void CVoxelTree::ComputeSweptRayBounds( const Ray_t &ray, const Vector &vecStart } } +bool CVoxelTree::EnumerateRayStartVoxels( SpatialPartitionListMask_t listMask, IPartitionEnumerator *pIterator, CIntersectSweptBox &intersectSweptBox, int voxelBounds[4][2][3] ) +{ + // Iterate over all voxels that intersect the box around the starting ray point + int nMinX = voxelBounds[0][0][0]; + int nMinY = voxelBounds[0][0][1]; + int nMinZ = voxelBounds[0][0][2]; + + int nMaxX = voxelBounds[0][1][0]; + int nMaxY = voxelBounds[0][1][1]; + int nMaxZ = voxelBounds[0][1][2]; + for ( int i = 0; i < m_nLevelCount; ++i ) + { + if ( i != 0 ) + { + nMinX >>= SPHASH_LEVEL_SKIP; + nMinY >>= SPHASH_LEVEL_SKIP; + nMinZ >>= SPHASH_LEVEL_SKIP; + nMaxX >>= SPHASH_LEVEL_SKIP; + nMaxY >>= SPHASH_LEVEL_SKIP; + nMaxZ >>= SPHASH_LEVEL_SKIP; + + voxelBounds[i][0][0] = nMinX; + voxelBounds[i][0][1] = nMinY; + voxelBounds[i][0][2] = nMinZ; + + voxelBounds[i][1][0] = nMaxX; + voxelBounds[i][1][1] = nMaxY; + voxelBounds[i][1][2] = nMaxZ; + } + + Voxel_t voxel; + int iX, iY, iZ; + for ( iX = nMinX; iX <= nMaxX; ++iX ) + { + voxel.bitsVoxel.x = iX; + for ( iY = nMinY; iY <= nMaxY; ++iY ) + { + voxel.bitsVoxel.y = iY; + for ( iZ = nMinZ; iZ <= nMaxZ; ++iZ ) + { + voxel.bitsVoxel.z = iZ; + if ( !m_pVoxelHash[i].EnumerateElementsInVoxel( voxel, intersectSweptBox, listMask, pIterator ) ) + return false; + } + } + } + } + + return true; +} //----------------------------------------------------------------------------- // Purpose: @@ -2134,40 +2423,21 @@ bool CVoxelTree::EnumerateElementsAlongRay_ExtrudedRay( SpatialPartitionListMask CIntersectSweptBox intersectSweptBox( this, ray, vecInvDelta ); - // Iterate over all voxels that intersect the box around the starting ray point - for ( int i = 0; i < m_nLevelCount; ++i ) - { - voxelBounds[i][0][0] = voxelBounds[0][0][0] >> ( i * SPHASH_LEVEL_SKIP ); - voxelBounds[i][0][1] = voxelBounds[0][0][1] >> ( i * SPHASH_LEVEL_SKIP ); - voxelBounds[i][0][2] = voxelBounds[0][0][2] >> ( i * SPHASH_LEVEL_SKIP ); - - voxelBounds[i][1][0] = voxelBounds[0][1][0] >> ( i * SPHASH_LEVEL_SKIP ); - voxelBounds[i][1][1] = voxelBounds[0][1][1] >> ( i * SPHASH_LEVEL_SKIP ); - voxelBounds[i][1][2] = voxelBounds[0][1][2] >> ( i * SPHASH_LEVEL_SKIP ); - - Voxel_t voxel; - int iX, iY, iZ; - for ( iX = voxelBounds[i][0][0]; iX <= voxelBounds[i][1][0]; ++iX ) - { - voxel.bitsVoxel.x = iX; - for ( iY = voxelBounds[i][0][1]; iY <= voxelBounds[i][1][1]; ++iY ) - { - voxel.bitsVoxel.y = iY; - for ( iZ = voxelBounds[i][0][2]; iZ <= voxelBounds[i][1][2]; ++iZ ) - { - voxel.bitsVoxel.z = iZ; - if ( !m_pVoxelHash[i].EnumerateElementsInVoxel( voxel, intersectSweptBox, listMask, pIterator ) ) - return false; - } - } - } - } + if ( !EnumerateRayStartVoxels( listMask, pIterator, intersectSweptBox, voxelBounds ) ) + return false; // Early out: Check to see if the range of voxels at the endpoint // is the same as the range at the start point. If so, we're done. +#if defined(_X360) || defined(_PS3) + fltx4 fl4RayEnd = LoadUnaligned3SIMD(vecEnd.Base()); + fltx4 fl4Extents = LoadAlignedSIMD(ray.m_Extents.Base()); + fltx4 vecEndMin = SubSIMD( fl4RayEnd, fl4Extents ); + fltx4 vecEndMax = AddSIMD( fl4RayEnd, fl4Extents ); +#else Vector vecEndMin, vecEndMax; VectorSubtract( vecEnd, ray.m_Extents, vecEndMin ); VectorAdd( vecEnd, ray.m_Extents, vecEndMax ); +#endif int endVoxelMin[3], endVoxelMax[3]; m_pVoxelHash[0].VoxelIndexFromPoint( vecEndMin, endVoxelMin ); @@ -2247,15 +2517,44 @@ bool CVoxelTree::EnumerateElementsAlongRay_ExtrudedRay( SpatialPartitionListMask return true; } +#ifndef _PS3 +#define THINK_TRACE_COUNTER_COMPILE_FUNCTIONS_ENGINE +#include "engine/thinktracecounter.h" +#endif + +#ifdef THINK_TRACE_COUNTER_COMPILED +ConVar think_trace_limit( "think_trace_limit", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Break into the debugger if this many or more traces are performed in a single think function. Negative numbers mean that the same think function may be broken into many times (once per [x] may traces), positive numbers mean each think will break only once." ); +CTHREADLOCALINT g_DebugTracesRemainingBeforeTrap(0); +#endif //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- - void CVoxelTree::EnumerateElementsAlongRay( SpatialPartitionListMask_t listMask, const Ray_t &ray, bool coarseTest, IPartitionEnumerator *pIterator ) { VPROF("EnumerateElementsAlongRay"); +#ifdef THINK_TRACE_COUNTER_COMPILED + if ( DEBUG_THINK_TRACE_COUNTER_ALLOWED() && think_trace_limit.GetInt() != 0 && g_DebugTracesRemainingBeforeTrap > 0 ) + { + if ( --g_DebugTracesRemainingBeforeTrap <= 0 ) + { + if ( Plat_IsInDebugSession() ) + { + + DebuggerBreakIfDebugging(); + if ( think_trace_limit.GetInt() < 0 ) + { + g_DebugTracesRemainingBeforeTrap = -think_trace_limit.GetInt(); + } + } + else + { + AssertMsg1( false, "Performed %d traces in a single think function!\n", think_trace_limit.GetInt() ); + } + } + } +#endif if ( !ray.m_IsSwept ) { @@ -2297,9 +2596,9 @@ void CVoxelTree::EnumerateElementsAlongRay( SpatialPartitionListMask_t listMask, vecInvDelta[1] = ( clippedRay.m_Delta[1] != 0.0f ) ? 1.0f / clippedRay.m_Delta[1] : FLT_MAX; vecInvDelta[2] = ( clippedRay.m_Delta[2] != 0.0f ) ? 1.0f / clippedRay.m_Delta[2] : FLT_MAX; - m_lock.LockForRead(); - CPartitionVisits *pPrevVisits = BeginVisit(); + + m_lock.LockForRead(); if ( ray.m_IsRay ) { EnumerateElementsAlongRay_Ray( listMask, clippedRay, vecInvDelta, vecEnd, pIterator ); @@ -2424,6 +2723,7 @@ CSpatialPartition::~CSpatialPartition() void CSpatialPartition::Init( const Vector &worldmin, const Vector &worldmax ) { // Clear the handle list and ensure some new memory. + MEM_ALLOC_CREDIT(); m_aHandles.Purge(); m_aHandles.EnsureCapacity( SPHASH_HANDLELIST_BLOCK ); @@ -2459,26 +2759,6 @@ void CSpatialPartition::InstallQueryCallback( IPartitionQueryCallback *pCallback return; m_pQueryCallback[m_nQueryCallbackCount] = pCallback; - m_bUseOldQueryCallback[m_nQueryCallbackCount] = false; - ++m_nQueryCallbackCount; -} - -//----------------------------------------------------------------------------- -// Purpose: Add a callback to the query callback list. Functions get called -// right before a query occurs. -// Input: pCallback - pointer to the callback function to add -//----------------------------------------------------------------------------- -void CSpatialPartition::InstallQueryCallback_V1( IPartitionQueryCallback *pCallback ) -{ - // Verify data. - Assert( pCallback && m_nQueryCallbackCount < MAX_QUERY_CALLBACK ); - if ( !pCallback || ( m_nQueryCallbackCount >= MAX_QUERY_CALLBACK ) ) - return; - - // NOTE: the query callbacks are not mutexed. Only add and remove when threads are joined - - m_pQueryCallback[m_nQueryCallbackCount] = pCallback; - m_bUseOldQueryCallback[m_nQueryCallbackCount] = true; ++m_nQueryCallbackCount; } @@ -2514,21 +2794,11 @@ void CSpatialPartition::InvokeQueryCallbacks( SpatialPartitionListMask_t listMas { if ( !bDone ) { - if ( m_bUseOldQueryCallback[iQuery] ) - { - m_pQueryCallback[iQuery]->OnPreQuery_V1(); - } - else - { - m_pQueryCallback[iQuery]->OnPreQuery( listMask ); - } + m_pQueryCallback[iQuery]->OnPreQuery( listMask ); } else { - if ( !m_bUseOldQueryCallback[iQuery] ) - { - m_pQueryCallback[iQuery]->OnPostQuery( listMask ); - } + m_pQueryCallback[iQuery]->OnPostQuery( listMask ); } } } @@ -2595,6 +2865,25 @@ SpatialPartitionHandle_t CSpatialPartition::CreateHandle( IHandleEntity *pHandle return hPartition; } + +void CSpatialPartition::UpdateListMask( SpatialPartitionHandle_t hPartition, uint16 nListMask ) +{ + EntityInfo_t &entityInfo = EntityInfo( hPartition ); + if ( entityInfo.m_fList != nListMask ) + { + entityInfo.m_fList = nListMask; + + if ( entityInfo.m_flags & IN_CLIENT_TREE ) + { + m_VoxelTrees[CLIENT_TREE].UpdateListMask( hPartition ); + } + + if ( entityInfo.m_flags & IN_SERVER_TREE ) + { + m_VoxelTrees[SERVER_TREE].UpdateListMask( hPartition ); + } + } +} //----------------------------------------------------------------------------- // Purpose: Insert object handle into group(s). // Input: listId - list(s) to insert the object handle into @@ -2604,7 +2893,7 @@ void CSpatialPartition::Insert( SpatialPartitionListMask_t listId, SpatialPartit { Assert( m_aHandles.IsValidIndex( handle ) ); Assert( listId <= USHRT_MAX ); - m_aHandles[handle].m_fList |= listId; + UpdateListMask( handle, m_aHandles[handle].m_fList | listId ); } //----------------------------------------------------------------------------- @@ -2616,7 +2905,7 @@ void CSpatialPartition::Remove( SpatialPartitionListMask_t listId, SpatialPartit { Assert( m_aHandles.IsValidIndex( handle ) ); Assert( listId <= USHRT_MAX ); - m_aHandles[handle].m_fList &= ~listId; + UpdateListMask( handle, m_aHandles[handle].m_fList & ~listId ); } //----------------------------------------------------------------------------- @@ -2628,8 +2917,9 @@ void CSpatialPartition::RemoveAndInsert( SpatialPartitionListMask_t removeMask, Assert( m_aHandles.IsValidIndex( handle ) ); Assert( removeMask <= USHRT_MAX ); Assert( insertMask <= USHRT_MAX ); - m_aHandles[handle].m_fList &= ~removeMask; - m_aHandles[handle].m_fList |= insertMask; + uint16 nOriginalListMask = m_aHandles[handle].m_fList; + uint16 nListMask = (nOriginalListMask & ~removeMask) | insertMask; + UpdateListMask( handle, nListMask ); } //----------------------------------------------------------------------------- @@ -2639,7 +2929,7 @@ void CSpatialPartition::RemoveAndInsert( SpatialPartitionListMask_t removeMask, void CSpatialPartition::Remove( SpatialPartitionHandle_t handle ) { Assert( m_aHandles.IsValidIndex( handle ) ); - m_aHandles[handle].m_fList = 0; + UpdateListMask( handle, 0 ); } //----------------------------------------------------------------------------- @@ -2656,6 +2946,7 @@ void CSpatialPartition::UnhideElement( SpatialPartitionHandle_t handle, SpatialT } + //----------------------------------------------------------------------------- // Purpose: Remove handle quickly saving the old list data, to be restored later // via the UnhideElement call. @@ -2787,19 +3078,19 @@ void CSpatialPartition::InsertIntoTree( SpatialPartitionHandle_t hPartition, con { if ( ( listMask & PARTITION_ALL_CLIENT_EDICTS ) && !( entityInfo.m_flags & IN_CLIENT_TREE ) ) { - m_VoxelTrees[CLIENT_TREE].InsertIntoTree( hPartition, mins, maxs ); + m_VoxelTrees[CLIENT_TREE].InsertIntoTree( hPartition, mins, maxs, false ); entityInfo.m_flags |= IN_CLIENT_TREE; } if ( ( listMask & ~PARTITION_ALL_CLIENT_EDICTS ) && !( entityInfo.m_flags & IN_SERVER_TREE ) ) { - m_VoxelTrees[SERVER_TREE].InsertIntoTree( hPartition, mins, maxs ); + m_VoxelTrees[SERVER_TREE].InsertIntoTree( hPartition, mins, maxs, false ); entityInfo.m_flags |= IN_SERVER_TREE; } } else if ( !( entityInfo.m_flags & IN_CLIENT_TREE ) ) { - m_VoxelTrees[CLIENT_TREE].InsertIntoTree( hPartition, mins, maxs ); + m_VoxelTrees[CLIENT_TREE].InsertIntoTree( hPartition, mins, maxs, false ); entityInfo.m_flags |= IN_CLIENT_TREE; } } @@ -2878,7 +3169,7 @@ void CVoxelTree::ReportStats( const char *pFileName ) void CSpatialPartition::ReportStats( const char *pFileName ) { - Msg( "Handle Count %d (%llu bytes)\n", m_aHandles.Count(), (uint64)( m_aHandles.Count() * ( sizeof(EntityInfo_t) + 2 * sizeof(SpatialPartitionHandle_t) ) ) ); + Msg( "Handle Count %d (%d bytes)\n", m_aHandles.Count(), m_aHandles.Count() * ( sizeof(EntityInfo_t) + 2 * sizeof(SpatialPartitionHandle_t) ) ); for ( int i = 0; i < NUM_TREES; i++ ) { m_VoxelTrees[i].ReportStats( pFileName ); @@ -2926,5 +3217,3 @@ void DestroySpatialPartition( ISpatialPartition *pPartition ) Assert( pPartition != (ISpatialPartition*)&g_SpatialPartition ); delete pPartition; } - - From 2e7fa2dfc8b1fe5a60ee71cb83fa084f4a8bd4e1 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 19 Jun 2022 15:07:41 +0300 Subject: [PATCH 34/34] aarch64: fix android build --- engine/host.cpp | 4 +- mathlib/sse.cpp | 12 +- public/XUnzip.cpp | 4 +- public/mathlib/mathlib.h | 4 +- public/mathlib/polyhedron.cpp | 2293 +++++++++++++++++++++++++++ public/mathlib/polyhedron.h | 6 +- public/mathlib/ssemath.h | 15 +- public/mathlib/vector4d.h | 2 +- public/saverestoretypes.h | 2 +- public/steam/steamtypes.h | 2 +- public/tier0/memvirt.h | 46 + public/tier0/platform.h | 14 +- public/tier0/threadtools.h | 16 +- public/tier0/threadtools.inl | 8 +- public/togles/linuxwin/dxabstract.h | 2 +- public/togles/linuxwin/glmgr.h | 4 +- tier0/cpu.cpp | 2 +- tier0/cpu_posix.cpp | 2 +- tier0/mem_impl_type.h | 6 + tier0/memdbg.cpp | 4 +- tier0/threadtools.cpp | 61 +- tier1/processor_detect_linux.cpp | 2 +- tier1/reliabletimer.cpp | 2 +- tier1/strtools.cpp | 8 +- tier1/wscript | 1 + togles/linuxwin/glmgr.cpp | 6 +- togles/linuxwin/glmgr_flush.inl | 2 +- vphysics/vphysics_saverestore.cpp | 2 +- 28 files changed, 2446 insertions(+), 86 deletions(-) create mode 100644 public/mathlib/polyhedron.cpp create mode 100644 public/tier0/memvirt.h create mode 100644 tier0/mem_impl_type.h diff --git a/engine/host.cpp b/engine/host.cpp index 57370866..1bc1693d 100644 --- a/engine/host.cpp +++ b/engine/host.cpp @@ -4850,7 +4850,9 @@ void Host_FreeToLowMark( bool server ) //----------------------------------------------------------------------------- void Host_Shutdown(void) { +#ifndef ANDROID extern void ShutdownMixerControls(); +#endif if ( host_checkheap ) { @@ -4962,7 +4964,7 @@ void Host_Shutdown(void) #ifndef SWDS TRACESHUTDOWN( Key_Shutdown() ); -#ifndef _X360 +#if !defined _X360 && !defined ANDROID TRACESHUTDOWN( ShutdownMixerControls() ); #endif #endif diff --git a/mathlib/sse.cpp b/mathlib/sse.cpp index 86377a6f..6122b664 100644 --- a/mathlib/sse.cpp +++ b/mathlib/sse.cpp @@ -11,7 +11,7 @@ #include "tier0/dbg.h" #include "mathlib/mathlib.h" #include "mathlib/vector.h" -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) #include "sse2neon.h" #endif @@ -180,7 +180,7 @@ float _SSE_RSqrtFast(float x) Assert( s_bMathlibInitialized ); float rroot; -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) rroot = _SSE_RSqrtAccurate(x); #elif _WIN32 _asm @@ -217,7 +217,7 @@ float FASTCALL _SSE_VectorNormalize (Vector& vec) // be much of a performance win, considering you will very likely miss 3 branch predicts in a row. if ( v[0] || v[1] || v[2] ) { -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) float rsqrt = _SSE_RSqrtAccurate( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); r[0] = v[0] * rsqrt; r[1] = v[1] * rsqrt; @@ -296,7 +296,7 @@ void FASTCALL _SSE_VectorNormalizeFast (Vector& vec) float _SSE_InvRSquared(const float* v) { float inv_r2 = 1.f; -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) return _SSE_RSqrtAccurate( FLT_EPSILON + v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); #elif _WIN32 _asm { // Intel SSE only routine @@ -391,7 +391,7 @@ typedef __m64 v2si; // vector of 2 int (mmx) void _SSE_SinCos(float x, float* s, float* c) { -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) #if defined( OSX ) __sincosf(x, s, c); #elif defined( POSIX ) @@ -607,7 +607,7 @@ void _SSE_SinCos(float x, float* s, float* c) float _SSE_cos( float x ) { -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) return cos(x); #elif _WIN32 float temp; diff --git a/public/XUnzip.cpp b/public/XUnzip.cpp index 9d7c4362..bf6310a7 100644 --- a/public/XUnzip.cpp +++ b/public/XUnzip.cpp @@ -4244,12 +4244,12 @@ ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) #ifdef _WIN32 SetFileTime(h,&ze.ctime,&ze.atime,&ze.mtime); #elif defined( ANDROID ) - struct timespec ts[2]; + struct timespec ts[2]; ts[0].tv_sec = ze.atime; ts[0].tv_nsec = 0; ts[1].tv_sec = ze.mtime; ts[1].tv_nsec = 0; - utimensat((int)h, NULL, ts, 0); + utimensat((intptr_t)h, NULL, ts, 0); #else struct timeval tv[2]; tv[0].tv_sec = ze.atime; diff --git a/public/mathlib/mathlib.h b/public/mathlib/mathlib.h index 4a765fcd..3afb27f2 100644 --- a/public/mathlib/mathlib.h +++ b/public/mathlib/mathlib.h @@ -1215,7 +1215,7 @@ FORCEINLINE int RoundFloatToInt(float f) }; flResult = __fctiw( f ); return pResult[1]; -#elif defined (__arm__) || defined (__arm64__) +#elif defined (__arm__) || defined (__aarch64__) return (int)(f + 0.5f); #else #error Unknown architecture @@ -1247,7 +1247,7 @@ FORCEINLINE unsigned long RoundFloatToUnsignedLong(float f) Assert( pIntResult[1] >= 0 ); return pResult[1]; #else // !X360 -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) return (unsigned long)(f + 0.5f); #elif defined( PLATFORM_WINDOWS_PC64 ) uint nRet = ( uint ) f; diff --git a/public/mathlib/polyhedron.cpp b/public/mathlib/polyhedron.cpp new file mode 100644 index 00000000..54e243ff --- /dev/null +++ b/public/mathlib/polyhedron.cpp @@ -0,0 +1,2293 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "mathlib/polyhedron.h" +#include "mathlib/vmatrix.h" +#include +#include +#include "tier1/utlvector.h" + + + +struct GeneratePolyhedronFromPlanes_Point; +struct GeneratePolyhedronFromPlanes_PointLL; +struct GeneratePolyhedronFromPlanes_Line; +struct GeneratePolyhedronFromPlanes_LineLL; +struct GeneratePolyhedronFromPlanes_Polygon; +struct GeneratePolyhedronFromPlanes_PolygonLL; + +struct GeneratePolyhedronFromPlanes_UnorderedPointLL; +struct GeneratePolyhedronFromPlanes_UnorderedLineLL; +struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL; + +Vector FindPointInPlanes( const float *pPlanes, int planeCount ); +bool FindConvexShapeLooseAABB( const float *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs ); +CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ); +CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory ); + +//#define ENABLE_DEBUG_POLYHEDRON_DUMPS //Dumps debug information to disk for use with glview. Requires that tier2 also be in all projects using debug mathlib +//#define DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS //dumps successfully generated polyhedrons + +#ifdef _DEBUG +void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform ); +void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform ); +void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile ); +void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile ); + +#if defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( WIN32 ) +#include "winlite.h" +#endif + +static VMatrix s_matIdentity( 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f ); +#endif + +#if defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS ) +static int g_iPolyhedronDumpCounter = 0; +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#if defined( _DEBUG ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) +void CreateDumpDirectory( const char *szDirectoryName ) +{ +#if defined( WIN32 ) + CreateDirectory( szDirectoryName, NULL ); +#else + Assert( false ); //TODO: create directories in linux +#endif +} +#endif + + + +void CPolyhedron_AllocByNew::Release( void ) +{ + delete this; +} + +CPolyhedron_AllocByNew *CPolyhedron_AllocByNew::Allocate( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ) //creates the polyhedron along with enough memory to hold all it's data in a single allocation +{ + void *pMemory = new unsigned char [ sizeof( CPolyhedron_AllocByNew ) + + (iVertices * sizeof(Vector)) + + (iLines * sizeof(Polyhedron_IndexedLine_t)) + + (iIndices * sizeof( Polyhedron_IndexedLineReference_t )) + + (iPolygons * sizeof( Polyhedron_IndexedPolygon_t ))]; + +#include "tier0/memdbgoff.h" //the following placement new doesn't compile with memory debugging + CPolyhedron_AllocByNew *pAllocated = new ( pMemory ) CPolyhedron_AllocByNew; +#include "tier0/memdbgon.h" + + pAllocated->iVertexCount = iVertices; + pAllocated->iLineCount = iLines; + pAllocated->iIndexCount = iIndices; + pAllocated->iPolygonCount = iPolygons; + pAllocated->pVertices = (Vector *)(pAllocated + 1); //start vertex memory at the end of the class + pAllocated->pLines = (Polyhedron_IndexedLine_t *)(pAllocated->pVertices + iVertices); + pAllocated->pIndices = (Polyhedron_IndexedLineReference_t *)(pAllocated->pLines + iLines); + pAllocated->pPolygons = (Polyhedron_IndexedPolygon_t *)(pAllocated->pIndices + iIndices); + + return pAllocated; +} + + +class CPolyhedron_TempMemory : public CPolyhedron +{ +public: +#ifdef DBGFLAG_ASSERT + int iReferenceCount; +#endif + + virtual void Release( void ) + { +#ifdef DBGFLAG_ASSERT + --iReferenceCount; +#endif + } + + CPolyhedron_TempMemory( void ) +#ifdef DBGFLAG_ASSERT + : iReferenceCount( 0 ) +#endif + { }; +}; + + +static CUtlVector s_TempMemoryPolyhedron_Buffer; +static CPolyhedron_TempMemory s_TempMemoryPolyhedron; + +CPolyhedron *GetTempPolyhedron( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ) //grab the temporary polyhedron. Avoids new/delete for quick work. Can only be in use by one chunk of code at a time +{ + AssertMsg( s_TempMemoryPolyhedron.iReferenceCount == 0, "Temporary polyhedron memory being rewritten before released" ); +#ifdef DBGFLAG_ASSERT + ++s_TempMemoryPolyhedron.iReferenceCount; +#endif + s_TempMemoryPolyhedron_Buffer.SetCount( (sizeof( Vector ) * iVertices) + + (sizeof( Polyhedron_IndexedLine_t ) * iLines) + + (sizeof( Polyhedron_IndexedLineReference_t ) * iIndices) + + (sizeof( Polyhedron_IndexedPolygon_t ) * iPolygons) ); + + s_TempMemoryPolyhedron.iVertexCount = iVertices; + s_TempMemoryPolyhedron.iLineCount = iLines; + s_TempMemoryPolyhedron.iIndexCount = iIndices; + s_TempMemoryPolyhedron.iPolygonCount = iPolygons; + + s_TempMemoryPolyhedron.pVertices = (Vector *)s_TempMemoryPolyhedron_Buffer.Base(); + s_TempMemoryPolyhedron.pLines = (Polyhedron_IndexedLine_t *)(&s_TempMemoryPolyhedron.pVertices[s_TempMemoryPolyhedron.iVertexCount]); + s_TempMemoryPolyhedron.pIndices = (Polyhedron_IndexedLineReference_t *)(&s_TempMemoryPolyhedron.pLines[s_TempMemoryPolyhedron.iLineCount]); + s_TempMemoryPolyhedron.pPolygons = (Polyhedron_IndexedPolygon_t *)(&s_TempMemoryPolyhedron.pIndices[s_TempMemoryPolyhedron.iIndexCount]); + + return &s_TempMemoryPolyhedron; +} + + +Vector CPolyhedron::Center( void ) +{ + if( iVertexCount == 0 ) + return vec3_origin; + + Vector vAABBMin, vAABBMax; + vAABBMin = vAABBMax = pVertices[0]; + for( int i = 1; i != iVertexCount; ++i ) + { + Vector &vPoint = pVertices[i]; + if( vPoint.x < vAABBMin.x ) + vAABBMin.x = vPoint.x; + if( vPoint.y < vAABBMin.y ) + vAABBMin.y = vPoint.y; + if( vPoint.z < vAABBMin.z ) + vAABBMin.z = vPoint.z; + + if( vPoint.x > vAABBMax.x ) + vAABBMax.x = vPoint.x; + if( vPoint.y > vAABBMax.y ) + vAABBMax.y = vPoint.y; + if( vPoint.z > vAABBMax.z ) + vAABBMax.z = vPoint.z; + } + return ((vAABBMin + vAABBMax) * 0.5f); +} + +enum PolyhedronPointPlanarity +{ + POINT_DEAD, + POINT_ONPLANE, + POINT_ALIVE +}; + +struct GeneratePolyhedronFromPlanes_Point +{ + Vector ptPosition; + GeneratePolyhedronFromPlanes_LineLL *pConnectedLines; //keep these in a clockwise order, circular linking + float fPlaneDist; //used in plane cutting + PolyhedronPointPlanarity planarity; + int iSaveIndices; +}; + +struct GeneratePolyhedronFromPlanes_Line +{ + GeneratePolyhedronFromPlanes_Point *pPoints[2]; //the 2 connecting points in no particular order + GeneratePolyhedronFromPlanes_Polygon *pPolygons[2]; //viewing from the outside with the point connections going up, 0 is the left polygon, 1 is the right + int iSaveIndices; + bool bAlive; //connected to at least one living point + bool bCut; //connected to at least one dead point + + GeneratePolyhedronFromPlanes_LineLL *pPointLineLinks[2]; //rather than going into a point and searching for its link to this line, lets just cache it to eliminate searching + GeneratePolyhedronFromPlanes_LineLL *pPolygonLineLinks[2]; //rather than going into a polygon and searching for its link to this line, lets just cache it to eliminate searching +#ifdef POLYHEDRON_EXTENSIVE_DEBUGGING + int iDebugFlags; +#endif +}; + +struct GeneratePolyhedronFromPlanes_LineLL +{ + GeneratePolyhedronFromPlanes_Line *pLine; + int iReferenceIndex; //whatever is referencing the line should know which side of the line it's on (points and polygons), for polygons, it's which point to follow to continue going clockwise, which makes polygon 0 the one on the left side of an upward facing line vector, for points, it's the OTHER point's index + GeneratePolyhedronFromPlanes_LineLL *pPrev; + GeneratePolyhedronFromPlanes_LineLL *pNext; +}; + +struct GeneratePolyhedronFromPlanes_Polygon +{ + Vector vSurfaceNormal; + GeneratePolyhedronFromPlanes_LineLL *pLines; //keep these in a clockwise order, circular linking + + bool bMissingASide; +}; + +struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL //an unordered collection of polygons +{ + GeneratePolyhedronFromPlanes_Polygon *pPolygon; + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pNext; + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPrev; +}; + +struct GeneratePolyhedronFromPlanes_UnorderedLineLL //an unordered collection of lines +{ + GeneratePolyhedronFromPlanes_Line *pLine; + GeneratePolyhedronFromPlanes_UnorderedLineLL *pNext; + GeneratePolyhedronFromPlanes_UnorderedLineLL *pPrev; +}; + +struct GeneratePolyhedronFromPlanes_UnorderedPointLL //an unordered collection of points +{ + GeneratePolyhedronFromPlanes_Point *pPoint; + GeneratePolyhedronFromPlanes_UnorderedPointLL *pNext; + GeneratePolyhedronFromPlanes_UnorderedPointLL *pPrev; +}; + + + + +CPolyhedron *ClipPolyhedron( const CPolyhedron *pExistingPolyhedron, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ) +{ + if( pExistingPolyhedron == NULL ) + return NULL; + + AssertMsg( (pExistingPolyhedron->iVertexCount >= 3) && (pExistingPolyhedron->iPolygonCount >= 2), "Polyhedron doesn't meet absolute minimum spec" ); + + float *pUsefulPlanes = (float *)stackalloc( sizeof( float ) * 4 * iPlaneCount ); + int iUsefulPlaneCount = 0; + Vector *pExistingVertices = pExistingPolyhedron->pVertices; + + //A large part of clipping will either eliminate the polyhedron entirely, or clip nothing at all, so lets just check for those first and throw away useless planes + { + int iLiveCount = 0; + int iDeadCount = 0; + const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon; + + for( int i = 0; i != iPlaneCount; ++i ) + { + Vector vNormal = *((Vector *)&pOutwardFacingPlanes[(i * 4) + 0]); + float fPlaneDist = pOutwardFacingPlanes[(i * 4) + 3]; + + for( int j = 0; j != pExistingPolyhedron->iVertexCount; ++j ) + { + float fPointDist = vNormal.Dot( pExistingVertices[j] ) - fPlaneDist; + + if( fPointDist <= fNegativeOnPlaneEpsilon ) + ++iLiveCount; + else if( fPointDist > fOnPlaneEpsilon ) + ++iDeadCount; + } + + if( iLiveCount == 0 ) + { + //all points are dead or on the plane, so the polyhedron is dead + return NULL; + } + + if( iDeadCount != 0 ) + { + //at least one point died, this plane yields useful results + pUsefulPlanes[(iUsefulPlaneCount * 4) + 0] = vNormal.x; + pUsefulPlanes[(iUsefulPlaneCount * 4) + 1] = vNormal.y; + pUsefulPlanes[(iUsefulPlaneCount * 4) + 2] = vNormal.z; + pUsefulPlanes[(iUsefulPlaneCount * 4) + 3] = fPlaneDist; + ++iUsefulPlaneCount; + } + } + } + + if( iUsefulPlaneCount == 0 ) + { + //testing shows that the polyhedron won't even be cut, clone the existing polyhedron and return that + + CPolyhedron *pReturn; + if( bUseTemporaryMemory ) + { + pReturn = GetTempPolyhedron( pExistingPolyhedron->iVertexCount, + pExistingPolyhedron->iLineCount, + pExistingPolyhedron->iIndexCount, + pExistingPolyhedron->iPolygonCount ); + } + else + { + pReturn = CPolyhedron_AllocByNew::Allocate( pExistingPolyhedron->iVertexCount, + pExistingPolyhedron->iLineCount, + pExistingPolyhedron->iIndexCount, + pExistingPolyhedron->iPolygonCount ); + } + + memcpy( pReturn->pVertices, pExistingPolyhedron->pVertices, sizeof( Vector ) * pReturn->iVertexCount ); + memcpy( pReturn->pLines, pExistingPolyhedron->pLines, sizeof( Polyhedron_IndexedLine_t ) * pReturn->iLineCount ); + memcpy( pReturn->pIndices, pExistingPolyhedron->pIndices, sizeof( Polyhedron_IndexedLineReference_t ) * pReturn->iIndexCount ); + memcpy( pReturn->pPolygons, pExistingPolyhedron->pPolygons, sizeof( Polyhedron_IndexedPolygon_t ) * pReturn->iPolygonCount ); + + return pReturn; + } + + + + //convert the polyhedron to linked geometry + GeneratePolyhedronFromPlanes_Point *pStartPoints = (GeneratePolyhedronFromPlanes_Point *)stackalloc( pExistingPolyhedron->iVertexCount * sizeof( GeneratePolyhedronFromPlanes_Point ) ); + GeneratePolyhedronFromPlanes_Line *pStartLines = (GeneratePolyhedronFromPlanes_Line *)stackalloc( pExistingPolyhedron->iLineCount * sizeof( GeneratePolyhedronFromPlanes_Line ) ); + GeneratePolyhedronFromPlanes_Polygon *pStartPolygons = (GeneratePolyhedronFromPlanes_Polygon *)stackalloc( pExistingPolyhedron->iPolygonCount * sizeof( GeneratePolyhedronFromPlanes_Polygon ) ); + + GeneratePolyhedronFromPlanes_LineLL *pStartLineLinks = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( pExistingPolyhedron->iLineCount * 4 * sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + int iCurrentLineLinkIndex = 0; + + //setup points + for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i ) + { + pStartPoints[i].ptPosition = pExistingPolyhedron->pVertices[i]; + pStartPoints[i].pConnectedLines = NULL; //we won't be circular linking until later + } + + //setup lines and interlink to points (line links are not yet circularly linked, and are unordered) + for( int i = 0; i != pExistingPolyhedron->iLineCount; ++i ) + { + for( int j = 0; j != 2; ++j ) + { + pStartLines[i].pPoints[j] = &pStartPoints[pExistingPolyhedron->pLines[i].iPointIndices[j]]; + + GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pStartLineLinks[iCurrentLineLinkIndex++]; + pStartLines[i].pPointLineLinks[j] = pLineLink; + pLineLink->pLine = &pStartLines[i]; + pLineLink->iReferenceIndex = 1 - j; + //pLineLink->pPrev = NULL; + pLineLink->pNext = pStartLines[i].pPoints[j]->pConnectedLines; + pStartLines[i].pPoints[j]->pConnectedLines = pLineLink; + } + } + + + + //setup polygons + for( int i = 0; i != pExistingPolyhedron->iPolygonCount; ++i ) + { + pStartPolygons[i].vSurfaceNormal = pExistingPolyhedron->pPolygons[i].polyNormal; + Polyhedron_IndexedLineReference_t *pOffsetPolyhedronLines = &pExistingPolyhedron->pIndices[pExistingPolyhedron->pPolygons[i].iFirstIndex]; + + + GeneratePolyhedronFromPlanes_LineLL *pFirstLink = &pStartLineLinks[iCurrentLineLinkIndex]; + pStartPolygons[i].pLines = pFirstLink; //technically going to link to itself on first pass, then get linked properly immediately afterward + for( int j = 0; j != pExistingPolyhedron->pPolygons[i].iIndexCount; ++j ) + { + GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pStartLineLinks[iCurrentLineLinkIndex++]; + pLineLink->pLine = &pStartLines[pOffsetPolyhedronLines[j].iLineIndex]; + pLineLink->iReferenceIndex = pOffsetPolyhedronLines[j].iEndPointIndex; + + pLineLink->pLine->pPolygons[pLineLink->iReferenceIndex] = &pStartPolygons[i]; + pLineLink->pLine->pPolygonLineLinks[pLineLink->iReferenceIndex] = pLineLink; + + pLineLink->pPrev = pStartPolygons[i].pLines; + pStartPolygons[i].pLines->pNext = pLineLink; + pStartPolygons[i].pLines = pLineLink; + } + + pFirstLink->pPrev = pStartPolygons[i].pLines; + pStartPolygons[i].pLines->pNext = pFirstLink; + } + + Assert( iCurrentLineLinkIndex == (pExistingPolyhedron->iLineCount * 4) ); + + //go back to point line links so we can circularly link them as well as order them now that every point has all its line links + for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i ) + { + //interlink the points + { + GeneratePolyhedronFromPlanes_LineLL *pLastVisitedLink = pStartPoints[i].pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pCurrentLink = pLastVisitedLink; + + do + { + pCurrentLink->pPrev = pLastVisitedLink; + pLastVisitedLink = pCurrentLink; + pCurrentLink = pCurrentLink->pNext; + } while( pCurrentLink ); + + //circular link + pLastVisitedLink->pNext = pStartPoints[i].pConnectedLines; + pStartPoints[i].pConnectedLines->pPrev = pLastVisitedLink; + } + + + //fix ordering + GeneratePolyhedronFromPlanes_LineLL *pFirstLink = pStartPoints[i].pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pFirstLink; + GeneratePolyhedronFromPlanes_LineLL *pSearchLink; + GeneratePolyhedronFromPlanes_Polygon *pLookingForPolygon; + Assert( pFirstLink->pNext != pFirstLink ); + do + { + pLookingForPolygon = pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex]; //grab pointer to left polygon + pSearchLink = pWorkLink->pPrev; + + while( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] != pLookingForPolygon ) + pSearchLink = pSearchLink->pPrev; + + Assert( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] == pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex] ); + + //pluck the search link from wherever it is + pSearchLink->pPrev->pNext = pSearchLink->pNext; + pSearchLink->pNext->pPrev = pSearchLink->pPrev; + + //insert the search link just before the work link + pSearchLink->pPrev = pWorkLink->pPrev; + pSearchLink->pNext = pWorkLink; + + pSearchLink->pPrev->pNext = pSearchLink; + pWorkLink->pPrev = pSearchLink; + + pWorkLink = pSearchLink; + } while( pWorkLink != pFirstLink ); + } + + GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints = (GeneratePolyhedronFromPlanes_UnorderedPointLL *)stackalloc( pExistingPolyhedron->iVertexCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPointLL ) ); + GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines = (GeneratePolyhedronFromPlanes_UnorderedLineLL *)stackalloc( pExistingPolyhedron->iLineCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedLineLL ) ); + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)stackalloc( pExistingPolyhedron->iPolygonCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPolygonLL ) ); + + //setup point collection + { + pPoints[0].pPrev = NULL; + pPoints[0].pPoint = &pStartPoints[0]; + pPoints[0].pNext = &pPoints[1]; + int iLastPoint = pExistingPolyhedron->iVertexCount - 1; + for( int i = 1; i != iLastPoint; ++i ) + { + pPoints[i].pPrev = &pPoints[i - 1]; + pPoints[i].pPoint = &pStartPoints[i]; + pPoints[i].pNext = &pPoints[i + 1]; + } + pPoints[iLastPoint].pPrev = &pPoints[iLastPoint - 1]; + pPoints[iLastPoint].pPoint = &pStartPoints[iLastPoint]; + pPoints[iLastPoint].pNext = NULL; + } + + //setup line collection + { + pLines[0].pPrev = NULL; + pLines[0].pLine = &pStartLines[0]; + pLines[0].pNext = &pLines[1]; + int iLastLine = pExistingPolyhedron->iLineCount - 1; + for( int i = 1; i != iLastLine; ++i ) + { + pLines[i].pPrev = &pLines[i - 1]; + pLines[i].pLine = &pStartLines[i]; + pLines[i].pNext = &pLines[i + 1]; + } + pLines[iLastLine].pPrev = &pLines[iLastLine - 1]; + pLines[iLastLine].pLine = &pStartLines[iLastLine]; + pLines[iLastLine].pNext = NULL; + } + + //setup polygon collection + { + pPolygons[0].pPrev = NULL; + pPolygons[0].pPolygon = &pStartPolygons[0]; + pPolygons[0].pNext = &pPolygons[1]; + int iLastPolygon = pExistingPolyhedron->iPolygonCount - 1; + for( int i = 1; i != iLastPolygon; ++i ) + { + pPolygons[i].pPrev = &pPolygons[i - 1]; + pPolygons[i].pPolygon = &pStartPolygons[i]; + pPolygons[i].pNext = &pPolygons[i + 1]; + } + pPolygons[iLastPolygon].pPrev = &pPolygons[iLastPolygon - 1]; + pPolygons[iLastPolygon].pPolygon = &pStartPolygons[iLastPolygon]; + pPolygons[iLastPolygon].pNext = NULL; + } + + return ClipLinkedGeometry( pPolygons, pLines, pPoints, pUsefulPlanes, iUsefulPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory ); +} + + + +Vector FindPointInPlanes( const float *pPlanes, int planeCount ) +{ + Vector point = vec3_origin; + + for ( int i = 0; i < planeCount; i++ ) + { + float fD = DotProduct( *(Vector *)&pPlanes[i*4], point ) - pPlanes[i*4 + 3]; + if ( fD < 0 ) + { + point -= fD * (*(Vector *)&pPlanes[i*4]); + } + } + return point; +} + + + +bool FindConvexShapeLooseAABB( const float *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs ) //bounding box of the convex shape (subject to floating point error) +{ + //returns false if the AABB hasn't been set + if( pAABBMins == NULL && pAABBMaxs == NULL ) //no use in actually finding out what it is + return false; + + struct FindConvexShapeAABB_Polygon_t + { + float *verts; + int iVertCount; + }; + + float *pMovedPlanes = (float *)stackalloc( iPlaneCount * 4 * sizeof( float ) ); + //Vector vPointInPlanes = FindPointInPlanes( pInwardFacingPlanes, iPlaneCount ); + + for( int i = 0; i != iPlaneCount; ++i ) + { + pMovedPlanes[(i * 4) + 0] = pInwardFacingPlanes[(i * 4) + 0]; + pMovedPlanes[(i * 4) + 1] = pInwardFacingPlanes[(i * 4) + 1]; + pMovedPlanes[(i * 4) + 2] = pInwardFacingPlanes[(i * 4) + 2]; + pMovedPlanes[(i * 4) + 3] = pInwardFacingPlanes[(i * 4) + 3] - 100.0f; //move planes out a lot to kill some imprecision problems + } + + + + //vAABBMins = vAABBMaxs = FindPointInPlanes( pPlanes, iPlaneCount ); + float *vertsIn = NULL; //we'll be allocating a new buffer for this with each new polygon, and moving it off to the polygon array + float *vertsOut = (float *)stackalloc( (iPlaneCount + 4) * (sizeof( float ) * 3) ); //each plane will initially have 4 points in its polygon representation, and each plane clip has the possibility to add 1 point to the polygon + float *vertsSwap; + + FindConvexShapeAABB_Polygon_t *pPolygons = (FindConvexShapeAABB_Polygon_t *)stackalloc( iPlaneCount * sizeof( FindConvexShapeAABB_Polygon_t ) ); + int iPolyCount = 0; + + for ( int i = 0; i < iPlaneCount; i++ ) + { + Vector *pPlaneNormal = (Vector *)&pInwardFacingPlanes[i*4]; + float fPlaneDist = pInwardFacingPlanes[(i*4) + 3]; + + if( vertsIn == NULL ) + vertsIn = (float *)stackalloc( (iPlaneCount + 4) * (sizeof( float ) * 3) ); + + // Build a big-ass poly in this plane + int vertCount = PolyFromPlane( (Vector *)vertsIn, *pPlaneNormal, fPlaneDist, 100000.0f ); + + //chop it by every other plane + for( int j = 0; j < iPlaneCount; j++ ) + { + // don't clip planes with themselves + if ( i == j ) + continue; + + // Chop the polygon against this plane + vertCount = ClipPolyToPlane( (Vector *)vertsIn, vertCount, (Vector *)vertsOut, *(Vector *)&pMovedPlanes[j*4], pMovedPlanes[(j*4) + 3], 0.0f ); + + //swap the input and output arrays + vertsSwap = vertsIn; vertsIn = vertsOut; vertsOut = vertsSwap; + + // Less than a poly left, something's wrong, don't bother with this polygon + if ( vertCount < 3 ) + break; + } + + if ( vertCount < 3 ) + continue; //not enough to work with + + pPolygons[iPolyCount].iVertCount = vertCount; + pPolygons[iPolyCount].verts = vertsIn; + vertsIn = NULL; + ++iPolyCount; + } + + if( iPolyCount == 0 ) + return false; + + //initialize the AABB to the first point available + Vector vAABBMins, vAABBMaxs; + vAABBMins = vAABBMaxs = ((Vector *)pPolygons[0].verts)[0]; + + if( pAABBMins && pAABBMaxs ) //they want the full box + { + for( int i = 0; i != iPolyCount; ++i ) + { + Vector *PolyVerts = (Vector *)pPolygons[i].verts; + for( int j = 0; j != pPolygons[i].iVertCount; ++j ) + { + if( PolyVerts[j].x < vAABBMins.x ) + vAABBMins.x = PolyVerts[j].x; + if( PolyVerts[j].y < vAABBMins.y ) + vAABBMins.y = PolyVerts[j].y; + if( PolyVerts[j].z < vAABBMins.z ) + vAABBMins.z = PolyVerts[j].z; + + if( PolyVerts[j].x > vAABBMaxs.x ) + vAABBMaxs.x = PolyVerts[j].x; + if( PolyVerts[j].y > vAABBMaxs.y ) + vAABBMaxs.y = PolyVerts[j].y; + if( PolyVerts[j].z > vAABBMaxs.z ) + vAABBMaxs.z = PolyVerts[j].z; + } + } + *pAABBMins = vAABBMins; + *pAABBMaxs = vAABBMaxs; + } + else if( pAABBMins ) //they only want the min + { + for( int i = 0; i != iPolyCount; ++i ) + { + Vector *PolyVerts = (Vector *)pPolygons[i].verts; + for( int j = 0; j != pPolygons[i].iVertCount; ++j ) + { + if( PolyVerts[j].x < vAABBMins.x ) + vAABBMins.x = PolyVerts[j].x; + if( PolyVerts[j].y < vAABBMins.y ) + vAABBMins.y = PolyVerts[j].y; + if( PolyVerts[j].z < vAABBMins.z ) + vAABBMins.z = PolyVerts[j].z; + } + } + *pAABBMins = vAABBMins; + } + else //they only want the max + { + for( int i = 0; i != iPolyCount; ++i ) + { + Vector *PolyVerts = (Vector *)pPolygons[i].verts; + for( int j = 0; j != pPolygons[i].iVertCount; ++j ) + { + if( PolyVerts[j].x > vAABBMaxs.x ) + vAABBMaxs.x = PolyVerts[j].x; + if( PolyVerts[j].y > vAABBMaxs.y ) + vAABBMaxs.y = PolyVerts[j].y; + if( PolyVerts[j].z > vAABBMaxs.z ) + vAABBMaxs.z = PolyVerts[j].z; + } + } + *pAABBMaxs = vAABBMaxs; + } + + return true; +} + + + + + + + +CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory ) +{ + Assert( (pPolygons != NULL) && (pLines != NULL) && (pPoints != NULL) ); + unsigned int iPolyCount = 0, iLineCount = 0, iPointCount = 0, iIndexCount = 0; + + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pPolygons; + do + { + ++iPolyCount; + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->pPolygon->pLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + Assert( pLineWalk != NULL ); + + do + { + ++iIndexCount; + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + + pActivePolygonWalk = pActivePolygonWalk->pNext; + } while( pActivePolygonWalk ); + + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pLines; + do + { + ++iLineCount; + pActiveLineWalk = pActiveLineWalk->pNext; + } while( pActiveLineWalk ); + + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pPoints; + do + { + ++iPointCount; + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + + CPolyhedron *pReturn; + if( bUseTemporaryMemory ) + { + pReturn = GetTempPolyhedron( iPointCount, iLineCount, iIndexCount, iPolyCount ); + } + else + { + pReturn = CPolyhedron_AllocByNew::Allocate( iPointCount, iLineCount, iIndexCount, iPolyCount ); + } + + Vector *pVertexArray = pReturn->pVertices; + Polyhedron_IndexedLine_t *pLineArray = pReturn->pLines; + Polyhedron_IndexedLineReference_t *pIndexArray = pReturn->pIndices; + Polyhedron_IndexedPolygon_t *pPolyArray = pReturn->pPolygons; + + //copy points + pActivePointWalk = pPoints; + for( unsigned int i = 0; i != iPointCount; ++i ) + { + pVertexArray[i] = pActivePointWalk->pPoint->ptPosition; + pActivePointWalk->pPoint->iSaveIndices = i; //storing array indices + pActivePointWalk = pActivePointWalk->pNext; + } + + //copy lines + pActiveLineWalk = pLines; + for( unsigned int i = 0; i != iLineCount; ++i ) + { + pLineArray[i].iPointIndices[0] = (unsigned short)pActiveLineWalk->pLine->pPoints[0]->iSaveIndices; + pLineArray[i].iPointIndices[1] = (unsigned short)pActiveLineWalk->pLine->pPoints[1]->iSaveIndices; + + pActiveLineWalk->pLine->iSaveIndices = i; //storing array indices + + pActiveLineWalk = pActiveLineWalk->pNext; + } + + //copy polygons and indices at the same time + pActivePolygonWalk = pPolygons; + iIndexCount = 0; + for( unsigned int i = 0; i != iPolyCount; ++i ) + { + pPolyArray[i].polyNormal = pActivePolygonWalk->pPolygon->vSurfaceNormal; + pPolyArray[i].iFirstIndex = iIndexCount; + + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->pPolygon->pLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + do + { + //pIndexArray[iIndexCount] = pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->iWorkData; //startpoint of each line, iWorkData is the index of the vertex + pIndexArray[iIndexCount].iLineIndex = pLineWalk->pLine->iSaveIndices; + pIndexArray[iIndexCount].iEndPointIndex = pLineWalk->iReferenceIndex; + + ++iIndexCount; + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + + pPolyArray[i].iIndexCount = iIndexCount - pPolyArray[i].iFirstIndex; + + pActivePolygonWalk = pActivePolygonWalk->pNext; + } + +#if defined( _DEBUG ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS ) + char szCollisionFile[128]; + CreateDumpDirectory( "PolyhedronDumps" ); + Q_snprintf( szCollisionFile, 128, "PolyhedronDumps/NewStyle_PolyhedronDump%i.txt", g_iPolyhedronDumpCounter ); + ++g_iPolyhedronDumpCounter; + + remove( szCollisionFile ); + DumpPolyhedronToGLView( pReturn, szCollisionFile, &s_matIdentity ); + DumpPolyhedronToGLView( pReturn, "PolyhedronDumps/NewStyle_PolyhedronDump_All-Appended.txt", &s_matIdentity ); +#endif + + return pReturn; +} + + + +#ifdef _DEBUG + +void DumpPointListToGLView( GeneratePolyhedronFromPlanes_UnorderedPointLL *pHead, PolyhedronPointPlanarity planarity, const Vector &vColor, const char *szDumpFile, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + FILE *pFile = fopen( szDumpFile, "ab" ); + + while( pHead ) + { + if( pHead->pPoint->planarity == planarity ) + { + const Vector vPointExtents( 0.5f, 0.5f, 0.01f ); + DumpAABBToGLView( (*pTransform) * pHead->pPoint->ptPosition, vPointExtents, vColor, pFile ); + } + pHead = pHead->pNext; + } + + fclose( pFile ); +#endif +} + +const char * DumpPolyhedronCutHistory( const CUtlVector &DumpedHistory, const CUtlVector &CutHistory, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + static char szDumpFile[100] = "FailedPolyhedronCut_Error.txt"; //most recent filename returned for further dumping + + for( int i = 0; i != DumpedHistory.Count(); ++i ) + { + if( DumpedHistory[i] != NULL ) + { + Q_snprintf( szDumpFile, 100, "FailedPolyhedronCut_%d.txt", i ); + DumpPolyhedronToGLView( DumpedHistory[i], szDumpFile, pTransform ); + DumpPlaneToGlView( CutHistory[i], 1.0f, szDumpFile, pTransform ); + } + } + + return szDumpFile; +#else + return NULL; +#endif +} + +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS +#define AssertMsg_DumpPolyhedron(condition, message)\ + if( (condition) == false )\ + {\ + VMatrix matTransform;\ + matTransform.Identity();\ + matTransform[0][0] = matTransform[1][1] = matTransform[2][2] = 25.0f;\ + matTransform.SetTranslation( -DebugCutHistory.Tail()->Center() * 25.0f );\ + const char *szLastDumpFile = DumpPolyhedronCutHistory( DebugCutHistory, PlaneCutHistory, &matTransform );\ + DumpPointListToGLView( pAllPoints, POINT_ALIVE, Vector( 0.9f, 0.9f, 0.9f ), szLastDumpFile, &matTransform );\ + DumpPointListToGLView( pAllPoints, POINT_ONPLANE, Vector( 0.5f, 0.5f, 0.5f ), szLastDumpFile, &matTransform );\ + DumpPointListToGLView( pDeadPointCollection, POINT_DEAD, Vector( 0.1f, 0.1f, 0.1f ), szLastDumpFile, &matTransform );\ + if( pStartPoint )\ + {\ + FILE *pFileDumpRepairProgress = fopen( szLastDumpFile, "ab" );\ + DumpAABBToGLView( matTransform * pStartPoint->ptPosition, Vector( 2.0f, 0.05f, 0.05f ), Vector( 0.0f, 1.0f, 0.0f ), pFileDumpRepairProgress );\ + DumpAABBToGLView( matTransform * pWorkPoint->ptPosition, Vector( 2.0f, 0.05f, 0.05f ), Vector( 1.0f, 0.0f, 0.0f ), pFileDumpRepairProgress );\ + fclose( pFileDumpRepairProgress );\ + }\ + AssertMsg( condition, message );\ + } +#else +#define AssertMsg_DumpPolyhedron(condition, message) AssertMsg( condition, message ) +#endif +#define Assert_DumpPolyhedron(condition) AssertMsg_DumpPolyhedron( condition, #condition ) + +#else + +#define AssertMsg_DumpPolyhedron(condition, message) NULL; +#define Assert_DumpPolyhedron(condition) NULL; + +#endif + +CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pAllPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pAllLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pAllPoints, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ) +{ + const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon; + +#ifdef _DEBUG + CUtlVector DebugCutHistory; + CUtlVector PlaneCutHistory; + GeneratePolyhedronFromPlanes_Point *pStartPoint = NULL; + GeneratePolyhedronFromPlanes_Point *pWorkPoint = NULL; + + static int iPolyhedronClipCount = 0; + ++iPolyhedronClipCount; + + DebugCutHistory.AddToTail( ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false ) ); +#endif + + //clear out polygon work variables + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons; + do + { + pActivePolygonWalk->pPolygon->bMissingASide = false; + pActivePolygonWalk = pActivePolygonWalk->pNext; + } while( pActivePolygonWalk ); + } + + + //Collections of dead pointers for reallocation, shouldn't be touched until the current loop iteration is done. + GeneratePolyhedronFromPlanes_UnorderedPointLL *pDeadPointCollection = NULL; + GeneratePolyhedronFromPlanes_UnorderedLineLL *pDeadLineCollection = NULL; + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDeadPolygonCollection = NULL; + GeneratePolyhedronFromPlanes_LineLL *pDeadLineLinkCollection = NULL; + + + for( int iCurrentPlane = 0; iCurrentPlane != iPlaneCount; ++iCurrentPlane ) + { + //clear out line work variables + { + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines; + do + { + pActiveLineWalk->pLine->bAlive = false; + pActiveLineWalk->pLine->bCut = false; + + pActiveLineWalk = pActiveLineWalk->pNext; + } while( pActiveLineWalk ); + } + + //TODO: Move these pointers into a reallocation pool + pDeadPointCollection = NULL; + pDeadLineCollection = NULL; + pDeadLineLinkCollection = NULL; + pDeadPolygonCollection = NULL; + + Vector vNormal = *((Vector *)&pOutwardFacingPlanes[(iCurrentPlane * 4) + 0]); + /*double vNormalAsDouble[3]; + vNormalAsDouble[0] = vNormal.x; + vNormalAsDouble[1] = vNormal.y; + vNormalAsDouble[2] = vNormal.z;*/ + float fPlaneDist = pOutwardFacingPlanes[(iCurrentPlane * 4) + 3]; + + //=================================================================================================== + // Step 1: Categorize each point as being either cut, split, or alive + //=================================================================================================== + { + bool bAllPointsDead = true; + bool bAllPointsAlive = true; + + //find point distances from the plane + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + GeneratePolyhedronFromPlanes_Point *pPoint = pActivePointWalk->pPoint; + float fPointDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; + if( fPointDist > fOnPlaneEpsilon ) + { + pPoint->planarity = POINT_DEAD; //point is dead, bang bang + + //mark connected lines as cut + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + do + { + pLineWalk->pLine->bCut = true; + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + + bAllPointsAlive = false; + } + else if( fPointDist <= fNegativeOnPlaneEpsilon ) + { + pPoint->planarity = POINT_ALIVE; //point is in behind plane, not voted off the island....yet + bAllPointsDead = false; + + //mark connected lines as alive + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + do + { + pLineWalk->pLine->bAlive = true; //mark the line as alive + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + } + else + { + pPoint->planarity = POINT_ONPLANE; //point is on the plane, he's everyone's buddy + + //Project on-plane points leaning towards death closer to the plane. This battles floating point precision decay. + // Consider the case of a large on-plane epsilon leaving protrusions over time + /*if( fPointDist < 0.0f ) + { + double distAsDouble = fPointDist; + double vPositionAsDouble[3]; + vPositionAsDouble[0] = pPoint->ptPosition.x; + vPositionAsDouble[1] = pPoint->ptPosition.y; + vPositionAsDouble[2] = pPoint->ptPosition.z; + + pPoint->ptPosition.x = vPositionAsDouble[0] - (distAsDouble * vNormalAsDouble[0]); + pPoint->ptPosition.y = vPositionAsDouble[1] - (distAsDouble * vNormalAsDouble[1]); + pPoint->ptPosition.z = vPositionAsDouble[2] - (distAsDouble * vNormalAsDouble[2]); + +#if ( 0 && defined( _DEBUG ) ) + float fDebugDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; //just for looking at in watch windows + AssertMsg( fabs( fDebugDist ) < fabs(fPointDist), "Projected point is further from plane than unprojected." ); +#endif + fPointDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; //recompute dist (not guaranteed to be 0.0 like we want) + }*/ + } + + pPoint->fPlaneDist = fPointDist; + + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + + if( bAllPointsDead ) //all the points either died or are on the plane, no polyhedron left at all + { +#ifdef _DEBUG + for( int i = DebugCutHistory.Count(); --i >= 0; ) + { + if( DebugCutHistory[i] ) + DebugCutHistory[i]->Release(); + } + DebugCutHistory.RemoveAll(); +#endif + + return NULL; + } + + if( bAllPointsAlive ) + continue; //no cuts made + + + //Scan for onplane points connected to only other onplane/dead points, these points get downgraded to dead status. + { + pActivePointWalk = pAllPoints; + do + { + if( pActivePointWalk->pPoint->planarity == POINT_ONPLANE ) + { + GeneratePolyhedronFromPlanes_LineLL *pOnPlaneLineWalk = pActivePointWalk->pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pStartLineWalk = pOnPlaneLineWalk; + bool bDead = true; //assume it's dead and disprove + do + { + if ( pOnPlaneLineWalk->pLine->bAlive ) + { + bDead = false; + } + else if ( pOnPlaneLineWalk->pLine->bCut ) + { + //connected to a dead point. + if( pOnPlaneLineWalk->pNext->pLine->bCut || pOnPlaneLineWalk->pPrev->pLine->bCut ) + { + //This on-plane point is surrounded by dead points on one polygon of the polyhedron. + // We have to downgrade this point to dead to avoid situations where float imprecision + // turns the polyhedron into a *slightly* concave shape. Concave shapes might break this algorithm, even falsely concave shapes. + bDead = true; + break; + } + } + + pOnPlaneLineWalk = pOnPlaneLineWalk->pNext; + } while( pOnPlaneLineWalk != pStartLineWalk ); + + if( bDead ) + { + pActivePointWalk->pPoint->planarity = POINT_DEAD; + + pOnPlaneLineWalk = pStartLineWalk; + + //mark connected lines as cut + do + { + pOnPlaneLineWalk->pLine->bCut = true; + pOnPlaneLineWalk = pOnPlaneLineWalk->pNext; + } while( pOnPlaneLineWalk != pStartLineWalk ); + } + } + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + } +#ifdef _DEBUG + PlaneCutHistory.AddToTail( &pOutwardFacingPlanes[iCurrentPlane * 4] ); +#endif + } + + + + +#ifdef _DEBUG + //Run around the edges of all the polygons and ensure they don't have more than one point of lowered "alive" status (alive > onplane > dead) surrounded by higher status + // It indicates a concave shape. It's impossible to have it occur in theoretical space. But floating point numbers introduce error. + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDebugPolygonWalk = pAllPolygons; + do + { + int iSurroundedCount = 0; + GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pDebugPolygonWalk->pPolygon->pLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstDebugLine = pDebugLineWalk; + + do + { + PolyhedronPointPlanarity currentPlanarity = pDebugLineWalk->pLine->pPoints[pDebugLineWalk->iReferenceIndex]->planarity; + + GeneratePolyhedronFromPlanes_LineLL *pNext = pDebugLineWalk->pNext; + PolyhedronPointPlanarity nextPlanarity = pNext->pLine->pPoints[pNext->iReferenceIndex]->planarity; + + if( currentPlanarity < nextPlanarity ) + { + GeneratePolyhedronFromPlanes_LineLL *pPrev = pDebugLineWalk->pPrev; + PolyhedronPointPlanarity prevPlanarity = pPrev->pLine->pPoints[pPrev->iReferenceIndex]->planarity; + + if( currentPlanarity < prevPlanarity ) + { + ++iSurroundedCount; + } + } + + pDebugLineWalk = pDebugLineWalk->pNext; + } while( pDebugLineWalk != pFirstDebugLine ); + + AssertMsg_DumpPolyhedron( iSurroundedCount <= 1, "Concave polygon, cutting process might break. Consider adjusting the on-plane epsilon to better compensate for floating point precision." ); + pDebugPolygonWalk = pDebugPolygonWalk->pNext; + } while( pDebugPolygonWalk ); + } +#endif + + //=================================================================================================== + // Step 2: Remove dead lines. A dead line is one with a dead point that isn't connected to a living point + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines; + do + { + GeneratePolyhedronFromPlanes_Line *pLine = pActiveLineWalk->pLine; + if( (pLine->bAlive == false) && (pLine->bCut == true) ) //not connected to a live point, but connected to a dead one. Dead line + { + //remove line from connected polygons + for( int i = 0; i != 2; ++i ) + { + GeneratePolyhedronFromPlanes_Polygon *pPolygon = pLine->pPolygons[i]; + GeneratePolyhedronFromPlanes_LineLL *pLineLink = pLine->pPolygonLineLinks[i]; + + pPolygon->bMissingASide = true; + + if( pLineLink->pNext == pLineLink ) + { + //this was the last line of the polygon, it's dead + pPolygon->pLines = NULL; + } + else + { + //link around this line + pPolygon->pLines = pLineLink->pPrev; //Always have the polygon's head line be just before the gap in the polygon + pLineLink->pNext->pPrev = pLineLink->pPrev; + pLineLink->pPrev->pNext = pLineLink->pNext; + } + + //move the line link to the dead list + pLineLink->pNext = pDeadLineLinkCollection; + pDeadLineLinkCollection = pLineLink; + } + + //remove the line from connected points + for( int i = 0; i != 2; ++i ) + { + GeneratePolyhedronFromPlanes_Point *pPoint = pLine->pPoints[i]; + GeneratePolyhedronFromPlanes_LineLL *pLineLink = pLine->pPointLineLinks[i]; + + if( pLineLink->pNext == pLineLink ) + { + //this is the last line + pPoint->pConnectedLines = NULL; + Assert( pPoint->planarity != POINT_ALIVE ); + pPoint->planarity = POINT_DEAD; //in case it was merely POINT_ONPLANE before + } + else + { + //link around this line + pPoint->pConnectedLines = pLineLink->pNext; //in case pLineLink was the head line + pLineLink->pNext->pPrev = pLineLink->pPrev; + pLineLink->pPrev->pNext = pLineLink->pNext; + } + + //move the line link to the dead list + pLineLink->pNext = pDeadLineLinkCollection; + pDeadLineLinkCollection = pLineLink; + } + + //move the line to the dead list + { + //link past this node + if( pActiveLineWalk->pPrev ) + pActiveLineWalk->pPrev->pNext = pActiveLineWalk->pNext; + else + pAllLines = pActiveLineWalk->pNext; + + if( pActiveLineWalk->pNext ) + pActiveLineWalk->pNext->pPrev = pActiveLineWalk->pPrev; + + GeneratePolyhedronFromPlanes_UnorderedLineLL *pNextLineWalk = pActiveLineWalk->pNext; + + //add to the dead list + pActiveLineWalk->pNext = pDeadLineCollection; + pDeadLineCollection = pActiveLineWalk; + + //next + pActiveLineWalk = pNextLineWalk; + } + } + else + { + pActiveLineWalk = pActiveLineWalk->pNext; + } + } while( pActiveLineWalk ); + } + + + //=================================================================================================== + // Step 3: Remove dead polygons. A dead polygon has less than 2 lines. + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons; + do + { + GeneratePolyhedronFromPlanes_Polygon *pPolygon = pActivePolygonWalk->pPolygon; + GeneratePolyhedronFromPlanes_LineLL *pHeadLine = pPolygon->pLines; + + bool bDead = (pHeadLine == NULL) || (pHeadLine->pNext == pHeadLine); + if( !bDead ) + { + //there's a rare case where a polygon can be almost entirely coplanar with the cut, it comes purely out of the land of imprecision + bDead = true; //assume it's dead, and disprove + + GeneratePolyhedronFromPlanes_LineLL *pTestLineWalk = pHeadLine; + do + { + if( pTestLineWalk->pLine->bAlive ) + { + bDead = false; + break; + } + + pTestLineWalk = pTestLineWalk->pNext; + } while( pTestLineWalk != pHeadLine ); + } + + if( bDead ) + { + //dead polygon, move it to the dead list + + //link around this node + if( pActivePolygonWalk->pPrev ) + pActivePolygonWalk->pPrev->pNext = pActivePolygonWalk->pNext; + else + pAllPolygons = pAllPolygons->pNext; //pActivePolygonWalk was the head node + + if( pActivePolygonWalk->pNext ) + pActivePolygonWalk->pNext->pPrev = pActivePolygonWalk->pPrev; + + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pNextPolygonWalk = pActivePolygonWalk->pNext; + + //add to the dead list + pActivePolygonWalk->pNext = pDeadPolygonCollection; + pDeadPolygonCollection = pActivePolygonWalk; + + //next + pActivePolygonWalk = pNextPolygonWalk; + } + else + { + AssertMsg_DumpPolyhedron( (pActivePolygonWalk->pPolygon->pLines != NULL) && + (pActivePolygonWalk->pPolygon->pLines != pActivePolygonWalk->pPolygon->pLines->pNext), "Living polygon with less than 2 lines" ); + + pActivePolygonWalk = pActivePolygonWalk->pNext; + } + } while( pActivePolygonWalk ); + } + + //=================================================================================================== + // Step 4: Remove dead points. + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + if( pActivePointWalk->pPoint->planarity == POINT_DEAD ) + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pNext = pActivePointWalk->pNext; + + if( pActivePointWalk->pPrev ) + pActivePointWalk->pPrev->pNext = pActivePointWalk->pNext; + else + pAllPoints = pAllPoints->pNext; + + if( pActivePointWalk->pNext ) + pActivePointWalk->pNext->pPrev = pActivePointWalk->pPrev; + + pActivePointWalk->pNext = pDeadPointCollection; + pDeadPointCollection = pActivePointWalk; + + pActivePointWalk = pNext; + } + else + { + pActivePointWalk = pActivePointWalk->pNext; + } + } while( pActivePointWalk ); + } + + + //=================================================================================================== + // Step 5: Handle cut lines + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines; + do + { + GeneratePolyhedronFromPlanes_Line *pWorkLine = pActiveLineWalk->pLine; + Assert_DumpPolyhedron( (pWorkLine->bAlive == true) || (pWorkLine->bCut == false) ); //all dead lines should have already been removed + + if( pWorkLine->bCut ) + { + GeneratePolyhedronFromPlanes_Point **pLinePoints = pWorkLine->pPoints; + + Assert_DumpPolyhedron( (pLinePoints[0]->planarity == POINT_DEAD) || (pLinePoints[1]->planarity == POINT_DEAD) ); //one of the two has to be a dead point + + int iDeadIndex = (pLinePoints[0]->planarity == POINT_DEAD)?(0):(1); + int iLivingIndex = 1 - iDeadIndex; + GeneratePolyhedronFromPlanes_Point *pDeadPoint = pLinePoints[iDeadIndex]; + GeneratePolyhedronFromPlanes_Point *pLivingPoint = pLinePoints[iLivingIndex]; + + Assert_DumpPolyhedron( pLivingPoint->planarity == POINT_ALIVE ); //if this point were on-plane or dead, the line should be dead + + //We'll be de-linking from the old point and generating a new one. We do this so other lines can still access the dead point's untouched data. + + //Generate a new point + GeneratePolyhedronFromPlanes_Point *pNewPoint = (GeneratePolyhedronFromPlanes_Point *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Point ) ); + { + //add this point to the active list + pAllPoints->pPrev = (GeneratePolyhedronFromPlanes_UnorderedPointLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedPointLL ) ); + pAllPoints->pPrev->pNext = pAllPoints; + pAllPoints = pAllPoints->pPrev; + pAllPoints->pPrev = NULL; + pAllPoints->pPoint = pNewPoint; + + + float fInvTotalDist = 1.0f/(pDeadPoint->fPlaneDist - pLivingPoint->fPlaneDist); //subtraction because the living index is known to be negative + pNewPoint->ptPosition = (pLivingPoint->ptPosition * (pDeadPoint->fPlaneDist * fInvTotalDist)) - (pDeadPoint->ptPosition * (pLivingPoint->fPlaneDist * fInvTotalDist)); + +#if ( 0 && defined( _DEBUG ) ) + float fDebugDist = vNormal.Dot( pNewPoint->ptPosition ) - fPlaneDist; //just for looking at in watch windows + AssertMsg_DumpPolyhedron( fabs( fDebugDist ) < fOnPlaneEpsilon, "Generated split point is far from plane" ); + + //verify that the new point isn't sitting on top of another + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + if( pActivePointWalk->pPoint != pNewPoint ) + { + Vector vDiff = pActivePointWalk->pPoint->ptPosition - pNewPoint->ptPosition; + + AssertMsg_DumpPolyhedron( vDiff.Length() > fOnPlaneEpsilon, "Generated a point on top of another" ); + } + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + } +#endif + + pNewPoint->planarity = POINT_ONPLANE; + pNewPoint->fPlaneDist = 0.0f; + } + + GeneratePolyhedronFromPlanes_LineLL *pNewLineLink = pNewPoint->pConnectedLines = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + pNewLineLink->pLine = pWorkLine; + pNewLineLink->pNext = pNewLineLink; + pNewLineLink->pPrev = pNewLineLink; + pNewLineLink->iReferenceIndex = iLivingIndex; + + pWorkLine->pPoints[iDeadIndex] = pNewPoint; + pWorkLine->pPointLineLinks[iDeadIndex] = pNewLineLink; + pNewPoint->pConnectedLines = pNewLineLink; + + //A new line is needed on each polygon touching the dead point to connect the two new endpoints for split lines. + // So mark connected polygons as missing a side. + for( int i = 0; i != 2; ++i ) + pWorkLine->pPolygons[i]->bMissingASide = true; + + + //Always have a cut polygon's head line be just before the gap in the polygon. + // In this case, we know that one of the two polygons goes clockwise into the dead point, so have that polygon point at this line. + // We don't know enough about the other polygon to do anything here, but another cut line will handle that polygon. So it all works out in the end. + pWorkLine->pPolygons[iDeadIndex]->pLines = pWorkLine->pPolygonLineLinks[iDeadIndex]; + } + + pActiveLineWalk = pActiveLineWalk->pNext; + } while( pActiveLineWalk ); + } + + + //=================================================================================================== + // Step 6: Repair polygons that are missing a side. And generate the new coplanar polygon. + //=================================================================================================== + { + //Find the first polygon missing a side. + // We'll then walk from polygon to polygon using line connections so that we can generate the new polygon in a clockwise manner. + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons; + + while( (pActivePolygonWalk != NULL) && (pActivePolygonWalk->pPolygon->bMissingASide == false) ) + { + pActivePolygonWalk = pActivePolygonWalk->pNext; + } + + //acquire iteration data +#ifndef _DEBUG + GeneratePolyhedronFromPlanes_Point *pStartPoint; + GeneratePolyhedronFromPlanes_Point *pWorkPoint; +#endif + + GeneratePolyhedronFromPlanes_LineLL *pLastLineLink; + GeneratePolyhedronFromPlanes_Polygon *pWorkPolygon; + GeneratePolyhedronFromPlanes_LineLL *pTestLine; + +#ifdef _DEBUG + GeneratePolyhedronFromPlanes_Polygon *pLastWorkPolygon = NULL; + GeneratePolyhedronFromPlanes_Point *pLastWorkPoint = NULL; +#endif + + if( pActivePolygonWalk ) + { + //grab the polygon we'll be starting with + GeneratePolyhedronFromPlanes_Polygon *pBrokenPolygon = pActivePolygonWalk->pPolygon; + + { + GeneratePolyhedronFromPlanes_LineLL *pTemp = pBrokenPolygon->pLines->pNext; + pStartPoint = pTemp->pLine->pPoints[1 - pTemp->iReferenceIndex]; + Assert_DumpPolyhedron( pStartPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar + pLastLineLink = pTemp->pLine->pPointLineLinks[1 - pTemp->iReferenceIndex]->pNext; + pWorkPolygon = pBrokenPolygon; + } + + pWorkPoint = pStartPoint; + pTestLine = pLastLineLink->pPrev; //rotate counterclockwise around the point + } + else + { + //apparently the plane was entirely through existing polygonal borders, extremely rare but it can happen with inefficient cutting planes + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + while( (pActivePointWalk != NULL) && (pActivePointWalk->pPoint->planarity != POINT_ONPLANE) ) + { + pActivePointWalk = pActivePointWalk->pNext; + } + + Assert( pActivePointWalk != NULL ); + + pStartPoint = pWorkPoint = pActivePointWalk->pPoint; + GeneratePolyhedronFromPlanes_LineLL *pLines = pWorkPoint->pConnectedLines; + + while( !pLines->pLine->bAlive ) //seek clockwise until we find a line not on the plane + pLines = pLines->pNext; + + while( pLines->pLine->bAlive ) //now seek counterclockwise until we find a line on the plane (in case we started on an alive line last seek) + pLines = pLines->pPrev; + + //now pLines points at one side of the polygon, with pActivePointWalk + pLastLineLink = pLines; + pTestLine = pLines->pPrev; + pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex]; + + } + + //create the new polygon + GeneratePolyhedronFromPlanes_Polygon *pNewPolygon = (GeneratePolyhedronFromPlanes_Polygon *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Polygon ) ); + { + //before we forget, add this polygon to the active list + pAllPolygons->pPrev = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedPolygonLL ) ); + pAllPolygons->pPrev->pNext = pAllPolygons; + pAllPolygons = pAllPolygons->pPrev; + pAllPolygons->pPrev = NULL; + pAllPolygons->pPolygon = pNewPolygon; + + pNewPolygon->bMissingASide = false; //technically missing all it's sides, but we're fixing it now + pNewPolygon->vSurfaceNormal = vNormal; + pNewPolygon->pLines = NULL; + } + + + + //=================================================================================================================== + // The general idea of the upcoming algorithm to put together a new polygon and patch broken polygons... + // You have a point and a line the algorithm just jumped across. + // 1. Rotate through the point's line links one time counterclockwise (pPrev) + // 2. If the line is cut, then we make a new bridging line in the polygon between that line and the one counterclockwise to it. (pPrev) + // If the line is on-plane. Skip the bridge line making, but set links to the new polygon as if we'd just created the bridge + // 3. Once we follow a line back to the point where we started, we should be all done. + + do + { + if( pWorkPolygon->bMissingASide ) + { + //during the cutting process we made sure that the head line link was going clockwise into the missing area + GeneratePolyhedronFromPlanes_LineLL *pGapLines[2]; + pGapLines[1] = pTestLine->pLine->pPolygonLineLinks[pTestLine->iReferenceIndex]; //get the same line, but in the polygons linked list. + Assert_DumpPolyhedron( pGapLines[1]->pLine == pTestLine->pLine ); + pGapLines[0] = pGapLines[1]->pPrev; + + Assert_DumpPolyhedron( pWorkPolygon->bMissingASide ); + +#ifdef _DEBUG + { + //ensure that the space between the gap lines is the only space where fixing is required + GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pGapLines[1]->pNext; + + while( pDebugLineWalk != pGapLines[0] ) + { + Assert_DumpPolyhedron( pDebugLineWalk->pLine->bCut == false ); + pDebugLineWalk = pDebugLineWalk->pNext; + } + } +#endif + + GeneratePolyhedronFromPlanes_Line *pJoinLine = (GeneratePolyhedronFromPlanes_Line *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Line ) ); + { + //before we forget, add this line to the active list + pAllLines->pPrev = (GeneratePolyhedronFromPlanes_UnorderedLineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedLineLL ) ); + pAllLines->pPrev->pNext = pAllLines; + pAllLines = pAllLines->pPrev; + pAllLines->pPrev = NULL; + pAllLines->pLine = pJoinLine; + + pJoinLine->bAlive = false; + pJoinLine->bCut = false; + } + + + pJoinLine->pPoints[0] = pGapLines[0]->pLine->pPoints[pGapLines[0]->iReferenceIndex]; + pJoinLine->pPoints[1] = pGapLines[1]->pLine->pPoints[1 - pGapLines[1]->iReferenceIndex]; + + pJoinLine->pPolygons[0] = pNewPolygon; + pJoinLine->pPolygons[1] = pWorkPolygon; + + //now create all 4 links into the line + GeneratePolyhedronFromPlanes_LineLL *pPointLinks[2]; + pPointLinks[0] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + pPointLinks[1] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + GeneratePolyhedronFromPlanes_LineLL *pPolygonLinks[2]; + pPolygonLinks[0] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + pPolygonLinks[1] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + pPointLinks[0]->pLine = pPointLinks[1]->pLine = pPolygonLinks[0]->pLine = pPolygonLinks[1]->pLine = pJoinLine; + + pJoinLine->pPointLineLinks[0] = pPointLinks[0]; + pJoinLine->pPointLineLinks[1] = pPointLinks[1]; + pJoinLine->pPolygonLineLinks[0] = pPolygonLinks[0]; + pJoinLine->pPolygonLineLinks[1] = pPolygonLinks[1]; + + + + pPointLinks[0]->iReferenceIndex = 1; + pPointLinks[1]->iReferenceIndex = 0; + + //Insert before the link from point 0 to gap line 0 (counterclockwise rotation) + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pGapLines[0]->pLine->pPointLineLinks[pGapLines[0]->iReferenceIndex]; + Assert_DumpPolyhedron( pWorkLink->pLine == pGapLines[0]->pLine ); + + pPointLinks[0]->pPrev = pWorkLink->pPrev; + pPointLinks[0]->pNext = pWorkLink; + + pWorkLink->pPrev->pNext = pPointLinks[0]; + pWorkLink->pPrev = pPointLinks[0]; + } + + //Insert after the link from point 1 to gap line 1 (clockwise rotation) + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pGapLines[1]->pLine->pPointLineLinks[1 - pGapLines[1]->iReferenceIndex]; + Assert_DumpPolyhedron( pWorkLink->pLine == pGapLines[1]->pLine ); + + pPointLinks[1]->pNext = pWorkLink->pNext; + pPointLinks[1]->pPrev = pWorkLink; + + pWorkLink->pNext->pPrev = pPointLinks[1]; + pWorkLink->pNext = pPointLinks[1]; + } + + + + + pPolygonLinks[0]->iReferenceIndex = 0; + pPolygonLinks[1]->iReferenceIndex = 1; + + //Insert before the head line in the new polygon (at the end of the clockwise order) + { + if( pNewPolygon->pLines == NULL ) + { + //this is the first line being added to the polygon + pNewPolygon->pLines = pPolygonLinks[0]; + pPolygonLinks[0]->pNext = pPolygonLinks[0]; + pPolygonLinks[0]->pPrev = pPolygonLinks[0]; + } + else + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pNewPolygon->pLines; + + pPolygonLinks[0]->pNext = pWorkLink; + pPolygonLinks[0]->pPrev = pWorkLink->pPrev; + + pWorkLink->pPrev->pNext = pPolygonLinks[0]; + pWorkLink->pPrev = pPolygonLinks[0]; + } + } + + //Insert after the head line in the work polygon + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pWorkPolygon->pLines; + + pPolygonLinks[1]->pNext = pWorkLink->pNext; + pPolygonLinks[1]->pPrev = pWorkLink; + + pWorkLink->pNext->pPrev = pPolygonLinks[1]; + pWorkLink->pNext = pPolygonLinks[1]; + } + + pWorkPolygon->bMissingASide = false; //repairs are finished + +#ifdef _DEBUG + pLastWorkPolygon = pWorkPolygon; + pLastWorkPoint = pWorkPoint; +#endif + //move to the next point + pWorkPoint = pJoinLine->pPoints[0]; + pLastLineLink = pJoinLine->pPointLineLinks[0]; + Assert_DumpPolyhedron( pWorkPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar + + pTestLine = pLastLineLink->pPrev; + if( pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]->planarity == POINT_ALIVE ) + pWorkPolygon = pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex]; + else + pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex]; + + Assert_DumpPolyhedron( pWorkPolygon != pLastWorkPolygon ); + Assert_DumpPolyhedron( (pWorkPoint == pStartPoint) || + (pGapLines[0]->pLine->bCut == false) || + (pWorkPolygon->bMissingASide == true) ); //if we're not done fixing, and if the shared line was cut, the next polygon must be missing a side + } + else + { + //line is on the plane, meaning the polygon isn't broken and doesn't need patching + Assert_DumpPolyhedron( pTestLine->pLine->bCut == false ); + Assert_DumpPolyhedron( (pTestLine->pLine->pPoints[0]->planarity == POINT_ONPLANE) && (pTestLine->pLine->pPoints[1]->planarity == POINT_ONPLANE) ); + + + //link to this line from the new polygon + GeneratePolyhedronFromPlanes_LineLL *pNewLineLink; + pNewLineLink = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + pNewLineLink->pLine = pTestLine->pLine; + pNewLineLink->iReferenceIndex = pTestLine->iReferenceIndex; + + //Insert before the head line in the new polygon (at the end of the clockwise order) + { + if( pNewPolygon->pLines == NULL ) + { + //this is the first line being added to the polygon + pNewPolygon->pLines = pNewLineLink; + pNewLineLink->pNext = pNewLineLink; + pNewLineLink->pPrev = pNewLineLink; + } + else + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pNewPolygon->pLines; + + pNewLineLink->pNext = pWorkLink; + pNewLineLink->pPrev = pWorkLink->pPrev; + + pWorkLink->pPrev->pNext = pNewLineLink; + pWorkLink->pPrev = pNewLineLink; + } + } + + //Since the entire line is on the plane, that means it used to point to something that used to reside where the new polygon is going + // Update the link to the new the polygon pointer and be on our way + pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex] = pNewPolygon; + pTestLine->pLine->pPolygonLineLinks[pTestLine->iReferenceIndex] = pNewLineLink; + +#ifdef _DEBUG + pLastWorkPolygon = pWorkPolygon; + pLastWorkPoint = pWorkPoint; +#endif + + pWorkPoint = pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]; + pLastLineLink = pTestLine->pLine->pPointLineLinks[pTestLine->iReferenceIndex]; + Assert_DumpPolyhedron( pWorkPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar + + pTestLine = pLastLineLink->pPrev; + if( pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]->planarity == POINT_ALIVE ) + pWorkPolygon = pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex]; + else + pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex]; + + Assert_DumpPolyhedron( pWorkPolygon != pLastWorkPolygon ); + } + } while( pWorkPoint != pStartPoint ); + } + +#ifdef _DEBUG + //verify that repairs are complete + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDebugPolygonWalk = pAllPolygons; + do + { + AssertMsg_DumpPolyhedron( pDebugPolygonWalk->pPolygon->bMissingASide == false, "Some polygons not repaired after cut" ); + pDebugPolygonWalk = pDebugPolygonWalk->pNext; + } while( pDebugPolygonWalk ); + + + GeneratePolyhedronFromPlanes_UnorderedPointLL *pDebugPointWalk = pAllPoints; + do + { + AssertMsg_DumpPolyhedron( pDebugPointWalk->pPoint->pConnectedLines, "Point connected to no lines after cut" ); + pDebugPointWalk = pDebugPointWalk->pNext; + } while( pDebugPointWalk ); + + pStartPoint = NULL; + } + + //maintain the cut history + DebugCutHistory.AddToTail( ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false ) ); +#endif + } + +#ifdef _DEBUG + for( int i = DebugCutHistory.Count(); --i >= 0; ) + { + if( DebugCutHistory[i] ) + DebugCutHistory[i]->Release(); + } + DebugCutHistory.RemoveAll(); +#endif + + return ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, bUseTemporaryMemory ); +} + + + +#define STARTPOINTTOLINELINKS(iPointNum, lineindex1, iOtherPointIndex1, lineindex2, iOtherPointIndex2, lineindex3, iOtherPointIndex3 )\ + StartingBoxPoints[iPointNum].pConnectedLines = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pLine = &StartingBoxLines[lineindex1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].iReferenceIndex = iOtherPointIndex1;\ + StartingBoxLines[lineindex1].pPointLineLinks[1 - iOtherPointIndex1] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pLine = &StartingBoxLines[lineindex2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].iReferenceIndex = iOtherPointIndex2;\ + StartingBoxLines[lineindex2].pPointLineLinks[1 - iOtherPointIndex2] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pLine = &StartingBoxLines[lineindex3];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].iReferenceIndex = iOtherPointIndex3;\ + StartingBoxLines[lineindex3].pPointLineLinks[1 - iOtherPointIndex3] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0]; + +#define STARTBOXCONNECTION( linenum, point1, point2, poly1, poly2 )\ + StartingBoxLines[linenum].pPoints[0] = &StartingBoxPoints[point1];\ + StartingBoxLines[linenum].pPoints[1] = &StartingBoxPoints[point2];\ + StartingBoxLines[linenum].pPolygons[0] = &StartingBoxPolygons[poly1];\ + StartingBoxLines[linenum].pPolygons[1] = &StartingBoxPolygons[poly2]; + +#define STARTPOLYGONTOLINELINKS( polynum, lineindex1, iThisPolyIndex1, lineindex2, iThisPolyIndex2, lineindex3, iThisPolyIndex3, lineindex4, iThisPolyIndex4 )\ + StartingBoxPolygons[polynum].pLines = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pLine = &StartingBoxLines[lineindex1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].iReferenceIndex = iThisPolyIndex1;\ + StartingBoxLines[lineindex1].pPolygonLineLinks[iThisPolyIndex1] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pLine = &StartingBoxLines[lineindex2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].iReferenceIndex = iThisPolyIndex2;\ + StartingBoxLines[lineindex2].pPolygonLineLinks[iThisPolyIndex2] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pLine = &StartingBoxLines[lineindex3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].iReferenceIndex = iThisPolyIndex3;\ + StartingBoxLines[lineindex3].pPolygonLineLinks[iThisPolyIndex3] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pLine = &StartingBoxLines[lineindex4];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].iReferenceIndex = iThisPolyIndex4;\ + StartingBoxLines[lineindex4].pPolygonLineLinks[iThisPolyIndex4] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0]; + + +CPolyhedron *GeneratePolyhedronFromPlanes( const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ) +{ + //this is version 2 of the polyhedron generator, version 1 made individual polygons and joined points together, some guesswork is involved and it therefore isn't a solid method + //this version will start with a cube and hack away at it (retaining point connection information) to produce a polyhedron with no guesswork involved, this method should be rock solid + + //the polygon clipping functions we're going to use want inward facing planes + float *pFlippedPlanes = (float *)stackalloc( (iPlaneCount * 4) * sizeof( float ) ); + for( int i = 0; i != iPlaneCount * 4; ++i ) + { + pFlippedPlanes[i] = -pOutwardFacingPlanes[i]; + } + + //our first goal is to find the size of a cube big enough to encapsulate all points that will be in the final polyhedron + Vector vAABBMins, vAABBMaxs; + if( FindConvexShapeLooseAABB( pFlippedPlanes, iPlaneCount, &vAABBMins, &vAABBMaxs ) == false ) + return NULL; //no shape to work with apparently + + + //grow the bounding box to a larger size since it's probably inaccurate a bit + { + Vector vGrow = (vAABBMaxs - vAABBMins) * 0.5f; + vGrow.x += 100.0f; + vGrow.y += 100.0f; + vGrow.z += 100.0f; + + vAABBMaxs += vGrow; + vAABBMins -= vGrow; + } + + //generate our starting cube using the 2x AABB so we can start hacking away at it + + + + //create our starting box on the stack + GeneratePolyhedronFromPlanes_Point StartingBoxPoints[8]; + GeneratePolyhedronFromPlanes_Line StartingBoxLines[12]; + GeneratePolyhedronFromPlanes_Polygon StartingBoxPolygons[6]; + GeneratePolyhedronFromPlanes_LineLL StartingPoints_To_Lines_Links[24]; //8 points, 3 lines per point + GeneratePolyhedronFromPlanes_LineLL StartingPolygon_To_Lines_Links[24]; //6 polygons, 4 lines per poly + + GeneratePolyhedronFromPlanes_UnorderedPolygonLL StartingPolygonList[6]; //6 polygons + GeneratePolyhedronFromPlanes_UnorderedLineLL StartingLineList[12]; //12 lines + GeneratePolyhedronFromPlanes_UnorderedPointLL StartingPointList[8]; //8 points + + + //I had to work all this out on a whiteboard if it seems completely unintuitive. + { + StartingBoxPoints[0].ptPosition.Init( vAABBMins.x, vAABBMins.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 0, 0, 1, 4, 1, 3, 0 ); + + StartingBoxPoints[1].ptPosition.Init( vAABBMins.x, vAABBMaxs.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 1, 0, 0, 1, 1, 5, 1 ); + + StartingBoxPoints[2].ptPosition.Init( vAABBMins.x, vAABBMins.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 2, 4, 0, 8, 1, 11, 0 ); + + StartingBoxPoints[3].ptPosition.Init( vAABBMins.x, vAABBMaxs.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 3, 5, 0, 9, 1, 8, 0 ); + + StartingBoxPoints[4].ptPosition.Init( vAABBMaxs.x, vAABBMins.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 4, 2, 0, 3, 1, 7, 1 ); + + StartingBoxPoints[5].ptPosition.Init( vAABBMaxs.x, vAABBMaxs.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 5, 1, 0, 2, 1, 6, 1 ); + + StartingBoxPoints[6].ptPosition.Init( vAABBMaxs.x, vAABBMins.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 6, 7, 0, 11, 1, 10, 0 ); + + StartingBoxPoints[7].ptPosition.Init( vAABBMaxs.x, vAABBMaxs.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 7, 6, 0, 10, 1, 9, 0 ); + + STARTBOXCONNECTION( 0, 0, 1, 0, 5 ); + STARTBOXCONNECTION( 1, 1, 5, 1, 5 ); + STARTBOXCONNECTION( 2, 5, 4, 2, 5 ); + STARTBOXCONNECTION( 3, 4, 0, 3, 5 ); + STARTBOXCONNECTION( 4, 0, 2, 3, 0 ); + STARTBOXCONNECTION( 5, 1, 3, 0, 1 ); + STARTBOXCONNECTION( 6, 5, 7, 1, 2 ); + STARTBOXCONNECTION( 7, 4, 6, 2, 3 ); + STARTBOXCONNECTION( 8, 2, 3, 4, 0 ); + STARTBOXCONNECTION( 9, 3, 7, 4, 1 ); + STARTBOXCONNECTION( 10, 7, 6, 4, 2 ); + STARTBOXCONNECTION( 11, 6, 2, 4, 3 ); + + + STARTBOXCONNECTION( 0, 0, 1, 5, 0 ); + STARTBOXCONNECTION( 1, 1, 5, 5, 1 ); + STARTBOXCONNECTION( 2, 5, 4, 5, 2 ); + STARTBOXCONNECTION( 3, 4, 0, 5, 3 ); + STARTBOXCONNECTION( 4, 0, 2, 0, 3 ); + STARTBOXCONNECTION( 5, 1, 3, 1, 0 ); + STARTBOXCONNECTION( 6, 5, 7, 2, 1 ); + STARTBOXCONNECTION( 7, 4, 6, 3, 2 ); + STARTBOXCONNECTION( 8, 2, 3, 0, 4 ); + STARTBOXCONNECTION( 9, 3, 7, 1, 4 ); + STARTBOXCONNECTION( 10, 7, 6, 2, 4 ); + STARTBOXCONNECTION( 11, 6, 2, 3, 4 ); + + StartingBoxPolygons[0].vSurfaceNormal.Init( -1.0f, 0.0f, 0.0f ); + StartingBoxPolygons[1].vSurfaceNormal.Init( 0.0f, 1.0f, 0.0f ); + StartingBoxPolygons[2].vSurfaceNormal.Init( 1.0f, 0.0f, 0.0f ); + StartingBoxPolygons[3].vSurfaceNormal.Init( 0.0f, -1.0f, 0.0f ); + StartingBoxPolygons[4].vSurfaceNormal.Init( 0.0f, 0.0f, 1.0f ); + StartingBoxPolygons[5].vSurfaceNormal.Init( 0.0f, 0.0f, -1.0f ); + + + STARTPOLYGONTOLINELINKS( 0, 0, 1, 5, 1, 8, 0, 4, 0 ); + STARTPOLYGONTOLINELINKS( 1, 1, 1, 6, 1, 9, 0, 5, 0 ); + STARTPOLYGONTOLINELINKS( 2, 2, 1, 7, 1, 10, 0, 6, 0 ); + STARTPOLYGONTOLINELINKS( 3, 3, 1, 4, 1, 11, 0, 7, 0 ); + STARTPOLYGONTOLINELINKS( 4, 8, 1, 9, 1, 10, 1, 11, 1 ); + STARTPOLYGONTOLINELINKS( 5, 0, 0, 3, 0, 2, 0, 1, 0 ); + + + { + StartingPolygonList[0].pPolygon = &StartingBoxPolygons[0]; + StartingPolygonList[0].pNext = &StartingPolygonList[1]; + StartingPolygonList[0].pPrev = NULL; + + StartingPolygonList[1].pPolygon = &StartingBoxPolygons[1]; + StartingPolygonList[1].pNext = &StartingPolygonList[2]; + StartingPolygonList[1].pPrev = &StartingPolygonList[0]; + + StartingPolygonList[2].pPolygon = &StartingBoxPolygons[2]; + StartingPolygonList[2].pNext = &StartingPolygonList[3]; + StartingPolygonList[2].pPrev = &StartingPolygonList[1]; + + StartingPolygonList[3].pPolygon = &StartingBoxPolygons[3]; + StartingPolygonList[3].pNext = &StartingPolygonList[4]; + StartingPolygonList[3].pPrev = &StartingPolygonList[2]; + + StartingPolygonList[4].pPolygon = &StartingBoxPolygons[4]; + StartingPolygonList[4].pNext = &StartingPolygonList[5]; + StartingPolygonList[4].pPrev = &StartingPolygonList[3]; + + StartingPolygonList[5].pPolygon = &StartingBoxPolygons[5]; + StartingPolygonList[5].pNext = NULL; + StartingPolygonList[5].pPrev = &StartingPolygonList[4]; + } + + + + { + StartingLineList[0].pLine = &StartingBoxLines[0]; + StartingLineList[0].pNext = &StartingLineList[1]; + StartingLineList[0].pPrev = NULL; + + StartingLineList[1].pLine = &StartingBoxLines[1]; + StartingLineList[1].pNext = &StartingLineList[2]; + StartingLineList[1].pPrev = &StartingLineList[0]; + + StartingLineList[2].pLine = &StartingBoxLines[2]; + StartingLineList[2].pNext = &StartingLineList[3]; + StartingLineList[2].pPrev = &StartingLineList[1]; + + StartingLineList[3].pLine = &StartingBoxLines[3]; + StartingLineList[3].pNext = &StartingLineList[4]; + StartingLineList[3].pPrev = &StartingLineList[2]; + + StartingLineList[4].pLine = &StartingBoxLines[4]; + StartingLineList[4].pNext = &StartingLineList[5]; + StartingLineList[4].pPrev = &StartingLineList[3]; + + StartingLineList[5].pLine = &StartingBoxLines[5]; + StartingLineList[5].pNext = &StartingLineList[6]; + StartingLineList[5].pPrev = &StartingLineList[4]; + + StartingLineList[6].pLine = &StartingBoxLines[6]; + StartingLineList[6].pNext = &StartingLineList[7]; + StartingLineList[6].pPrev = &StartingLineList[5]; + + StartingLineList[7].pLine = &StartingBoxLines[7]; + StartingLineList[7].pNext = &StartingLineList[8]; + StartingLineList[7].pPrev = &StartingLineList[6]; + + StartingLineList[8].pLine = &StartingBoxLines[8]; + StartingLineList[8].pNext = &StartingLineList[9]; + StartingLineList[8].pPrev = &StartingLineList[7]; + + StartingLineList[9].pLine = &StartingBoxLines[9]; + StartingLineList[9].pNext = &StartingLineList[10]; + StartingLineList[9].pPrev = &StartingLineList[8]; + + StartingLineList[10].pLine = &StartingBoxLines[10]; + StartingLineList[10].pNext = &StartingLineList[11]; + StartingLineList[10].pPrev = &StartingLineList[9]; + + StartingLineList[11].pLine = &StartingBoxLines[11]; + StartingLineList[11].pNext = NULL; + StartingLineList[11].pPrev = &StartingLineList[10]; + } + + { + StartingPointList[0].pPoint = &StartingBoxPoints[0]; + StartingPointList[0].pNext = &StartingPointList[1]; + StartingPointList[0].pPrev = NULL; + + StartingPointList[1].pPoint = &StartingBoxPoints[1]; + StartingPointList[1].pNext = &StartingPointList[2]; + StartingPointList[1].pPrev = &StartingPointList[0]; + + StartingPointList[2].pPoint = &StartingBoxPoints[2]; + StartingPointList[2].pNext = &StartingPointList[3]; + StartingPointList[2].pPrev = &StartingPointList[1]; + + StartingPointList[3].pPoint = &StartingBoxPoints[3]; + StartingPointList[3].pNext = &StartingPointList[4]; + StartingPointList[3].pPrev = &StartingPointList[2]; + + StartingPointList[4].pPoint = &StartingBoxPoints[4]; + StartingPointList[4].pNext = &StartingPointList[5]; + StartingPointList[4].pPrev = &StartingPointList[3]; + + StartingPointList[5].pPoint = &StartingBoxPoints[5]; + StartingPointList[5].pNext = &StartingPointList[6]; + StartingPointList[5].pPrev = &StartingPointList[4]; + + StartingPointList[6].pPoint = &StartingBoxPoints[6]; + StartingPointList[6].pNext = &StartingPointList[7]; + StartingPointList[6].pPrev = &StartingPointList[5]; + + StartingPointList[7].pPoint = &StartingBoxPoints[7]; + StartingPointList[7].pNext = NULL; + StartingPointList[7].pPrev = &StartingPointList[6]; + } + } + + return ClipLinkedGeometry( StartingPolygonList, StartingLineList, StartingPointList, pOutwardFacingPlanes, iPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory ); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifdef _DEBUG +void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + Vector vMins = vCenter - vExtents; + Vector vMaxs = vCenter + vExtents; + + //x min side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + //x max side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + //y min side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + + //y max side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + + //z min side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + //z max side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); +#endif +} + +void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + Vector vDirection = vPoint2 - vPoint1; + vDirection.NormalizeInPlace(); + + Vector vPseudoPerpandicular = vec3_origin; + + if( vDirection.x != 0.0f ) + vPseudoPerpandicular.z = 1.0f; + else + vPseudoPerpandicular.x = 1.0f; + + Vector vWidth = vDirection.Cross( vPseudoPerpandicular ); + vWidth.NormalizeInPlace(); + + Vector vHeight = vDirection.Cross( vWidth ); + vHeight.NormalizeInPlace(); + + fThickness *= 0.5f; //we use half thickness in both directions + vDirection *= fThickness; + vWidth *= fThickness; + vHeight *= fThickness; + + Vector vLinePoints[8]; + vLinePoints[0] = vPoint1 - vDirection - vWidth - vHeight; + vLinePoints[1] = vPoint1 - vDirection - vWidth + vHeight; + vLinePoints[2] = vPoint1 - vDirection + vWidth - vHeight; + vLinePoints[3] = vPoint1 - vDirection + vWidth + vHeight; + + vLinePoints[4] = vPoint2 + vDirection - vWidth - vHeight; + vLinePoints[5] = vPoint2 + vDirection - vWidth + vHeight; + vLinePoints[6] = vPoint2 + vDirection + vWidth - vHeight; + vLinePoints[7] = vPoint2 + vDirection + vWidth + vHeight; + + const Vector *pLineColors[8] = { &vColor1, &vColor1, &vColor1, &vColor1, &vColor2, &vColor2, &vColor2, &vColor2 }; + + +#define DPTGLV_LINE_WRITEPOINT(index) fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vLinePoints[index].x, vLinePoints[index].y, vLinePoints[index].z, pLineColors[index]->x, pLineColors[index]->y, pLineColors[index]->z ); +#define DPTGLV_LINE_DOUBLESIDEDQUAD(index1,index2,index3,index4)\ + fprintf( pFile, "4\n" );\ + DPTGLV_LINE_WRITEPOINT(index1);\ + DPTGLV_LINE_WRITEPOINT(index2);\ + DPTGLV_LINE_WRITEPOINT(index3);\ + DPTGLV_LINE_WRITEPOINT(index4);\ + fprintf( pFile, "4\n" );\ + DPTGLV_LINE_WRITEPOINT(index4);\ + DPTGLV_LINE_WRITEPOINT(index3);\ + DPTGLV_LINE_WRITEPOINT(index2);\ + DPTGLV_LINE_WRITEPOINT(index1); + + + DPTGLV_LINE_DOUBLESIDEDQUAD(0,4,6,2); + DPTGLV_LINE_DOUBLESIDEDQUAD(3,7,5,1); + DPTGLV_LINE_DOUBLESIDEDQUAD(1,5,4,0); + DPTGLV_LINE_DOUBLESIDEDQUAD(2,6,7,3); + DPTGLV_LINE_DOUBLESIDEDQUAD(0,2,3,1); + DPTGLV_LINE_DOUBLESIDEDQUAD(5,7,6,4); +#endif +} + +void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if ( (pPolyhedron == NULL) || (pPolyhedron->iVertexCount == 0) ) + return; + + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + printf("Writing %s...\n", pFilename ); + + FILE *pFile = fopen( pFilename, "ab" ); + + //randomizing an array of colors to help spot shared/unshared vertices + Vector *pColors = (Vector *)stackalloc( sizeof( Vector ) * pPolyhedron->iVertexCount ); + int counter; + for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter ) + { + pColors[counter].Init( rand()/32768.0f, rand()/32768.0f, rand()/32768.0f ); + } + + Vector *pTransformedPoints = (Vector *)stackalloc( pPolyhedron->iVertexCount * sizeof( Vector ) ); + for ( counter = 0; counter != pPolyhedron->iVertexCount; ++counter ) + { + pTransformedPoints[counter] = (*pTransform) * pPolyhedron->pVertices[counter]; + } + + for ( counter = 0; counter != pPolyhedron->iPolygonCount; ++counter ) + { + fprintf( pFile, "%i\n", pPolyhedron->pPolygons[counter].iIndexCount ); + int counter2; + for( counter2 = 0; counter2 != pPolyhedron->pPolygons[counter].iIndexCount; ++counter2 ) + { + Polyhedron_IndexedLineReference_t *pLineReference = &pPolyhedron->pIndices[pPolyhedron->pPolygons[counter].iFirstIndex + counter2]; + + Vector *pVertex = &pTransformedPoints[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]]; + Vector *pColor = &pColors[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]]; + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n",pVertex->x, pVertex->y, pVertex->z, pColor->x, pColor->y, pColor->z ); + } + } + + for( counter = 0; counter != pPolyhedron->iLineCount; ++counter ) + { + const Vector vOne( 1.0f, 1.0f, 1.0f ); + DumpLineToGLView( pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[0]], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[0]], + pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[1]], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[1]], + 0.1f, pFile ); + } + + for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter ) + { + const Vector vPointHalfSize(0.15f, 0.15f, 0.15f ); + DumpAABBToGLView( pTransformedPoints[counter], vPointHalfSize, pColors[counter], pFile ); + } + + fclose( pFile ); +#endif +} + + +void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + FILE *pFile = fopen( pszFileName, "ab" ); + + //transform the plane + Vector vNormal = pTransform->ApplyRotation( *(Vector *)pPlane ); + float fDist = pPlane[3] * vNormal.NormalizeInPlace(); //possible scaling going on + fDist += vNormal.Dot( pTransform->GetTranslation() ); + + Vector vPlaneVerts[4]; + + PolyFromPlane( vPlaneVerts, vNormal, fDist, 100000.0f ); + + fprintf( pFile, "4\n" ); + + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[0].x, vPlaneVerts[0].y, vPlaneVerts[0].z, fGrayScale, fGrayScale, fGrayScale ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[1].x, vPlaneVerts[1].y, vPlaneVerts[1].z, fGrayScale, fGrayScale, fGrayScale ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[2].x, vPlaneVerts[2].y, vPlaneVerts[2].z, fGrayScale, fGrayScale, fGrayScale ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[3].x, vPlaneVerts[3].y, vPlaneVerts[3].z, fGrayScale, fGrayScale, fGrayScale ); + + fclose( pFile ); +#endif +} +#endif + + diff --git a/public/mathlib/polyhedron.h b/public/mathlib/polyhedron.h index 8f4a4955..38b465c7 100644 --- a/public/mathlib/polyhedron.h +++ b/public/mathlib/polyhedron.h @@ -42,7 +42,7 @@ public: Polyhedron_IndexedLine_t *pLines; Polyhedron_IndexedLineReference_t *pIndices; Polyhedron_IndexedPolygon_t *pPolygons; - + unsigned short iVertexCount; unsigned short iLineCount; unsigned short iIndexCount; @@ -53,10 +53,10 @@ public: Vector Center( void ); }; -class CPolyhedron_AllocByNew final : public CPolyhedron +class CPolyhedron_AllocByNew : public CPolyhedron { public: - void Release( void ) override; + virtual void Release( void ); static CPolyhedron_AllocByNew *Allocate( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ); //creates the polyhedron along with enough memory to hold all it's data in a single allocation private: diff --git a/public/mathlib/ssemath.h b/public/mathlib/ssemath.h index 4580a4bd..b8cba33b 100644 --- a/public/mathlib/ssemath.h +++ b/public/mathlib/ssemath.h @@ -8,7 +8,7 @@ #if defined( _X360 ) #include -#elif defined(__arm__) || defined(__arm64__) +#elif defined(__arm__) || defined(__aarch64__) #include "sse2neon.h" #else #include @@ -1787,6 +1787,18 @@ FORCEINLINE fltx4 LoadAlignedSIMD( const VectorAligned & pSIMD ) return SetWToZeroSIMD( LoadAlignedSIMD(pSIMD.Base()) ); } +#ifdef __SANITIZE_ADDRESS__ +static __attribute__((no_sanitize("address"))) fltx4 LoadUnalignedSIMD( const void *pSIMD ) +{ + return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); + +} + +static __attribute__((no_sanitize("address"))) fltx4 LoadUnaligned3SIMD( const void *pSIMD ) +{ + return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); +} +#else FORCEINLINE fltx4 LoadUnalignedSIMD( const void *pSIMD ) { return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); @@ -1796,6 +1808,7 @@ FORCEINLINE fltx4 LoadUnaligned3SIMD( const void *pSIMD ) { return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); } +#endif /// replicate a single 32 bit integer value to all 4 components of an m128 FORCEINLINE fltx4 ReplicateIX4( int i ) diff --git a/public/mathlib/vector4d.h b/public/mathlib/vector4d.h index 72c63129..cca45242 100644 --- a/public/mathlib/vector4d.h +++ b/public/mathlib/vector4d.h @@ -23,7 +23,7 @@ #include "tier0/dbg.h" #include "mathlib/math_pfns.h" -#ifdef __arm__ +#if defined (__arm__) || defined(__aarch64__) #include "sse2neon.h" #endif diff --git a/public/saverestoretypes.h b/public/saverestoretypes.h index 55fa0042..45a3d844 100644 --- a/public/saverestoretypes.h +++ b/public/saverestoretypes.h @@ -512,7 +512,7 @@ inline const char *CSaveRestoreSegment::StringFromSymbol( int token ) /// compilers. Either way, there's no portable intrinsic. // Newer GCC versions provide this in this header, older did by default. -#if !defined( _rotr ) && defined( COMPILER_GCC ) && !defined( __arm__ ) && !defined( __arm64__ ) +#if !defined( _rotr ) && defined( COMPILER_GCC ) && !defined( __arm__ ) && !defined( __aarch64__ ) #include #endif diff --git a/public/steam/steamtypes.h b/public/steam/steamtypes.h index f229f238..c32150e2 100644 --- a/public/steam/steamtypes.h +++ b/public/steam/steamtypes.h @@ -24,7 +24,7 @@ typedef unsigned char uint8; #define POSIX 1 #endif -#if defined(__x86_64__) || defined(_WIN64) || defined(__arm64__) +#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) #define X64BITS #endif diff --git a/public/tier0/memvirt.h b/public/tier0/memvirt.h new file mode 100644 index 00000000..eeb09964 --- /dev/null +++ b/public/tier0/memvirt.h @@ -0,0 +1,46 @@ +//========== Copyright (C) Valve Corporation, All rights reserved. ==========// +// +// Purpose: CVirtualMemoryManager interface +// +//===========================================================================// + +#ifndef MEM_VIRT_H +#define MEM_VIRT_H +#ifdef _WIN32 +#pragma once +#endif + + +#define VMM_KB ( 1024 ) +#define VMM_MB ( 1024 * VMM_KB ) + +#ifdef _PS3 +// Total virtual address space reserved by CVirtualMemoryManager on startup: +#define VMM_VIRTUAL_SIZE ( 512 * VMM_MB ) +#define VMM_PAGE_SIZE ( 64 * VMM_KB ) +#endif + + + +// Allocate virtual sections via IMemAlloc::AllocateVirtualMemorySection +abstract_class IVirtualMemorySection +{ +public: + // Information about memory section + virtual void * GetBaseAddress() = 0; + virtual size_t GetPageSize() = 0; + virtual size_t GetTotalSize() = 0; + + // Functions to manage physical memory mapped to virtual memory + virtual bool CommitPages( void *pvBase, size_t numBytes ) = 0; + virtual void DecommitPages( void *pvBase, size_t numBytes ) = 0; + + // Release the physical memory and associated virtual address space + virtual void Release() = 0; +}; + +// Get the IVirtualMemorySection associated with a given memory address (if any): +extern IVirtualMemorySection *GetMemorySectionForAddress( void *pAddress ); + + +#endif // MEM_VIRT_H diff --git a/public/tier0/platform.h b/public/tier0/platform.h index 701c62ff..30b2ec0f 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -9,7 +9,7 @@ #ifndef PLATFORM_H #define PLATFORM_H -#if defined(__x86_64__) || defined(_WIN64) || defined(__arm64__) +#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) #define PLATFORM_64BITS 1 #endif @@ -440,7 +440,7 @@ typedef void * HINSTANCE; // On OSX, SIGTRAP doesn't really stop the thread cold when debugging. // So if being debugged, use INT3 which is precise. #ifdef OSX -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) #ifdef __clang__ #define DebuggerBreak() do { if ( Plat_IsInDebugSession() ) { __builtin_debugtrap(); } else { raise(SIGTRAP); } } while(0) #elif defined __GNUC__ @@ -631,6 +631,7 @@ typedef void * HINSTANCE; #endif // Used for standard calling conventions + #if defined( _WIN32 ) && !defined( _X360 ) #define STDCALL __stdcall #define FASTCALL __fastcall @@ -687,6 +688,11 @@ typedef void * HINSTANCE; #ifdef _WIN32 +#ifdef __SANITIZE_ADDRESS__ +#undef FORCEINLINE +#define FORCEINLINE static +#endif + // Remove warnings from warning level 4. #pragma warning(disable : 4514) // warning C4514: 'acosl' : unreferenced inline function has been removed #pragma warning(disable : 4100) // warning C4100: 'hwnd' : unreferenced formal parameter @@ -861,7 +867,7 @@ static FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) #endif #endif -#elif defined (__arm__) || defined (__arm64__) +#elif defined (__arm__) || defined (__aarch64__) inline void SetupFPUControlWord() {} #else inline void SetupFPUControlWord() @@ -1198,7 +1204,7 @@ PLATFORM_INTERFACE struct tm * Plat_localtime( const time_t *timep, struct tm * inline uint64 Plat_Rdtsc() { -#if (defined( __arm__ ) || defined( __arm64__ )) && defined (POSIX) +#if (defined( __arm__ ) || defined( __aarch64__ )) && defined (POSIX) struct timespec t; clock_gettime( CLOCK_REALTIME, &t); return t.tv_sec * 1000000000ULL + t.tv_nsec; diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h index 00a38422..7714fe4f 100644 --- a/public/tier0/threadtools.h +++ b/public/tier0/threadtools.h @@ -81,7 +81,7 @@ enum ThreadPriorityEnum_t TP_PRIORITY_LOW = 2001, TP_PRIORITY_DEFAULT = 1001 #error "Need PRIORITY_LOWEST/HIGHEST" -#elif defined( PLATFORM_LINUX ) +#elif defined( LINUX ) // We can use nice on Linux threads to change scheduling. // pthreads on Linux only allows priority setting on // real-time threads. @@ -103,7 +103,7 @@ enum ThreadPriorityEnum_t #endif // PLATFORM_PS3 }; -#if defined( PLATFORM_LINUX ) +#if defined( LINUX ) #define TP_IS_PRIORITY_HIGHER( a, b ) ( ( a ) < ( b ) ) #else #define TP_IS_PRIORITY_HIGHER( a, b ) ( ( a ) > ( b ) ) @@ -229,6 +229,8 @@ inline void ThreadPause() { #if defined( COMPILER_PS3 ) __db16cyc(); +#elif defined(__arm__) || defined(__aarch64__) + sched_yield(); #elif defined( COMPILER_GCC ) __asm __volatile( "pause" ); #elif defined ( COMPILER_MSVC64 ) @@ -301,15 +303,7 @@ inline int32 ThreadInterlockedDecrement( int32 volatile *p ) inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); - int32 nRet; - - // Note: The LOCK instruction prefix is assumed on the XCHG instruction and GCC gets very confused on the Mac when we use it. - __asm __volatile( - "xchgl %2,(%1)" - : "=r" (nRet) - : "r" (p), "0" (value) - : "memory"); - return nRet; + return __sync_lock_test_and_set( p, value ); } inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) diff --git a/public/tier0/threadtools.inl b/public/tier0/threadtools.inl index dda4b5f5..694c653e 100644 --- a/public/tier0/threadtools.inl +++ b/public/tier0/threadtools.inl @@ -120,7 +120,7 @@ INLINE_ON_PS3 bool CThread::Start( unsigned nBytesStack, ThreadPriorityEnum_t nP } #endif -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 m_hThread = (HANDLE)CreateThread( NULL, nBytesStack, (LPTHREAD_START_ROUTINE)GetThreadProc(), @@ -168,7 +168,7 @@ INLINE_ON_PS3 bool CThread::Start( unsigned nBytesStack, ThreadPriorityEnum_t nP } bInitSuccess = true; -#elif PLATFORM_POSIX +#elif POSIX pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setstacksize( &attr, MAX( nBytesStack, 1024u*1024 ) ); @@ -236,7 +236,7 @@ INLINE_ON_PS3 bool CThread::Start( unsigned nBytesStack, ThreadPriorityEnum_t nP INLINE_ON_PS3 bool CThread::IsAlive() { -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 DWORD dwExitCode; return ( m_hThread @@ -526,7 +526,7 @@ INLINE_ON_PS3 void CThread::ThreadProcRunWithMinidumpHandler( void *pv ) pInit->pThread->m_result = pInit->pThread->Run(); } -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 unsigned long STDCALL CThread::ThreadProc(LPVOID pv) #else INLINE_ON_PS3 void* CThread::ThreadProc(LPVOID pv) diff --git a/public/togles/linuxwin/dxabstract.h b/public/togles/linuxwin/dxabstract.h index 93ef9267..d335c650 100644 --- a/public/togles/linuxwin/dxabstract.h +++ b/public/togles/linuxwin/dxabstract.h @@ -373,7 +373,7 @@ struct RenderTargetState_t static inline bool LessFunc( const RenderTargetState_t &lhs, const RenderTargetState_t &rhs ) { - COMPILE_TIME_ASSERT( sizeof( lhs.m_pRenderTargets[0] ) == sizeof( uint32 ) ); + COMPILE_TIME_ASSERT( sizeof( lhs.m_pRenderTargets[0] ) == sizeof( uintp ) ); uint64 lhs0 = reinterpret_cast(lhs.m_pRenderTargets)[0]; uint64 rhs0 = reinterpret_cast(rhs.m_pRenderTargets)[0]; if ( lhs0 < rhs0 ) diff --git a/public/togles/linuxwin/glmgr.h b/public/togles/linuxwin/glmgr.h index 3729911e..cd02464f 100644 --- a/public/togles/linuxwin/glmgr.h +++ b/public/togles/linuxwin/glmgr.h @@ -1838,11 +1838,11 @@ FORCEINLINE void GLMContext::DrawRangeElements( GLenum mode, GLuint start, GLuin if ( pIndexBuf->m_bPseudo ) { // you have to pass actual address, not offset - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_pPseudoBuf ); } if (pIndexBuf->m_bUsingPersistentBuffer) { - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_nPersistentBufferStartOffset ); } //#if GLMDEBUG diff --git a/tier0/cpu.cpp b/tier0/cpu.cpp index 9b0a9d6a..2018c8b0 100644 --- a/tier0/cpu.cpp +++ b/tier0/cpu.cpp @@ -22,7 +22,7 @@ const tchar* GetProcessorVendorId(); static bool cpuid(uint32 function, uint32& out_eax, uint32& out_ebx, uint32& out_ecx, uint32& out_edx) { -#if defined (__arm__) || defined (__arm64__) || defined( _X360 ) +#if defined (__arm__) || defined (__aarch64__) || defined( _X360 ) return false; #elif defined(GNUC) diff --git a/tier0/cpu_posix.cpp b/tier0/cpu_posix.cpp index 2b158947..d822883c 100644 --- a/tier0/cpu_posix.cpp +++ b/tier0/cpu_posix.cpp @@ -129,7 +129,7 @@ uint64 CalculateCPUFreq() } #endif -#if !defined(__arm__) && !defined(__arm64__) +#if !defined(__arm__) && !defined(__aarch64__) // Compute the period. Loop until we get 3 consecutive periods that // are the same to within a small error. The error is chosen // to be +/- 0.02% on a P-200. diff --git a/tier0/mem_impl_type.h b/tier0/mem_impl_type.h new file mode 100644 index 00000000..f01b6538 --- /dev/null +++ b/tier0/mem_impl_type.h @@ -0,0 +1,6 @@ + +#if ( (!defined( POSIX )||defined(_GAMECONSOLE)) && (defined(_DEBUG) || defined(USE_MEM_DEBUG) ) ) +#define MEM_IMPL_TYPE_DBG 1 +#else +#define MEM_IMPL_TYPE_STD 1 +#endif diff --git a/tier0/memdbg.cpp b/tier0/memdbg.cpp index 6b9379f0..e5304869 100644 --- a/tier0/memdbg.cpp +++ b/tier0/memdbg.cpp @@ -1836,7 +1836,7 @@ static inline void unprotect_malloc_zone( malloc_zone_t *malloc_zone ) // The version check may not be necessary, but we know it was RW before that. if ( malloc_zone->version >= 8 ) { -#ifdef __arm64__ +#ifdef __aarch64__ // MoeMod : this is required for Apple Silicon pthread_jit_write_protect_np(false); #endif @@ -1849,7 +1849,7 @@ static inline void protect_malloc_zone( malloc_zone_t *malloc_zone ) if ( malloc_zone->version >= 8 ) { vm_protect( mach_task_self(), (uintptr_t)malloc_zone, sizeof( malloc_zone_t ), 0, VM_PROT_READ ); -#ifdef __arm64__ +#ifdef __aarch64__ // MoeMod : this is required for Apple Silicon pthread_jit_write_protect_np(true); #endif diff --git a/tier0/threadtools.cpp b/tier0/threadtools.cpp index 2d00d706..01217e49 100644 --- a/tier0/threadtools.cpp +++ b/tier0/threadtools.cpp @@ -6,29 +6,19 @@ #include "tier0/platform.h" -#if defined( PLATFORM_WINDOWS_PC ) +#if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x0403 #include #endif -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 #include - #ifdef PLATFORM_WINDOWS_PC + #ifdef _WIN32 #include #pragma comment(lib, "winmm.lib") #endif -#elif PLATFORM_PS3 - #include - #include - #include - #include - #include - #include - #include - #define GetLastError() errno - typedef void *LPVOID; -#elif PLATFORM_POSIX +#elif POSIX #include #include #include @@ -38,8 +28,13 @@ #define GetLastError() errno typedef void *LPVOID; #if !defined(OSX) - #include - #include +#if defined(ANDROID) + #include + #include +#else + #include + #include +#endif #define sem_unlink( arg ) #define OS_TO_PTHREAD(x) (x) #else @@ -155,7 +150,7 @@ struct ThreadProcInfo_t //--------------------------------------------------------- -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 static DWORD WINAPI ThreadProcConvert( void *pParam ) { ThreadProcInfo_t info = *((ThreadProcInfo_t *)pParam); @@ -165,7 +160,7 @@ static DWORD WINAPI ThreadProcConvert( void *pParam ) FreeThreadID(); return nRet; } -#elif defined( PLATFORM_PS3 ) +#elif defined( PS3 ) union ThreadProcInfoUnion_t { struct Val_t @@ -262,7 +257,7 @@ void TlsSetValue( uint32 index, void *pValue ) -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 class CThreadHandleToIDMap { public: @@ -421,12 +416,12 @@ void JoinTestThreads( ThreadHandle_t *pHandles ) ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, unsigned stackSize ) { -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 DWORD threadID; HANDLE hThread = (HANDLE)CreateThread( NULL, stackSize, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ), stackSize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0, &threadID ); AddThreadHandleToIDMap( hThread, threadID ); return (ThreadHandle_t)hThread; -#elif PLATFORM_PS3 +#elif PS3 //TestThreads(); ThreadHandle_t th; ThreadProcInfoUnion_t info; @@ -439,7 +434,7 @@ ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, unsigne return 0; } return th; -#elif PLATFORM_POSIX +#elif POSIX pthread_t tid; pthread_create( &tid, NULL, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ) ); return ( ThreadHandle_t ) tid; @@ -452,14 +447,14 @@ ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, unsigne ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, ThreadId_t *pID, unsigned stackSize ) { -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 DWORD threadID; HANDLE hThread = (HANDLE)CreateThread( NULL, stackSize, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ), stackSize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0, &threadID ); if( pID ) *pID = (ThreadId_t)threadID; AddThreadHandleToIDMap( hThread, threadID ); return (ThreadHandle_t)hThread; -#elif PLATFORM_POSIX +#elif POSIX pthread_t tid; pthread_create( &tid, NULL, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ) ); if( pID ) @@ -494,7 +489,7 @@ void ThreadSleep(unsigned nMilliseconds) { #ifdef _WIN32 -#ifdef PLATFORM_WINDOWS_PC +#ifdef _WIN32_PC static bool bInitialized = false; if ( !bInitialized ) { @@ -508,7 +503,7 @@ void ThreadSleep(unsigned nMilliseconds) #endif Sleep( nMilliseconds ); -#elif PLATFORM_PS3 +#elif PS3 if( nMilliseconds == 0 ) { // sys_ppu_thread_yield doesn't seem to function properly, so sleep instead. @@ -530,7 +525,7 @@ void ThreadNanoSleep(unsigned ns) #ifdef _WIN32 // ceil Sleep( ( ns + 999 ) / 1000 ); -#elif PLATFORM_PS3 +#elif PS3 sys_timer_usleep( ns ); #elif defined(POSIX) struct timespec tm; @@ -814,7 +809,7 @@ sys_lwmutex_t CThreadSyncObject::m_staticMutex; CThreadSyncObject::CThreadSyncObject() #ifdef _WIN32 : m_hSyncObject( NULL ), m_bCreatedHandle(false) -#elif defined(POSIX) && !defined(PLATFORM_PS3) +#elif defined(POSIX) && !defined(PS3) : m_bInitalized( false ) #endif { @@ -857,7 +852,7 @@ CThreadSyncObject::~CThreadSyncObject() Assert( 0 ); } } -#elif defined(POSIX) && !defined( PLATFORM_PS3 ) +#elif defined(POSIX) && !defined( PS3 ) if ( m_bInitalized ) { pthread_cond_destroy( &m_Condition ); @@ -871,7 +866,7 @@ CThreadSyncObject::~CThreadSyncObject() bool CThreadSyncObject::operator!() const { -#if PLATFORM_PS3 +#if PS3 return m_bstaticMutexInitialized; #elif defined( _WIN32 ) return !m_hSyncObject; @@ -885,7 +880,7 @@ bool CThreadSyncObject::operator!() const void CThreadSyncObject::AssertUseable() { #ifdef THREADS_DEBUG -#if PLATFORM_PS3 +#if PS3 AssertMsg( m_bstaticMutexInitialized, "Thread synchronization object is unuseable" ); #elif defined( _WIN32 ) AssertMsg( m_hSyncObject, "Thread synchronization object is unuseable" ); @@ -905,7 +900,7 @@ bool CThreadSyncObject::Wait( uint32 dwTimeout ) #endif #ifdef _WIN32 return ( WaitForSingleObject( m_hSyncObject, dwTimeout ) == WAIT_OBJECT_0 ); -#elif defined( POSIX ) && !defined( PLATFORM_PS3 ) +#elif defined( POSIX ) && !defined( PS3 ) pthread_mutex_lock( &m_Mutex ); bool bRet = false; if ( m_cSet > 0 ) @@ -1263,7 +1258,7 @@ void CThreadEvent::UnregisterWaitingThread(sys_semaphore_t *pSemaphore) #endif // _PS3 -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 CThreadEvent::CThreadEvent( const char *name, bool initialState, bool bManualReset ) { m_hSyncObject = CreateEvent( NULL, bManualReset, (BOOL) initialState, name ); diff --git a/tier1/processor_detect_linux.cpp b/tier1/processor_detect_linux.cpp index 8887926e..64d771a2 100644 --- a/tier1/processor_detect_linux.cpp +++ b/tier1/processor_detect_linux.cpp @@ -13,7 +13,7 @@ bool CheckMMXTechnology(void) { return false; } bool CheckSSETechnology(void) { return false; } bool CheckSSE2Technology(void) { return false; } bool Check3DNowTechnology(void) { return false; } -#elif defined (__arm__) || defined (__arm64__) +#elif defined (__arm__) || defined (__aarch64__) bool CheckMMXTechnology(void) { return false; } bool CheckSSETechnology(void) { return false; } bool CheckSSE2Technology(void) { return false; } diff --git a/tier1/reliabletimer.cpp b/tier1/reliabletimer.cpp index 73556e90..f575a679 100644 --- a/tier1/reliabletimer.cpp +++ b/tier1/reliabletimer.cpp @@ -87,7 +87,7 @@ int64 CReliableTimer::GetPerformanceCountNow() uint64 ulNow; SYS_TIMEBASE_GET( ulNow ); return ulNow; -#elif (defined( __arm__ ) || defined( __arm64__ )) && defined (POSIX) +#elif (defined( __arm__ ) || defined( __aarch64__ )) && defined (POSIX) struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return ts.tv_sec * 1000000000ULL + ts.tv_nsec; diff --git a/tier1/strtools.cpp b/tier1/strtools.cpp index af4fa688..af81b059 100644 --- a/tier1/strtools.cpp +++ b/tier1/strtools.cpp @@ -47,7 +47,6 @@ #include #ifdef POSIX -#include #include #include #include @@ -79,7 +78,12 @@ #include "xbox/xbox_win32stubs.h" #endif #include "tier0/memdbgon.h" -#include "iconv.h" + +#ifdef ANDROID +#include "common/iconv.h" +#elif POSIX +#include +#endif static int FastToLower( char c ) { diff --git a/tier1/wscript b/tier1/wscript index 80a32f69..903fb5da 100755 --- a/tier1/wscript +++ b/tier1/wscript @@ -66,6 +66,7 @@ def build(bld): includes = [ '.', + '../', '../public', '../public/tier1', '../public/tier0', diff --git a/togles/linuxwin/glmgr.cpp b/togles/linuxwin/glmgr.cpp index 01a2bf72..8271b236 100644 --- a/togles/linuxwin/glmgr.cpp +++ b/togles/linuxwin/glmgr.cpp @@ -667,7 +667,7 @@ void GLMContext::DumpCaps( void ) #define dumpfield_hex( fff ) printf( "\n %-30s : 0x%08x", #fff, (int) m_caps.fff ) #define dumpfield_str( fff ) printf( "\n %-30s : %s", #fff, m_caps.fff ) - printf("\n-------------------------------- context caps for context %08x", (uint)this); + printf("\n-------------------------------- context caps for context %zx", (size_t)this); dumpfield( m_fullscreen ); dumpfield( m_accelerated ); @@ -4925,11 +4925,11 @@ void GLMContext::DrawRangeElementsNonInline( GLenum mode, GLuint start, GLuint e if ( pIndexBuf->m_bPseudo ) { // you have to pass actual address, not offset - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_pPseudoBuf ); } if (pIndexBuf->m_bUsingPersistentBuffer) { - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_nPersistentBufferStartOffset ); } #if GL_ENABLE_INDEX_VERIFICATION diff --git a/togles/linuxwin/glmgr_flush.inl b/togles/linuxwin/glmgr_flush.inl index be98692f..126d08b1 100644 --- a/togles/linuxwin/glmgr_flush.inl +++ b/togles/linuxwin/glmgr_flush.inl @@ -573,7 +573,7 @@ FORCEINLINE void GLMContext::FlushDrawStates( uint nStartIndex, uint nEndIndex, SetBufAndVertexAttribPointer( nIndex, pBuf->GetHandle(), pStream->m_stride, pDeclElem->m_gldecl.m_datatype, pDeclElem->m_gldecl.m_normalized, pDeclElem->m_gldecl.m_nCompCount, - reinterpret_cast< const GLvoid * >( reinterpret_cast< int >( pBuf->m_pPseudoBuf ) + nBufOffset ), + reinterpret_cast< const GLvoid * >( reinterpret_cast< intp >( pBuf->m_pPseudoBuf ) + nBufOffset ), pBuf->m_nRevision ); if ( !( m_lastKnownVertexAttribMask & nMask ) ) diff --git a/vphysics/vphysics_saverestore.cpp b/vphysics/vphysics_saverestore.cpp index dc4b8434..34fb585b 100644 --- a/vphysics/vphysics_saverestore.cpp +++ b/vphysics/vphysics_saverestore.cpp @@ -131,7 +131,7 @@ void CPhysicsEnvironment::PostRestore() void CVPhysPtrSaveRestoreOps::Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) { - void *pField = (void *)fieldInfo.pField; + char *pField = (char *)fieldInfo.pField; int nObjects = fieldInfo.pTypeDesc->fieldSize; for ( int i = 0; i < nObjects; i++ ) {