[mapserver-commits] r9260 - trunk/mapserver

svn at osgeo.org svn at osgeo.org
Mon Aug 17 15:52:08 EDT 2009


Author: warmerdam
Date: 2009-08-17 15:52:07 -0400 (Mon, 17 Aug 2009)
New Revision: 9260

Modified:
   trunk/mapserver/HISTORY.TXT
   trunk/mapserver/mapdrawgdal.c
Log:
Load all GDAL image bands in one pass for faster processing

Modified: trunk/mapserver/HISTORY.TXT
===================================================================
--- trunk/mapserver/HISTORY.TXT	2009-08-17 19:47:44 UTC (rev 9259)
+++ trunk/mapserver/HISTORY.TXT	2009-08-17 19:52:07 UTC (rev 9260)
@@ -14,6 +14,10 @@
 Current Version (SVN trunk):
 ----------------------------
 
+- Modify loading imagery from GDAL to load all bands at once to avoid multiple
+  passes through pixel interleaved data (mapdrawgdal.c).  This is just an
+  optimization - there should be no change in results or features.
+
 - Modern GDALs clear the config when destroying driver manager.  Skip this
   call to avoid TLS leakage on cleanup (mapgdal.c).
 

Modified: trunk/mapserver/mapdrawgdal.c
===================================================================
--- trunk/mapserver/mapdrawgdal.c	2009-08-17 19:47:44 UTC (rev 9259)
+++ trunk/mapserver/mapdrawgdal.c	2009-08-17 19:52:07 UTC (rev 9260)
@@ -54,10 +54,11 @@
 #endif
 
 static int
-LoadGDALImage( GDALRasterBandH hBand, int iColorIndex, 
-               layerObj *layer, 
-               int src_xoff, int src_yoff, int src_xsize, int src_ysize, 
-               GByte *pabyBuffer, int dst_xsize, int dst_ysize );
+LoadGDALImages( GDALDatasetH hDS, int band_numbers[4], int band_count,
+		layerObj *layer, 
+		int src_xoff, int src_yoff, int src_xsize, int src_ysize, 
+		GByte *pabyBuffer,
+		int dst_xsize, int dst_ysize );
 static int 
 msDrawRasterLayerGDAL_RawMode(
     mapObj *map, layerObj *layer, imageObj *image, GDALDatasetH hDS, 
@@ -118,11 +119,11 @@
                 *pabyRawAlpha = NULL;
   int truecolor = FALSE, classified = FALSE;
   int red_band=0, green_band=0, blue_band=0, alpha_band=0, cmt=0;
+  int band_count, band_numbers[4];
   gdImagePtr gdImg = NULL;
   GDALDatasetH hDS = hDSVoid;
   GDALColorTableH hColorMap;
-  GDALRasterBandH hBand1, hBand2, hBand3, hBandAlpha;
-
+  GDALRasterBandH hBand1=NULL, hBand2=NULL, hBand3=NULL, hBandAlpha=NULL;
   memset( cmap, 0xff, MAXCOLORS * sizeof(int) );
 
 /* -------------------------------------------------------------------- */
@@ -386,7 +387,7 @@
   }
   else
   {
-      int band_count, *band_list;
+      int *band_list;
 
       band_list = msGetGDALBandList( layer, hDS, 4, &band_count );
       if( band_list == NULL )
@@ -415,6 +416,26 @@
       free( band_list );
   }
 
+  band_numbers[0] = red_band;
+  band_numbers[1] = green_band;
+  band_numbers[2] = blue_band;
+  band_numbers[3] = 0;
+  
+  if( blue_band != 0 && alpha_band != 0 )
+  {
+      band_numbers[3] = alpha_band;
+      band_count = 4;
+  }
+  else if( blue_band != 0 && alpha_band == 0 )
+      band_count = 3;
+  else if( alpha_band != 0 )
+  {
+      band_numbers[1] = alpha_band;
+      band_count = 2;
+  }
+  else
+      band_count = 1;
+  
   if( layer->debug > 1 || (layer->debug > 0 && green_band != 0) )
   {
       msDebug( "msDrawGDAL(): red,green,blue,alpha bands = %d,%d,%d,%d\n", 
@@ -676,90 +697,40 @@
   }
 
   /*
-   * Read the entire region of interest in one gulp.  GDAL will take
-   * care of downsampling and window logic.  
+   * Allocate imagery buffers.
    */
-  pabyRaw1 = (unsigned char *) malloc(dst_xsize * dst_ysize);
+  pabyRaw1 = (unsigned char *) malloc(dst_xsize * dst_ysize * band_count);
   if( pabyRaw1 == NULL )
   {
-      msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
-                 "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
+      msSetError(MS_MEMERR, "Allocating work image of size %dx%dx%d failed.",
+                 "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize, band_count );
       return -1;
   }
 
-  if( LoadGDALImage( hBand1, 1, layer, 
-                     src_xoff, src_yoff, src_xsize, src_ysize, 
-                     pabyRaw1, dst_xsize, dst_ysize ) == -1 )
+  if( hBand2 != NULL && hBand3 != NULL )
   {
-      free( pabyRaw1 );
-      return -1;
+      pabyRaw2 = pabyRaw1 + dst_xsize * dst_ysize * 1;
+      pabyRaw3 = pabyRaw1 + dst_xsize * dst_ysize * 2;
   }
 
-  if( hBand2 != NULL && hBand3 != NULL )
+  if( hBandAlpha != NULL )
   {
-      pabyRaw2 = (unsigned char *) malloc(dst_xsize * dst_ysize);
-      if( pabyRaw2 == NULL )
-      {
-          msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
-                     "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
-          return -1;
-      }
-      
-      if( LoadGDALImage( hBand2, 2, layer, 
-                         src_xoff, src_yoff, src_xsize, src_ysize, 
-                         pabyRaw2, dst_xsize, dst_ysize ) == -1 )
-      {
-          free( pabyRaw1 );
-          free( pabyRaw2 );
-          return -1;
-      }
-
-      pabyRaw3 = (unsigned char *) malloc(dst_xsize * dst_ysize);
-      if( pabyRaw3 == NULL )
-      {
-          msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
-                     "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
-          return -1;
-      }
-      
-      if( LoadGDALImage( hBand3, 3, layer, 
-                         src_xoff, src_yoff, src_xsize, src_ysize, 
-                         pabyRaw3, dst_xsize, dst_ysize ) == -1 )
-      {
-          free( pabyRaw1 );
-          free( pabyRaw2 );
-          free( pabyRaw3 );
-          return -1;
-      }
+      if( hBand2 != NULL )
+          pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 3;
+      else
+          pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 1;
   }
 
-  if( hBandAlpha != NULL )
+  /*
+   * Load image data into buffers with scaling, etc.
+   */
+  if( LoadGDALImages( hDS, band_numbers, band_count, layer, 
+		      src_xoff, src_yoff, src_xsize, src_ysize, 
+		      pabyRaw1, dst_xsize, dst_ysize ) == -1 )
   {
-      pabyRawAlpha = (unsigned char *) malloc(dst_xsize * dst_ysize);
-      if( pabyRawAlpha == NULL )
-      {
-          msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
-                     "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
-          return -1;
-      }
-      
-      if( LoadGDALImage( hBandAlpha, 4, layer, 
-                         src_xoff, src_yoff, src_xsize, src_ysize, 
-                         pabyRawAlpha, dst_xsize, dst_ysize ) == -1 )
-      {
-          free( pabyRaw1 );
-          if( pabyRaw3 != NULL )
-          {
-              free( pabyRaw2 );
-              free( pabyRaw3 );
-          }
-
-          free( pabyRawAlpha );
-          return -1;
-      }
+      free( pabyRaw1 );
+      return -1;
   }
-  else
-      pabyRawAlpha = NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Single band plus colormap with alpha blending to 8bit.          */
@@ -986,15 +957,6 @@
   ** Cleanup
   */
 
-  if( pabyRaw3 != NULL )
-  {
-      free( pabyRaw2 );
-      free( pabyRaw3 );
-  }
-
-  if( pabyRawAlpha != NULL )
-      free( pabyRawAlpha );
-
   free( pabyRaw1 );
 
   if( hColorMap != NULL )
@@ -1263,172 +1225,220 @@
 }
 
 /************************************************************************/
-/*                           LoadGDALImage()                            */
+/*                           LoadGDALImages()                           */
 /*                                                                      */
-/*      This call will load and process one band of input for the       */
+/*      This call will load and process 1-4 bands of input for the      */
 /*      selected rectangle, loading the result into the passed 8bit     */
 /*      buffer.  The processing options include scaling.                */
 /************************************************************************/
 
 static int
-LoadGDALImage( GDALRasterBandH hBand, int iColorIndex,  layerObj *layer, 
-               int src_xoff, int src_yoff, int src_xsize, int src_ysize, 
-               GByte *pabyBuffer, int dst_xsize, int dst_ysize )
+LoadGDALImages( GDALDatasetH hDS, int band_numbers[4], int band_count,
+		layerObj *layer, 
+		int src_xoff, int src_yoff, int src_xsize, int src_ysize, 
+		GByte *pabyWholeBuffer,
+		int dst_xsize, int dst_ysize )
     
 {
+    int    iColorIndex, result_code=0;
     CPLErr eErr;
-    double dfScaleMin=0.0, dfScaleMax=255.0, dfScaleRatio, dfNoDataValue;
-    const char *pszScaleInfo;
-    float *pafRawData;
-    int   nPixelCount = dst_xsize * dst_ysize, i, bGotNoData = FALSE;
+    float *pafWholeRawData;
 
 /* -------------------------------------------------------------------- */
-/*      Fetch the scale processing option.                              */
+/*      Are we doing a simple, non-scaling case?  If so, read directly  */
+/*      and return.                                                     */
 /* -------------------------------------------------------------------- */
-    pszScaleInfo = CSLFetchNameValue( layer->processing, "SCALE" );
-    if( pszScaleInfo == NULL )
+    if( CSLFetchNameValue( layer->processing, "SCALE" ) == NULL
+	&& CSLFetchNameValue( layer->processing, "SCALE_1" ) == NULL
+	&& CSLFetchNameValue( layer->processing, "SCALE_2" ) == NULL
+	&& CSLFetchNameValue( layer->processing, "SCALE_3" ) == NULL
+	&& CSLFetchNameValue( layer->processing, "SCALE_4" ) == NULL )
     {
-        char szBandScalingName[20];
+        eErr = GDALDatasetRasterIO( hDS, GF_Read, 
+				    src_xoff, src_yoff, src_xsize, src_ysize, 
+				    pabyWholeBuffer, 
+				    dst_xsize, dst_ysize, GDT_Byte,
+				    band_count, band_numbers,
+				    0,0,0);
 
-        sprintf( szBandScalingName, "SCALE_%d", iColorIndex );
-        pszScaleInfo = CSLFetchNameValue( layer->processing, 
-                                          szBandScalingName);
-    }
-
-    if( pszScaleInfo != NULL )
-    {
-        char **papszTokens;
-
-        papszTokens = CSLTokenizeStringComplex( pszScaleInfo, " ,", 
-                                                FALSE, FALSE );
-        if( CSLCount(papszTokens) == 1
-            && EQUAL(papszTokens[0],"AUTO") )
-        {
-            dfScaleMin = dfScaleMax = 0.0;
-        }
-        else if( CSLCount(papszTokens) != 2 )
-        {
-            msSetError( MS_MISCERR, 
-                        "SCALE PROCESSING option unparsable for layer %s.",
-                        layer->name, 
-                        "msDrawGDAL()" );
-            return -1;
-        }
-        else
-        {
-            dfScaleMin = atof(papszTokens[0]);
-            dfScaleMax = atof(papszTokens[1]);
-        }
-        CSLDestroy( papszTokens );
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      If we have no scaling parameters, just truncate to 8bit.        */
-/* -------------------------------------------------------------------- */
-    if( pszScaleInfo == NULL )
-    {
-        eErr = GDALRasterIO( hBand, GF_Read, 
-                             src_xoff, src_yoff, src_xsize, src_ysize, 
-                             pabyBuffer, dst_xsize, dst_ysize, GDT_Byte, 0,0);
-
         if( eErr != CE_None )
-            msSetError( MS_IOERR, "GDALRasterIO() failed: %s", 
+	{
+            msSetError( MS_IOERR, "GDALDatasetRasterIO() failed: %s", 
                         CPLGetLastErrorMsg(), "drawGDAL()" );
+	    return -1;
+	}
 
-        if( eErr == CE_None )
-        {
-            return ApplyLUT( iColorIndex, layer, 
-                             pabyBuffer, dst_xsize, dst_ysize );;
-        }
-        else
-            return -1;
+	for( iColorIndex = 0; 
+	     iColorIndex < band_count && result_code == 0; iColorIndex++ )
+	{
+	    result_code = ApplyLUT( iColorIndex+1, layer, 
+				    pabyWholeBuffer 
+				    + dst_xsize*dst_ysize*iColorIndex, 
+				    dst_xsize, dst_ysize );
+	}
+	
+	return result_code;
     }
 
 /* -------------------------------------------------------------------- */
-/*      Otherwise, allocate a temporary floating point buffer, and      */
-/*      load into that.                                                 */
+/*      We need to do some scaling.  Will load into either a 16bit      */
+/*      unsigned or a floating point buffer depending on the source     */
+/*      data.  We offer a special case for 16U data because it is       */
+/*      common and it is a substantial win to avoid alot of floating    */
+/*      point operations on it.                                         */
 /* -------------------------------------------------------------------- */
-    pafRawData = (float *) malloc(sizeof(float) * dst_xsize * dst_ysize );
+    /* TODO */
 
-    if( pafRawData == NULL )
+/* -------------------------------------------------------------------- */
+/*      Allocate the raw imagery buffer, and load into it (band         */
+/*      interleaved).                                                   */
+/* -------------------------------------------------------------------- */
+    pafWholeRawData = 
+        (float *) malloc(sizeof(float) * dst_xsize * dst_ysize * band_count );
+
+    if( pafWholeRawData == NULL )
     {
         msSetError(MS_MEMERR, 
-                   "Allocating work float image of size %dx%d failed.",
-                   "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
+                   "Allocating work float image of size %dx%dx%d failed.",
+                   "msDrawRasterLayerGDAL()", 
+                   dst_xsize, dst_ysize, band_count );
         return -1;
     }
-
-    eErr = GDALRasterIO( hBand, GF_Read, 
-                         src_xoff, src_yoff, src_xsize, src_ysize, 
-                         pafRawData, dst_xsize, dst_ysize, GDT_Float32, 0, 0 );
+	
+    eErr = GDALDatasetRasterIO( 
+        hDS, GF_Read, 
+        src_xoff, src_yoff, src_xsize, src_ysize, 
+        pafWholeRawData, dst_xsize, dst_ysize, GDT_Float32, 
+        band_count, band_numbers,
+        0, 0, 0 );
     
     if( eErr != CE_None )
     {
-        msSetError( MS_IOERR, "GDALRasterIO() failed: %s", 
+        msSetError( MS_IOERR, "GDALDatasetRasterIO() failed: %s", 
                     CPLGetLastErrorMsg(), "drawGDAL()" );
-
-        free( pafRawData );
+        
+        free( pafWholeRawData );
         return -1;
     }
 
 /* -------------------------------------------------------------------- */
+/*      Fetch the scale processing option.                              */
+/* -------------------------------------------------------------------- */
+    for( iColorIndex = 0; iColorIndex < band_count; iColorIndex++ )
+    {
+	unsigned char *pabyBuffer;
+	double dfScaleMin=0.0, dfScaleMax=255.0, dfScaleRatio, dfNoDataValue;
+	const char *pszScaleInfo;
+	float *pafRawData;
+	int   nPixelCount = dst_xsize * dst_ysize, i, bGotNoData = FALSE;
+	GDALRasterBandH hBand =GDALGetRasterBand(hDS,band_numbers[iColorIndex]);
+	pszScaleInfo = CSLFetchNameValue( layer->processing, "SCALE" );
+	if( pszScaleInfo == NULL )
+        {
+	    char szBandScalingName[20];
+	    
+	    sprintf( szBandScalingName, "SCALE_%d", iColorIndex+1 );
+	    pszScaleInfo = CSLFetchNameValue( layer->processing, 
+					      szBandScalingName);
+        }
+	
+	if( pszScaleInfo != NULL )
+        {
+	    char **papszTokens;
+	    
+	    papszTokens = CSLTokenizeStringComplex( pszScaleInfo, " ,", 
+						    FALSE, FALSE );
+	    if( CSLCount(papszTokens) == 1
+		&& EQUAL(papszTokens[0],"AUTO") )
+            {
+		dfScaleMin = dfScaleMax = 0.0;
+            }
+	    else if( CSLCount(papszTokens) != 2 )
+            {
+                free( pafWholeRawData );
+		msSetError( MS_MISCERR, 
+			    "SCALE PROCESSING option unparsable for layer %s.",
+			    layer->name, 
+			    "msDrawGDAL()" );
+		return -1;
+            }
+	    else
+            {
+		dfScaleMin = atof(papszTokens[0]);
+		dfScaleMax = atof(papszTokens[1]);
+            }
+	    CSLDestroy( papszTokens );
+        }
+    
+/* -------------------------------------------------------------------- */
 /*      If we are using autoscaling, then compute the max and min       */
 /*      now.  Perhaps we should eventually honour the offsite value     */
 /*      as a nodata value, or get it from GDAL.                         */
 /* -------------------------------------------------------------------- */
-    if( dfScaleMin == dfScaleMax )
-    {
-        dfScaleMin = dfScaleMax = pafRawData[0];
+	pafRawData = pafWholeRawData + iColorIndex * dst_xsize * dst_ysize;
 
-        for( i = 1; i < nPixelCount; i++ )
+	if( dfScaleMin == dfScaleMax )
         {
-            dfScaleMin = MIN(dfScaleMin,pafRawData[i]);
-            dfScaleMax = MAX(dfScaleMax,pafRawData[i]);
+	    dfScaleMin = dfScaleMax = pafRawData[0];
+	    
+	    for( i = 1; i < nPixelCount; i++ )
+            {
+		dfScaleMin = MIN(dfScaleMin,pafRawData[i]);
+		dfScaleMax = MAX(dfScaleMax,pafRawData[i]);
+            }
+	    if( dfScaleMin == dfScaleMax )
+                dfScaleMax = dfScaleMin + 1.0;
         }
-        if( dfScaleMin == dfScaleMax )
-            dfScaleMax = dfScaleMin + 1.0;
-    }
-
-    if( layer->debug > 0 )
-        msDebug( "msDrawGDAL(%s): scaling to 8bit, src range=%g,%g\n",
-                 layer->name, dfScaleMin, dfScaleMax );
-
+	
+	if( layer->debug > 0 )
+            msDebug( "msDrawGDAL(%s): scaling to 8bit, src range=%g,%g\n",
+                     layer->name, dfScaleMin, dfScaleMax );
+	
 /* -------------------------------------------------------------------- */
 /*      Now process the data.                                           */
 /* -------------------------------------------------------------------- */
-    dfScaleRatio = 256.0 / (dfScaleMax - dfScaleMin);
+	dfScaleRatio = 256.0 / (dfScaleMax - dfScaleMin);
+	pabyBuffer = pabyWholeBuffer + iColorIndex * nPixelCount;
 
-    for( i = 0; i < nPixelCount; i++ )
-    {
-        float fScaledValue = (float) ((pafRawData[i]-dfScaleMin)*dfScaleRatio);
-
-        if( fScaledValue < 0.0 )
-            pabyBuffer[i] = 0;
-        else if( fScaledValue > 255.0 )
-            pabyBuffer[i] = 255;
-        else
-            pabyBuffer[i] = (int) fScaledValue;
-    }
-
-    free( pafRawData );
-
+	for( i = 0; i < nPixelCount; i++ )
+        {
+	    float fScaledValue = (float) ((pafRawData[i]-dfScaleMin)*dfScaleRatio);
+	    
+	    if( fScaledValue < 0.0 )
+                pabyBuffer[i] = 0;
+	    else if( fScaledValue > 255.0 )
+                pabyBuffer[i] = 255;
+	    else
+                pabyBuffer[i] = (int) fScaledValue;
+        }
+	
 /* -------------------------------------------------------------------- */
 /*      Report a warning if NODATA keyword was applied.  We are         */
 /*      unable to utilize it since we can't return any pixels marked    */
 /*      as nodata from this function.  Need to fix someday.             */
 /* -------------------------------------------------------------------- */
-    dfNoDataValue = msGetGDALNoDataValue( layer, hBand, &bGotNoData );
-    if( bGotNoData )
-        msDebug( "LoadGDALImage(%s): NODATA value %g in GDAL\n"
-                 "file or PROCESSING directive ignored.  Not yet supported for\n"
-                 "unclassified scaled data.\n",
-                 layer->name, dfNoDataValue );
-
+	dfNoDataValue = msGetGDALNoDataValue( layer, hBand, &bGotNoData );
+	if( bGotNoData )
+            msDebug( "LoadGDALImage(%s): NODATA value %g in GDAL\n"
+                     "file or PROCESSING directive ignored.  Not yet supported for\n"
+                     "unclassified scaled data.\n",
+                     layer->name, dfNoDataValue );
+	
 /* -------------------------------------------------------------------- */
 /*      Apply LUT if there is one.                                      */
 /* -------------------------------------------------------------------- */
-    return ApplyLUT( iColorIndex, layer, 
-                             pabyBuffer, dst_xsize, dst_ysize );;
+	result_code = ApplyLUT( iColorIndex+1, layer, 
+				pabyBuffer, dst_xsize, dst_ysize );;
+	if( result_code == -1 )
+        {
+            free( pafWholeRawData );
+            return result_code;
+        }
+    }
+
+    free( pafWholeRawData );
+
+    return result_code;
 }
 
 /************************************************************************/



More information about the mapserver-commits mailing list