• Views
  • Iteration Report
  • My Iteration Report
  •  
OMERO.server
  • Login
  • Help/Guide
  • About Trac
  • Preferences
  • Wiki
  • Timeline
  • Roadmap
  • Browse Source
  • View Tickets
  • Search

Context Navigation

  • ← Previous Changeset
  • Next Changeset →

Changeset 1048

Show
Ignore:
Timestamp:
10/26/06 17:59:06 (2 years ago)
Author:
callan
Message:

Huge rendering engine optimization and patch that closes and/or implements #190, #260, #449, #450, #451 and #453. Further information on rendering engine optimization can be found on the RenderingEngine Wiki page.

Location:
trunk/components
Files:
3 added
1 removed
17 modified

  • common/src/omeis/providers/re/RGBBuffer.java (modified) (3 diffs)
  • common/src/omeis/providers/re/RGBIntBuffer.java (added)
  • common/src/omeis/providers/re/RenderingEngine.java (modified) (1 diff)
  • rendering/src/omeis/providers/re/GreyScaleStrategy.java (modified) (5 diffs)
  • rendering/src/omeis/providers/re/HSBStrategy.java (modified) (6 diffs)
  • rendering/src/omeis/providers/re/QuantumManager.java (modified) (4 diffs)
  • rendering/src/omeis/providers/re/RGBStrategy.java (modified) (6 diffs)
  • rendering/src/omeis/providers/re/RenderHSBRegionTask.java (added)
  • rendering/src/omeis/providers/re/RenderHSBWaveTask.java (deleted)
  • rendering/src/omeis/providers/re/RenderRGBWaveTask.java (modified) (2 diffs)
  • rendering/src/omeis/providers/re/Renderer.java (modified) (6 diffs)
  • rendering/src/omeis/providers/re/RenderingStrategy.java (modified) (1 diff)
  • rendering/src/omeis/providers/re/RenderingTask.java (added)
  • rendering/src/omeis/providers/re/data/PlaneFactory.java (modified) (1 diff)
  • rendering/src/omeis/providers/re/quantum/Quantization_8_16_bit.java (modified) (2 diffs)
  • rendering/src/omeis/providers/re/quantum/QuantumFactory.java (modified) (4 diffs)
  • rendering/src/omeis/providers/re/quantum/QuantumStrategy.java (modified) (2 diffs)
  • server/src/ome/logic/PixelsImpl.java (modified) (1 diff)
  • server/src/ome/logic/ThumbImpl.java (modified) (9 diffs)
  • server/src/ome/security/basic/CurrentDetails.java (modified) (1 diff)
  • server/src/ome/services/RenderingBean.java (modified) (5 diffs)

Legend:

Unmodified
Added
Removed
  • trunk/components/common/src/omeis/providers/re/RGBBuffer.java

    r868 r1048  
    5858 
    5959    /** The serial number. */ 
    60         private static final long serialVersionUID = 5319594152389817322L; 
     60        private static final long serialVersionUID = 5319594152389817323L; 
    6161 
    6262        /** Index of the red band in the image's data buffer. */ 
    63     private static final int    R_BAND = 0; 
     63    public static final int    R_BAND = 0; 
    6464     
    6565    /** Index of the green band in the image's data buffer. */ 
    66     private static final int    G_BAND = 1; 
     66    public static final int    G_BAND = 1; 
    6767     
    6868    /** Index of the blue band in the image's data buffer. */ 
    69     private static final int    B_BAND = 2; 
     69    public static final int    B_BAND = 2; 
    7070     
    7171     
    … …  
    9393    private int         sizeX2; 
    9494     
     95    /** 
     96     * Simple constructor to avoid memory allocations. 
     97     * 
     98     */ 
     99    protected RGBBuffer() {} 
    95100     
    96101    /** 
    … …  
    157162    public int getSizeX2() { return sizeX2; } 
    158163     
     164    /** 
     165     * Sets the Red value for a particular pixel index. 
     166     * @param index The index in the band array. 
     167     * @param value The pixel value to set. 
     168     */ 
     169    public synchronized void setRedValue(int index, int value) 
     170    { 
     171        bands[R_BAND][index] = (byte) value; 
     172    } 
     173     
     174    /** 
     175     * Sets the Green value for a particular pixel index. 
     176     * @param index The index in the band array. 
     177     * @param value The pixel value to set. 
     178     */ 
     179    public synchronized void setGreenValue(int index, int value) 
     180    { 
     181        bands[G_BAND][index] = (byte) value; 
     182    } 
     183     
     184    /** 
     185     * Sets the Blue value for a particular pixel index. 
     186     * @param index The index in the band array. 
     187     * @param value The pixel value to set. 
     188     */ 
     189    public synchronized void setBlueValue(int index, int value) 
     190    { 
     191        bands[B_BAND][index] = (byte) value; 
     192    } 
     193     
     194    /** 
     195     * Retrieves the Red value for a particular pixel index. 
     196     * @param index The index in the band array. 
     197     * @return The pixel value at the index. 
     198     */ 
     199    public byte getRedValue(int index) 
     200    { 
     201        return bands[R_BAND][index]; 
     202    } 
     203     
     204    /** 
     205     * Retrieves the Green value for a particular pixel index. 
     206     * @param index The index in the band array. 
     207     * @return The pixel value at the index. 
     208     */ 
     209    public byte getGreenValue(int index) 
     210    { 
     211        return bands[G_BAND][index]; 
     212    } 
     213     
     214    /** 
     215     * Retrieves the Blue value for a particular pixel index. 
     216     * @param index The index in the band array. 
     217     * @return The pixel value at the index. 
     218     */ 
     219    public byte getBlueValue(int index) 
     220    { 
     221        return bands[B_BAND][index]; 
     222    } 
    159223} 
  • trunk/components/common/src/omeis/providers/re/RenderingEngine.java

    r1030 r1048  
    9999     
    100100    /** 
     101     * Renders the data selected by <code>pd</code> according to the current 
     102     * rendering settings. 
     103     * The passed argument selects a plane orthogonal to one of the <i>X</i>,  
     104     * <i>Y</i>, or <i>Z</i> axes.  How many wavelengths are rendered and 
     105     * what color model is used depends on the current rendering settings. 
     106     *  
     107     * @param pd Selects a plane orthogonal to one of the <i>X</i>, <i>Y</i>, 
     108     *           or <i>Z</i> axes. 
     109     * @return An <i>RGB</i> image ready to be displayed on screen. 
     110     * @throws ValidationException If <code>pd</code> is <code>null</code>. 
     111     * @see render() 
     112     */ 
     113    public int[] renderAsPackedInt(PlaneDef pd)  
     114        throws ValidationException; 
     115     
     116    /** 
    101117     * Loads the <code>Pixels</code> set this Rendering Engine is for. 
    102118     *  
  • trunk/components/rendering/src/omeis/providers/re/GreyScaleStrategy.java

    r732 r1048  
    135135        throws QuantizationException 
    136136    { 
    137         System.err.println("Render wave."); 
    138137        CodomainChain cc = renderer.getCodomainChain(); 
    139138        int x1, x2, discreteValue, pixelIndex; 
    140         byte value; 
    141         float alpha =  color.getAlpha().floatValue()/255; 
    142         byte[] red = dataBuf.getRedBand(), green = dataBuf.getGreenBand(), 
    143                blue = dataBuf.getBlueBand(); 
    144         for (x2 = 0; x2 < sizeX2; ++x2) { 
    145             for (x1 = 0; x1 < sizeX1; ++x1) { 
    146                 pixelIndex = sizeX1*x2+x1; 
    147                 discreteValue = qs.quantize(plane.getPixelValue(x1, x2)); 
    148                 discreteValue = cc.transform(discreteValue); 
    149                 value = (byte) (discreteValue*alpha); 
    150                 red[pixelIndex] = value; 
    151                 green[pixelIndex] = value; 
    152                 blue[pixelIndex] = value; 
    153             }  
     139         
     140        // Perform optimised pixel settings for integer arrays 
     141        if (dataBuf instanceof RGBIntBuffer) 
     142        { 
     143                int alpha = color.getAlpha(); 
     144                int[] buf = ((RGBIntBuffer) dataBuf).getDataBuffer(); 
     145                for (x2 = 0; x2 < sizeX2; ++x2) { 
     146                        int index = sizeX1 * x2; 
     147                    for (x1 = 0; x1 < sizeX1; ++x1) { 
     148                        discreteValue = qs.quantize(plane.getPixelValue(x1, x2)); 
     149                        discreteValue = cc.transform(discreteValue); 
     150                        buf[index + x1] = 
     151                                alpha << 24 | discreteValue << 16 
     152                            | discreteValue << 8 | discreteValue; 
     153                    } 
     154            } 
    154155        } 
     156        else  // We have just a plain RGBBuffer 
     157        { 
     158                byte value; 
     159                float alpha = color.getAlpha().floatValue() / 255; 
     160                byte[] r = dataBuf.getRedBand(); 
     161                byte[] g = dataBuf.getBlueBand(); 
     162                byte[] b = dataBuf.getGreenBand(); 
     163                for (x2 = 0; x2 < sizeX2; ++x2) { 
     164                    for (x1 = 0; x1 < sizeX1; ++x1) { 
     165                        pixelIndex = sizeX1*x2+x1; 
     166                        discreteValue = qs.quantize(plane.getPixelValue(x1, x2)); 
     167                        discreteValue = cc.transform(discreteValue); 
     168                        value = (byte) (discreteValue*alpha); 
     169                        r[pixelIndex] = value; 
     170                        g[pixelIndex] = value; 
     171                        b[pixelIndex] = value; 
     172                    } 
     173            } 
     174        } 
    155175    } 
    156176     
    … …  
    159179     * @see RenderingStrategy#render(Renderer ctx, PlaneDef planeDef) 
    160180     */ 
    161         RGBBuffer render(Renderer ctx, PlaneDef planeDef) 
     181    RGBBuffer render(Renderer ctx, PlaneDef planeDef) 
     182        throws IOException, QuantizationException 
     183    { 
     184                //Set the context and retrieve objects we're gonna use. 
     185                renderer = ctx; 
     186        RenderingStats performanceStats = renderer.getStats(); 
     187        Pixels metadata = renderer.getMetadata(); 
     188         
     189                //Initialize sizeX1 and sizeX2 according to the plane definition and 
     190                //create the RGB buffer. 
     191                initAxesSize(planeDef, metadata); 
     192        performanceStats.startMalloc(); 
     193        log.info("Creating RGBBuffer of size " + sizeX1 + "x" + sizeX2); 
     194        RGBBuffer buf = new RGBBuffer(sizeX1, sizeX2); 
     195        performanceStats.endMalloc(); 
     196         
     197        render(buf, planeDef); 
     198        return buf; 
     199    } 
     200     
     201    /** 
     202     * Implemented as specified by the superclass. 
     203     * @see RenderingStrategy#render(Renderer ctx, PlaneDef planeDef) 
     204     */ 
     205    RGBIntBuffer renderAsPackedInt(Renderer ctx, PlaneDef planeDef) 
    162206                throws IOException, QuantizationException 
    163207        { 
    164208                //Set the context and retrieve objects we're gonna use. 
    165209                renderer = ctx; 
     210        RenderingStats performanceStats = renderer.getStats(); 
     211        Pixels metadata = renderer.getMetadata(); 
     212         
     213                //Initialize sizeX1 and sizeX2 according to the plane definition and 
     214                //create the RGB buffer. 
     215                initAxesSize(planeDef, metadata); 
     216        log.info("Creating RGBBuffer of size " + sizeX1 + "x" + sizeX2); 
     217        RGBIntBuffer buf = new RGBIntBuffer(sizeX1, sizeX2); 
     218        performanceStats.endMalloc(); 
     219         
     220        render(buf, planeDef); 
     221                return buf; 
     222        } 
     223     
     224    /** 
     225     * Implemented as specified by the superclass. 
     226     * @see RenderingStrategy#render(Renderer ctx, PlaneDef planeDef) 
     227     */ 
     228        private void render(RGBBuffer buf, PlaneDef planeDef) 
     229                throws IOException, QuantizationException 
     230        { 
    166231                QuantumManager qManager = renderer.getQuantumManager(); 
    167232                PixelBuffer pixels = renderer.getPixels(); 
    … …  
    169234                ChannelBinding[] cBindings = renderer.getChannelBindings(); 
    170235        RenderingStats performanceStats = renderer.getStats(); 
    171                  
    172                 //Initialize sizeX1 and sizeX2 according to the plane definition and 
    173                 //create the RGB buffer. 
    174                 initAxesSize(planeDef, metadata); 
    175         performanceStats.startMalloc(); 
    176         log.info("Creating RGBBuffer of size " + sizeX1 + "x" + sizeX2); 
    177         RGBBuffer renderedDataBuf = new RGBBuffer(sizeX1, sizeX2); 
    178         performanceStats.endMalloc(); 
    179236         
    180237                //Process the first active wavelength.  
    … …  
    189246                                try {  //Transform it into an RGB image. 
    190247                    performanceStats.startRendering(); 
    191                     renderWave(renderedDataBuf, wData, cBindings[i].getColor(), 
     248                    renderWave(buf, wData, cBindings[i].getColor(), 
    192249                               qManager.getStrategyFor(i)); 
    193250                    performanceStats.endRendering(); 
    … …  
    199256                        } 
    200257                } 
    201  
    202                 //Done. 
    203         return renderedDataBuf; 
    204258        } 
    205259     
  • trunk/components/rendering/src/omeis/providers/re/HSBStrategy.java

    r732 r1048  
    3333import java.io.IOException; 
    3434import java.util.ArrayList; 
    35 import java.util.concurrent.ExecutorService;//j.m 
    36 import java.util.concurrent.Executors;//j.m 
    37 import java.util.concurrent.Future;//j.m 
     35import java.util.List; 
     36import java.util.concurrent.Callable; 
     37import java.util.concurrent.ExecutorService; 
     38import java.util.concurrent.Executors; 
     39import java.util.concurrent.Future; 
    3840 
    3941//Third-party libraries 
    … …  
    4749import ome.model.core.Pixels; 
    4850import ome.model.display.ChannelBinding; 
     51import ome.model.display.Color; 
    4952 
    5053//j.mimport omeis.env.Env; 
    … …  
    5457import omeis.providers.re.data.PlaneDef; 
    5558import omeis.providers.re.quantum.QuantizationException; 
     59import omeis.providers.re.quantum.QuantumStrategy; 
    5660 
    5761/**  
    … …  
    101105    private Renderer    renderer; 
    102106     
     107    /** 
     108     * The maximum number of tasks (regions to split the image up into) that 
     109     * we will be using. 
     110     */ 
     111    private static final int maxTasks = 2; 
    103112     
    104113    /**  
    … …  
    133142     
    134143    /** 
    135      * Creates a rendering task for each active wavelength. 
     144     * Retrieves the maximum number of reasonable tasks to schedule based on 
     145     * image size and <i>maxTasks</i>. 
     146     * @return the number of tasks to schedule. 
     147     */ 
     148    private int numTasks() 
     149    { 
     150        for (int i = maxTasks; i > 0; i--) 
     151        { 
     152                if ((sizeX2 % i) == 0) 
     153                        return i; 
     154        } 
     155        return 1; 
     156    } 
     157     
     158     
     159    /** 
     160     * Retrieves the wavelength data for all the active channels. 
     161     * @return the wavelength data. 
     162     */ 
     163    private List<Plane2D> getWavelengthData(PlaneDef pDef) 
     164    { 
     165        ChannelBinding[] channelBindings = renderer.getChannelBindings(); 
     166        Pixels metadata = renderer.getMetadata(); 
     167        PixelBuffer pixels = renderer.getPixels(); 
     168        RenderingStats performanceStats = renderer.getStats(); 
     169        ArrayList<Plane2D> wData = new ArrayList<Plane2D>(); 
     170         
     171        for (int w = 0; w < channelBindings.length; w++) 
     172        { 
     173                if (channelBindings[w].getActive()) 
     174                { 
     175                        performanceStats.startIO(w); 
     176                        wData.add(PlaneFactory.createPlane(pDef, w, metadata, pixels)); 
     177                        performanceStats.endIO(w); 
     178                } 
     179        } 
     180        return wData; 
     181    } 
     182     
     183    /** 
     184     * Retrieves the color for each active channels. 
     185     * @return the active channel color data. 
     186     */ 
     187    private List<Color> getColors() 
     188    { 
     189        ChannelBinding[] channelBindings = renderer.getChannelBindings(); 
     190        ArrayList<Color> colors = new ArrayList<Color>(); 
     191         
     192        for (int w = 0; w < channelBindings.length; w++) 
     193        { 
     194                if (channelBindings[w].getActive()) 
     195                { 
     196                        colors.add(channelBindings[w].getColor()); 
     197                } 
     198        } 
     199        return colors; 
     200    } 
     201     
     202    /** 
     203     * Retrieves the quantum strategy for each active channels 
     204     * @return the active channel color data. 
     205     */ 
     206    private List<QuantumStrategy> getStrategies() 
     207    { 
     208        ChannelBinding[] channelBindings = renderer.getChannelBindings(); 
     209        QuantumManager qManager = renderer.getQuantumManager(); 
     210        ArrayList<QuantumStrategy> strats = new ArrayList<QuantumStrategy>(); 
     211         
     212        for (int w = 0; w < channelBindings.length; w++) 
     213        { 
     214                if (channelBindings[w].getActive()) 
     215                { 
     216                        strats.add(qManager.getStrategyFor(w)); 
     217                } 
     218        } 
     219        return strats; 
     220    } 
     221     
     222    /** 
     223     * Creates a set of rendering tasks for the image based on the calling 
     224     * buffer type. 
    136225     *  
    137226     * @param planeDef The plane to render. 
     227     * @param buf The buffer to render into. 
    138228     * @return An array containing the tasks. 
    139229     */ 
    140     private RenderHSBWaveTask[] makeRndTasks(PlaneDef planeDef) 
    141     { 
    142         ArrayList tasks = new ArrayList(); 
     230    private RenderingTask[] makeRenderingTasks(PlaneDef def, RGBBuffer buf) 
     231    { 
     232        ArrayList<RenderHSBRegionTask> tasks = 
     233                new ArrayList<RenderHSBRegionTask>(); 
     234 
     235        //Get all objects we need to create the tasks.  
     236        CodomainChain cc = renderer.getCodomainChain(); 
     237        RenderingStats performanceStats = renderer.getStats(); 
     238        List<Plane2D> wData = getWavelengthData(def); 
     239        List<Color> colors = getColors(); 
     240        List<QuantumStrategy> strategies = getStrategies(); 
     241 
     242        //Create a number of rendering tasks. 
     243        int taskCount = numTasks(); 
     244        int delta = sizeX2 / taskCount; 
     245        for (int i = 0; i < taskCount; i++) 
     246        { 
     247                //Allocate the RGB buffer for this wavelength. 
     248                performanceStats.startMalloc(); 
     249                performanceStats.endMalloc(); 
     250 
     251                int x1Start = 0; 
     252                int x1End = sizeX1; 
     253                int x2Start = i * delta; 
     254                int x2End = (i + 1) * delta; 
     255                tasks.add( 
     256                        new RenderHSBRegionTask(buf, wData, strategies, cc, colors, 
     257                                            x1Start, x1End, x2Start, x2End)); 
     258        } 
     259 
     260        //Turn the list into an array an return it. 
     261        RenderingTask[] tArray = new RenderingTask[tasks.size()]; 
     262        return tasks.toArray(tArray); 
     263    } 
     264 
     265    /** 
     266     * Implemented as specified by the superclass. 
     267     * @see RenderingStrategy#render(Renderer ctx, PlaneDef planeDef) 
     268     */ 
     269    RGBBuffer render(Renderer ctx, PlaneDef planeDef) 
     270        throws IOException, QuantizationException 
     271    { 
     272                //Set the context and retrieve objects we're gonna use. 
     273                renderer = ctx; 
     274        RenderingStats performanceStats = renderer.getStats(); 
     275        Pixels metadata = renderer.getMetadata(); 
     276         
     277                //Initialize sizeX1 and sizeX2 according to the plane definition and 
     278                //create the RGB buffer. 
     279                initAxesSize(planeDef, metadata); 
     280        performanceStats.startMalloc(); 
     281        RGBBuffer buf = new RGBBuffer(sizeX1, sizeX2); 
     282        performanceStats.endMalloc(); 
    143283         
    144         //Get all objects we need to create the tasks.  
    145         Plane2D wData; 
    146         ChannelBinding[] cBindings =  
    147                 renderer.getChannelBindings(); 
    148         CodomainChain cc = renderer.getCodomainChain(); 
    149         Pixels metadata = renderer.getMetadata(); 
    150         PixelBuffer pixels = renderer.getPixels(); 
    151         QuantumManager qManager = renderer.getQuantumManager(); 
    152         RenderingStats performanceStats = renderer.getStats(); 
    153         RGBBuffer channelBuf; 
    154          
    155         //Create a task for each active wavelength. 
    156         for (int w = 0; w < cBindings.length; w++) { 
    157             if (cBindings[w].getActive().booleanValue()) { 
    158                 //Allocate the RGB buffer for this wavelength. 
    159                 performanceStats.startMalloc(); 
    160                 channelBuf = new RGBBuffer(sizeX1, sizeX2); 
    161                 performanceStats.endMalloc(); 
    162                  
    163                 //Get the raw data. 
    164                 performanceStats.startIO(w); 
    165                 wData = PlaneFactory.createPlane(planeDef, w, metadata, pixels); 
    166                 performanceStats.endIO(w); 
    167                  
    168                 //Create a rendering task for this wavelength. 
    169                 tasks.add(new RenderHSBWaveTask(channelBuf, wData,  
    170                                                 qManager.getStrategyFor(w),  
    171                                                 cc, cBindings[w].getColor(),  
    172                                                 sizeX1, sizeX2)); 
    173             } 
    174         } 
    175          
    176         //Turn the list into an array an return it. 
    177         RenderHSBWaveTask[] t = new RenderHSBWaveTask[tasks.size()]; 
    178         return (RenderHSBWaveTask[]) tasks.toArray(t); 
    179     } 
    180      
    181     /** 
    182      * Implemented as specified by superclass. 
     284        render(buf, planeDef); 
     285        return buf; 
     286    } 
     287     
     288    /** 
     289     * Implemented as specified by the superclass. 
    183290     * @see RenderingStrategy#render(Renderer ctx, PlaneDef planeDef) 
    184291     */ 
    185     RGBBuffer render(Renderer ctx, PlaneDef planeDef) 
    186         throws IOException, QuantizationException 
    187     { 
    188         //Set the rendering context for the current invocation. 
    189         renderer = ctx; 
     292    RGBIntBuffer renderAsPackedInt(Renderer ctx, PlaneDef planeDef) 
     293                throws IOException, QuantizationException 
     294        { 
     295                //Set the context and retrieve objects we're gonna use. 
     296                renderer = ctx; 
     297        RenderingStats performanceStats = renderer.getStats(); 
     298        Pixels metadata = renderer.getMetadata(); 
     299         
     300                //Initialize sizeX1 and sizeX2 according to the plane definition and 
     301                //create the RGB buffer. 
     302                initAxesSize(planeDef, metadata); 
     303        performanceStats.startMalloc(); 
     304        RGBIntBuffer buf = new RGBIntBuffer(sizeX1, sizeX2); 
     305        performanceStats.endMalloc(); 
     306         
     307        render(buf, planeDef); 
     308                return buf; 
     309        } 
     310     
     311    /** 
     312     * Implemented as specified by the superclass. 
     313     * @see RenderingStrategy#render(Renderer ctx, PlaneDef planeDef) 
     314     */ 
     315        private void render(RGBBuffer buf, PlaneDef planeDef) 
     316                throws IOException, QuantizationException 
     317        { 
    190318        RenderingStats performanceStats = renderer.getStats(); 
    191319         
    … …  
    196324        //process N-1 async and one in the current thread.  If N = 1,  
    197325        //just use the current thread. 
    198         RenderHSBWaveTask[] tasks = makeRndTasks(planeDef); 
     326        RenderingTask[] tasks = makeRenderingTasks(planeDef, buf); 
    199327        performanceStats.startRendering(); 
    200328        int n = tasks.length; 
    201329        Future[] rndTskFutures = new Future[n];  //[0] unused. 
    202         //CmdProcessor processor = Env.getProcessor(); 
    203         ExecutorService processor = Executors.newCachedThreadPool();//j.m 
     330        ExecutorService processor = Executors.newCachedThreadPool(); 
    204331         
    205332        while (0 < --n) 
    206             rndTskFutures[n] = processor.submit(tasks[n]); //j.m exec(tasks[n]); 
    207         RGBBuffer rndDataBuf = null; 
    208         byte[] red = null, green = null, blue = null; 
    209         if (n == 0) { 
    210             rndDataBuf = (RGBBuffer) tasks[0].call();  
    211             red = rndDataBuf.getRedBand(); 
    212             green = rndDataBuf.getGreenBand(); 
    213             blue = rndDataBuf.getBlueBand(); 
    214         } 
     333            rndTskFutures[n] = processor.submit(tasks[n]); 
     334         
     335        //Call the task in the current thread. 
     336        if (n == 0) 
     337                                tasks[0].call(); 
    215338     
    216339        //Wait for all forked tasks (if any) to complete. 
    217         //When a task completes, assemble its RGB buffer into rndDataBuf. 
    218         RGBBuffer taskBuffer; 
    219         int x1, x2, pix; 
    220         byte[] r, g, b; 
    221340        for (n = 1; n < rndTskFutures.length; ++n) { 
    222341            try { 
    223                 taskBuffer = (RGBBuffer) rndTskFutures[n].get();//j.m getResult(); 
    224                 r = taskBuffer.getRedBand(); 
    225                 g = taskBuffer.getGreenBand(); 
    226                 b = taskBuffer.getBlueBand(); 
    227                 for (x2 = 0; x2 < sizeX2; ++x2) { 
    228                     for (x1 = 0; x1 < sizeX1; ++x1) { 
    229                         pix = sizeX1*x2+x1; 
    230                         red[pix] = (byte) (red[pix]+r[pix]); 
    231                         green[pix] = (byte) (green[pix]+g[pix]); 
    232                         blue[pix] = (byte) (blue[pix]+b[pix]); 
    233                     }  
    234                 }  
     342                rndTskFutures[n].get(); 
    235343            } catch (Exception e) { 
    236344                if (e instanceof QuantizationException) 
    237345                    throw (QuantizationException) e; 
    238                 throw (RuntimeException) e;   
    239                 //B/c call() only throws QuantizationException, it must be RE. 
     346                throw new RuntimeException(e); 
    240347            } 
    241348        } 
    242349        performanceStats.endRendering(); 
    243          
    244         if (rndDataBuf == null)  //No active channel, return a black image.  
    245             return new RGBBuffer(sizeX1, sizeX2); 
    246          
    247         //Done. 
    248         return rndDataBuf; 
    249350    }