![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 // Polygon overlay 00030 // 00031 #include <iostream> 00032 #include <algorithm> 00033 #include <string.h> 00034 #include <cstdlib> 00035 #include <assert.h> 00036 #include "tbb/tick_count.h" 00037 #include "tbb/blocked_range.h" 00038 #include "tbb/task_scheduler_init.h" 00039 #include "tbb/parallel_for.h" 00040 #include "tbb/mutex.h" 00041 #include "tbb/spin_mutex.h" 00042 #include "polyover.h" 00043 #include "polymain.h" 00044 #include "pover_video.h" 00045 00046 using namespace std; 00047 00057 void OverlayOnePolygonWithMap(Polygon_map_t *resultMap, RPolygon *myPoly, Polygon_map_t *map2, tbb::spin_mutex *rMutex) { 00058 int r1, g1, b1, r2, g2, b2; 00059 int myr=0; 00060 int myg=0; 00061 int myb=0; 00062 int p1Area = myPoly->area(); 00063 for(unsigned int j=1; (j < map2->size()) && (p1Area > 0); j++) { 00064 RPolygon *p2 = (*map2)[j]; 00065 RPolygon *pnew; 00066 int newxMin, newxMax, newyMin, newyMax; 00067 myPoly->getColor(&r1, &g1, &b1); 00068 if(PolygonsOverlap(myPoly, p2, newxMin, newyMin, newxMax, newyMax)) { 00069 p2->getColor(&r2, &g2, &b2); 00070 myr = r1 + r2; 00071 myg = g1 + g2; 00072 myb = b1 + b2; 00073 pnew = RPolygon::alloc_RPolygon(newxMin, newyMin, newxMax, newyMax, myr, myg, myb); 00074 p1Area -= pnew->area(); // when all the area of the polygon is accounted for, we can quit. 00075 if(rMutex) { 00076 tbb::spin_mutex::scoped_lock lock(*rMutex); 00077 #if _DEBUG 00078 pnew->print(int(resultMap->size())); 00079 #endif 00080 resultMap->push_back(pnew); 00081 } 00082 else { 00083 #ifdef _DEBUG 00084 pnew->print(int(resultMap->size())); 00085 #endif 00086 resultMap->push_back(pnew); 00087 } 00088 } 00089 } 00090 } 00091 00098 void SerialOverlayMaps(Polygon_map_t **resultMap, Polygon_map_t *map1, Polygon_map_t *map2) { 00099 cout << "SerialOverlayMaps called" << std::endl; 00100 *resultMap = new Polygon_map_t; 00101 00102 RPolygon *p0 = (*map1)[0]; 00103 int mapxSize, mapySize, ignore1, ignore2; 00104 p0->get(&ignore1, &ignore2, &mapxSize, &mapySize); 00105 (*resultMap)->reserve(mapxSize*mapySize); // can't be any bigger than this 00106 // push the map size as the first polygon, 00107 p0 = RPolygon::alloc_RPolygon(0,0,mapxSize, mapySize); 00108 (*resultMap)->push_back(p0); 00109 for(unsigned int i=1; i < map1->size(); i++) { 00110 RPolygon *p1 = (*map1)[i]; 00111 OverlayOnePolygonWithMap(*resultMap, p1, map2, NULL); 00112 } 00113 } 00114 00119 class ApplyOverlay { 00120 Polygon_map_t *m_map1, *m_map2, *m_resultMap; 00121 tbb::spin_mutex *m_rMutex; 00122 public: 00127 void operator()( const tbb::blocked_range<int> & r) const { 00128 PRINT_DEBUG("From " << r.begin() << " to " << r.end()); 00129 for(int i=r.begin(); i != r.end(); i++) { 00130 RPolygon *myPoly = (*m_map1)[i]; 00131 OverlayOnePolygonWithMap(m_resultMap, myPoly, m_map2, m_rMutex); 00132 } 00133 } 00134 ApplyOverlay(Polygon_map_t *resultMap, Polygon_map_t *map1, Polygon_map_t *map2, tbb::spin_mutex *rmutex) : 00135 m_resultMap(resultMap), m_map1(map1), m_map2(map2), m_rMutex(rmutex) {} 00136 }; 00137 00144 void NaiveParallelOverlay(Polygon_map_t *&result_map, Polygon_map_t &polymap1, Polygon_map_t &polymap2) { 00145 // ----------------------------------- 00146 bool automatic_threadcount = false; 00147 00148 if(gThreadsLow == THREADS_UNSET || gThreadsLow == tbb::task_scheduler_init::automatic) { 00149 gThreadsLow = gThreadsHigh = tbb::task_scheduler_init::automatic; 00150 automatic_threadcount = true; 00151 } 00152 result_map = new Polygon_map_t; 00153 00154 RPolygon *p0 = polymap1[0]; 00155 int mapxSize, mapySize, ignore1, ignore2; 00156 p0->get(&ignore1, &ignore2, &mapxSize, &mapySize); 00157 result_map->reserve(mapxSize*mapySize); // can't be any bigger than this 00158 // push the map size as the first polygon, 00159 tbb::spin_mutex *resultMutex = new tbb::spin_mutex(); 00160 int grain_size = gGrainSize; 00161 00162 for(int nthreads = gThreadsLow; nthreads <= gThreadsHigh; nthreads++) { 00163 tbb::task_scheduler_init init(nthreads); 00164 if(gIsGraphicalVersion) { 00165 RPolygon *xp = RPolygon::alloc_RPolygon(0, 0, gMapXSize-1, gMapYSize-1, 0, 0, 0); // Clear the output space 00166 RPolygon::free_RPolygon( xp ); 00167 } 00168 // put size polygon in result map 00169 p0 = RPolygon::alloc_RPolygon(0,0,mapxSize, mapySize); 00170 result_map->push_back(p0); 00171 00172 tbb::tick_count t0 = tbb::tick_count::now(); 00173 tbb::parallel_for (tbb::blocked_range<int>(1,(int)(polymap1.size()),grain_size), ApplyOverlay(result_map, &polymap1, &polymap2, resultMutex)); 00174 tbb::tick_count t1 = tbb::tick_count::now(); 00175 00176 double naiveParallelTime = (t1-t0).seconds() * 1000; 00177 cout << "Naive parallel with spin lock and "; 00178 if(automatic_threadcount) cout << "automatic"; 00179 else cout << nthreads; 00180 cout << ((nthreads == 1) ? " thread" : " threads"); 00181 cout << " took " << naiveParallelTime << " msec : speedup over serial " << (gSerialTime / naiveParallelTime) << std::endl; 00182 if(gCsvFile.is_open()) { 00183 gCsvFile << "," << naiveParallelTime; 00184 } 00185 #if _DEBUG 00186 CheckPolygonMap(result_map); 00187 ComparePolygonMaps(result_map, gResultMap); 00188 #endif 00189 for(int i=0; i<int(result_map->size());i++) { 00190 RPolygon::free_RPolygon(result_map->at(i)); 00191 } 00192 result_map->clear(); 00193 } 00194 delete resultMutex; 00195 if(gCsvFile.is_open()) { 00196 gCsvFile << std::endl; 00197 } 00198 // ----------------------------------- 00199 } 00200 00206 class ApplySplitOverlay { 00207 Polygon_map_t *m_map1, *m_map2, *m_resultMap; 00208 tbb::spin_mutex *m_rMutex; 00209 public: 00214 void operator()(const tbb::blocked_range<int> & r) const { 00215 #ifdef _DEBUG 00216 // if we are debugging, serialize the method. That way we can 00217 // see what is happening in each strip without the interleaving 00218 // confusing things. 00219 tbb::spin_mutex::scoped_lock lock(*m_rMutex); 00220 cout << unitbuf << "From " << r.begin() << " to " << r.end()-1 << std::endl; 00221 #endif 00222 // instead of handing out subsets of polygons from map1 to intersect 00223 // with the polygons in map2, we are handed a strip of the map from 00224 // [(r.begin(),0)-(r.end()-1,yMapSize)]. 00225 // 00226 // make a polygon with those values, and intersect with all the polygons 00227 // in map1 and map2, creating flagged polygon lists fmap1 and fmap2. 00228 // There are four possiblities: 00229 // 00230 // 1) a polygon is contained entirely within the strip. We just 00231 // add the polygon to our flagged map. 00232 // 2) the polygon will be partly contained in our strip, and partly 00233 // in the strip to our right (higher x values). Add the polygon 00234 // to our flagged map. 00235 // 3) the polygon is partly contained in our map, and partly in the 00236 // strip to our left. Add the polygon to our map, but flag it as 00237 // a duplicate. 00238 // 4) the polygons do not intersect. Don't add to flagged map. 00239 // 00240 00241 // get yMapSize 00242 int r1, g1, b1, r2, g2, b2; 00243 int myr=-1; 00244 int myg=-1; 00245 int myb=-1; 00246 int i1, i2, i3, yMapSize; 00247 m_map1->at(0)->get(&i1, &i2, &i3, &yMapSize); 00248 RPolygon *slicePolygon = RPolygon::alloc_RPolygon(r.begin(), 0, r.end() - 1, yMapSize); 00249 00250 Flagged_map_t *fmap1, *fmap2; 00251 fmap1 = new std::vector<RPolygon_flagged>; 00252 fmap1->reserve(m_map1->size()); 00253 fmap2 = new Flagged_map_t; 00254 fmap2->reserve(m_map2->size()); 00255 00256 PRINT_DEBUG(std::endl << "Map1 -------------------"); 00257 for(unsigned int i=1; i<m_map1->size(); i++) { 00258 int xl, yl, xh, yh; 00259 RPolygon *px = m_map1->at(i); 00260 if(PolygonsOverlap(slicePolygon, px, xl, yl, xh, yh)) { 00261 bool is_duplicate = false; 00262 int pxl, pyl, pxh, pyh; 00263 int indx = (int)(fmap1->size()); 00264 fmap1->resize(indx+1); 00265 fmap1->at(indx).setp(px); 00266 px->get(&pxl, &pyl, &pxh, &pyh); 00267 if(pxl < xl) { 00268 is_duplicate = true; 00269 } 00270 //fmap1->at(indx).setp(px); 00271 fmap1->at(indx).setDuplicate(is_duplicate); 00272 PRINT_DEBUG(" Polygon " << *px << " is in map, is_duplicate=" << is_duplicate); 00273 00274 } 00275 } 00276 00277 PRINT_DEBUG(std::endl << "Map2 -------------------"); 00278 00279 for(unsigned int i=1; i<m_map2->size(); i++) { 00280 int xl, yl, xh, yh; 00281 RPolygon *px = m_map2->at(i); 00282 00283 if(PolygonsOverlap(slicePolygon, px, xl, yl, xh, yh)) { 00284 bool is_duplicate = false; 00285 int pxl, pyl, pxh, pyh; 00286 int indx = (int)(fmap2->size()); 00287 fmap2->resize(indx+1); 00288 fmap2->at(indx).setp(px); 00289 px->get(&pxl, &pyl, &pxh, &pyh); 00290 if(pxl < xl) { 00291 is_duplicate = true; 00292 } 00293 fmap2->at(indx).setDuplicate(is_duplicate); 00294 PRINT_DEBUG(" Polygon " << *px << " is in map, is_duplicate=" << is_duplicate); 00295 } 00296 } 00297 00298 // When intersecting polygons from fmap1 and fmap2, if BOTH are flagged 00299 // as duplicate, don't add the result to the output map. We can still 00300 // intersect them, because we are keeping track of how much of the polygon 00301 // is left over from intersecting, and quitting when the polygon is 00302 // used up. 00303 00304 for(unsigned int ii=0; ii < fmap1->size(); ii++) { 00305 RPolygon *p1 = fmap1->at(ii).p(); 00306 bool is_dup = fmap1->at(ii).isDuplicate(); 00307 int parea = p1->area(); 00308 p1->getColor(&r1, &g1, &b1); 00309 for(unsigned int jj=0;(jj < fmap2->size()) && (parea > 0); jj++) { 00310 int xl, yl, xh, yh; 00311 RPolygon *p2 = fmap2->at(jj).p(); 00312 if(PolygonsOverlap(p1, p2, xl, yl, xh, yh)) { 00313 if(!(is_dup && fmap2->at(jj).isDuplicate())) { 00314 p2->getColor(&r2, &g2, &b2); 00315 myr = r1 + r2; 00316 myg = g1 + g2; 00317 myb = b1 + b2; 00318 RPolygon *pnew = RPolygon::alloc_RPolygon(xl, yl, xh, yh, myr, myg, myb); 00319 #ifdef _DEBUG 00320 #else 00321 tbb::spin_mutex::scoped_lock lock(*m_rMutex); 00322 #endif 00323 (*m_resultMap).push_back(pnew); 00324 } 00325 parea -= (xh-xl+1)*(yh-yl+1); 00326 } 00327 } 00328 } 00329 00330 delete fmap1; 00331 delete fmap2; 00332 RPolygon::free_RPolygon( slicePolygon ); 00333 } 00334 00335 ApplySplitOverlay(Polygon_map_t *resultMap, Polygon_map_t *map1, Polygon_map_t *map2, tbb::spin_mutex *rmutex) : 00336 m_resultMap(resultMap), m_map1(map1), m_map2(map2), m_rMutex(rmutex) {} 00337 }; 00338 00339 00347 void SplitParallelOverlay(Polygon_map_t **result_map, Polygon_map_t *polymap1, Polygon_map_t *polymap2) { 00348 int nthreads; 00349 bool automatic_threadcount = false; 00350 double domainSplitParallelTime; 00351 tbb::tick_count t0, t1; 00352 tbb::spin_mutex *resultMutex; 00353 if(gThreadsLow == THREADS_UNSET || gThreadsLow == tbb::task_scheduler_init::automatic ) { 00354 gThreadsLow = gThreadsHigh = tbb::task_scheduler_init::automatic; 00355 automatic_threadcount = true; 00356 } 00357 *result_map = new Polygon_map_t; 00358 00359 RPolygon *p0 = (*polymap1)[0]; 00360 int mapxSize, mapySize, ignore1, ignore2; 00361 p0->get(&ignore1, &ignore2, &mapxSize, &mapySize); 00362 (*result_map)->reserve(mapxSize*mapySize); // can't be any bigger than this 00363 resultMutex = new tbb::spin_mutex(); 00364 00365 int grain_size; 00366 #ifdef _DEBUG 00367 grain_size = gMapXSize / 4; 00368 #else 00369 grain_size = gGrainSize; 00370 #endif 00371 00372 for(nthreads = gThreadsLow; nthreads <= gThreadsHigh; nthreads++) { 00373 tbb::task_scheduler_init init(nthreads); 00374 if(gIsGraphicalVersion) { 00375 RPolygon *xp = RPolygon::alloc_RPolygon(0, 0, gMapXSize-1, gMapYSize-1, 0, 0, 0); // Clear the output space 00376 RPolygon::free_RPolygon( xp ); 00377 } 00378 // push the map size as the first polygon, 00379 p0 = RPolygon::alloc_RPolygon(0,0,mapxSize, mapySize); 00380 (*result_map)->push_back(p0); 00381 t0 = tbb::tick_count::now(); 00382 tbb::parallel_for (tbb::blocked_range<int>(0,(int)(mapxSize+1),grain_size), ApplySplitOverlay((*result_map), polymap1, polymap2, resultMutex)); 00383 t1 = tbb::tick_count::now(); 00384 domainSplitParallelTime = (t1-t0).seconds()*1000; 00385 cout << "Splitting parallel with spin lock and "; 00386 if(automatic_threadcount) cout << "automatic"; 00387 else cout << nthreads; 00388 cout << ((nthreads == 1) ? " thread" : " threads"); 00389 cout << " took " << domainSplitParallelTime << " msec : speedup over serial " << (gSerialTime / domainSplitParallelTime) << std::endl; 00390 if(gCsvFile.is_open()) { 00391 gCsvFile << "," << domainSplitParallelTime; 00392 } 00393 #if _DEBUG 00394 CheckPolygonMap(*result_map); 00395 ComparePolygonMaps(*result_map, gResultMap); 00396 #endif 00397 for(int i=0; i<int((*result_map)->size());i++) { 00398 RPolygon::free_RPolygon((*result_map)->at(i)); 00399 } 00400 (*result_map)->clear(); 00401 00402 } 00403 delete resultMutex; 00404 if(gCsvFile.is_open()) { 00405 gCsvFile << std::endl; 00406 } 00407 00408 }
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.