Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r1471 - in trunk: Engine/ImageTraversers Interface StandAlone


Chronological Thread 
  • From: boulos@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r1471 - in trunk: Engine/ImageTraversers Interface StandAlone
  • Date: Fri, 13 Jul 2007 15:55:26 -0600 (MDT)

Author: boulos
Date: Fri Jul 13 15:55:25 2007
New Revision: 1471

Modified:
   trunk/Engine/ImageTraversers/DeadlineImageTraverser.cc
   trunk/Engine/ImageTraversers/DeadlineImageTraverser.h
   trunk/Interface/IdleMode.h
   trunk/StandAlone/manta.cc
Log:
Fixing bug in addIdleMode call (we need to revisit this)

Adding some documentation to the IdleMode interface so you
don't have to guess how it works.

DeadlineImageTraverser now supports super sampling (up to
1 packet == 1 pixel) and correctly allocates the tiles only
once (there was a += instead of =).




Modified: trunk/Engine/ImageTraversers/DeadlineImageTraverser.cc
==============================================================================
--- trunk/Engine/ImageTraversers/DeadlineImageTraverser.cc      (original)
+++ trunk/Engine/ImageTraversers/DeadlineImageTraverser.cc      Fri Jul 13 
15:55:25 2007
@@ -36,6 +36,7 @@
 
 #include <Engine/ImageTraversers/DeadlineImageTraverser.h>
 #include <Core/Exceptions/IllegalArgument.h>
+#include <Core/Exceptions/InternalError.h>
 #include <Core/Math/MinMax.h>
 #include <Core/Math/Expon.h>
 #include <Core/Thread/Time.h>
@@ -46,12 +47,14 @@
 #include <Interface/Fragment.h>
 #include <Interface/Image.h>
 #include <Interface/LoadBalancer.h>
+#include <Interface/MantaInterface.h>
 #include <Interface/PixelSampler.h>
 #include <Engine/PixelSamplers/SingleSampler.h>
+#include <Engine/PixelSamplers/JitterSampler.h>
 #include <Interface/RayPacket.h> // for maxsize
 #include <MantaSSE.h>
 #include <set>
-
+#include <sstream>
 using namespace Manta;
 using SCIRun::Time;
 
@@ -63,6 +66,8 @@
 DeadlineImageTraverser::DeadlineImageTraverser(const vector<string>& args)
   : qlock("DeadlineImageTraverser queue lock")
 {
+  finished_coarse = false;
+  reset_every_frame = false;
   float frameRate = 15;
   ypacketsize = 1;
   while(ypacketsize * ypacketsize * 2 < Fragment::MaxSize)
@@ -102,6 +107,8 @@
     } else if(arg == "-refinmentRatio"){
       if(!getResolutionArg(i, args, xrefinementRatio, yrefinementRatio))
         throw IllegalArgument("DeadlineImageTraverser -refinement", i, args);
+    } else if(arg == "-showtime"){
+      ShowTimeSupersample = true;
     } else {
       throw IllegalArgument("DeadlineImageTraverser", i, args);
     }
@@ -112,6 +119,22 @@
   total_tiles = 0;
   qsize = 0;
   singleSampler = new SingleSampler(vector<string>());
+
+  //cerr << "xpacketsize = " << xpacketsize << endl;
+  //cerr << "ypacketsize = " << ypacketsize << endl;
+
+  jitterSamplers = new JitterSampler*[kNumJitterLevels];
+  int num_spp = 4;
+  for (int i = 0; i < kNumJitterLevels; i++) {
+    vector<string> args;
+    args.push_back("-numberOfSamples");
+
+    ostringstream r;
+    r << num_spp;
+    args.push_back(r.str());
+    jitterSamplers[i] = new JitterSampler(args);
+    num_spp *= 4;
+  }
 }
 
 DeadlineImageTraverser::~DeadlineImageTraverser()
@@ -121,6 +144,9 @@
 void DeadlineImageTraverser::setupBegin(SetupContext& context, int 
numChannels)
 {
   singleSampler->setupBegin(context, numChannels);
+  for (int i = 0; i < 4; i++) {
+    jitterSamplers[i]->setupBegin(context, numChannels);
+  }
   context.loadBalancer->setupBegin(context, numChannels);
   context.pixelSampler->setupBegin(context, numChannels);
   if(total_tiles){
@@ -129,10 +155,37 @@
   }
   total_tiles = 0;
   top_tiles = 0;
+
+  context.rtrt_int->addIdleMode(this);
+}
+
+void DeadlineImageTraverser::changeIdleMode(const SetupContext& context,
+                                            bool changed,
+                                            bool firstFrame,
+                                            bool& pipelineNeedsSetup) {
+  if (firstFrame)
+    reset_every_frame = true;
+
+  if (context.proc == 0) {
+    // NOTE(boulos): Someone probably moved the camera or
+    // something... Time to restart.  The setupFrame call for the next
+    // frame will clean up the other data (qsize and next_tile)
+    //cerr << "changeIdleMode called with changed = " << changed << endl;
+    if (changed) {
+      reset_every_frame = true;
+    } else {
+      // Nothing is changing... we are idle
+      reset_every_frame = false;
+    }
+  }
 }
 
 void DeadlineImageTraverser::setupDisplayChannel(SetupContext& context)
 {
+  //if (context.proc == 0)
+  //  cerr << __func__ << endl;
+  StartFrameTime = Time::currentSeconds();
+  finished_coarse = false;
   // Determine the resolution.
   bool stereo;
   int xres, yres;
@@ -149,18 +202,27 @@
   int numAssignments = xtiles * ytiles;
   context.loadBalancer->setupDisplayChannel(context, numAssignments);
 
+  // Single bufferd, please.
+  context.constrainPipelineDepth(1,1);
+
   // Continue setting up the rendering stack.
   context.pixelSampler->setupDisplayChannel(context);
 
   int cur = 1;
   int ntotal = 0;
-  int x = xcoarsepixelsize;
-  int y = ycoarsepixelsize;
+  float x = xcoarsepixelsize;
+  float y = ycoarsepixelsize;
   // NOTE(boulos): This used to be > 1, but needs to be >= to account
   // for (current) lowest level of a single tile of 1 pixel.  In the
   // future this should get updated with something that accounts for
   // super sampling too.
-  while(x >= 1 || y >= 1){
+  const float min_x = 1./16.f;
+  const float min_y = 1./16.f;
+  while(x >= min_x || y >= min_y){
+    //cerr << "Cur is " << cur;
+    //cerr << " x is " << x;
+    //cerr << " y is " << y;
+    //cerr << " ntotal is " << ntotal << endl;
     ntotal += cur;
     cur *= xrefinementRatio * yrefinementRatio;
     x /= xrefinementRatio;
@@ -176,28 +238,65 @@
   }
   if(numAssignments > top_tiles)
     top_tiles = numAssignments;
-  total_tiles += ntotal * xtiles * ytiles;
+  total_tiles = ntotal * xtiles * ytiles;
+  //cerr << "Total tiles is now " << total_tiles << endl;
   tiles = new Tile[total_tiles];
   queue = new Tile*[total_tiles];
 
   singleSampler->setupDisplayChannel(context);
+  // NOTE(boulos): Having the sampler tell the renderer to setup is a
+  // bit confusing and redundant but oh well...
+  for (int i = 0; i < kNumJitterLevels; i++) {
+    jitterSamplers[i]->setupDisplayChannel(context);
+  }
 }
 
 void DeadlineImageTraverser::setupFrame(const RenderContext& context)
 {
-  context.loadBalancer->setupFrame(context);
+  // TODO(boulos): Determine what stuff only proc0 should do...
+  //if (context.proc == 0)
+  //  cerr << __func__ << endl;
+  // TODO(boulos): What other stuff shouldn't get reset?
+  if (reset_every_frame) {
+    //if (context.proc == 0) cerr << "We are resetting every frame"<< endl;
+    finished_coarse = false;
+  }
+  if (!finished_coarse) {
+    context.loadBalancer->setupFrame(context);
+    qsize = 0;
+    next_tile = top_tiles;
+  }
+
   context.pixelSampler->setupFrame(context);
-  qsize = 0;
-  next_tile = top_tiles;
+
 
   singleSampler->setupFrame(context);
+  for (int i = 0; i < kNumJitterLevels; i++) {
+    jitterSamplers[i]->setupFrame(context);
+  }
   // Determine how long we should render this frame.
   frameEnd = Time::currentSeconds() + frameTime;
+  if (context.proc == 0) {
+    if (finished_coarse && qsize == 0) {
+      double EndTime = Time::currentSeconds();
+      double total_time = EndTime - StartFrameTime;
+      //cerr << "Took " << total_time << " seconds to refine to 64 spp" << 
endl;
+    }
+    //cerr << "qsize = " << qsize << ", next_tile = " << next_tile << endl;
+    //cerr << "totalTiles = " << total_tiles << endl;
+  }
 }
 
 void DeadlineImageTraverser::insertIntoQueue(Tile* tiles, int numtiles)
 {
   qlock.lock();
+  if (qsize + numtiles >= total_tiles) {
+    cerr << "Can't resize for insertion, but I'll just drop for now." << 
endl;
+    qlock.unlock();
+    return;
+    throw SCIRun::InternalError("Can't currently resize during rendering", 
__FILE__, __LINE__);
+    resizeQueue(2*(qsize + numtiles));
+  }
 
   for(int i=0;i<numtiles;i++){
     Tile* tile = &tiles[i];
@@ -225,6 +324,23 @@
   qlock.unlock();
 }
 
+// NOTE(boulos): This function assumes you own the lock for the queue
+void DeadlineImageTraverser::resizeQueue(int new_size) {
+  // Must allocate a new queue of size new_size and then copy all
+  // the elements from 0 to qsize-1 into the new array
+  Tile** new_queue = new Tile*[new_size];
+  Tile*  new_tiles = new Tile[new_size];
+  for (int i = 0; i < qsize; i++) {
+    new_queue[i] = queue[i];
+    new_tiles[i] = tiles[i];
+  }
+  delete[] queue;
+  delete[] tiles;
+  queue = new_queue;
+  tiles = new_tiles;
+  total_tiles = new_size;
+}
+
 DeadlineImageTraverser::Tile* DeadlineImageTraverser::popFromQueue(Tile*& 
childtiles)
 {
   int numtiles = xrefinementRatio * yrefinementRatio;
@@ -238,8 +354,13 @@
   childtiles = &tiles[next_tile];
   next_tile += numtiles;
   if (next_tile >= total_tiles) {
-    cerr << "Uh oh, ran out of tile space for kids\n";
-    return 0;
+    cerr << "Can't resize for popFromQueue, so I'll just drop." << endl;
+    qlock.unlock();
+    return NULL;
+    throw SCIRun::InternalError("Can't currently resize during rendering", 
__FILE__, __LINE__);
+    resizeQueue(next_tile * 2);
+    //cerr << "Uh oh, ran out of tile space for kids\n";
+    //return 0;
   }
 
   // Get the next tile and update the queue
@@ -299,8 +420,11 @@
   int xcoarsetilesize = xpacketsize * xcoarsepixelsize;
   int ycoarsetilesize = ypacketsize * ycoarsepixelsize;
 
-  // First pass - do all of the coarse level tiles with the normal load 
balancer
+  // First pass - do all of the coarse level tiles with the normal
+  // load balancer
   int s,e;
+  // NOTE(boulos): If we've finished the coarse tiles, we have no
+  // assignments left
   while(context.loadBalancer->getNextAssignment(context, s, e)){
     for(int assignment = s; assignment < e; assignment++){
       int xtile = assignment/ytiles;
@@ -350,45 +474,145 @@
     }
   }
 
+  // NOTE(boulos): I don't care about this, but James thinks we should
+  // check ;)
+  if (!finished_coarse)
+    finished_coarse = true;
+
   while(Time::currentSeconds() < frameEnd){
     Tile* childtiles;
     Tile* tile = popFromQueue(childtiles);
     if(!tile)
-      break;
+      continue;
 
-    int newxmag = tile->xmag/xrefinementRatio;
-    if(newxmag < 1)
-      newxmag = 1;
-    int newymag = tile->ymag/yrefinementRatio;
-    if(newymag < 1)
-      newymag = 1;
-    int xs = xpacketsize * newxmag;
-    int ys = ypacketsize * newymag;
+    float newxmag = tile->xmag/xrefinementRatio;
+    float newymag = tile->ymag/yrefinementRatio;
 
     int nchild = 0;
-    for(int y = tile->ystart; y < tile->yend; y += ys){
-      for(int x = tile->xstart; x < tile->xend; x += xs){
-        int xend = x + xs;
-        if(xend > tile->xend)
-          xend = tile->xend;
-        int yend = y + ys;
-        if(yend > tile->yend)
-          yend = tile->yend;
 
-        Fragment frag(Fragment::SquareShape, Fragment::ConstantEye);
-        frag.setPixelSize(newxmag, newymag);
-        int idx = 0;
-        for (int j = y; j < yend; j+=newymag) {
-          for (int i = x; i < xend; i+=newxmag) {
-            frag.pixel[0][idx] = i;
-            frag.pixel[1][idx] = j;
-            frag.whichEye[idx] = 0;
-            idx++;
+    if(newxmag < 1 || newymag < 1) {
+      // Super sample the fragments. We want our fragment to exactly
+      // place 1./newxmag samples into each pixel, so we need to
+      // determine how many pixels we can render per packet.
+      int x_samples = static_cast<int>(1./newxmag);
+      int y_samples = static_cast<int>(1./newymag);
+
+      // TODO(boulos): Can we do some other number of samples?
+      int samples_per_pixel = x_samples * y_samples;
+
+      int xs = static_cast<int>(xpacketsize * newxmag);
+      int ys = static_cast<int>(ypacketsize * newymag);
+      // We might be asking for more samples than we can fit in a
+      // packet.
+      if (xs < 1 || ys < 1)
+        continue;
+
+      for(int y = tile->ystart; y < tile->yend; y += ys){
+        for(int x = tile->xstart; x < tile->xend; x += xs){
+          int xend = x + xs;
+          if(xend > tile->xend)
+            xend = tile->xend;
+          int yend = y + ys;
+          if(yend > tile->yend)
+            yend = tile->yend;
+
+          // NOTE(boulos): This logic is now slightly different as we
+          // are going to make smaller fragments.  This makes it so we
+          // don't need to change the render fragment logic (a single
+          // fragment will now just have many samples) so the fragment
+          // size will be smaller than before
+          Fragment frag(Fragment::SquareShape, Fragment::ConstantEye);
+          frag.setPixelSize(1, 1);
+          int idx = 0;
+          for (int j = y; j < yend; j++) {
+            for (int i = x; i < xend; i++) {
+              frag.pixel[0][idx] = i;
+              frag.pixel[1][idx] = j;
+              frag.whichEye[idx] = 0;
+              idx++;
+            }
+          }
+          frag.setSize(idx);
+
+          // NOTE(boulos): We know that we don't just stop anymore due
+          // to super sampling
+          JitterSampler* jitter_sampler = NULL;
+          switch (samples_per_pixel) {
+          case 4:
+            //cerr << "Using a 4 spp sampler" << endl;
+            jitter_sampler = jitterSamplers[0];
+            break;
+          case 16:
+            //cerr << "Using a 16 spp sampler" << endl;
+            jitter_sampler = jitterSamplers[1];
+            break;
+          case 64:
+            //cerr << "Using a 64 spp sampler" << endl;
+            jitter_sampler = jitterSamplers[2];
+            break;
+          case 256:
+            //cerr << "Using a 256 spp sampler" << endl;
+            jitter_sampler = jitterSamplers[3];
+            break;
+          default:
+            throw SCIRun::InternalError("Expected either 4, 16, 64, or 256 
spp", __FILE__, __LINE__);
+            break;
+          }
+          //cout << "Rendering a super sampled fragment" << endl;
+          jitter_sampler->renderFragment(context, frag);
+
+          if (ShowTimeSupersample) {
+            ColorComponent color = Time::currentSeconds()/60.;
+            for (int i = frag.begin(); i < frag.end(); i++) {
+              for ( int c = 0; c < Color::NumComponents; c++ )
+                frag.color[c][i] = color;
+            }
           }
+
+          Tile* childtile = &childtiles[nchild];
+          childtile->xstart = x;
+          childtile->xend = xend;
+          childtile->ystart = y;
+          childtile->yend = yend;
+          childtile->xmag = newxmag;
+          childtile->ymag = newymag;
+          computePriority(childtile, frag);
+          nchild++;
+          image->set(frag);
         }
-        frag.setSize(idx);
+      }
+    } else {
+      int newxmag_int = static_cast<int>(newxmag);
+      int newymag_int = static_cast<int>(newymag);
+
+      int xs = xpacketsize * newxmag_int;
+      int ys = ypacketsize * newymag_int;
 
-        if((newxmag | newymag) > 1){
+      for(int y = tile->ystart; y < tile->yend; y += ys){
+        for(int x = tile->xstart; x < tile->xend; x += xs){
+          int xend = x + xs;
+          if(xend > tile->xend)
+            xend = tile->xend;
+          int yend = y + ys;
+          if(yend > tile->yend)
+            yend = tile->yend;
+
+          Fragment frag(Fragment::SquareShape, Fragment::ConstantEye);
+
+          frag.setPixelSize(newxmag_int, newymag_int);
+          int idx = 0;
+          for (int j = y; j < yend; j+=newymag_int) {
+            for (int i = x; i < xend; i+=newxmag_int) {
+              frag.pixel[0][idx] = i;
+              frag.pixel[1][idx] = j;
+              frag.whichEye[idx] = 0;
+              idx++;
+            }
+          }
+          frag.setSize(idx);
+
+          // NOTE(boulos): We know that we don't just stop anymore due
+          // to super sampling
           singleSampler->renderFragment(context, frag);
           Tile* childtile = &childtiles[nchild];
           childtile->xstart = x;
@@ -399,12 +623,12 @@
           childtile->ymag = newymag;
           computePriority(childtile, frag);
           nchild++;
-        } else {
-          context.pixelSampler->renderFragment(context, frag);
+
+          image->set(frag);
         }
-        image->set(frag);
       }
     }
+
     if(nchild)
       insertIntoQueue(childtiles, nchild);
   }

Modified: trunk/Engine/ImageTraversers/DeadlineImageTraverser.h
==============================================================================
--- trunk/Engine/ImageTraversers/DeadlineImageTraverser.h       (original)
+++ trunk/Engine/ImageTraversers/DeadlineImageTraverser.h       Fri Jul 13 
15:55:25 2007
@@ -30,6 +30,7 @@
   DEALINGS IN THE SOFTWARE.
 */
 
+#include <Interface/IdleMode.h>
 #include <Interface/ImageTraverser.h>
 #include <Interface/Fragment.h>
 #include <Core/Thread/Mutex.h>
@@ -42,22 +43,31 @@
 namespace Manta {
   using namespace std;
   class SingleSampler;
+  class JitterSampler;
 
-  class DeadlineImageTraverser : public ImageTraverser {
+  class DeadlineImageTraverser : public ImageTraverser, public IdleMode {
   public:
     DeadlineImageTraverser(const vector<string>& args);
     virtual ~DeadlineImageTraverser();
+
+    virtual void changeIdleMode(const SetupContext&,
+                                bool changed,
+                                bool firstFrame,
+                                bool& pipelineNeedsSetup);
+
     virtual void setupBegin(SetupContext&, int numChannels);
     virtual void setupDisplayChannel(SetupContext&);
     virtual void setupFrame(const RenderContext& context);
     virtual void renderImage(const RenderContext& context, Image* image);
 
     static ImageTraverser* create(const vector<string>& args);
+    static const int kNumJitterLevels = 4; // This provides 4, 16, 64, and 
256 spp
   private:
     DeadlineImageTraverser(const DeadlineImageTraverser&);
     DeadlineImageTraverser& operator=(const DeadlineImageTraverser&);
 
     SingleSampler* singleSampler;
+    JitterSampler** jitterSamplers; // An array of different jittered 
samplers
 
     int xpacketsize;
     int ypacketsize;
@@ -75,8 +85,8 @@
       int ystart;
       int xend;
       int yend;
-      int xmag;
-      int ymag;
+      float xmag;
+      float ymag;
     };
     SCIRun::Mutex qlock;
     Tile* tiles;
@@ -85,7 +95,10 @@
     int qsize;
     int total_tiles;
     int top_tiles;
-
+    bool reset_every_frame;
+    bool finished_coarse;
+    bool ShowTimeSupersample;
+    double StartFrameTime;
     enum PriorityScheme {
       FIFO, LuminanceVariance, Contrast
     };
@@ -93,6 +106,7 @@
 
     void insertIntoQueue(Tile* oldtile, int numtiles);
     Tile* popFromQueue(Tile*& childtiles);
+    void resizeQueue(int new_size);
     void computePriority(Tile* tile, const Fragment& frag) const;
   };
 }

Modified: trunk/Interface/IdleMode.h
==============================================================================
--- trunk/Interface/IdleMode.h  (original)
+++ trunk/Interface/IdleMode.h  Fri Jul 13 15:55:25 2007
@@ -10,6 +10,11 @@
   public:
     virtual ~IdleMode();
 
+    // changeIdleMode is called whenever a switch from Idle->Active or
+    // Active->Idle occurs.  If something in the universe has changed,
+    // then changed = true, otherwise changed=false.  For example,
+    // moving the camera will notify you that changed=true.
+    // Additionally, changeIdleMode is called for the first frame.
     virtual void changeIdleMode(const SetupContext&, bool changed,
                                 bool firstFrame, bool& pipelineNeedsSetup) = 
0;
   protected:

Modified: trunk/StandAlone/manta.cc
==============================================================================
--- trunk/StandAlone/manta.cc   (original)
+++ trunk/StandAlone/manta.cc   Fri Jul 13 15:55:25 2007
@@ -333,7 +333,8 @@
           string s;
           if(!getStringArg(i, args, s))
             usage(factory);
-          if(!factory->addIdleMode(s)){
+          // NOTE(boulos): This is a very bad way to do this...
+          if(factory->addIdleMode(s) == static_cast<unsigned int>(-1)){
             cerr << "Invalid idle mode: " << s << ", available idle modes 
are:\n";
             printList(cerr, factory->listIdleModes());
             throw IllegalArgument( s, i, args );




  • [MANTA] r1471 - in trunk: Engine/ImageTraversers Interface StandAlone, boulos, 07/13/2007

Archive powered by MHonArc 2.6.16.

Top of page