// Initialize rendering components and render a frame. IRendererController::Status initialize_and_render_frame() { // Construct an abort switch that will allow to abort initialization or rendering. RendererControllerAbortSwitch abort_switch(*m_renderer_controller); // Create the texture store. TextureStore texture_store( *m_project.get_scene(), m_params.child("texture_store")); // Initialize OSL's shading system. if (!initialize_osl_shading_system(texture_store, abort_switch) || abort_switch.is_aborted()) { // If it wasn't an abort, it was a failure. return abort_switch.is_aborted() ? m_renderer_controller->get_status() : IRendererController::AbortRendering; } // Let scene entities perform their pre-render actions. Don't proceed if that failed. // This is done before creating renderer components because renderer components need // to access the scene's render data such as the scene's bounding box. OnRenderBeginRecorder recorder; if (!m_project.get_scene()->on_render_begin(m_project, nullptr, recorder, &abort_switch) || abort_switch.is_aborted()) { recorder.on_render_end(m_project); return m_renderer_controller->get_status(); } // Create renderer components. RendererComponents components( m_project, m_params, m_tile_callback_factory, texture_store, *m_texture_system, *m_shading_system); if (!components.create()) { recorder.on_render_end(m_project); return IRendererController::AbortRendering; } // Print renderer components settings. components.print_settings(); // Report whether Embree is used or not. #ifdef APPLESEED_WITH_EMBREE const bool use_embree = m_params.get_optional<bool>("use_embree", false); m_project.set_use_embree(use_embree); #else const bool use_embree = false; #endif if (use_embree) RENDERER_LOG_INFO("using Intel Embree ray tracing kernel."); else RENDERER_LOG_INFO("using built-in ray tracing kernel."); // Updating the trace context causes ray tracing acceleration structures to be updated or rebuilt. m_project.update_trace_context(); // Load the checkpoint if any. Frame& frame = *m_project.get_frame(); const size_t pass_count = m_params.get_optional<size_t>("passes", 1); if (!frame.load_checkpoint(&components.get_shading_result_framebuffer_factory(), pass_count)) { recorder.on_render_end(m_project); return IRendererController::AbortRendering; } // Let renderer components perform their pre-render actions. Don't proceed if that failed. if (!components.on_render_begin(recorder, &abort_switch) || abort_switch.is_aborted()) { recorder.on_render_end(m_project); return m_renderer_controller->get_status(); } // Execute the main rendering loop. const auto status = render_frame(components, abort_switch); // Perform post-render actions. recorder.on_render_end(m_project); // End light path recording. const CanvasProperties& props = m_project.get_frame()->image().properties(); m_project.get_light_path_recorder().finalize( props.m_canvas_width, props.m_canvas_height); // Print texture store performance statistics. RENDERER_LOG_DEBUG("%s", texture_store.get_statistics().to_string().c_str()); return status; }
IRendererController::Status MasterRenderer::initialize_and_render_frame_sequence() { assert(m_project.get_scene()); assert(m_project.get_frame()); // Reset the abort switch. if (m_abort_switch) m_abort_switch->clear(); #ifdef WITH_OSL // Create the error handler. OIIOErrorHandler error_handler; // While debugging, we want all possible outputs. #ifndef NDEBUG error_handler.verbosity(OIIO::ErrorHandler::VERBOSE); #endif const size_t texture_cache_size = m_params.get_optional<size_t>("texture_cache_size", 256 * 1024 * 1024); // If the texture cache size changes, we have to recreate the texture system. if (texture_cache_size != m_texture_cache_size) { m_texture_cache_size = texture_cache_size; m_texture_system.reset(); } // Create the OIIO texture system, if needed. if (!m_texture_system) { m_texture_system.reset( OIIO::TextureSystem::create(false), bind(&OIIO::TextureSystem::destroy, _1)); } // Set the texture system mem limit. m_texture_system->attribute("max_memory_MB", static_cast<float>(m_texture_cache_size / 1024)); std::string search_paths; // Skip search paths for builtin projects. if (m_project.search_paths().has_root_path()) { // Setup texture / shader search paths. // In OIIO / OSL, the path priorities are the opposite of appleseed, // so we copy the paths in reverse order. const filesystem::path root_path = m_project.search_paths().get_root_path(); if (!m_project.search_paths().empty()) { for (size_t i = 0, e = m_project.search_paths().size(); i != e; ++i) { filesystem::path p(m_project.search_paths()[e - 1 - i]); if (p.is_relative()) p = root_path / p; search_paths.append(p.string()); search_paths.append(";"); } } search_paths.append(root_path.string()); } if (!search_paths.empty()) m_texture_system->attribute("searchpath", search_paths); // TODO: set other texture system options here. // Create our renderer services. RendererServices services(m_project, *m_texture_system); // Create our OSL shading system. boost::shared_ptr<OSL::ShadingSystem> shading_system( OSL::ShadingSystem::create( &services, m_texture_system.get(), &error_handler), bind(&destroy_osl_shading_system, _1, m_texture_system.get())); if (!search_paths.empty()) shading_system->attribute("searchpath:shader", search_paths); shading_system->attribute("lockgeom", 1); shading_system->attribute("colorspace", "Linear"); shading_system->attribute("commonspace", "world"); // This array needs to be kept in sync with the ShadingRay::Type enumeration. static const char* ray_type_labels[] = { "camera", "light", "shadow", "probe", "diffuse", "glossy", "specular" }; shading_system->attribute( "raytypes", OSL::TypeDesc( OSL::TypeDesc::STRING, sizeof(ray_type_labels) / sizeof(ray_type_labels[0])), ray_type_labels); #ifndef NDEBUG // While debugging, we want all possible outputs. shading_system->attribute("debug", 1); shading_system->attribute("statistics:level", 1); shading_system->attribute("compile_report", 1); shading_system->attribute("countlayerexecs", 1); shading_system->attribute("clearmemory", 1); #endif register_closures(*shading_system); #endif // WITH_OSL // We start by binding entities inputs. This must be done before creating/updating the trace context. if (!bind_scene_entities_inputs()) return IRendererController::AbortRendering; m_project.create_aov_images(); m_project.update_trace_context(); const Scene& scene = *m_project.get_scene(); Frame& frame = *m_project.get_frame(); frame.print_settings(); const TraceContext& trace_context = m_project.get_trace_context(); // Create the texture store. TextureStore texture_store(scene, m_params.child("texture_store")); // Create the light sampler. LightSampler light_sampler(scene, m_params.child("light_sampler")); // Create the shading engine. ShadingEngine shading_engine(m_params.child("shading_engine")); // // Create a lighting engine factory. // auto_ptr<IPassCallback> pass_callback; auto_ptr<ILightingEngineFactory> lighting_engine_factory; { const string value = m_params.get_required<string>("lighting_engine", "pt"); if (value == "drt") { lighting_engine_factory.reset( new DRTLightingEngineFactory( light_sampler, m_params.child("drt"))); // todo: change to "drt_lighting_engine" -- or? } else if (value == "pt") { lighting_engine_factory.reset( new PTLightingEngineFactory( light_sampler, m_params.child("pt"))); // todo: change to "pt_lighting_engine" -- or? } else if (value == "sppm") { const SPPMParameters params(m_params.child("sppm")); SPPMPassCallback* sppm_pass_callback = new SPPMPassCallback( scene, light_sampler, trace_context, texture_store, #ifdef WITH_OSL *shading_system, #endif params); pass_callback.reset(sppm_pass_callback); lighting_engine_factory.reset( new SPPMLightingEngineFactory( *sppm_pass_callback, light_sampler, params)); } else { RENDERER_LOG_ERROR( "invalid value for \"lighting_engine\" parameter: \"%s\".", value.c_str()); return IRendererController::AbortRendering; } } // // Create a sample renderer factory. // auto_ptr<ISampleRendererFactory> sample_renderer_factory; { const string value = m_params.get_required<string>("sample_renderer", "generic"); if (value == "generic") { sample_renderer_factory.reset( new GenericSampleRendererFactory( scene, frame, trace_context, texture_store, lighting_engine_factory.get(), shading_engine, #ifdef WITH_OSL *shading_system, #endif m_params.child("generic_sample_renderer"))); } else if (value == "blank") { sample_renderer_factory.reset(new BlankSampleRendererFactory()); } else if (value == "debug") { sample_renderer_factory.reset(new DebugSampleRendererFactory()); } else { RENDERER_LOG_ERROR( "invalid value for \"sample_renderer\" parameter: \"%s\".", value.c_str()); return IRendererController::AbortRendering; } } // // Create a sample generator factory. // auto_ptr<ISampleGeneratorFactory> sample_generator_factory; { const string value = m_params.get_optional<string>("sample_generator", ""); if (value == "generic") { sample_generator_factory.reset( new GenericSampleGeneratorFactory( frame, sample_renderer_factory.get())); } else if (value == "lighttracing") { sample_generator_factory.reset( new LightTracingSampleGeneratorFactory( scene, frame, trace_context, texture_store, light_sampler, #ifdef WITH_OSL *shading_system, #endif m_params.child("lighttracing_sample_generator"))); } else if (!value.empty()) { RENDERER_LOG_ERROR( "invalid value for \"sample_generator\" parameter: \"%s\".", value.c_str()); return IRendererController::AbortRendering; } } // // Create a pixel renderer factory. // auto_ptr<IPixelRendererFactory> pixel_renderer_factory; { const string value = m_params.get_optional<string>("pixel_renderer", ""); if (value == "uniform") { pixel_renderer_factory.reset( new UniformPixelRendererFactory( sample_renderer_factory.get(), m_params.child("uniform_pixel_renderer"))); } else if (value == "adaptive") { pixel_renderer_factory.reset( new AdaptivePixelRendererFactory( frame, sample_renderer_factory.get(), m_params.child("adaptive_pixel_renderer"))); } else if (!value.empty()) { RENDERER_LOG_ERROR( "invalid value for \"pixel_renderer\" parameter: \"%s\".", value.c_str()); return IRendererController::AbortRendering; } } // // Create a shading result framebuffer factory. // auto_ptr<IShadingResultFrameBufferFactory> shading_result_framebuffer_factory; { const string value = m_params.get_optional<string>("shading_result_framebuffer", "ephemeral"); if (value == "ephemeral") { shading_result_framebuffer_factory.reset( new EphemeralShadingResultFrameBufferFactory()); } else if (value == "permanent") { shading_result_framebuffer_factory.reset( new PermanentShadingResultFrameBufferFactory(frame)); } else if (!value.empty()) { RENDERER_LOG_ERROR( "invalid value for \"shading_result_framebuffer\" parameter: \"%s\".", value.c_str()); return IRendererController::AbortRendering; } } // // Create a tile renderer factory. // auto_ptr<ITileRendererFactory> tile_renderer_factory; { const string value = m_params.get_optional<string>("tile_renderer", ""); if (value == "generic") { tile_renderer_factory.reset( new GenericTileRendererFactory( frame, pixel_renderer_factory.get(), shading_result_framebuffer_factory.get(), m_params.child("generic_tile_renderer"))); } else if (value == "blank") { tile_renderer_factory.reset(new BlankTileRendererFactory()); } else if (value == "debug") { tile_renderer_factory.reset(new DebugTileRendererFactory()); } else if (!value.empty()) { RENDERER_LOG_ERROR( "invalid value for \"tile_renderer\" parameter: \"%s\".", value.c_str()); return IRendererController::AbortRendering; } } // // Create a frame renderer. // auto_release_ptr<IFrameRenderer> frame_renderer; { const string value = m_params.get_required<string>("frame_renderer", "generic"); if (value == "generic") { ParamArray params = m_params.child("generic_frame_renderer"); copy_param(params, m_params, "rendering_threads"); frame_renderer.reset( GenericFrameRendererFactory::create( frame, tile_renderer_factory.get(), m_tile_callback_factory, pass_callback.get(), params)); } else if (value == "progressive") { ParamArray params = m_params.child("progressive_frame_renderer"); copy_param(params, m_params, "rendering_threads"); frame_renderer.reset( ProgressiveFrameRendererFactory::create( m_project, sample_generator_factory.get(), m_tile_callback_factory, params)); } else { RENDERER_LOG_ERROR( "invalid value for \"frame_renderer\" parameter: \"%s\".", value.c_str()); return IRendererController::AbortRendering; } } // Execute the main rendering loop. const IRendererController::Status status = render_frame_sequence( frame_renderer.get() #ifdef WITH_OSL , *shading_system #endif ); // Print texture store performance statistics. RENDERER_LOG_DEBUG("%s", texture_store.get_statistics().to_string().c_str()); return status; }