/// Get the package loader to use to load the object with the given path, creating it if necessary. /// /// @param[in] path Asset path. /// /// @return Package loader to use to load the specified object. LoosePackageLoader* LoosePackageLoaderMap::GetPackageLoader( AssetPath path ) { HELIUM_ASSERT( !path.IsEmpty() ); // Resolve the object's package. AssetPath packagePath = path; while( !packagePath.IsPackage() ) { packagePath = packagePath.GetParent(); if( packagePath.IsEmpty() ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "LoosePackageLoaderMap::GetPackageLoader(): Cannot resolve package loader for \"%s\", as it " ) TXT( "is not located in a package.\n" ) ), *path.ToString() ); return NULL; } } // Locate an existing package loader. ConcurrentHashMap< AssetPath, LoosePackageLoader* >::ConstAccessor constMapAccessor; if( m_packageLoaderMap.Find( constMapAccessor, packagePath ) ) { LoosePackageLoader* pLoader = constMapAccessor->Second(); HELIUM_ASSERT( pLoader ); return pLoader; } // Add a new package loader entry. ConcurrentHashMap< AssetPath, LoosePackageLoader* >::Accessor mapAccessor; bool bInserted = m_packageLoaderMap.Insert( mapAccessor, KeyValue< AssetPath, LoosePackageLoader* >( packagePath, NULL ) ); if( bInserted ) { // Entry added, so create and initialize the package loader. LoosePackageLoader* pLoader = new LoosePackageLoader; HELIUM_ASSERT( pLoader ); bool bInitResult = pLoader->Initialize( packagePath ); HELIUM_ASSERT( bInitResult ); if( !bInitResult ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoaderMap::GetPackageLoader(): Failed to initialize package loader for \"%s\".\n" ), *packagePath.ToString() ); m_packageLoaderMap.Remove( mapAccessor ); return NULL; } HELIUM_VERIFY( pLoader->BeginPreload() ); mapAccessor->Second() = pLoader; } // PMD: I am not 100% sure this is all thread safe. I think it could break if: // - Thread 1 inserts a key/value of path and NULL, as above // - Thread 2 returns false from the insert so we come straight here // - Thread 2 tries to use pLoader before thread 1 assigns ploader to the value of the key // Note: If we did not do this assert here, we could potentially get nulls from this same thread later when // trying to find pLoader. // // Leaving it alone for now since I'm not sure, but if this assert gets tripped, we need to revisit this. // Easy fix may be to allocate and construct (but don't completely init) an LoosePackageLoader, and try // to insert that directly rather than the null above. If insert succeeds, finish, else ditch our loader // and grab the one out of the array LoosePackageLoader* pLoader = mapAccessor->Second(); HELIUM_ASSERT( pLoader ); return pLoader; }
int Helium::Execute( const tstring& command, tstring& output, bool showWindow ) { HANDLE hReadPipe; HANDLE hWritePipe; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; if( !CreatePipe( &hReadPipe, &hWritePipe, &sa, 0 ) ) { return -1; } STARTUPINFO si; memset( &si, 0, sizeof(si) ); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; si.wShowWindow = static_cast<int>( showWindow ); si.hStdOutput = hWritePipe; si.hStdError = hWritePipe; PROCESS_INFORMATION pi; memset( &pi, 0, sizeof( pi ) ); if( !CreateProcess( NULL, // filename (tchar_t*) command.c_str(), // command line for child NULL, // process security descriptor NULL, // thread security descriptor TRUE, // inherit handles? showWindow ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW, // creation flags NULL, // inherited environment address NULL, // startup dir; NULL = start in current &si, // pointer to startup info (input) &pi ) ) // pointer to process info (output) { ::CloseHandle( hReadPipe ); ::CloseHandle( hWritePipe ); return -1; } // close the write end of the pipe so the child will terminate it with EOF ::CloseHandle( hWritePipe ); // read from the pipe until EOF condition reached tchar_t buffer[80]; unsigned long count; tstringstream stream; BOOL success = TRUE; do { while ( success = ReadFile( hReadPipe, buffer, sizeof(buffer), &count, NULL ) ) { if( success ) { stream.write( buffer, count ); } else { if ( ::GetLastError() == ERROR_BROKEN_PIPE ) { break; } else { return -1; } } } } while( success && count ); // done reading, close our read pipe ::CloseHandle( hReadPipe ); // copy output string output = stream.str(); // get exit code DWORD result = 0; BOOL codeResult = ::GetExitCodeProcess( pi.hProcess, &result ); HELIUM_ASSERT( codeResult ); // close the process handle ::CloseHandle( pi.hProcess ); ::CloseHandle( pi.hThread ); return result; }
/// Compute the corners of this view frustum, outputting the result in separate arrays for each component. /// /// A view frustum can have either four or eight corners depending on whether a far clip plane exists (eight /// corners) or whether an infinite far clip plane is used (four corners). /// /// Note that this assumes that the frustum is always properly defined, with each possible combination of /// neighboring clip planes intersecting at a valid point. /// /// @param[out] pCornersX SIMD-aligned array in which the frustum corner x coordinates will be stored. This must /// point to a region of memory large enough for four points if this frustum has an infinite /// far clip plane, or eight points if this frustum has a normal far clip plane. /// @param[out] pCornersY SIMD-aligned array in which the frustum corner y coordinates will be stored. This must /// point to a region of memory large enough for four points if this frustum has an infinite /// far clip plane, or eight points if this frustum has a normal far clip plane. /// @param[out] pCornersZ SIMD-aligned array in which the frustum corner z coordinates will be stored. This must /// point to a region of memory large enough for four points if this frustum has an infinite /// far clip plane, or eight points if this frustum has a normal far clip plane. /// /// @return Number of clip planes computed (either four or eight). size_t Helium::Simd::Frustum::ComputeCornersSoa( float32_t* pCornersX, float32_t* pCornersY, float32_t* pCornersZ ) const { HELIUM_ASSERT( pCornersX ); HELIUM_ASSERT( pCornersY ); HELIUM_ASSERT( pCornersZ ); // Load the plane combinations used to compute the four corners on the near clip plane. Helium::Simd::Register plane0A = Helium::Simd::LoadAligned( m_planeA ); Helium::Simd::Register plane0B = Helium::Simd::LoadAligned( m_planeB ); Helium::Simd::Register plane0C = Helium::Simd::LoadAligned( m_planeC ); Helium::Simd::Register plane0D = Helium::Simd::LoadAligned( m_planeD ); Helium::Simd::Register plane1A = _mm_shuffle_ps( plane0A, plane0A, _MM_SHUFFLE( 0, 1, 3, 2 ) ); Helium::Simd::Register plane1B = _mm_shuffle_ps( plane0B, plane0B, _MM_SHUFFLE( 0, 1, 3, 2 ) ); Helium::Simd::Register plane1C = _mm_shuffle_ps( plane0C, plane0C, _MM_SHUFFLE( 0, 1, 3, 2 ) ); Helium::Simd::Register plane1D = _mm_shuffle_ps( plane0D, plane0D, _MM_SHUFFLE( 0, 1, 3, 2 ) ); Helium::Simd::Register plane2A = Helium::Simd::LoadSplat32( m_planeA + PLANE_NEAR ); Helium::Simd::Register plane2B = Helium::Simd::LoadSplat32( m_planeB + PLANE_NEAR ); Helium::Simd::Register plane2C = Helium::Simd::LoadSplat32( m_planeC + PLANE_NEAR ); Helium::Simd::Register plane2D = Helium::Simd::LoadSplat32( m_planeD + PLANE_NEAR ); // Compute all four near clip corners. Helium::Simd::Register detAB = _mm_sub_ps( _mm_mul_ps( plane0A, plane1B ), _mm_mul_ps( plane0B, plane1A ) ); Helium::Simd::Register detAC = _mm_sub_ps( _mm_mul_ps( plane0A, plane1C ), _mm_mul_ps( plane0C, plane1A ) ); Helium::Simd::Register detBC = _mm_sub_ps( _mm_mul_ps( plane0B, plane1C ), _mm_mul_ps( plane0C, plane1B ) ); Helium::Simd::Register detAD = _mm_sub_ps( _mm_mul_ps( plane0A, plane1D ), _mm_mul_ps( plane0D, plane1A ) ); Helium::Simd::Register detBD = _mm_sub_ps( _mm_mul_ps( plane0B, plane1D ), _mm_mul_ps( plane0D, plane1B ) ); Helium::Simd::Register detDC = _mm_sub_ps( _mm_mul_ps( plane0D, plane1C ), _mm_mul_ps( plane0C, plane1D ) ); // XXX: Denominator sign is flipped here to handle the fact our plane D component is the negative distance from // the origin (sign gets flipped when placed at the opposite side of the linear equation set for each plane when // solving). // // Our plane equation: // Ax + By + Cz + D = 0 /// // ...in the form needed for solving using Cramer's rule: // Ax + By + Cz = -D Helium::Simd::Register denominator = _mm_rcp_ps( _mm_sub_ps( _mm_mul_ps( plane2B, detAC ), _mm_add_ps( _mm_mul_ps( plane2A, detBC ), _mm_mul_ps( plane2C, detAB ) ) ) ); //Helium::Simd::Register cornerXVec = _mm_mul_ps( // _mm_add_ps( // _mm_sub_ps( // _mm_mul_ps( plane2D, detBC ), // _mm_mul_ps( plane2B, detDC ) ), // _mm_mul_ps( plane2C, detDB ) ), // denominator ); Helium::Simd::Register cornerXVec = _mm_mul_ps( _mm_sub_ps( // Note that we subtract... _mm_sub_ps( _mm_mul_ps( plane2D, detBC ), _mm_mul_ps( plane2B, detDC ) ), _mm_mul_ps( plane2C, detBD ) ), // ...because the 2x2 sub-matrix components are switched here. denominator ); Helium::Simd::Register cornerYVec = _mm_mul_ps( _mm_add_ps( _mm_sub_ps( _mm_mul_ps( plane2A, detDC ), _mm_mul_ps( plane2D, detAC ) ), _mm_mul_ps( plane2C, detAD ) ), denominator ); Helium::Simd::Register cornerZVec = _mm_mul_ps( _mm_add_ps( _mm_sub_ps( _mm_mul_ps( plane2A, detBD ), _mm_mul_ps( plane2B, detAD ) ), _mm_mul_ps( plane2D, detAB ) ), denominator ); Helium::Simd::StoreAligned( pCornersX, cornerXVec ); Helium::Simd::StoreAligned( pCornersY, cornerYVec ); Helium::Simd::StoreAligned( pCornersZ, cornerZVec ); // If this frustum has an infinite far clip plane, we are done. if( m_bInfiniteFarClip ) { return 4; } // Compute the far clip plane corners, reusing data from the near clip plane corner calculations where possible. plane2A = Helium::Simd::LoadSplat32( m_planeA + PLANE_FAR ); plane2B = Helium::Simd::LoadSplat32( m_planeB + PLANE_FAR ); plane2C = Helium::Simd::LoadSplat32( m_planeC + PLANE_FAR ); plane2D = Helium::Simd::LoadSplat32( m_planeD + PLANE_FAR ); denominator = _mm_rcp_ps( _mm_sub_ps( _mm_mul_ps( plane2B, detAC ), _mm_add_ps( _mm_mul_ps( plane2A, detBC ), _mm_mul_ps( plane2C, detAB ) ) ) ); //cornerXVec = _mm_mul_ps( // _mm_add_ps( // _mm_sub_ps( // _mm_mul_ps( plane2D, detBC ), // _mm_mul_ps( plane2B, detDC ) ), // _mm_mul_ps( plane2C, detDB ) ), // denominator ); cornerXVec = _mm_mul_ps( _mm_sub_ps( // Note that we subtract... _mm_sub_ps( _mm_mul_ps( plane2D, detBC ), _mm_mul_ps( plane2B, detDC ) ), _mm_mul_ps( plane2C, detBD ) ), // ...because the 2x2 sub-matrix components are switched here. denominator ); cornerYVec = _mm_mul_ps( _mm_add_ps( _mm_sub_ps( _mm_mul_ps( plane2A, detDC ), _mm_mul_ps( plane2D, detAC ) ), _mm_mul_ps( plane2C, detAD ) ), denominator ); cornerZVec = _mm_mul_ps( _mm_add_ps( _mm_sub_ps( _mm_mul_ps( plane2A, detBD ), _mm_mul_ps( plane2B, detAD ) ), _mm_mul_ps( plane2D, detAB ) ), denominator ); Helium::Simd::StoreAligned( pCornersX + 4, cornerXVec ); Helium::Simd::StoreAligned( pCornersY + 4, cornerYVec ); Helium::Simd::StoreAligned( pCornersZ + 4, cornerZVec ); return 8; }