Commit 7aed1a73 authored by Kenneth Moreland's avatar Kenneth Moreland
Browse files

Add icetCompositeImage to composite pre-rendered images

I got a request from a developer who was having trouble shoehorning
IceT's rendering callback mechanism into his client code. This method
lets the application render an image beforehand and then let IceT just
do the composite, which is much easier for him.
parent e08b8265
......@@ -161,6 +161,43 @@ void icetDataReplicationGroupColor(IceTInt color)
icetDataReplicationGroup(size, mygroup);
}
static void drawUseMatrices(const IceTDouble *projection_matrix,
const IceTDouble *modelview_matrix)
{
if ((projection_matrix != NULL) && (modelview_matrix != NULL)) {
icetStateSetDoublev(ICET_PROJECTION_MATRIX, 16, projection_matrix);
icetStateSetDoublev(ICET_MODELVIEW_MATRIX, 16, modelview_matrix);
} else {
IceTDouble identity[16];
icetMatrixIdentity(identity);
if (projection_matrix == NULL) {
icetStateSetDoublev(ICET_PROJECTION_MATRIX, 16, identity);
} else {
icetRaiseWarning("Drawing with a projection matrix but no "
"modelview matrix. Confused on what to do.",
ICET_INVALID_VALUE);
icetStateSetDoublev(ICET_PROJECTION_MATRIX, 16, projection_matrix);
}
if (modelview_matrix == NULL) {
icetStateSetDoublev(ICET_MODELVIEW_MATRIX, 16, identity);
} else {
icetRaiseWarning("Drawing with a modelview matrix but no "
"projection matrix. Confused on what to do.",
ICET_INVALID_VALUE);
icetStateSetDoublev(ICET_MODELVIEW_MATRIX, 16, projection_matrix);
}
if (*icetUnsafeStateGetInteger(ICET_NUM_BOUNDING_VERTS) != 0) {
icetRaiseWarning(
"Geometry bounds were given (with icetBoundingBox or icetBoundingVertices)\n"
"but projection matrices not given to icetCompositeImage. Clearing out the\n"
"bounding information. (Use icetBoundingVertices(0, ICET_VOID, 0, 0, NULL)\n"
"to avoid this error.)",
ICET_INVALID_VALUE);
icetBoundingVertices(0, ICET_VOID, 0, 0, NULL);
}
}
}
static IceTFloat black[] = {0.0f, 0.0f, 0.0f, 0.0f};
static void drawUseBackgroundColor(const IceTFloat *background_color)
......@@ -581,30 +618,50 @@ static void drawProjectBounds(void)
sizeof(IceTBoolean)*num_tiles);
if (num_bounding_verts < 1) {
/* User never set bounding vertices. Assume image covers all tiles. */
IceTInt i;
for (i = 0; i < num_tiles; i++) {
contained_list[i] = i;
contained_mask[i] = 1;
}
/* User never set bounding vertices. Assume image covers global
* viewport. */
icetGetIntegerv(ICET_GLOBAL_VIEWPORT, contained_viewport);
znear = -1.0;
zfar = 1.0;
num_contained = num_tiles;
} else {
/* Figure out how the geometry projects onto the display. */
drawFindContainedViewport(contained_viewport, &znear, &zfar);
}
/* Now use this information to figure out which tiles need to be
drawn. */
drawDetermineContainedTiles(contained_viewport,
znear,
zfar,
contained_list,
contained_mask,
&num_contained);
if ( icetUnsafeStateGetBoolean(ICET_PRE_RENDERED)[0]
&& (icetStateGetNumEntries(ICET_RENDERED_VIEWPORT) == 4) ) {
/* If we are using a pre-rendered image (from icetCompositeImage) and
* a valid pixels viewport was given, then clip the current contained
* viewport with that one. */
const IceTInt *rendered_viewport =
icetUnsafeStateGetInteger(ICET_RENDERED_VIEWPORT);
if (rendered_viewport[0] > contained_viewport[0]) {
contained_viewport[2] -= rendered_viewport[0]-contained_viewport[0];
if (contained_viewport[2] < 0) { contained_viewport[2] = 0; }
contained_viewport[0] = rendered_viewport[0];
}
if (rendered_viewport[2] < contained_viewport[2]) {
contained_viewport[2] = rendered_viewport[2];
}
if (rendered_viewport[1] > contained_viewport[1]) {
contained_viewport[3] -= rendered_viewport[1]-contained_viewport[1];
if (contained_viewport[3] < 0) { contained_viewport[3] = 0; }
contained_viewport[1] = rendered_viewport[1];
}
if (rendered_viewport[3] < contained_viewport[3]) {
contained_viewport[3] = rendered_viewport[3];
}
}
/* Now use this information to figure out which tiles need to be
drawn. */
drawDetermineContainedTiles(contained_viewport,
znear,
zfar,
contained_list,
contained_mask,
&num_contained);
icetRaiseDebug4("contained_viewport = %d %d %d %d",
(int)contained_viewport[0], (int)contained_viewport[1],
(int)contained_viewport[2], (int)contained_viewport[3]);
......@@ -632,6 +689,18 @@ static void drawCollectTileInformation(void)
IceTInt num_proc;
IceTInt num_tiles;
{
IceTEnum strategy;
icetGetEnumv(ICET_STRATEGY, &strategy);
/* This function performs allgathers to collect information about
* all tiles on all processes, which IceT strategies need to cull
* out unused tiles and set up communication patterns. However,
* the sequential strategy ignores this information and just uses
* all processes for all tiles, so we can skip this step. */
if (strategy == ICET_STRATEGY_SEQUENTIAL) { return; }
}
icetGetIntegerv(ICET_NUM_PROCESSES, &num_proc);
icetGetIntegerv(ICET_NUM_TILES, &num_tiles);
......@@ -680,7 +749,8 @@ static IceTImage drawInvokeStrategy(void)
IceTInt valid_tile;
icetGetPointerv(ICET_DRAW_FUNCTION, &value);
if (value == NULL) {
if ( (value == NULL)
&& !icetUnsafeStateGetBoolean(ICET_PRE_RENDERED)[0]) {
icetRaiseError("Drawing function not set. Call icetDrawCallback.",
ICET_INVALID_OPERATION);
return icetImageNull();
......@@ -728,9 +798,9 @@ static IceTImage drawInvokeStrategy(void)
return image;
}
IceTImage icetDrawFrame(const IceTDouble *projection_matrix,
const IceTDouble *modelview_matrix,
const IceTFloat *background_color)
static IceTImage drawDoFrame(const IceTDouble *projection_matrix,
const IceTDouble *modelview_matrix,
const IceTFloat *background_color)
{
IceTInt frame_count;
IceTImage image;
......@@ -739,8 +809,6 @@ IceTImage icetDrawFrame(const IceTDouble *projection_matrix,
IceTDouble compose_time;
IceTDouble total_time;
icetRaiseDebug("In icetDrawFrame");
{
IceTBoolean isDrawing;
icetGetBooleanv(ICET_IS_DRAWING_FRAME, &isDrawing);
......@@ -754,8 +822,7 @@ IceTImage icetDrawFrame(const IceTDouble *projection_matrix,
icetStateResetTiming();
icetTimingDrawFrameBegin();
icetStateSetDoublev(ICET_PROJECTION_MATRIX, 16, projection_matrix);
icetStateSetDoublev(ICET_MODELVIEW_MATRIX, 16, modelview_matrix);
drawUseMatrices(projection_matrix, modelview_matrix);
drawUseBackgroundColor(background_color);
......@@ -765,21 +832,7 @@ IceTImage icetDrawFrame(const IceTDouble *projection_matrix,
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();
}
}
drawCollectTileInformation();
{
IceTInt tile_displayed;
......@@ -819,3 +872,42 @@ IceTImage icetDrawFrame(const IceTDouble *projection_matrix,
return image;
}
IceTImage icetDrawFrame(const IceTDouble *projection_matrix,
const IceTDouble *modelview_matrix,
const IceTFloat *background_color)
{
icetRaiseDebug("In icetDrawFrame");
icetStateSetBoolean(ICET_PRE_RENDERED, ICET_FALSE);
return drawDoFrame(projection_matrix, modelview_matrix, background_color);
}
IceTImage icetCompositeImage(const IceTVoid *color_buffer,
const IceTVoid *depth_buffer,
const IceTInt *valid_pixels_viewport,
const IceTDouble *projection_matrix,
const IceTDouble *modelview_matrix,
const IceTFloat *background_color)
{
IceTInt global_viewport[4];
icetRaiseDebug("In icetCompositeImage");
icetGetIntegerv(ICET_GLOBAL_VIEWPORT, global_viewport);
icetStateSetBoolean(ICET_PRE_RENDERED, ICET_TRUE);
icetGetStatePointerImage(ICET_RENDER_BUFFER,
global_viewport[2],
global_viewport[3],
color_buffer,
depth_buffer);
if (valid_pixels_viewport) {
icetStateSetIntegerv(ICET_RENDERED_VIEWPORT, 4, valid_pixels_viewport);
} else {
icetStateSetIntegerv(ICET_RENDERED_VIEWPORT, 0, NULL);
}
return drawDoFrame(projection_matrix, modelview_matrix, background_color);
}
......@@ -191,6 +191,18 @@ static void icetSparseImageSplitChoosePartitions(
IceTSizeType first_offset,
IceTSizeType *offsets);
/* This function is used to get the image for a tile. It will either render
the tile on demand (with renderTile) or get the image from a pre-rendered
image (with prerenderedTile). The screen_viewport is set to the region of
valid pixels in the returned image. The tile_viewport gives the region
where the pixels reside in the tile. (The width and height of the two
viewports will be the same.) Pixels outside of these viewports are
undefined. */
static IceTImage generateTile(int tile,
IceTInt *screen_viewport,
IceTInt *target_viewport,
IceTImage tile_buffer);
/* Renders the geometry for a tile and returns an image of the rendered data.
If IceT determines that it is most efficient to render the data directly to
the tile projection, then screen_viewport and tile_viewport will be set to
......@@ -199,15 +211,23 @@ static void icetSparseImageSplitChoosePartitions(
cleared to the background before used. If tile_buffer is not a null image,
that image will be used to render and be returned. If IceT determines that
it is most efficient to render a projection that does not exactly fit a tile,
tile_buffer will be ignored an image with an internal buffer will be
tile_buffer will be ignored and image with an internal buffer will be
returned. screen_viewport will give the offset and dimensions of the valid
pixels in the returned buffer. tile_viewport gives the offset and dimensions
where these pixels reside in the tile. (The dimensions for both will be the
same.) As before, pixels outside of these viewports are undefined. */
where these pixels reside in the tile. (The width and height for both will
be the same.) As before, pixels outside of these viewports are undefined. */
static IceTImage renderTile(int tile,
IceTInt *screen_viewport,
IceTInt *tile_viewport,
IceTInt *target_viewport,
IceTImage tile_buffer);
/* Returns the pre-rendered image, the region of valid pixels in the tile in
screen_viewport, and the region where the pixels reside in the tile in
tile_viewport. */
static IceTImage prerenderedTile(int tile,
IceTInt *screen_viewport,
IceTInt *target_viewport);
/* Gets an image buffer attached to this context. */
static IceTImage getRenderBuffer(void);
......@@ -2022,7 +2042,8 @@ void icetGetTileImage(IceTInt tile, IceTImage image)
height = viewports[4*tile+3];
icetImageSetDimensions(image, width, height);
rendered_image = renderTile(tile, screen_viewport, target_viewport, image);
rendered_image =
generateTile(tile, screen_viewport, target_viewport, image);
icetTimingBufferReadBegin();
......@@ -2032,7 +2053,7 @@ void icetGetTileImage(IceTInt tile, IceTImage image)
|| (screen_viewport[1] != target_viewport[1])
|| (screen_viewport[2] != target_viewport[2])
|| (screen_viewport[3] != target_viewport[3]) ) {
icetRaiseError("Inconsistent values returned from renderTile.",
icetRaiseError("Inconsistent values returned from generateTile.",
ICET_SANITY_CHECK_FAIL);
}
} else {
......@@ -2059,8 +2080,8 @@ void icetGetCompressedTileImage(IceTInt tile, IceTSparseImage compressed_image)
height = viewports[4*tile+3];
icetSparseImageSetDimensions(compressed_image, width, height);
raw_image = renderTile(tile, screen_viewport, target_viewport,
icetImageNull());
raw_image = generateTile(tile, screen_viewport, target_viewport,
icetImageNull());
if ((target_viewport[2] < 1) || (target_viewport[3] < 1)) {
/* Tile empty. Just clear result. */
......@@ -2442,6 +2463,20 @@ void icetClearImageTrueBackground(IceTImage image)
icetStateSetInteger(ICET_BACKGROUND_COLOR_WORD, original_background_word);
}
static IceTImage generateTile(int tile,
IceTInt *screen_viewport,
IceTInt *target_viewport,
IceTImage tile_buffer)
{
IceTBoolean use_prerender;
icetGetBooleanv(ICET_PRE_RENDERED, &use_prerender);
if (use_prerender) {
return prerenderedTile(tile, screen_viewport, target_viewport);
} else {
return renderTile(tile, screen_viewport, target_viewport, tile_buffer);
}
}
static IceTImage renderTile(int tile,
IceTInt *screen_viewport,
IceTInt *target_viewport,
......@@ -2672,6 +2707,53 @@ static IceTImage renderTile(int tile,
return render_buffer;
}
static IceTImage prerenderedTile(int tile,
IceTInt *screen_viewport,
IceTInt *target_viewport)
{
const IceTInt *contained_viewport;
const IceTInt *tile_viewport;
icetRaiseDebug1("Getting viewport for tile %d in prerendered image", tile);
contained_viewport = icetUnsafeStateGetInteger(ICET_CONTAINED_VIEWPORT);
tile_viewport = icetUnsafeStateGetInteger(ICET_TILE_VIEWPORTS) + 4*tile;
/* Start with the tile viewport. */
screen_viewport[0] = tile_viewport[0];
screen_viewport[1] = tile_viewport[1];
screen_viewport[2] = tile_viewport[2];
screen_viewport[3] = tile_viewport[3];
target_viewport[0] = target_viewport[1] = 0;
/* Clip by the contained viewport. */
if (contained_viewport[0] > screen_viewport[0]) {
IceTInt diff = contained_viewport[0] - screen_viewport[0];
screen_viewport[0] = contained_viewport[0];
target_viewport[0] = diff;
screen_viewport[2] -= diff;
if (screen_viewport[2] < 0) { screen_viewport[2] = 0; }
}
if (contained_viewport[2] < screen_viewport[2]) {
screen_viewport[2] = contained_viewport[2];
}
if (contained_viewport[1] > screen_viewport[1]) {
IceTInt diff = contained_viewport[1] - screen_viewport[1];
screen_viewport[1] = contained_viewport[1];
target_viewport[1] = diff;
screen_viewport[3] -= diff;
if (screen_viewport[3] < 0) { screen_viewport[3] = 0; }
}
if (contained_viewport[3] < screen_viewport[3]) {
screen_viewport[3] = contained_viewport[3];
}
target_viewport[2] = screen_viewport[2];
target_viewport[3] = screen_viewport[3];
return icetRetrieveStateImage(ICET_RENDER_BUFFER);
}
static IceTImage getRenderBuffer(void)
{
/* Check to see if we are in the same frame as the last time we returned
......
......@@ -40,7 +40,7 @@ void icetResetTiles(void)
#define MAX(x, y) ((x) >= (y) ? (x) : (y))
#endif
int icetAddTile(IceTInt x, IceTInt y, IceTSizeType width, IceTSizeType height,
int display_rank)
int display_rank)
{
IceTInt num_tiles;
IceTInt *viewports;
......@@ -69,26 +69,26 @@ int icetAddTile(IceTInt x, IceTInt y, IceTSizeType width, IceTSizeType height,
/* Check and update display ranks. */
if (display_rank >= num_processors) {
sprintf(msg, "icetDisplayNodes: Invalid rank for tile %d.",
(int)num_tiles);
icetRaiseError(msg, ICET_INVALID_VALUE);
free(display_nodes);
return -1;
sprintf(msg, "icetDisplayNodes: Invalid rank for tile %d.",
(int)num_tiles);
icetRaiseError(msg, ICET_INVALID_VALUE);
free(display_nodes);
return -1;
}
for (i = 0; i < num_tiles; i++) {
if (display_nodes[i] == display_rank) {
sprintf(msg, "icetDisplayNodes: Rank %d used for tiles %d and %d.",
display_rank, i, (int)num_tiles);
icetRaiseError(msg, ICET_INVALID_VALUE);
free(display_nodes);
return -1;
}
if (display_nodes[i] == display_rank) {
sprintf(msg, "icetDisplayNodes: Rank %d used for tiles %d and %d.",
display_rank, i, (int)num_tiles);
icetRaiseError(msg, ICET_INVALID_VALUE);
free(display_nodes);
return -1;
}
}
display_nodes[num_tiles] = display_rank;
icetStateSetIntegerv(ICET_DISPLAY_NODES, num_tiles+1, display_nodes);
free(display_nodes);
if (display_rank == rank) {
icetStateSetInteger(ICET_TILE_DISPLAYED, num_tiles);
icetStateSetInteger(ICET_TILE_DISPLAYED, num_tiles);
}
/* Get viewports. */
......@@ -99,10 +99,10 @@ int icetAddTile(IceTInt x, IceTInt y, IceTSizeType width, IceTSizeType height,
gvp[0] = x; gvp[1] = y;
gvp[2] = x + (IceTInt)width; gvp[3] = y + (IceTInt)height;
for (i = 0; i < num_tiles; i++) {
gvp[0] = MIN(gvp[0], viewports[i*4+0]);
gvp[1] = MIN(gvp[1], viewports[i*4+1]);
gvp[2] = MAX(gvp[2], viewports[i*4+0] + viewports[i*4+2]);
gvp[3] = MAX(gvp[3], viewports[i*4+1] + viewports[i*4+3]);
gvp[0] = MIN(gvp[0], viewports[i*4+0]);
gvp[1] = MIN(gvp[1], viewports[i*4+1]);
gvp[2] = MAX(gvp[2], viewports[i*4+0] + viewports[i*4+2]);
gvp[3] = MAX(gvp[3], viewports[i*4+1] + viewports[i*4+3]);
}
gvp[2] -= gvp[0];
gvp[3] -= gvp[1];
......@@ -142,8 +142,8 @@ void icetPhysicalRenderSize(IceTInt width, IceTInt height)
icetGetIntegerv(ICET_TILE_MAX_WIDTH, &max_width);
icetGetIntegerv(ICET_TILE_MAX_HEIGHT, &max_height);
if ((width < max_width) || (height < max_height)) {
icetRaiseWarning("Physical render dimensions not large enough"
" to render all tiles.", ICET_INVALID_VALUE);
icetRaiseWarning("Physical render dimensions not large enough"
" to render all tiles.", ICET_INVALID_VALUE);
}
icetStateSetInteger(ICET_PHYSICAL_RENDER_WIDTH, width);
......@@ -151,8 +151,8 @@ void icetPhysicalRenderSize(IceTInt width, IceTInt height)
}
void icetBoundingBoxd(IceTDouble x_min, IceTDouble x_max,
IceTDouble y_min, IceTDouble y_max,
IceTDouble z_min, IceTDouble z_max)
IceTDouble y_min, IceTDouble y_max,
IceTDouble z_min, IceTDouble z_max)
{
IceTDouble vertices[8*3];
......@@ -170,26 +170,33 @@ void icetBoundingBoxd(IceTDouble x_min, IceTDouble x_max,
}
void icetBoundingBoxf(IceTFloat x_min, IceTFloat x_max,
IceTFloat y_min, IceTFloat y_max,
IceTFloat z_min, IceTFloat z_max)
IceTFloat y_min, IceTFloat y_max,
IceTFloat z_min, IceTFloat z_max)
{
icetBoundingBoxd(x_min, x_max, y_min, y_max, z_min, z_max);
}
void icetBoundingVertices(IceTInt size, IceTEnum type, IceTSizeType stride,
IceTSizeType count, const IceTVoid *pointer)
IceTSizeType count, const IceTVoid *pointer)
{
IceTDouble *verts;
int i, j;
if (count < 1) {
/* No vertices. (Must be clearing them out.) */
icetStateSetDoublev(ICET_GEOMETRY_BOUNDS, 0, NULL);
icetStateSetInteger(ICET_NUM_BOUNDING_VERTS, 0);
return;
}
if (stride < 1) {
stride = size*icetTypeWidth(type);
}
verts = malloc(count*3*sizeof(IceTDouble));
for (i = 0; i < count; i++) {
for (j = 0; j < 3; j++) {
switch (type) {
for (j = 0; j < 3; j++) {
switch (type) {
#define castcopy(ptype) \
if (j < size) { \
verts[i*3+j] = ((ptype *)pointer)[i*stride/sizeof(type)+j]; \
......@@ -200,21 +207,21 @@ void icetBoundingVertices(IceTInt size, IceTEnum type, IceTSizeType stride,
verts[i*3+j] /= ((ptype *)pointer)[i*stride/sizeof(type)+4]; \
} \
break;
case ICET_SHORT:
castcopy(IceTShort);
case ICET_INT:
castcopy(IceTInt);
case ICET_FLOAT:
castcopy(IceTFloat);
case ICET_DOUBLE:
castcopy(IceTDouble);
default:
icetRaiseError("Bad type to icetBoundingVertices.",
ICET_INVALID_ENUM);
free(verts);
return;
}
}
case ICET_SHORT:
castcopy(IceTShort);
case ICET_INT:
castcopy(IceTInt);
case ICET_FLOAT:
castcopy(IceTFloat);
case ICET_DOUBLE:
castcopy(IceTDouble);
default:
icetRaiseError("Bad type to icetBoundingVertices.",
ICET_INVALID_ENUM);
free(verts);
return;
}
}
}
icetStateSetDoublev(ICET_GEOMETRY_BOUNDS, count*3, verts);
......
......@@ -241,6 +241,13 @@ ICET_EXPORT IceTImage icetDrawFrame(const IceTDouble *projection_matrix,
const IceTDouble *modelview_matrix,
const IceTFloat *background_color);
ICET_EXPORT IceTImage icetCompositeImage(const IceTVoid *color_buffer,
const IceTVoid *depth_buffer,
const IceTInt *valid_pixels_viewport,
const IceTDouble *projection_matrix,
const IceTDouble *modelview_matrix,
const IceTFloat *background_color);
#define ICET_DIAG_OFF (IceTEnum)0x0000
#define ICET_DIAG_ERRORS (IceTEnum)0x0001
#define ICET_DIAG_WARNINGS (IceTEnum)0x0003
......@@ -315,7 +322,8 @@ ICET_EXPORT void icetDiagnostics(IceTBitField mask);
#define ICET_RENDERED_VIEWPORT (ICET_STATE_FRAME_START | (IceTEnum)0x0020)
#define ICET_RENDER_BUFFER (ICET_STATE_FRAME_START | (IceTEnum)0x0021)
#define ICET_TILE_PROJECTIONS (ICET_STATE_FRAME_START | (IceTEnum)0x0024)
#define ICET_PRE_RENDERED (ICET_STATE_FRAME_START | (IceTEnum)0x0022)
#define ICET_TILE_PROJECTIONS (ICET_STATE_FRAME_START | (IceTEnum)0x0023)
#define ICET_STATE_TIMING_START (IceTEnum)0x000000C0
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment