void EnqueueTasks(const vector<Task *> &tasks) { if (PbrtOptions.nCores == 1) { for (unsigned int i = 0; i < tasks.size(); ++i) tasks[i]->Run(); return; } #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH for (uint32_t i = 0; i < tasks.size(); ++i) dispatch_group_async_f(gcdGroup, gcdQueue, tasks[i], lRunTask); #else if (!threads) TasksInit(); { MutexLock lock(*taskQueueMutex); for (unsigned int i = 0; i < tasks.size(); ++i) taskQueue.push_back(tasks[i]); } tasksRunningCondition.Lock(); numUnfinishedTasks += tasks.size(); tasksRunningCondition.Unlock(); workerSemaphore.Post(tasks.size()); #endif }
void EnqueueTasks(const vector<Task *> &tasks) { #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH static bool oneThread = (getenv("PBRT_NTHREADS") && atoi(getenv("PBRT_NTHREADS")) == 1); for (u_int i = 0; i < tasks.size(); ++i) if (oneThread) dispatch_sync_f(gcdQueue, tasks[i], lRunTask); else dispatch_group_async_f(gcdGroup, gcdQueue, tasks[i], lRunTask); #else if (!threads) TasksInit(); { MutexLock lock(*taskQueueMutex); for (unsigned int i = 0; i < tasks.size(); ++i) taskQueue.push_back(tasks[i]); } tasksRunningCondition.Lock(); numUnfinishedTasks += tasks.size(); tasksRunningCondition.Unlock(); workerSemaphore.Post(tasks.size()); #endif }
int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: mbrast [grid_file.out]\n"); return 1; } // Read grids from grid dump file std::vector<ShadedGrid> grids; if (!ReadGrids(argv[1], &grids)) return 1; InitSamples(); // Extract the name of the scene in case a full pathname was provided // on the command line char *sceneName = rindex(argv[1], '/'); if (sceneName != NULL) ++sceneName; else sceneName = argv[1]; // Remove trailing ".grids" from scene name char *end = rindex(sceneName, '.'); assert(end); *end = '\0'; printf("Rendering scene \"%s\"\n", sceneName); // Change this call to switch to creating an instance of your 3D // rasterizer once you start implementing it. #if MBRAST_MODE == NAIVE_RAST_2D || MBRAST_MODE == SMART_RAST_2D Rasterizer *rast = Create2DRasterizer(); #elif MBRAST_MODE == BASIC_RAST_3D || MBRAST_MODE == INTER_RAST_3D Rasterizer *rast = Create3DRasterizer(); #elif MBRAST_MODE == BASIC_RAST_5D Rasterizer *rast = Create5DRasterizer(); #endif // Initialize task system for multithreading if the rasterizer // indicates that it's thread safe. bool useTasks = rast->IsThreadSafe(); int nThreads = NumSystemCores(); assert(nThreads < MAX_CORES); if (useTasks) { printf("Using %d threads!\n", nThreads); TasksInit(); } // Render the scene multiple times, with each of the pixelSamples // sample counts. The sample counts must all be powers of two. // The bucketSize array, which must be the same size as // pixelSamples[], gives the length of the side of the bucket we'll // decompose the image into for the corresponding sample count. int pixelSamples[] = { 1, 4, 32 }; int bucketSize[] = { 64, 32, 8 }; assert(sizeof(pixelSamples) == sizeof(bucketSize)); int samplesSize = sizeof(pixelSamples) / sizeof(pixelSamples[0]); int failures = 0; for (int samplesIndex = 0; samplesIndex < samplesSize; ++samplesIndex) { assert(pixelSamples[samplesIndex] <= MAX_SAMPLES_PER_PIXEL); int nPixelSamples = pixelSamples[samplesIndex]; int bucketExtent = bucketSize[samplesIndex]; printf("Rendering with %d samples per pixel\n", nPixelSamples); // 720p resolution. (This can't be easily changed, as it's baked // into the xy coordinates of the micropolygons. So changing this // here would require a corresponding adjustment to those // coordinate values when the grids are read in....) int xRes = 1280, yRes = 720; // Allow the rasterizer to preprocess the grids ResetAndStartTimer(); rast->PreprocessGrids(grids, bucketExtent, xRes, yRes); double preprocessCycles = GetElapsedMCycles() / 1024.; printf(" Spent %.3f billion cycles on grid preprocessing.\n", preprocessCycles); // Allocate final output image as well as one Bucket structure for // each rasterization task thread we're running; this way the // rasterizer can update the framebuffer in its Bucket directly // without needing to coordinate with any other rasterizer threads. uint8_t *image = new uint8_t[xRes * yRes * 3]; Bucket *buckets[MAX_CORES]; int nBuckets = useTasks ? nThreads : 1; for (int i = 0; i < nBuckets; ++i) buckets[i] = new Bucket(bucketExtent, nPixelSamples); // Render with intervals set from 1 to the number of pixel samples // in multiples of two. for (int logIntervals = 0; (1 << logIntervals) <= nPixelSamples; ++logIntervals) { int nIntervals = (1 << logIntervals); printf(" Rendering with %d intervals: ", nIntervals); fflush(stdout); if (useTasks) { // Create a RastTask instance for each of the buckets of // the image; do this outside of the timer so as not to // penalize for the unnecessary dynamic allocation overhead // in the implementation here. std::vector<Task *> rastTasks; for (int y = 0; y < yRes; y += bucketExtent) { for (int x = 0; x < xRes; x += bucketExtent) { int x1 = std::min(x + bucketExtent, xRes); int y1 = std::min(y + bucketExtent, yRes); RastTask *rt = new RastTask(rast, &buckets[0], x, y, x1, y1, nIntervals, grids, image, xRes, yRes); rastTasks.push_back(rt); } } ResetAndStartTimer(); EnqueueTasks(rastTasks); WaitForAllTasks(); } else { // If not using tasks, just loop over all of the buckets // and rasterize. ResetAndStartTimer(); for (int y = 0; y < yRes; y += bucketExtent) { for (int x = 0; x < xRes; x += bucketExtent) { buckets[0]->Start(x, y, std::min(x + bucketExtent, xRes), std::min(y + bucketExtent, yRes)); rast->Rasterize(grids, nIntervals, buckets[0]); buckets[0]->Resolve(image, xRes, yRes); } } } // Report total time for rasterization double rastGCycles = GetElapsedMCycles() / 1024.; printf(" %.3f billion cycles\n", rastGCycles); // Write the image char outName[256]; sprintf(outName, "%s_int%d_samp%d.ppm", sceneName, nIntervals, nPixelSamples); WritePPM(image, xRes, yRes, outName); printf(" Wrote output image \"%s\"\n", outName); // Compare to the "golden" image for correctness char goldenName[256]; sprintf(goldenName, "golden/%s_%d.ppm", sceneName, nPixelSamples); if (!CompareToGolden(image, xRes, yRes, goldenName, outName)) ++failures; } printf("\n"); for (int i = 0; i < nBuckets; ++i) delete buckets[i]; delete[] image; } if (useTasks) TasksCleanup(); delete rast; return failures; }