コード例 #1
0
ファイル: Node.cpp プロジェクト: scott-nelson/fastbuild
// Load
//------------------------------------------------------------------------------
/*static*/ Node * Node::Load( IOStream & stream )
{
	// read type
	uint32_t nodeType;
	if ( stream.Read( nodeType ) == false )
	{
		return nullptr;
	}

    PROFILE_SECTION(Node::GetTypeName((Type)nodeType));

	// read stamp (but not for file nodes)
	uint64_t stamp( 0 );
	if ( nodeType != Node::FILE_NODE )
	{
		if ( stream.Read( stamp ) == false )
		{
			return nullptr;
		}
	}

	// read contents
	Node * n = nullptr;
	switch ( (Node::Type)nodeType )
	{
		case Node::PROXY_NODE:			ASSERT( false );						break;
		case Node::COPY_NODE:			n = CopyNode::Load( stream );			break;
		case Node::DIRECTORY_LIST_NODE: n = DirectoryListNode::Load( stream );	break;
		case Node::EXEC_NODE:			n = ExecNode::Load( stream );			break;
		case Node::FILE_NODE:			n = FileNode::Load( stream );			break;
		case Node::LIBRARY_NODE:		n = LibraryNode::Load( stream );		break;
		case Node::OBJECT_NODE:			n = ObjectNode::Load( stream );			break;
		case Node::ALIAS_NODE:			n = AliasNode::Load( stream );			break;
		case Node::EXE_NODE:			n = ExeNode::Load( stream );			break;
		case Node::CS_NODE:				n = CSNode::Load( stream );				break;
		case Node::UNITY_NODE:			n = UnityNode::Load( stream );			break;
		case Node::TEST_NODE:			n = TestNode::Load( stream );			break;
		case Node::COMPILER_NODE:		n = CompilerNode::Load( stream );		break;
		case Node::DLL_NODE:			n = DLLNode::Load( stream );			break;
		case Node::VCXPROJECT_NODE:		n = VCXProjectNode::Load( stream );		break;
		case Node::OBJECT_LIST_NODE:	n = ObjectListNode::Load( stream );		break;
		case Node::COPY_DIR_NODE:		n = CopyDirNode::Load( stream );		break;
		case Node::SLN_NODE:			n = SLNNode::Load( stream );			break;
		case Node::NUM_NODE_TYPES:		ASSERT( false );						break;
	}

	ASSERT( n );
	if ( n )
	{
		// set stamp
		n->m_Stamp = stamp;
	}

	return n;
}
コード例 #2
0
void ProcessAdjacentMapTiles(Path& thePath, Map* map, const IntVec2& start, const IntVec2& goal, TilePtrs& adjacentTilePtrs){
	PROFILE_SECTION();
	//7 for (adjacent List of PathNodes)
	for (TilePtrsIterator it = adjacentTilePtrs.begin(); it != adjacentTilePtrs.end(); ++it){
		Tile* tile = (*it);

		ProcessAdjacentMapTile(thePath, tile, map, start, goal);
		
	}//end of for
	
}
コード例 #3
0
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void MyWindow::display()
{
  WindowInertiaCamera::display();
  if(!s_pCurRenderer->valid())
  {
      glClearColor(0.5,0.0,0.0,0.0);
      glClear(GL_COLOR_BUFFER_BIT);
      swapBuffers();
      return;
  }
  float dt = (float)m_realtime.getTiming();
  //
  // render the scene
  //
  std::string stats;
  static std::string hudStats = "...";
  {
    nv_helpers::Profiler::FrameHelper helper(g_profiler,sysGetTime(), 2.0, stats);
    PROFILE_SECTION("display");

    s_pCurRenderer->display(m_camera, m_projection);
    //
    // additional HUD stuff
    //
    WindowInertiaCamera::beginDisplayHUD();
    s_helpText -= dt;
    m_oglTextBig.drawString(5, 5, "('h' for help)", 1, vec4f(0.8,0.8,1.0,0.5f).vec_array);
    float h = 30;
    if(s_bStats)
        h += m_oglTextBig.drawString(5, m_winSz[1]-h, hudStats.c_str(), 0, vec4f(0.8,0.8,1.0,0.5).vec_array);
    if(s_helpText > 0)
    {
        // camera help
        const char *txt = getHelpText();
        h += m_oglTextBig.drawString(5, m_winSz[1]-h, txt, 0, vec4f(0.8,0.8,1.0,s_helpText/HELPDURATION).vec_array);
        h += m_oglTextBig.drawString(5, m_winSz[1]-h, s_sampleHelp, 0, vec4f(0.8,0.8,1.0,s_helpText/HELPDURATION).vec_array);
    }
    WindowInertiaCamera::endDisplayHUD();
    {
      //PROFILE_SECTION("SwapBuffers");
      swapBuffers();
    }
  } //PROFILE_SECTION("display");
  //
  // Stats
  //
  if (s_bStats && (!stats.empty()))
  {
    hudStats = stats; // make a copy for the hud display
  }

}
コード例 #4
0
ファイル: GameApp.cpp プロジェクト: hulcyp/GuildhallProjects
	//-------------------------------------------------------------------------------
	void GameApp::updateDisplay()
	{
		PROFILE_SECTION( "GameApp" );
		glClearColor( 0.2f, 0.2f, 0.2f, 1.0f );
		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
		m_renderer->pushCamera( m_camera );
		if( m_camera )
		{
			m_camera->update( DELTA_TIME );
		}
		//m_renderer->setWireFrame( m_wireFrame );
		m_actorManager.renderActors();
		renderDebugHUD();
		//m_GDOManager->renderGDOs( m_renderer, m_frameClock.getElapsedSecondsFloat() );
		m_renderer->popCamera();
		ProfileSystem::getInstance()->clearFrameData();		
	}
コード例 #5
0
ファイル: Client.cpp プロジェクト: scott-nelson/fastbuild
// CommunicateJobAvailability
//------------------------------------------------------------------------------
void Client::CommunicateJobAvailability()
{
	// too soon since last status update?
	if ( m_StatusUpdateTimer.GetElapsed() < CLIENT_STATUS_UPDATE_FREQUENCY_SECONDS )
	{
		return;
	}

	m_StatusUpdateTimer.Start(); // reset time

	// possible for job queue to not exist yet
	if ( !JobQueue::IsValid() )
	{
		return;
	}

	// has status changed since we last sent it?
	uint32_t numJobsAvailable = (uint32_t)JobQueue::Get().GetNumDistributableJobsAvailable();
	Protocol::MsgStatus msg( numJobsAvailable );

	MutexHolder mh( m_ServerListMutex );
	if ( m_ServerList.IsEmpty() )
	{
		return; // no servers to communicate with
	}

	// update each server to know how many jobs we have now
	ServerState * it = m_ServerList.Begin();
	const ServerState * const end = m_ServerList.End();
	while ( it != end )
	{
		if ( it->m_Connection )
		{
			MutexHolder ssMH( it->m_Mutex );
			if ( it->m_NumJobsAvailable != numJobsAvailable )
			{
                PROFILE_SECTION( "UpdateJobAvailability" )
				msg.Send( it->m_Connection );
				it->m_NumJobsAvailable = numJobsAvailable;
			}
		}
		++it;
	}
}
コード例 #6
0
//much slower than the regular one
void RecursiveCalcPath(Path& thePath, Map* map, const IntVec2& start, const IntVec2& goal, bool ignoreEntities){
	PROFILE_SECTION();
	if (!thePath.m_initialized && map){
		thePath = Path(map, start, goal); //this adds a start node to open list
	}
	
	if (!thePath.IsOpenListEmpty() && !thePath.m_isComplete){
		thePath = ProcessOneStepOfPath(thePath, map, start, goal, ignoreEntities);

		RecursiveCalcPath(thePath, map, start, goal, ignoreEntities);

	}
	else{

		return;

	}


}
コード例 #7
0
ファイル: WorkerThread.cpp プロジェクト: zhangf911/fastbuild
// Main
//------------------------------------------------------------------------------
/*virtual*/ void WorkerThread::Main()
{
	while ( ( m_ShouldExit == false ) && ( FBuild::GetStopBuild() == false ) )
	{
		PROFILE_FUNCTION

		bool didSomeWork = Update();
		if ( didSomeWork )
		{
			continue; // try to build some more
		}

		// no work to do right now
		{
			PROFILE_SECTION( "WorkerThread::Main::Sleep" )
			Thread::Sleep( 1 ); // wait and try again later
		}
	}

	m_Exited = true;
}
コード例 #8
0
ファイル: FLog.cpp プロジェクト: dontnod/fastbuild
// Monitor
//------------------------------------------------------------------------------
/*static*/ void FLog::Monitor( const char * formatString, ... )
{
    // Is monitoring enabled?
    if ( g_MonitorFileStream == nullptr )
    {
        return; // No - nothing to do
    }

    PROFILE_SECTION( "FLog::Monitor" )

    AStackString< 1024 > buffer;
    va_list args;
    va_start( args, formatString );
    buffer.VFormat( formatString, args );
    va_end( args );

    AStackString< 1024 > finalBuffer;
    finalBuffer.Format( "%llu %s", Time::GetCurrentFileTime(), buffer.Get() );

    MutexHolder lock( g_MonitorMutex );
    g_MonitorFileStream->WriteBuffer( finalBuffer.Get(), finalBuffer.GetLength() );
}
コード例 #9
0
//A* Pathfinding Algorithm
//pass in a blank myPath to be filled
Path& CalcPath(Path& thePath, Map* map, const MapPosition& start, const MapPosition& goal, bool ignoreEntities){
	PROFILE_SECTION();

	if (!thePath.m_initialized && map){
		thePath = Path(map, start, goal); //this adds a start node to open list
	}
	
	//find the path and stuff
	while (!thePath.IsOpenListEmpty() && !thePath.m_isComplete){

		ProcessOneStepOfPath(thePath, map, start, goal, ignoreEntities);

	}//end of while
	
	if (thePath.IsOpenListEmpty() && !thePath.m_isComplete){
		thePath.m_isImpossible = true;
	}
	
	//17 return the path
	return thePath;

}//end of calc path
コード例 #10
0
ファイル: Args.cpp プロジェクト: JeremieA/fastbuild
// Finalize
//------------------------------------------------------------------------------
bool Args::Finalize( const AString & exe, const AString & nodeNameForError, bool canUseResponseFile )
{
	ASSERT( !m_Finalized );

	#if defined( __WINDOWS__ ) || defined( __OSX__ )
		#if defined( __WINDOWS__ )
			// Windows has a 32KiB (inc null terminator) command line length limit with CreateProcess
			// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
			const uint32_t argLimit( 32767 );
		#elif defined( __OSX__ )
			const uint32_t argLimit( ARG_MAX - 1 );		
		#endif
	
		// Calculate final length of args (including exe name)
		const uint32_t exeLen = exe.GetLength();
		const uint32_t extraLen = 3; // quotes around exe name and space
		const uint32_t argLen = m_Args.GetLength();

		// We need to consider the executable, quotes around the exe and a space 
		// as well as the args: "%exe%" %args%
		const uint32_t totalLen = ( argLen + exeLen + extraLen );

		// Small enough?
		if ( totalLen <= argLimit )
		{
			#if defined( ASSERTS_ENABLED )
				m_Finalized = true;
			#endif
			return true; // Ok to proceed
		}

		// Args are too long. Can we cope using a Response File?
		if ( canUseResponseFile )
		{
			// Handle per-line limit within response files (e.g. link.exe)
			#if defined( __WINDOWS__ )
				if ( argLen >= 131071 ) // From LNK1170
				{
					// Change spaces to carriage returns
					for ( uint32_t i : m_DelimiterIndices )
					{
						ASSERT( m_Args[ i ] == ' ' );
						m_Args[ i ] = '\n';
					}
				}
			#endif

			#if defined( ASSERTS_ENABLED )
				m_Finalized = true;
			#endif

			// Write args to response file
			{
				PROFILE_SECTION( "CreateResponseFile" )
				m_ResponseFile.Create( *this );
			}

			// Create new args referencing response file
			m_ResponseFileArgs = "@\"";
			m_ResponseFileArgs += m_ResponseFile.GetResponseFilePath();
			m_ResponseFileArgs += "\"";

			return true; // Ok to proceed
		}

		// Need response file but not supported
		FLOG_ERROR( "FBuild: Error: Command Line Limit Exceeded (len: %u, limit: %u) '%s'\n", argLen, argLimit, nodeNameForError.Get() );
		return false;
	#elif defined( __LINUX__ )
		// TODO:LINUX Difficult to reliable determine this due to complex interaction with environment
		#if defined( ASSERTS_ENABLED )
			m_Finalized = true;
		#endif
		return true; // Ok to proceed
	#endif
}
コード例 #11
0
Path& ProcessOneStepOfPath(Path& thePath, Map* map, const IntVec2& start, const IntVec2& goal, bool ignoreEntities ){
	PROFILE_SECTION();
	if (!thePath.m_initialized && map){
		thePath = Path(map, start, goal);
	}
	
	if (!thePath.IsOpenListEmpty() && !thePath.m_isComplete){

		thePath.m_iterations++;

		PROFILE_START(steps 1 to 4);
		//1 pick lowest f on openList check
		//2 remove from open list check
		PathNode* lowestFCostInThePath = thePath.PopLowestFCostInOpenList();

		//3 add lowest cost to closed list check
		Tile* tileToCheckID = map->GetTileAtMapPosition(lowestFCostInThePath->m_position);
		tilesPathIDOpenCritSec.Enter();
		tileToCheckID->m_inOpenListOfPathID = -1;
		tilesPathIDOpenCritSec.Exit();

		//tilesPathIDCritSec.Enter();
		if (tileToCheckID->m_inClosedListOfPathID != thePath.m_id){
			
			thePath.AddToClosedList(lowestFCostInThePath);
			CRITICAL_SECTION_SCOPE(tilesPathIDClosedCritSec);
			tileToCheckID->m_inClosedListOfPathID = thePath.m_id;
		}
		//tilesPathIDCritSec.Exit();

// 		if (!thePath.IsMapPositionInClosedList(lowestFCostInThePath->m_position)){
// 
// 			thePath.AddToClosedList(lowestFCostInThePath);
// 
// 		}

		//4 set lowest f node to active
		thePath.m_activeNode = lowestFCostInThePath;
		PROFILE_STOP();

		//5 check if node is goal, break;
		if (thePath.m_activeNode->m_position == goal){
			thePath.m_isComplete = true;
			//ConsoleGenericMessageBox("YAY Path is found.");

			thePath.m_openList.clear();

			return thePath;
		}
		else{
			TilePtrs adjacentTilePtrs;
			PROFILE_START(step 6);
			//6 ask "map" for adjacent positions of active node
			Tile* activeTile = map->GetTileAtMapPosition(thePath.m_activeNode->m_position);
			if (activeTile){
				adjacentTilePtrs = map->GetValidAdjacentTiles(activeTile, ignoreEntities);
			}
			PROFILE_STOP();

			//this is the longest part of pathing
			ProcessAdjacentMapTiles(thePath, map, start, goal, adjacentTilePtrs);

		}

	}//end of final outer if
	
// 	else if (thePath.IsOpenListEmpty()){
// 		//ConsoleGenericMessageBox("No Path =(");
// 
// 		//the path is impossible
// 		thePath.m_isImpossible = true;
// 
// 		return thePath;
// 	}
	
	return thePath;
}
コード例 #12
0
void ProcessAdjacentMapTile(Path& thePath, Tile* tile, Map* map, const IntVec2& start, const IntVec2& goal ){
	UNUSED(start);

	PROFILE_SECTION();
	if (tile == NULL)
		return;

	//8 Get adjacent pos
	MapPosition& adjacentNodePos = tile->m_mapPosition;

	//float newFinalCostCheck = newPathNode->m_nodeCost.h;
	//if (newFinalCostCheck < 2.0f * map->m_size.x * map->m_size.y){

	//9 if (adjacent pos on closed list) //continue;

	Tile* tileToCheckID = map->GetTileAtMapPosition(adjacentNodePos);
	bool tileCheckID;
	//tilesPathIDCritSec.Enter();
	tileCheckID = (tileToCheckID->m_inClosedListOfPathID == thePath.m_id);
	//tilesPathIDCritSec.Exit();
	if (tileCheckID){
	//if (thePath.IsMapPositionInClosedList(adjacentNodePos)){
		return;
	}
	else{
		//10 & 11 decently fast
		// 10 if (not on open list){ 
		if(tileToCheckID->m_inOpenListOfPathID != thePath.m_id){
		//if (!thePath.IsMapPositionInOpenList(adjacentNodePos)){
			PROFILE_START(step 10 and 11);
			//11 build new pathnode(local G, parentG = ActiveNode.G) //	Add to OpenList
			PathNode* newPathNode = new PathNode(tile, thePath.m_activeNode, goal, thePath.m_bestAvoidCost); //this bit of path node has a memory leak
	
			thePath.AddToOpenList(newPathNode);

			tilesPathIDOpenCritSec.Enter();
			tile->m_inOpenListOfPathID = thePath.m_id;
			tilesPathIDOpenCritSec.Exit();

			PROFILE_STOP();
			return;
		}
		else{
			//is on openList
			float altTotalG;
			float tileAvoidCost;
			float currentG;
			PathNode* nodeInOpenList;

			PROFILE_START(step 12 and 13); //doesn't seem to ever get called
			tileAvoidCost = tile->m_tileAvoidanceCost;
			nodeInOpenList = thePath.GetPathNodeAtMapPositionFromOpenList(adjacentNodePos);
			if (!nodeInOpenList){
				return;
			}
			//12 calc newG as calc hypothetical G to this node
			altTotalG = CalcHypotheticalGCostToAdjacentNodePosition(thePath.m_activeNode, adjacentNodePos, tileAvoidCost);
			//13 compare to G in openList for node holding this position	
			currentG = nodeInOpenList->m_nodeCost.g;
			PROFILE_STOP();
			
			//14 if better <
			if (altTotalG < currentG){
				//15 update openListNode, update localG, parent, 
				PROFILE_START(step 15);
				ReplaceOpenListPathNode(thePath, nodeInOpenList, tileAvoidCost);
				PROFILE_STOP();
				return;
			}
			else{
				//16 if worse or equal >= //throw out
				return;
			}//end of inside if/else

		}//end of if/else

	}//end of outer if/else

}
コード例 #13
0
// MainThreadWait
//------------------------------------------------------------------------------
void JobQueueRemote::MainThreadWait( uint32_t timeoutMS )
{
	PROFILE_SECTION( "MainThreadWait" )
	m_MainThreadSemaphore.Wait( timeoutMS );
}
コード例 #14
0
// DoBuild
//------------------------------------------------------------------------------
/*static*/ Node::BuildResult JobQueueRemote::DoBuild( Job * job, bool racingRemoteJob )
{
	Timer timer; // track how long the item takes

	ObjectNode * node = job->GetNode()->CastTo< ObjectNode >();

	// remote tasks must output to a tmp file
	if ( job->IsLocal() == false )
	{
		// file name should be the same as on host
		const char * fileName = ( job->GetRemoteName().FindLast( NATIVE_SLASH ) + 1 );

		AStackString<> tmpFileName;
		WorkerThread::CreateTempFilePath( fileName, tmpFileName );
		node->ReplaceDummyName( tmpFileName );

		#ifdef DEBUG
			DEBUGSPAM( "REMOTE: %s (%s)\n", fileName, job->GetRemoteName().Get() );
		#endif
	}

	ASSERT( node->IsAFile() );

	// make sure the output path exists
	if ( Node::EnsurePathExistsForFile( node->GetName() ) == false )
	{
		// error already output by EnsurePathExistsForFile
		return Node::NODE_RESULT_FAILED;
	}

	// Delete any left over PDB from a previous run (to be sure we have a clean pdb)
	if ( node->IsUsingPDB() && ( job->IsLocal() == false ) )
	{
		AStackString<> pdbName;
		node->GetPDBName( pdbName );
		FileIO::FileDelete( pdbName.Get() );
	}

    Node::BuildResult result;
    {
        PROFILE_SECTION( racingRemoteJob ? "RACE" : "LOCAL" );
    	result = ((Node *)node )->DoBuild2( job, racingRemoteJob );
    }

	uint32_t timeTakenMS = uint32_t( timer.GetElapsedMS() );

	if ( result == Node::NODE_RESULT_OK )
	{
		// record new build time only if built (i.e. if failed, the time
		// does not represent how long it takes to create this resource)
		node->SetLastBuildTime( timeTakenMS );
		node->SetStatFlag( Node::STATS_BUILT );
		//FLOG_INFO( "-Build: %u ms\t%s", timeTakenMS, node->GetName().Get() );

		#ifdef DEBUG
			if ( job->IsLocal() )
			{
				// record new file time for remote job we built locally
				ASSERT( node->m_Stamp == FileIO::GetFileLastWriteTime(node->GetName()) );
			}
		#endif
	}

	if ( result == Node::NODE_RESULT_FAILED )
	{
		// build of file failed - if there is a file....
		if ( FileIO::FileExists( node->GetName().Get() ) )
		{
			// ... it is invalid, so try to delete it
			if ( FileIO::FileDelete( node->GetName().Get() ) == false )
			{
				// failed to delete it - this might cause future build problems!
				FLOG_ERROR( "Post failure deletion failed for '%s'", node->GetName().Get() );
			}
		}
	}
	else
	{
		// build completed ok, or retrieved from cache...
		ASSERT( result == Node::NODE_RESULT_OK );

		// TODO:A Also read into job if cache is being used
		if ( job->IsLocal() == false )
		{
			// read results into memory to send back to client	
			if ( ReadResults( job ) == false )
			{	
				result = Node::NODE_RESULT_FAILED;
			}
		}
	}

	// if compiling to a tmp file, do cleanup	
	if ( job->IsLocal() == false )
	{
		// Cleanup obj file
		FileIO::FileDelete( node->GetName().Get() );

		// Cleanup PDB file
		if ( node->IsUsingPDB() )
		{
			AStackString<> pdbName;
			node->GetPDBName( pdbName );
			FileIO::FileDelete( pdbName.Get() );
		}
	}

	// log processing time
	node->AddProcessingTime( timeTakenMS );
	
	return result;
}
コード例 #15
0
// WorkerThreadWait
//------------------------------------------------------------------------------
void JobQueueRemote::WorkerThreadWait( uint32_t timeoutMS )
{
	PROFILE_SECTION( "WorkerThreadWait" )
	m_WorkerThreadSemaphore.Wait( timeoutMS );
}
コード例 #16
0
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void RendererVk::display(const InertiaCamera& camera, const mat4f& projection)
{
    PROFILE_SECTION("RendererVk::display");
    if(m_bValid == false) return;
    //NXPROFILEFUNC(__FUNCTION__);
    //
    // Update general params for all sub-sequent operations IN CMD BUFFER #1
    //
    g_globalMatrices.mV = camera.m4_view;
    g_globalMatrices.mP = projection;
    float w = (float)m_nvFBOBox.getBufferWidth();
    float h = (float)m_nvFBOBox.getBufferHeight();
    VkRenderPass    renderPass  = m_nvFBOBox.getScenePass();
    VkFramebuffer   framebuffer = m_nvFBOBox.getFramebuffer();
    NVK::VkRect2D   viewRect    = m_nvFBOBox.getViewRect();
    //
    // Create the primary command buffer
    //
    //
    // pingpong between 2 cmd-buffers to avoid waiting for them to be done
    //
    m_cmdSceneIdx ^= 1;
    if(m_cmdScene[m_cmdSceneIdx])
    {
        while(nvk.vkWaitForFences(1, &m_sceneFence[m_cmdSceneIdx], VK_TRUE, 100000000) == false) { }
        nvk.vkResetFences(1, &m_sceneFence[m_cmdSceneIdx]);
        nvk.vkFreeCommandBuffer(m_cmdPool, m_cmdScene[m_cmdSceneIdx]);
        m_cmdScene[m_cmdSceneIdx] = NULL;
    }
    m_cmdScene[m_cmdSceneIdx] = nvk.vkAllocateCommandBuffer(m_cmdPool, true);
    nvk.vkBeginCommandBuffer(m_cmdScene[m_cmdSceneIdx], false, NVK::VkCommandBufferInheritanceInfo(renderPass, 0, framebuffer, VK_FALSE, 0, 0) );
    vkCmdBeginRenderPass(m_cmdScene[m_cmdSceneIdx],
        NVK::VkRenderPassBeginInfo(
        renderPass, framebuffer, viewRect,
            NVK::VkClearValue(NVK::VkClearColorValue(0.0f, 0.1f, 0.15f, 1.0f))
                             (NVK::VkClearDepthStencilValue(1.0, 0))), 
        VK_SUBPASS_CONTENTS_INLINE );
    vkCmdUpdateBuffer       (m_cmdScene[m_cmdSceneIdx], m_matrix.buffer, 0, sizeof(g_globalMatrices), (uint32_t*)&g_globalMatrices);
    //
    // render the mesh
    //
    vkCmdBindPipeline(m_cmdScene[m_cmdSceneIdx], VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelinefur); 
    vkCmdSetViewport( m_cmdScene[m_cmdSceneIdx], 0, 1, NVK::VkViewport(0.0, 0.0, w, h, 0.0f, 1.0f) );
    vkCmdSetScissor(  m_cmdScene[m_cmdSceneIdx], 0, 1, NVK::VkRect2D(0.0, 0.0, w, h) );
    VkDeviceSize vboffsets[1] = {0};
    vkCmdBindVertexBuffers(m_cmdScene[m_cmdSceneIdx], 0, 1, &m_furBuffer.buffer, vboffsets);
    //
    // bind the descriptor set for global stuff
    //
    vkCmdBindDescriptorSets(m_cmdScene[m_cmdSceneIdx], VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, DSET_GLOBAL, 1, &m_descriptorSetGlobal, 0, NULL);

    vkCmdDraw(m_cmdScene[m_cmdSceneIdx], m_nElmts, 1, 0, 0);
    //
    //
    //
    vkCmdEndRenderPass(m_cmdScene[m_cmdSceneIdx]);
    vkEndCommandBuffer(m_cmdScene[m_cmdSceneIdx]);

    const VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    nvk.vkQueueSubmit( NVK::VkSubmitInfo(
        1, &m_semOpenGLReadDone, &waitStages,
        1, &m_cmdScene[m_cmdSceneIdx], 
        1, &m_semVKRenderingDone),  
      m_sceneFence[m_cmdSceneIdx]
    );
    //
    // this is going to issue another command-buffer
    //
    m_nvFBOBox.Draw(downsamplingMode);

    w = m_nvFBOBox.getWidth();
    h = m_nvFBOBox.getHeight();
    // NO Depth test
    glDisable(GL_DEPTH_TEST);
    //
    // Wait for the queue of Our VK rendering to signal m_semVKRenderingDone so we know the image is ready
    //
    glWaitVkSemaphoreNV((GLuint64)m_semVKRenderingDone);
    //
    // Blit the image
    //
    glDrawVkImageNV((GLuint64)m_nvFBOBox.getColorImage(), 0, 0,0,w,h, 0, 0,1,1,0);
    //
    // Signal m_semOpenGLReadDone to tell the VK rendering queue that it can render the next one
    //
    glSignalVkSemaphoreNV((GLuint64)m_semOpenGLReadDone);
    //
    // Depth test back to ON (assuming we needed to put it back)
    //
    glEnable(GL_DEPTH_TEST);
}