// Save/Load to XML void ArTrackOrientation::_writeXML(ArRef<XmlNode> node) const { node->setName("TrackOrientation"); node->setPropertyReal("duration",_track->getDuration()); node->setPropertyInteger("degree",_track->getDegree()); node->setPropertyInteger("dimension",4); ArTrackOrientationInterpolator *track=(ArTrackOrientationInterpolator *)_track; StlVector<unsigned> keysPositions; track->getKeysPositions(keysPositions); VectorN<double,4> key; for (unsigned i=0;i<keysPositions.size();i++) { track->getKeyFrame(keysPositions[i],key ); ArRef<XmlNode> keyFrame=node->addChild("KeyFrameOrientation"); keyFrame->setPropertyInteger("frame",keysPositions[i]); Quaterniond q(key[0],key[1],key[2],key[3]); Vector3d axis; double angle; q.getAxisAngle(axis,angle); keyFrame->setPropertyReal("vx",axis.x()); keyFrame->setPropertyReal("vy",axis.y()); keyFrame->setPropertyReal("vz",axis.z()); keyFrame->setPropertyReal("angle",angle); } }
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(); }
KIHX_API void kiRenderToBuffer( void* buffer, int width, int height, int bpp ) { if ( buffer == nullptr ) { return; } __UNDONE( temporal testing code ); // Create color and depth stencil buffers. ColorFormat colorFormat = kih::GetSuitableColorFormatFromBpp( bpp ); static std::shared_ptr<Texture> renderTarget = Texture::Create( width, height, colorFormat, buffer ); static std::shared_ptr<Texture> depthStencil = Texture::Create( width, height, ColorFormat::D32F, NULL ); static std::shared_ptr<UnorderedAccessView<OutputMergerInputStream>> omUAV = std::make_shared<UnorderedAccessView<OutputMergerInputStream>>( width * height * 2 ); // Create rendering contexts as many of Thread::HardwareConcurrency. const int Concurrency = 8; // HACK static std::array<std::shared_ptr<RenderingContext>, Concurrency> contexts; if ( contexts[0] == nullptr ) { int index = 0; LoopUnroll<Concurrency>::Work( [&index]() { auto context = RenderingDevice::GetInstance()->CreateRenderingContext(); context->SetViewport( 0, 0, static_cast<unsigned short>( renderTarget->Width() ), static_cast<unsigned short>( renderTarget->Height() ) ); context->SetFixedPipelineMode( false ); context->SetRenderTarget( renderTarget, 0 ); context->SetDepthStencil( depthStencil ); contexts[index++] = context; } ); } auto context = contexts[0]; context->Clear( 0, 0, 0, 255 ); context->SetUnorderedAccessView( nullptr ); // Draw the world. const Matrix4& matWorld = RenderingDevice::GetInstance()->GetWorldMatrix(); // Grid arragement if ( grid_scene.Bool() ) { // threading or not if ( concurrency.Int() <= 1 ) { DrawGridScene( context, matWorld ); } else { // Copy array contexts to vector one. StlVector<std::shared_ptr<RenderingContext>> concurrencyContexts; concurrencyContexts.resize( concurrency.Int() - 1 ); // the other thread is for resolve. for ( size_t i = 0; i < concurrencyContexts.size(); ++i ) { contexts[i]->SetUnorderedAccessView( omUAV ); concurrencyContexts[i] = contexts[i]; } DrawGridSceneInParallel( concurrencyContexts, matWorld ); } } else { context->GetSharedConstantBuffer().SetMatrix4( ConstantBuffer::WorldMatrix, matWorld ); context->GetSharedConstantBuffer().SetVector4( ConstantBuffer::DiffuseColor, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) ); context->Draw( GetMeshes()[0] ); } }