// Sample Method Definitions Sample::Sample(SurfaceIntegrator *surf, VolumeIntegrator *vol, const Scene *scene) { surf->RequestSamples(this, scene); vol->RequestSamples(this, scene); // Allocate storage for sample pointers int nPtrs = n1D.size() + n2D.size(); if (!nPtrs) { oneD = twoD = NULL; return; } oneD = (float **)AllocAligned(nPtrs * sizeof(float *)); twoD = oneD + n1D.size(); // Compute total number of sample values needed int totSamples = 0; for (u_int i = 0; i < n1D.size(); ++i) totSamples += n1D[i]; for (u_int i = 0; i < n2D.size(); ++i) totSamples += 2 * n2D[i]; // Allocate storage for sample values float *mem = (float *)AllocAligned(totSamples * sizeof(float)); for (u_int i = 0; i < n1D.size(); ++i) { oneD[i] = mem; mem += n1D[i]; } for (u_int i = 0; i < n2D.size(); ++i) { twoD[i] = mem; mem += 2 * n2D[i]; } }
RandomSampler::RandomSampler(int xstart, int xend, int ystart, int yend, int xs, int ys) : Sampler(xstart, xend, ystart, yend, xs * ys) { xPos = xPixelStart; yPos = yPixelStart; xPixelSamples = xs; yPixelSamples = ys; // Get storage for a pixel's worth of stratified samples imageSamples = (float *)AllocAligned(5 * xPixelSamples * yPixelSamples * sizeof(float)); lensSamples = imageSamples + 2 * xPixelSamples * yPixelSamples; timeSamples = lensSamples + 2 * xPixelSamples * yPixelSamples; for (int i = 0; i < 5 * xPixelSamples * yPixelSamples; ++i) { imageSamples[i] = RandomFloat(); } // Shift image samples to pixel coordinates for (int o = 0; o < 2 * xPixelSamples * yPixelSamples; o += 2) { imageSamples[o] += xPos; imageSamples[o+1] += yPos; } samplePos = 0; }
// KdTreeAccel Method Definitions KdTreeAccel:: KdTreeAccel(const vector<Reference<Primitive> > &p, int icost, int tcost, float ebonus, int maxp, int maxDepth) : isectCost(icost), traversalCost(tcost), maxPrims(maxp), emptyBonus(ebonus) { vector<Reference<Primitive > > prims; for (u_int i = 0; i < p.size(); ++i) p[i]->FullyRefine(prims); // Initialize mailboxes for _KdTreeAccel_ curMailboxId = 0; nMailboxes = prims.size(); mailboxPrims = (MailboxPrim *)AllocAligned(nMailboxes * sizeof(MailboxPrim)); for (u_int i = 0; i < nMailboxes; ++i) new (&mailboxPrims[i]) MailboxPrim(prims[i]); // Build kd-tree for accelerator nextFreeNode = nAllocedNodes = 0; if (maxDepth <= 0) maxDepth = Round2Int(8 + 1.3f * Log2Int(float(prims.size()))); // Compute bounds for kd-tree construction vector<BBox> primBounds; primBounds.reserve(prims.size()); for (u_int i = 0; i < prims.size(); ++i) { BBox b = prims[i]->WorldBound(); bounds = Union(bounds, b); primBounds.push_back(b); } // Allocate working memory for kd-tree construction BoundEdge *edges[3]; for (int i = 0; i < 3; ++i) edges[i] = new BoundEdge[2*prims.size()]; int *prims0 = new int[prims.size()]; int *prims1 = new int[(maxDepth+1) * prims.size()]; // Initialize _primNums_ for kd-tree construction int *primNums = new int[prims.size()]; for (u_int i = 0; i < prims.size(); ++i) primNums[i] = i; // Start recursive construction of kd-tree buildTree(0, bounds, primBounds, primNums, prims.size(), maxDepth, edges, prims0, prims1); // Free working memory for kd-tree construction delete[] primNums; for (int i = 0; i < 3; ++i) delete[] edges[i]; delete[] prims0; delete[] prims1; }
// GridAccel Method Definitions GridAccel::GridAccel(const vector<Reference<Primitive> > &p, bool forRefined, bool refineImmediately) : gridForRefined(forRefined) { // Initialize _prims_ with primitives for grid vector<Reference<Primitive> > prims; if (refineImmediately) for (u_int i = 0; i < p.size(); ++i) p[i]->FullyRefine(prims); else prims = p; // Initialize mailboxes for grid nMailboxes = prims.size(); mailboxes = (MailboxPrim *)AllocAligned(nMailboxes * sizeof(MailboxPrim)); for (u_int i = 0; i < nMailboxes; ++i) new (&mailboxes[i]) MailboxPrim(prims[i]); // Compute bounds and choose grid resolution for (u_int i = 0; i < prims.size(); ++i) bounds = Union(bounds, prims[i]->WorldBound()); Vector delta = bounds.pMax - bounds.pMin; // Find _voxelsPerUnitDist_ for grid int maxAxis = bounds.MaximumExtent(); float invMaxWidth = 1.f / delta[maxAxis]; Assert(invMaxWidth > 0.f); // NOBOOK float cubeRoot = 3.f * powf(float(prims.size()), 1.f/3.f); float voxelsPerUnitDist = cubeRoot * invMaxWidth; for (int axis = 0; axis < 3; ++axis) { NVoxels[axis] = Round2Int(delta[axis] * voxelsPerUnitDist); NVoxels[axis] = Clamp(NVoxels[axis], 1, 64); } // Compute voxel widths and allocate voxels for (int axis = 0; axis < 3; ++axis) { Width[axis] = delta[axis] / NVoxels[axis]; InvWidth[axis] = (Width[axis] == 0.f) ? 0.f : 1.f / Width[axis]; } int nVoxels = NVoxels[0] * NVoxels[1] * NVoxels[2]; voxels = (Voxel **)AllocAligned(nVoxels * sizeof(Voxel *)); memset(voxels, 0, nVoxels * sizeof(Voxel *)); // Add primitives to grid voxels for (u_int i = 0; i < prims.size(); ++i) { // Find voxel extent of primitive BBox pb = prims[i]->WorldBound(); int vmin[3], vmax[3]; for (int axis = 0; axis < 3; ++axis) { vmin[axis] = PosToVoxel(pb.pMin, axis); vmax[axis] = PosToVoxel(pb.pMax, axis); } // Add primitive to overlapping voxels for (int z = vmin[2]; z <= vmax[2]; ++z) for (int y = vmin[1]; y <= vmax[1]; ++y) for (int x = vmin[0]; x <= vmax[0]; ++x) { int offset = Offset(x, y, z); if (!voxels[offset]) { // Allocate new voxel and store primitive in it voxels[offset] = new (voxelArena) Voxel(&mailboxes[i]); } else { // Add primitive to already-allocated voxel voxels[offset]->AddPrimitive(&mailboxes[i]); } } static StatsRatio nPrimitiveVoxels("Grid Accelerator", // NOBOOK "Voxels covered vs # / primitives"); // NOBOOK nPrimitiveVoxels.Add((1 + vmax[0]-vmin[0]) * (1 + vmax[1]-vmin[1]) * // NOBOOK (1 + vmax[2]-vmin[2]), 1); // NOBOOK } // Update grid statistics static StatsPercentage nEmptyVoxels("Grid Accelerator", "Empty voxels"); static StatsRatio avgPrimsInVoxel("Grid Accelerator", "Average # of primitives in voxel"); static StatsCounter maxPrimsInVoxel("Grid Accelerator", "Max # of primitives in a grid voxel"); nEmptyVoxels.Add(0, NVoxels[0] * NVoxels[1] * NVoxels[2]); avgPrimsInVoxel.Add(0,NVoxels[0] * NVoxels[1] * NVoxels[2]); for (int z = 0; z < NVoxels[2]; ++z) for (int y = 0; y < NVoxels[1]; ++y) for (int x = 0; x < NVoxels[0]; ++x) { int offset = Offset(x, y, z); if (!voxels[offset]) nEmptyVoxels.Add(1, 0); else { int nPrims = voxels[offset]->nPrimitives; maxPrimsInVoxel.Max(nPrims); avgPrimsInVoxel.Add(nPrims, 0); } } }
Mutex *Mutex::Create() { int sz = sizeof(Mutex); sz = (sz + (PBRT_L1_CACHE_LINE_SIZE-1)) & ~(PBRT_L1_CACHE_LINE_SIZE-1); return new (AllocAligned(sz)) Mutex; }
u32 BlockAllocator::Alloc(u32 &size, bool fromTop, const char *tag) { // We want to make sure it's aligned in case AllocAt() was used. return AllocAligned(size, grain_, grain_, fromTop, tag); }
void KdTreeAccel::buildTree(int nodeNum, const BBox &nodeBounds, const vector<BBox> &allPrimBounds, int *primNums, int nPrims, int depth, BoundEdge *edges[3], int *prims0, int *prims1, int badRefines) { Assert(nodeNum == nextFreeNode); // NOBOOK // Get next free node from _nodes_ array if (nextFreeNode == nAllocedNodes) { int nAlloc = max(2 * nAllocedNodes, 512); KdAccelNode *n = (KdAccelNode *)AllocAligned(nAlloc * sizeof(KdAccelNode)); if (nAllocedNodes > 0) { memcpy(n, nodes, nAllocedNodes * sizeof(KdAccelNode)); FreeAligned(nodes); } nodes = n; nAllocedNodes = nAlloc; } ++nextFreeNode; // Initialize leaf node if termination criteria met if (nPrims <= maxPrims || depth == 0) { nodes[nodeNum].initLeaf(primNums, nPrims, mailboxPrims, arena); return; } // Initialize interior node and continue recursion // Choose split axis position for interior node int bestAxis = -1, bestOffset = -1; float bestCost = INFINITY; float oldCost = isectCost * float(nPrims); Vector d = nodeBounds.pMax - nodeBounds.pMin; float totalSA = (2.f * (d.x*d.y + d.x*d.z + d.y*d.z)); float invTotalSA = 1.f / totalSA; // Choose which axis to split along int axis; if (d.x > d.y && d.x > d.z) axis = 0; else axis = (d.y > d.z) ? 1 : 2; int retries = 0; retrySplit: // Initialize edges for _axis_ for (int i = 0; i < nPrims; ++i) { int pn = primNums[i]; const BBox &bbox = allPrimBounds[pn]; edges[axis][2*i] = BoundEdge(bbox.pMin[axis], pn, true); edges[axis][2*i+1] = BoundEdge(bbox.pMax[axis], pn, false); } sort(&edges[axis][0], &edges[axis][2*nPrims]); // Compute cost of all splits for _axis_ to find best int nBelow = 0, nAbove = nPrims; for (int i = 0; i < 2*nPrims; ++i) { if (edges[axis][i].type == BoundEdge::END) --nAbove; float edget = edges[axis][i].t; if (edget > nodeBounds.pMin[axis] && edget < nodeBounds.pMax[axis]) { // Compute cost for split at _i_th edge int otherAxis[3][2] = { {1,2}, {0,2}, {0,1} }; int otherAxis0 = otherAxis[axis][0]; int otherAxis1 = otherAxis[axis][1]; float belowSA = 2 * (d[otherAxis0] * d[otherAxis1] + (edget - nodeBounds.pMin[axis]) * (d[otherAxis0] + d[otherAxis1])); float aboveSA = 2 * (d[otherAxis0] * d[otherAxis1] + (nodeBounds.pMax[axis] - edget) * (d[otherAxis0] + d[otherAxis1])); float pBelow = belowSA * invTotalSA; float pAbove = aboveSA * invTotalSA; float eb = (nAbove == 0 || nBelow == 0) ? emptyBonus : 0.f; float cost = traversalCost + isectCost * (1.f - eb) * (pBelow * nBelow + pAbove * nAbove); // Update best split if this is lowest cost so far if (cost < bestCost) { bestCost = cost; bestAxis = axis; bestOffset = i; } } if (edges[axis][i].type == BoundEdge::START) ++nBelow; } Assert(nBelow == nPrims && nAbove == 0); // NOBOOK // Create leaf if no good splits were found if (bestAxis == -1 && retries < 2) { ++retries; axis = (axis+1) % 3; goto retrySplit; } if (bestCost > oldCost) ++badRefines; if ((bestCost > 4.f * oldCost && nPrims < 16) || bestAxis == -1 || badRefines == 3) { nodes[nodeNum].initLeaf(primNums, nPrims, mailboxPrims, arena); return; } // Classify primitives with respect to split int n0 = 0, n1 = 0; for (int i = 0; i < bestOffset; ++i) if (edges[bestAxis][i].type == BoundEdge::START) prims0[n0++] = edges[bestAxis][i].primNum; for (int i = bestOffset+1; i < 2*nPrims; ++i) if (edges[bestAxis][i].type == BoundEdge::END) prims1[n1++] = edges[bestAxis][i].primNum; // Recursively initialize children nodes float tsplit = edges[bestAxis][bestOffset].t; nodes[nodeNum].initInterior(bestAxis, tsplit); BBox bounds0 = nodeBounds, bounds1 = nodeBounds; bounds0.pMax[bestAxis] = bounds1.pMin[bestAxis] = tsplit; buildTree(nodeNum+1, bounds0, allPrimBounds, prims0, n0, depth-1, edges, prims0, prims1 + nPrims, badRefines); nodes[nodeNum].aboveChild = nextFreeNode; buildTree(nodes[nodeNum].aboveChild, bounds1, allPrimBounds, prims1, n1, depth-1, edges, prims0, prims1 + nPrims, badRefines); }