const StlVectorSet<VarOpnd *> *getChangedVarsSet() { if (changedVars.empty()) { return 0; } else { if (removedPhiRecently) { changedVarsSet.clear(); changedVarsSet.insert(changedVars.begin(), changedVars.end()); removedPhiRecently = false; } return &changedVarsSet; } };
void RenderingContext::DrawInParallel( StlVector<std::shared_ptr<RenderingContext>>& contexts, const StlVector<std::shared_ptr<IMesh>>& meshes, int meshCount, FuncPreRender funcPreRender ) { if ( meshes.empty() ) { return; } if ( contexts.empty() ) { LOG_WARNING( "no contexts" ); return; } // Validate the specified rendering contexts. for ( auto context : contexts ) { if ( context == nullptr ) { LOG_WARNING( "forbidden null context usage" ); return; } } if ( meshes.size() < static_cast<size_t>( meshCount ) ) { LOG_WARNING( "invalid mesh count" ); return; } // If the number of meshes is less than 4, // draw all meshes on the first context without parallel processing. if ( meshCount < Thread::HardwareConcurrency() ) { auto context = contexts[0]; for ( const auto& mesh : meshes ) { context->Draw( mesh ); } return; } RenderingDevice* pDevice = RenderingDevice::GetInstance(); Assert( pDevice ); size_t numContexts = contexts.size(); // Note that the world matrix would be multiplied just before drawing a mesh // because the world matrix of a mesh is different each other. // So premultiply view-projection matrices only. Matrix4 viewProj = pDevice->GetViewMatrix() * pDevice->GetProjectionMatrix(); // Thread objects. ThreadPool* threadPool = ThreadPool::GetInstance(); Atomic<int> workIndex( 0 ); for ( size_t c = 0; c < numContexts; ++c ) { auto context = contexts[c]; Assert( context ); auto task = std::bind( [=, &workIndex]( std::shared_ptr<RenderingContext> context, Matrix4 viewProj, FuncPreRender funcPreRender ) { SCOPE_PROFILE_BEGIN( "RenderTask" ); ConstantBuffer& cbuffer = context->GetSharedConstantBuffer(); // Until the last index... while ( workIndex.Value() < meshCount ) { // Prefech the workIndex to avoid changing the value on other thread, and then increment the workIndex. int index = workIndex.FetchAndIncrement(); // Check the index again to guarantee atomic. // FIXME: Is this necessary? if ( index >= meshCount ) { return; } // Call the PreRender functor. funcPreRender( context, index ); // Now compute the final WVP matrix of this mesh. Matrix4 wvp = cbuffer.GetMatrix4( ConstantBuffer::WorldMatrix ) * viewProj; cbuffer.SetMatrix4( ConstantBuffer::WVPMatrix, wvp ); // Draw the mesh. context->Draw( meshes[index] ); } SCOPE_PROFILE_END(); }, context, viewProj, funcPreRender ); threadPool->Queue( task ); } // Join all rendering threads. SCOPE_PROFILE_BEGIN( "JoinRendering" ); threadPool->WaitForAllTasks(); SCOPE_PROFILE_END(); //// Resolve the UAV to display using the main context. //// We assume that rendering order is independent. //SCOPE_PROFILE_BEGIN( "ResolveUnorderedAccessView " ); //contexts[0]->ResolveUnorderedAccessViews( contexts ); //SCOPE_PROFILE_END(); }