Rendering image with Cycles - It happens only when the destructor is invoked


I hosted cycles in my rendering pipeline.
I have constructed Cycles scene and now I need to render screenshots of my scene from a couple of camera angles.


I need to set the write_render_cb field of session parameters so that once the rendering is done, this function is invoked with the pixel information as argument.

I have gone thru the session.cpp code and the write_render_cb is invoked only from the ~Session();
So, for every screenshot, I need to dispose my session and create a new session.

Is my understanding wrong?

Can we have a method which will provide the pixel information?

session->reset(buffer_params, samples);
const uchar* pixels = session->get_rendered_pixels(); //Can we have a method like this?   

I have been trying to implement this functionality but I am getting many access violation exceptions.

Can you please help me?

Thanks in advance.

Hi @jesterKing,
Can you please answer this if possible?

Thanks in advance

It would be useful to see what you’ve already written (post a patch) and the stack that fails.

Anyway, you could just do what the destructor does.

Perhaps something along the lines of (untested):

	DisplayBuffer* display = new DisplayBuffer(session->device, false);
	int w = display->draw_width;
	int h = display->draw_height;
	uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h);
	params.write_render_cb((uchar *)pixels, w, h, 4);
	delete display;
1 Like

Hi @jesterKing

Thanks for the response.

I am getting the below exception
Assertion failed: isfinite(slope_x), file cycles\kernel\closure\bsdf_microfacet_multi.h, line 98

I have gone thru Blender’s code and tried to mimic the same code but I could not understand what went wrong. Please help me.

Thanks in advance.

Here is my code.

In the Session’s constructor, I have done the below change as I am passing NULL to write_render_cb

/*if (params.background && !params.write_render_cb) {
    buffers = NULL;
    display = NULL;
  else {
    buffers = new RenderBuffers(device);
    display = new DisplayBuffer(device, params.display_buffer_linear);

  buffers = new RenderBuffers(device);
  display = new DisplayBuffer(device, params.display_buffer_linear);

I have extended the Session class and added the below methods to it

BufferParams *build_buffer_params(size_t width, size_t height)
  BufferParams *buffer_params = new BufferParams();
  buffer_params->width = width;
  buffer_params->height = height;

  buffer_params->full_width = buffer_params->width;
  buffer_params->full_height = buffer_params->height;
  return buffer_params;
void ExtendedSession::capture_screenshot(size_t width, size_t height, const char *output_image_file_path)
  scene->camera->width = width;
  scene->camera->height = height;
  scene->camera->need_update = true;
  scene->camera->need_device_update = true;
  scene->camera->need_update = true;
  scene->camera->need_device_update = true;

  BufferParams *buffer_params = build_buffer_params(width, height);
  reset(*buffer_params, params.samples);



  // stats.mem_peak = stats.mem_used;
  reset(*buffer_params, params.samples);

  params.write_render_cb = NULL;


  DisplayBuffer *display = new DisplayBuffer(device, false);

  int w = display->draw_width;
  int h = display->draw_height;
  uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h);
  write_render_image((const uchar *)pixels, w, h, 4, output_image_file_path);
  delete display;

And this is the utility method for creating Session Params

SessionParams *CyclesUtils::build_session_params(bool background)
  SessionParams *session_params = new SessionParams();
  session_params->device = get_device();
  session_params->background = background;
  session_params->samples = 100;
  session_params->experimental = false;
  session_params->progressive = false;
  session_params->progressive_refine = false;
  // session_params->start_resolution = 64;
  session_params->threads = 0;
  session_params->tile_size.x = 64;
  session_params->tile_size.y = 64;
  session_params->tile_order = background ? TileOrder::TILE_HILBERT_SPIRAL : TileOrder::TILE_CENTER;

  session_params->use_profiling = false;
  session_params->pixel_size = 1;
  session_params->display_buffer_linear = true;
  session_params->shadingsystem = ccl::ShadingSystem::SHADINGSYSTEM_SVM;
  // session_params->full_denoising = true;
  // session_params->run_denoising = true;
  // session_params->denoising_start_sample = 5;
  // session_params->write_denoising_passes = true;

  return session_params;

And this is the utility method for creating Scene Params

SceneParams *CyclesUtils::build_scene_params(const SessionParams *session_params)
  SceneParams *scene_params = new SceneParams();

  scene_params->shadingsystem = ShadingSystem::SHADINGSYSTEM_SVM;
  scene_params->use_bvh_spatial_split = false;
  scene_params->use_bvh_unaligned_nodes = true;
  scene_params->num_bvh_time_steps = 0;

  scene_params->persistent_data = false;
  scene_params->texture_limit = 0;
  scene_params->background = session_params->background;

  if (session_params->background) {
    scene_params->bvh_type = SceneParams::BVH_STATIC;
    scene_params->bvh_layout = BVHLayout::BVH_LAYOUT_BVH8;
  else {
    scene_params->bvh_type = SceneParams::BVH_DYNAMIC;
    scene_params->bvh_layout = BVHLayout::BVH_LAYOUT_BVH2;
  return scene_params;

Hi @jesterKing,
I made it working. I made it simple. Instead of following how blender is building scene, I followed how Cycles Stanalone is building scene and then applied your logic. It is simple and worked. :slight_smile:

Thanks a lot