INTEGRATION: CWS presfixes01 (1.2.8); FILE MERGED
2005/02/07 15:47:42 mbu 1.2.8.4: . 2005/02/07 15:34:51 mbu 1.2.8.3: more sort optimizations 2005/02/04 16:48:33 mbu 1.2.8.2: fixed strided element access in radix sort 2005/02/04 11:00:41 mbu 1.2.8.1: #i38960 performing radix sort now
This commit is contained in:
parent
d7a915a8d1
commit
4ee5a8dba0
1 changed files with 441 additions and 10 deletions
|
@ -2,9 +2,9 @@
|
|||
*
|
||||
* $RCSfile: b2dpolypolygonrasterconverter.cxx,v $
|
||||
*
|
||||
* $Revision: 1.2 $
|
||||
* $Revision: 1.3 $
|
||||
*
|
||||
* last change: $Author: rt $ $Date: 2004-11-26 18:39:11 $
|
||||
* last change: $Author: vg $ $Date: 2005-03-10 13:38:47 $
|
||||
*
|
||||
* The Contents of this file are made available subject to the terms of
|
||||
* either of the following licenses
|
||||
|
@ -72,9 +72,249 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace basegfx
|
||||
{
|
||||
class radixSort {
|
||||
|
||||
//! public interface
|
||||
public:
|
||||
|
||||
//! default constructor
|
||||
radixSort( void );
|
||||
|
||||
//! destructor
|
||||
~radixSort( void );
|
||||
|
||||
bool sort( const float *pInput, sal_uInt32 nNumElements, sal_uInt32 dwStride );
|
||||
|
||||
inline sal_uInt32 *indices( void ) const { return m_indices1; }
|
||||
|
||||
//! private attributes
|
||||
private:
|
||||
|
||||
// current size of index list
|
||||
sal_uInt32 m_current_size;
|
||||
|
||||
// last known size of index list
|
||||
sal_uInt32 m_previous_size;
|
||||
|
||||
// index lists
|
||||
sal_uInt32 *m_indices1;
|
||||
sal_uInt32 *m_indices2;
|
||||
|
||||
sal_uInt32 m_counter[256*4];
|
||||
sal_uInt32 m_offset[256];
|
||||
|
||||
//! private methods
|
||||
private:
|
||||
|
||||
bool resize( sal_uInt32 nNumElements );
|
||||
void reset_indices( void );
|
||||
bool prepareCounters( const float *pInput, sal_uInt32 nNumElements, sal_uInt32 dwStride );
|
||||
};
|
||||
|
||||
inline radixSort::radixSort( void ) {
|
||||
|
||||
m_indices1 = NULL;
|
||||
m_indices2 = NULL;
|
||||
m_current_size = 0;
|
||||
m_previous_size = 0;
|
||||
|
||||
reset_indices();
|
||||
}
|
||||
|
||||
inline radixSort::~radixSort( void ) {
|
||||
|
||||
delete [] m_indices2;
|
||||
delete [] m_indices1;
|
||||
}
|
||||
|
||||
bool radixSort::resize( sal_uInt32 nNumElements ) {
|
||||
|
||||
if(nNumElements==m_previous_size)
|
||||
return true;
|
||||
|
||||
if(nNumElements > m_current_size) {
|
||||
|
||||
// release index lists
|
||||
if(m_indices2)
|
||||
delete [] m_indices2;
|
||||
if(m_indices1)
|
||||
delete [] m_indices1;
|
||||
|
||||
// allocate new index lists
|
||||
m_indices1 = new sal_uInt32[nNumElements];
|
||||
m_indices2 = new sal_uInt32[nNumElements];
|
||||
|
||||
// check for out of memory situation
|
||||
if(!((sal_uInt32)m_indices1|(sal_uInt32)m_indices2)) {
|
||||
delete [] m_indices1;
|
||||
delete [] m_indices2;
|
||||
m_indices1 = NULL;
|
||||
m_indices2 = NULL;
|
||||
m_current_size = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_current_size = nNumElements;
|
||||
}
|
||||
|
||||
m_previous_size = nNumElements;
|
||||
|
||||
// initialize indices
|
||||
reset_indices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void radixSort::reset_indices( void ) {
|
||||
|
||||
for(sal_uInt32 i=0;i<m_current_size;i++)
|
||||
m_indices1[i] = i;
|
||||
}
|
||||
|
||||
bool radixSort::prepareCounters( const float *pInput, sal_uInt32 nNumElements, sal_uInt32 dwStride ) {
|
||||
|
||||
// clear counters
|
||||
sal_uInt32 *ptr = m_counter;
|
||||
for(int i=0; i<64; ++i) {
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
*ptr++ = NULL;
|
||||
}
|
||||
|
||||
// prepare pointers to relevant memory addresses
|
||||
sal_uInt8 *p = (sal_uInt8*)pInput;
|
||||
sal_uInt8 *pe = p+(nNumElements*dwStride);
|
||||
sal_uInt32 *h0= &m_counter[0];
|
||||
sal_uInt32 *h1= &m_counter[256];
|
||||
sal_uInt32 *h2= &m_counter[512];
|
||||
sal_uInt32 *h3= &m_counter[768];
|
||||
|
||||
sal_uInt32 *Indices = m_indices1;
|
||||
float previous_value = *(float *)(((sal_uInt8 *)pInput)+(m_indices1[0]*dwStride));
|
||||
bool bSorted = true;
|
||||
while(p!=pe) {
|
||||
float value = *(float *)(((sal_uInt8 *)pInput)+((*Indices++)*dwStride));
|
||||
if(value<previous_value) {
|
||||
bSorted = false;
|
||||
break;
|
||||
}
|
||||
previous_value = value;
|
||||
h0[*p++]++;
|
||||
h1[*p++]++;
|
||||
h2[*p++]++;
|
||||
h3[*p++]++;
|
||||
p += dwStride-4;
|
||||
}
|
||||
if(bSorted)
|
||||
return true;
|
||||
while(p!=pe) {
|
||||
h0[*p++]++;
|
||||
h1[*p++]++;
|
||||
h2[*p++]++;
|
||||
h3[*p++]++;
|
||||
p += dwStride-4;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool radixSort::sort( const float *pInput, sal_uInt32 nNumElements, sal_uInt32 dwStride ) {
|
||||
|
||||
if(!(pInput))
|
||||
return false;
|
||||
if(!(nNumElements))
|
||||
return false;
|
||||
if(!(resize(nNumElements)))
|
||||
return false;
|
||||
|
||||
// prepare radix counters, return if already sorted
|
||||
if(prepareCounters(pInput,nNumElements,dwStride))
|
||||
return true;
|
||||
|
||||
// count number of negative values
|
||||
sal_uInt32 num_negatives = 0;
|
||||
sal_uInt32 *h3= &m_counter[768];
|
||||
for(sal_uInt32 i=128;i<256;i++)
|
||||
num_negatives += h3[i];
|
||||
|
||||
// perform passes, one for each byte
|
||||
for(sal_uInt32 j=0;j<4;j++) {
|
||||
|
||||
// ignore this pass if all values have the same byte
|
||||
bool bRun = true;
|
||||
sal_uInt32 *current_counter = &m_counter[j<<8];
|
||||
sal_uInt8 unique_value = *(((sal_uInt8*)pInput)+j);
|
||||
if(current_counter[unique_value]==nNumElements)
|
||||
bRun=false;
|
||||
|
||||
// does the incoming byte contain the sign bit?
|
||||
sal_uInt32 i;
|
||||
if(j!=3) {
|
||||
if(bRun) {
|
||||
m_offset[0] = 0;
|
||||
for(i=1;i<256;i++)
|
||||
m_offset[i] = m_offset[i-1] + current_counter[i-1];
|
||||
sal_uInt8 *InputBytes = (sal_uInt8 *)pInput;
|
||||
sal_uInt32 *Indices = m_indices1;
|
||||
sal_uInt32 *IndicesEnd = &m_indices1[nNumElements];
|
||||
InputBytes += j;
|
||||
while(Indices!=IndicesEnd) {
|
||||
sal_uInt32 id = *Indices++;
|
||||
m_indices2[m_offset[InputBytes[id*dwStride]]++] = id;
|
||||
}
|
||||
sal_uInt32 *Tmp = m_indices1;
|
||||
m_indices1 = m_indices2;
|
||||
m_indices2 = Tmp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(bRun) {
|
||||
m_offset[0] = num_negatives;
|
||||
for(i=1;i<128;i++)
|
||||
m_offset[i] = m_offset[i-1] + current_counter[i-1];
|
||||
m_offset[255] = 0;
|
||||
for(i=0;i<127;i++)
|
||||
m_offset[254-i] = m_offset[255-i] + current_counter[255-i];
|
||||
for(i=128;i<256;i++)
|
||||
m_offset[i] += current_counter[i];
|
||||
for(i=0;i<nNumElements;i++) {
|
||||
sal_uInt32 Radix = (*(sal_uInt32 *)(((sal_uInt8 *)pInput)+(m_indices1[i]*dwStride)))>>24;
|
||||
if(Radix<128) m_indices2[m_offset[Radix]++] = m_indices1[i];
|
||||
else m_indices2[--m_offset[Radix]] = m_indices1[i];
|
||||
}
|
||||
sal_uInt32 *Tmp = m_indices1;
|
||||
m_indices1 = m_indices2;
|
||||
m_indices2 = Tmp;
|
||||
}
|
||||
else {
|
||||
if(unique_value>=128) {
|
||||
for(i=0;i<nNumElements;i++)
|
||||
m_indices2[i] = m_indices1[nNumElements-i-1];
|
||||
sal_uInt32 *Tmp = m_indices1;
|
||||
m_indices1 = m_indices2;
|
||||
m_indices2 = Tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//************************************************************
|
||||
// Internal vertex storage of B2DPolyPolygonRasterConverter
|
||||
//************************************************************
|
||||
|
@ -103,9 +343,10 @@ namespace basegfx
|
|||
{
|
||||
class ImplLineNode
|
||||
{
|
||||
public:
|
||||
sal_Int32 mnYCounter;
|
||||
double mfXPos;
|
||||
double mfXDelta;
|
||||
float mfXPos;
|
||||
float mfXDelta;
|
||||
bool mbDownwards;
|
||||
|
||||
public:
|
||||
|
@ -114,27 +355,30 @@ namespace basegfx
|
|||
*/
|
||||
ImplLineNode(const B2DPoint& rP1, const B2DPoint& rP2, bool bDown) :
|
||||
mnYCounter( fround(rP2.getY()) - fround(rP1.getY()) ),
|
||||
mfXPos( rP1.getX() ),
|
||||
mfXDelta( (rP2.getX() - rP1.getX()) / mnYCounter ),
|
||||
mfXPos( (float)(rP1.getX()) ),
|
||||
mfXDelta((float) ((rP2.getX() - rP1.getX()) / mnYCounter) ),
|
||||
mbDownwards( bDown )
|
||||
{
|
||||
}
|
||||
|
||||
/// get current x position
|
||||
const double& getXPos() const
|
||||
const float& getXPos() const
|
||||
{
|
||||
return mfXPos;
|
||||
}
|
||||
|
||||
/// returns true, if line ends on this Y value
|
||||
void nextLine()
|
||||
float nextLine()
|
||||
{
|
||||
if(mnYCounter>=0)
|
||||
{
|
||||
// go one step in Y
|
||||
mfXPos += mfXDelta;
|
||||
--mnYCounter;
|
||||
return mfXDelta;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
bool isEnded()
|
||||
|
@ -306,6 +550,193 @@ namespace basegfx
|
|||
// it crosses or touches the current scanline.
|
||||
VectorOfLineNodes aActiveVertices;
|
||||
|
||||
#if 1
|
||||
|
||||
// mickey's optimized version...
|
||||
radixSort rs;
|
||||
sal_uInt32 nb,nb_previous;
|
||||
sal_uInt32 nb_sort;
|
||||
bool bSort = false;
|
||||
nb_previous = 0;
|
||||
nb_sort = 0;
|
||||
|
||||
// process each scanline
|
||||
for( sal_Int32 y(0); y <= nScanlines; ++y )
|
||||
{
|
||||
// add vertices which start at current scanline into
|
||||
// active vertex vector
|
||||
::std::for_each( maScanlines[y].begin(),
|
||||
maScanlines[y].end(),
|
||||
LineNodeGenerator( aActiveVertices ) );
|
||||
nb = aActiveVertices.size();
|
||||
if(nb != nb_previous) {
|
||||
nb_previous = nb;
|
||||
bSort = true;
|
||||
}
|
||||
|
||||
// sort with increasing X
|
||||
if(bSort) {
|
||||
bSort = false;
|
||||
float *pInput = &((*aActiveVertices.begin()).mfXPos);
|
||||
rs.sort(pInput,nb,sizeof(ImplLineNode));
|
||||
++nb_sort;
|
||||
#if 0
|
||||
sal_uInt32 *sorted = rs.indices();
|
||||
OSL_TRACE("%d\n",nb);
|
||||
float last = aActiveVertices[sorted[0]].getXPos();
|
||||
for(int n=0; n<nb; ++n) {
|
||||
float current = aActiveVertices[sorted[n]].getXPos();
|
||||
if(last > current) {
|
||||
OSL_TRACE("error\n");
|
||||
}
|
||||
OSL_TRACE("%f\n",current);
|
||||
last = current;
|
||||
}
|
||||
OSL_TRACE("-------\n",nb);
|
||||
#endif
|
||||
}
|
||||
|
||||
const ::std::size_t nLen( nb );
|
||||
if( !nLen )
|
||||
{
|
||||
// empty scanline - call derived with an 'off' span
|
||||
// for the full width
|
||||
span( maPolyPolyRectangle.getMinX(),
|
||||
maPolyPolyRectangle.getMaxX(),
|
||||
nMinY + y,
|
||||
false );
|
||||
}
|
||||
else
|
||||
{
|
||||
const sal_Int32 nCurrY( nMinY + y );
|
||||
|
||||
// scanline not empty - forward all scans to derived,
|
||||
// according to selected fill rule
|
||||
|
||||
// TODO(P1): Maybe allow these 'off' span calls to be
|
||||
// switched off (or all 'on' span calls, depending on
|
||||
// use case scenario)
|
||||
|
||||
// sorting didn't change the order of the elements
|
||||
// in memory but prepared a list of indices in sorted order.
|
||||
// thus we now process the nodes with an additional indirection.
|
||||
sal_uInt32 *sorted = rs.indices();
|
||||
|
||||
// call derived with 'off' span for everything left of first active span
|
||||
if( aActiveVertices[sorted[0]].getXPos() > maPolyPolyRectangle.getMinX() )
|
||||
{
|
||||
span( maPolyPolyRectangle.getMinX(),
|
||||
aActiveVertices[sorted[0]].getXPos(),
|
||||
nCurrY,
|
||||
false );
|
||||
}
|
||||
|
||||
switch( eFillRule )
|
||||
{
|
||||
default:
|
||||
OSL_ENSURE(false,
|
||||
"B2DPolyPolygonRasterConverter::rasterConvert(): Unexpected fill rule");
|
||||
return;
|
||||
|
||||
case FillRule_EVEN_ODD:
|
||||
// process each span in current scanline, with
|
||||
// even-odd fill rule
|
||||
for( ::std::size_t i(0), nLen(aActiveVertices.size());
|
||||
i+1 < nLen;
|
||||
++i )
|
||||
{
|
||||
sal_uInt32 nIndex = sorted[i];
|
||||
sal_uInt32 nNextIndex = sorted[i+1];
|
||||
span( aActiveVertices[nIndex].getXPos(),
|
||||
aActiveVertices[nNextIndex].getXPos(),
|
||||
nCurrY,
|
||||
i % 2 == 0 );
|
||||
|
||||
float delta = aActiveVertices[nIndex].nextLine();
|
||||
if(delta > 0.0f) {
|
||||
if(aActiveVertices[nIndex].getXPos() > aActiveVertices[nNextIndex].getXPos())
|
||||
bSort = true;
|
||||
}
|
||||
else if(delta < 0.0f) {
|
||||
if(i) {
|
||||
sal_uInt32 nPrevIndex = sorted[i-1];
|
||||
if(aActiveVertices[nIndex].getXPos() < aActiveVertices[nPrevIndex].getXPos())
|
||||
bSort = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FillRule_NONZERO_WINDING_NUMBER:
|
||||
// process each span in current scanline, with
|
||||
// non-zero winding numbe fill rule
|
||||
sal_Int32 nWindingNumber(0);
|
||||
for( ::std::size_t i(0), nLen(aActiveVertices.size());
|
||||
i+1 < nLen;
|
||||
++i )
|
||||
{
|
||||
sal_uInt32 nIndex = sorted[i];
|
||||
sal_uInt32 nNextIndex = sorted[i+1];
|
||||
nWindingNumber += -1 + 2*aActiveVertices[nIndex].isDownwards();
|
||||
|
||||
span( aActiveVertices[nIndex].getXPos(),
|
||||
aActiveVertices[nNextIndex].getXPos(),
|
||||
nCurrY,
|
||||
nWindingNumber != 0 );
|
||||
|
||||
float delta = aActiveVertices[nIndex].nextLine();
|
||||
if(delta > 0.0f) {
|
||||
if(aActiveVertices[nIndex].getXPos() > aActiveVertices[nNextIndex].getXPos())
|
||||
bSort = true;
|
||||
}
|
||||
else if(delta < 0.0f) {
|
||||
if(i) {
|
||||
sal_uInt32 nPrevIndex = sorted[i-1];
|
||||
if(aActiveVertices[nIndex].getXPos() < aActiveVertices[nPrevIndex].getXPos())
|
||||
bSort = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// call derived with 'off' span for everything right of last active span
|
||||
if( aActiveVertices[sorted[nb-1]].getXPos() < maPolyPolyRectangle.getMaxX() )
|
||||
{
|
||||
span( aActiveVertices[sorted[nb-1]].getXPos()+1.0,
|
||||
maPolyPolyRectangle.getMaxX(),
|
||||
nCurrY,
|
||||
false );
|
||||
}
|
||||
|
||||
// also call nextLine on very last line node
|
||||
sal_uInt32 nIndex = sorted[nb-1];
|
||||
float delta = aActiveVertices[nIndex].nextLine();
|
||||
if(delta < 0.0f) {
|
||||
if(nb) {
|
||||
sal_uInt32 nPrevIndex = sorted[nb-2];
|
||||
if(aActiveVertices[nIndex].getXPos() < aActiveVertices[nPrevIndex].getXPos())
|
||||
bSort = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove line nodes which have ended on the current scanline
|
||||
aActiveVertices.erase( ::std::remove_if( aActiveVertices.begin(),
|
||||
aActiveVertices.end(),
|
||||
::boost::mem_fn( &ImplLineNode::isEnded ) ),
|
||||
aActiveVertices.end() );
|
||||
nb = aActiveVertices.size();
|
||||
if(nb != nb_previous) {
|
||||
nb_previous = nb;
|
||||
bSort = true;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%d %d",nb_sort,nScanlines);
|
||||
|
||||
#else
|
||||
|
||||
// process each scanline
|
||||
for( sal_Int32 y(0); y <= nScanlines; ++y )
|
||||
{
|
||||
|
@ -427,7 +858,7 @@ namespace basegfx
|
|||
aActiveVertices.end(),
|
||||
LineNodeComparator() );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
// eof
|
||||
|
|
Loading…
Reference in a new issue