IceTBoolean icetGLIsInitialized(void) { if (icetStateGetType(ICET_GL_INITIALIZED) != ICET_NULL) { IceTBoolean initialized; icetGetBooleanv(ICET_GL_INITIALIZED, &initialized); if (initialized) { return ICET_TRUE; } } return ICET_FALSE; }
IceTBoolean icetIsEnabled(IceTEnum pname) { IceTBoolean isEnabled; if ((pname < ICET_STATE_ENABLE_START) || (pname >= ICET_STATE_ENABLE_END)) { icetRaiseError("Bad value to icetIsEnabled", ICET_INVALID_VALUE); return ICET_FALSE; } icetGetBooleanv(pname, &isEnabled); return isEnabled; }
// **************************************************************************** // Function: SendImageToRenderNodes // // Purpose: IceT distinguishes between `tile nodes' and `render nodes'. All // nodes assist in image composition, but final images are only // collected on tile nodes. // Unfortunately various post-rendering algorithms in VisIt do not // make this distinction, which in IceT parlance means we assume all // nodes are tile nodes. This method should send out the image to // all other nodes, so we can still utilize IceT by blurring that // distinction so that the rest of VisIt never knows. // // Programmer: Tom Fogal // Creation: August 7, 2008 // // **************************************************************************** static void SendImageToRenderNodes(int width, int height, bool Z, GLubyte * const pixels, GLuint * const depth) { GLint n_tiles, n_procs, rank; GLboolean have_image; ICET(icetGetIntegerv(ICET_NUM_TILES, &n_tiles)); ICET(icetGetIntegerv(ICET_NUM_PROCESSES, &n_procs)); ICET(icetGetIntegerv(ICET_RANK, &rank)); ICET(icetGetBooleanv(ICET_COLOR_BUFFER_VALID, &have_image)); // 4: assuming GL_RGBA. MPI_Bcast(pixels, 4*width*height, MPI_BYTE, 0, VISIT_MPI_COMM); if(Z) { MPI_Bcast(depth, width*height, MPI_UNSIGNED, 0, VISIT_MPI_COMM); } }
IceTImage icetDrawFrame(const IceTDouble *projection_matrix, const IceTDouble *modelview_matrix, const IceTFloat *background_color) { IceTInt frame_count; IceTImage image; IceTDouble render_time; IceTDouble buf_read_time; IceTDouble compose_time; IceTDouble total_time; icetRaiseDebug("In icetDrawFrame"); { IceTBoolean isDrawing; icetGetBooleanv(ICET_IS_DRAWING_FRAME, &isDrawing); if (isDrawing) { icetRaiseError("Recursive frame draw detected.", ICET_INVALID_OPERATION); return icetImageNull(); } } icetStateResetTiming(); icetTimingDrawFrameBegin(); icetStateSetDoublev(ICET_PROJECTION_MATRIX, 16, projection_matrix); icetStateSetDoublev(ICET_MODELVIEW_MATRIX, 16, modelview_matrix); drawUseBackgroundColor(background_color); icetGetIntegerv(ICET_FRAME_COUNT, &frame_count); frame_count++; icetStateSetIntegerv(ICET_FRAME_COUNT, 1, &frame_count); drawProjectBounds(); { IceTEnum strategy; icetGetEnumv(ICET_STRATEGY, &strategy); /* drawCollectTileInformation does an allgather to get information * about the tiles in other processes. These variables are * ICET_ALL_CONTAINED_TILES_MASKS, ICET_TILE_CONTRIB_COUNTS, and * ICET_TOTAL_IMAGE_COUNT. However, the sequential strategy ignores * this information and just uses all processes for all tiles. When * compositing a single tile, this is a fine strategy and we can save * a significant proportion of frame time by skipping this step. */ if (strategy != ICET_STRATEGY_SEQUENTIAL) { drawCollectTileInformation(); } } { IceTInt tile_displayed; icetGetIntegerv(ICET_TILE_DISPLAYED, &tile_displayed); if (tile_displayed >= 0) { const IceTInt *tile_viewports = icetUnsafeStateGetInteger(ICET_TILE_VIEWPORTS); IceTInt num_pixels = ( tile_viewports[4*tile_displayed+2] * tile_viewports[4*tile_displayed+3] ); icetStateSetInteger(ICET_VALID_PIXELS_TILE, tile_displayed); icetStateSetInteger(ICET_VALID_PIXELS_OFFSET, 0); icetStateSetInteger(ICET_VALID_PIXELS_NUM, num_pixels); } else { icetStateSetInteger(ICET_VALID_PIXELS_TILE, -1); icetStateSetInteger(ICET_VALID_PIXELS_OFFSET, 0); icetStateSetInteger(ICET_VALID_PIXELS_NUM, 0); } } image = drawInvokeStrategy(); /* Calculate times. */ icetGetDoublev(ICET_RENDER_TIME, &render_time); icetGetDoublev(ICET_BUFFER_READ_TIME, &buf_read_time); icetTimingDrawFrameEnd(); icetGetDoublev(ICET_TOTAL_DRAW_TIME, &total_time); compose_time = total_time - render_time - buf_read_time; icetStateSetDouble(ICET_COMPOSITE_TIME, compose_time); icetStateSetDouble(ICET_BUFFER_WRITE_TIME, 0.0); icetStateCheckMemory(); return image; }
// **************************************************************************** // Method: Readback // // Purpose: Reads back the image buffer from IceT. // // Programmer: Tom Fogal // Creation: June 20, 2008 // // Modifications: // // Tom Fogal, Tue Jul 1 11:06:55 EDT 2008 // Hack the number of scalars in the vtkImageData we create to be 4, to // match the kind of buffer IceT gives us. This allows us to skip an // expensive GL_RGBA -> GL_RGB conversion. // Also, use a void*; don't know why it was a uchar* before ... // // Tom Fogal, Wed Jul 2 11:05:07 EDT 2008 // Readback and send/recv the Z buffer (unconditionally...). // // Tom Fogal, Thu Jul 17 17:02:40 EDT 2008 // Repurposed viewported argument for a boolean to grab Z. // // Tom Fogal, Mon Jul 28 14:44:28 EDT 2008 // Don't ask IceT for Z if we're not going to use it anyway. // // Tom Fogal, Mon Sep 1 14:21:46 EDT 2008 // Removed asserts / dependence on NDEBUG. // // Hank Childs, Mon Dec 29 18:24:05 CST 2008 // Make an image have 3 components, not 4, since 3 is better supported // throughout VisIt (including saving TIFFs). // // Hank Childs, Thu Jan 15 11:07:53 CST 2009 // Changed GetSize call to GetCaptureRegion, since that works for 2D. // // Hank Childs, Fri Feb 6 15:47:17 CST 2009 // Fix memory leak. // // Burlen Loring, Tue Sep 1 14:26:30 PDT 2015 // sync up with network manager(base class) order compositing refactor // // **************************************************************************** avtImage_p IceTNetworkManager::Readback(VisWindow * const viswin, bool readZ) const { GLboolean have_image; ICET(icetGetBooleanv(ICET_COLOR_BUFFER_VALID, &have_image)); int width=-42, height=-42, width_start, height_start; // This basically gets the width and the height. // The distinction is for 2D rendering, where we only want the // width and the height of the viewport. viswin->GetCaptureRegion(width_start, height_start, width, height, renderState.viewportedMode); GLubyte *pixels = NULL; GLuint *depth = NULL; if(readZ && have_image == GL_TRUE) { depth = icetGetDepthBuffer(); DEBUG_ONLY(ICET_CHECK_ERROR); } // We can't delete pointers IceT gives us. However if we're a receiving // node, we'll dynamically allocate our buffers and thus need to deallocate // them. bool dynamic = false; if(have_image == GL_TRUE) { // We have an image. First read it back from IceT. pixels = icetGetColorBuffer(); DEBUG_ONLY(ICET_CHECK_ERROR); this->VerifyColorFormat(); // Bail out if we don't get GL_RGBA data. } else { // We don't have an image -- we need to receive it from our buddy. // Purpose of static pixel_ptr ... if I delete this memory too soon (i.e. along // with "depth"), then there is a crash ... it is being used after the function // exits. So just wait until the next render to free it. static GLubyte *pixel_ptr = NULL; if (pixel_ptr != NULL) delete [] pixel_ptr; pixel_ptr = new GLubyte[4*width*height]; pixels = pixel_ptr; depth = new GLuint[width*height]; dynamic = true; } SendImageToRenderNodes(width, height, readZ, pixels, depth); vtkImageData *image = avtImageRepresentation::NewImage(width, height); // NewImage assumes we want a 3-component ("GL_RGB") image, but IceT gives // us back data in a GL_RGBA format. So we just reset the number of // components and reallocate the data; unfortunately this means we do an // allocate in NewImage and then immediately throw it away when doing an // allocate here. image->AllocateScalars(VTK_UNSIGNED_CHAR, 3); { unsigned char *img_pix = (unsigned char *) image->GetScalarPointer(); const int numPix = width*height; for (int i = 0 ; i < numPix ; i++) { *img_pix++ = *pixels++; *img_pix++ = *pixels++; *img_pix++ = *pixels++; pixels++; // Alpha } } float *visit_depth_buffer = NULL; if(readZ) { debug4 << "Converting depth values ..." << std::endl; visit_depth_buffer = utofv(depth, width*height); } avtSourceFromImage screenCapSrc(image, visit_depth_buffer); avtImage_p visit_img = screenCapSrc.GetTypedOutput(); visit_img->Update(screenCapSrc.GetGeneralContract()); visit_img->SetSource(NULL); image->Delete(); delete[] visit_depth_buffer; if(dynamic) { delete[] depth; } debug3 << "Readback complete." << std::endl; return visit_img; }
static IceTImage vtreeCompose(void) { GLint rank, num_proc; GLint num_tiles; GLint max_pixels; GLint *display_nodes; GLint tile_displayed; GLboolean *all_contained_tmasks; GLint *tile_viewports; IceTImage imageBuffer; IceTSparseImage inImage, outImage; struct node_info *info; struct node_info *my_info; int tile, node; int tiles_transfered; int tile_held = -1; icetRaiseDebug("In vtreeCompose"); /* Get state. */ icetGetIntegerv(ICET_RANK, &rank); icetGetIntegerv(ICET_NUM_PROCESSES, &num_proc); icetGetIntegerv(ICET_NUM_TILES, &num_tiles); icetGetIntegerv(ICET_TILE_MAX_PIXELS, &max_pixels); display_nodes = icetUnsafeStateGet(ICET_DISPLAY_NODES); tile_viewports = icetUnsafeStateGet(ICET_TILE_VIEWPORTS); icetGetIntegerv(ICET_TILE_DISPLAYED, &tile_displayed); /* Allocate buffers. */ icetResizeBuffer( icetFullImageSize(max_pixels) + icetSparseImageSize(max_pixels)*2 + sizeof(struct node_info)*num_proc + sizeof(GLboolean)*num_proc*num_tiles); imageBuffer = icetReserveBufferMem(icetFullImageSize(max_pixels)); inImage = icetReserveBufferMem(icetSparseImageSize(max_pixels)); outImage = icetReserveBufferMem(icetSparseImageSize(max_pixels)); info = icetReserveBufferMem(sizeof(struct node_info)*num_proc); all_contained_tmasks = icetReserveBufferMem(sizeof(GLboolean)*num_proc*num_tiles); icetGetBooleanv(ICET_ALL_CONTAINED_TILES_MASKS, all_contained_tmasks); /* Initialize info array. */ for (node = 0; node < num_proc; node++) { info[node].rank = node; info[node].tile_held = -1; /* Id of tile image held in memory. */ info[node].num_contained = 0; /* # of images to be rendered. */ for (tile = 0; tile < num_tiles; tile++) { if (all_contained_tmasks[node*num_tiles + tile]) { info[node].num_contained++; } } } #define CONTAINS_TILE(nodei, tile) \ (all_contained_tmasks[info[nodei].rank*num_tiles+(tile)]) tile_held = -1; do { int recv_node; tiles_transfered = 0; sort_by_contained(info, num_proc); for (node = 0; node < num_proc; node++) { info[node].tile_sending = -1; info[node].tile_receiving = -1; } for (recv_node = 0; recv_node < num_proc; recv_node++) { struct node_info *recv_info = info + recv_node; if (recv_info->tile_receiving >= 0) continue; if (recv_info->tile_held >= 0) { /* This node is holding a tile. It must either send or receive this tile. */ if (find_sender(info, num_proc, recv_node, recv_info->tile_held, display_nodes[recv_info->tile_held], num_tiles, all_contained_tmasks)) { tiles_transfered = 1; continue; } /* Could not find a match for a sender, how about someone who can receive it? */ if ( (recv_info->tile_sending < 0) && (recv_info->rank != display_nodes[recv_info->tile_held]) && find_receiver(info, num_proc, recv_node, recv_info->tile_held, display_nodes[recv_info->tile_held], num_tiles, all_contained_tmasks) ) { tiles_transfered = 1; } else { /* Could not send or receive. Give up. */ continue; } } /* OK. Let's try to receive any tile that we still have. */ for (tile = 0; tile < num_tiles; tile++) { if ( ( !CONTAINS_TILE(recv_node, tile) && (display_nodes[tile] != recv_info->rank) ) || (recv_info->tile_sending == tile) ) continue; if (find_sender(info, num_proc, recv_node, tile, display_nodes[tile], num_tiles, all_contained_tmasks)) { tiles_transfered = 1; break; } } } /* Now that we figured out who is sending to who, do the actual send and receive. */ my_info = NULL; for (node = 0; node < num_proc; node++) { if (info[node].rank == rank) { my_info = info + node; break; } } do_send_receive(my_info, tile_held, max_pixels, num_tiles, tile_viewports, all_contained_tmasks, imageBuffer, inImage, outImage); tile_held = my_info->tile_held; } while (tiles_transfered); /* It's possible that a composited image ended up on a processor that */ /* is not the display node for that image. Do one last round of */ /* transfers to make sure all the tiles ended up in the right place. */ for (node = 0; node < num_proc; node++) { if (info[node].rank == rank) { my_info = info + node; break; } } my_info->tile_receiving = -1; my_info->tile_sending = -1; if ((my_info->tile_held >= 0) && (my_info->tile_held != tile_displayed)) { /* I'm holding an image that does not belong to me. Ship it off. */ my_info->tile_sending = my_info->tile_held; my_info->send_dest = display_nodes[my_info->tile_held]; my_info->tile_held = -1; } if ((my_info->tile_held != tile_displayed) && (tile_displayed >= 0)) { /* Someone may be holding an image that belongs to me. Check. */ for (node = 0; node < num_proc; node++) { if (info[node].tile_held == tile_displayed) { my_info->tile_receiving = tile_displayed; my_info->recv_src = info[node].rank; my_info->tile_held = tile_displayed; break; } } } do_send_receive(my_info, tile_held, max_pixels, num_tiles, tile_viewports, all_contained_tmasks, imageBuffer, inImage, outImage); tile_held = my_info->tile_held; /* Hacks for when "this" tile was not rendered. */ if ((tile_displayed >= 0) && (tile_displayed != tile_held)) { if (all_contained_tmasks[rank*num_tiles + tile_displayed]) { /* Only "this" node draws "this" tile. Because the image never */ /* needed to be transferred, it was never rendered above. Just */ /* render it now. */ icetRaiseDebug("Rendering tile to display."); /* This may uncessarily read a buffer if not outputing an input buffer */ icetGetTileImage(tile_displayed, imageBuffer); } else { /* "This" tile is blank. */ icetRaiseDebug("Returning blank image."); icetInitializeImage(imageBuffer, max_pixels); icetClearImage(imageBuffer); } } return imageBuffer; }