SVN trunk also contains solid database device storage and a render function which given a view2model matrix, width, height, can generate an RGB8 bitmap. Diffuse and Surface Normal light models are supported. The renderer does BVH accelerated ray tracing and ignores the CSG operators. It is integrated as a render option in mged.

The code is recursive (which is problematic for OCL). I'll work on a simplified version of the rendering loop which only does the primary rays in C as a first approach. After I get the non-recursive parallel friendly C code I'll work on the OCL port.

Updated project proposal on Google Melange.

SVN r65153 fails to compile with a bogus error of an unused variable that's actually being used its just that GCC 4.9.1 is too dumb to figure that out.

Read code to better understand the main spatial partition construction routines. They seem to be something like this:

rt_prep_parallel() → rt_cut_it() → rt_nugrid_cut()

We need something less complex that is more amenable to porting to OCL. So I will be implementing the Lagae & Dutré compact grid construction algorithm published at EGSR. First I will program in ANSI C then I will port the code to OpenCL.

This allows us to ultimately reuse the CPU code for boolean weaving, primitive normals, shaders, to have a 100% pixel accurate result. At the expense of a lot of memory traffic and CPU-side computation of some fairly maths intensive parts like the normal compute and shade. However I presently see no other way of having a 100% accurate result in the time we have available.

# test results:
arb8: pixdiff bytes: 777500 matching, 8932 off by 1, 0 off by many
ehy: pixdiff bytes: 760977 matching, 25443 off by 1, 12 off by many
ell: pixdiff bytes: 764588 matching, 21844 off by 1, 0 off by many
sph: pixdiff bytes: 736942 matching, 49490 off by 1, 0 off by many
tgc: pixdiff bytes: 783191 matching, 3241 off by 1, 0 off by many
tor: pixdiff bytes: 774138 matching, 12294 off by 1, 0 off by many

RT (EHY)

OCL (EHY)

PIXDIFF (EHY)

The off by many problem with EHY is probably related to rounding errors with sqrt in OCL for NVIDIA using a different rounding mode than X86. It is possible to use PTX assembly, i.e. asm("sqrt.rp.f64 %0, %1;" : "=d"(b) : "d"(a));. OCL 1.1 and over have no support for setting rounding modes without using inline assembly.

This is not an apples to apple comparison since the work done is a lot different. The brute force version ignores the CSG operators. We don't have OCL normal computation. But it's a way to gauge the possibilities here. If we implemented a BVH we could cut the iterations per pixel from 2429 to around log2(2429)*depth complexity where log2(2429)=11.25. In opencl branch.

PS: The missile launcher tubes don't show up. The tgcs degenerate to recs. So need OCL rec shot to render this properly. Might also be an issue in other scenes.

Add REC shot routine to opencl branch. Fixes the issues with the havoc missile launchers as seen above.

On hindsight I think the grids are not a good option for BRL-CAD on the GPU. Spatial partitioning can result in duplicate shots. Shots of BRL-CAD primitives can be more expensive than simple ray-triangle shots. The alternative is to use mailboxing like the BRL-CAD ANSI C code currently does but this requires a lot of per thread memory which we can ill afford on a massively parallel architecture like a GPU. So I think we would be better served by object partitioning namely BVHs. Did another literature search to see if I could come up with some papers we could use for the boolean evaluation, BVH construction and traversal.

As for the boolean evaluator. If we can compute this incrementally this will have a significant impact on memory loads and memory consumption.

Retrofit HLBVH tree builder from pbrtv3 source into opencl branch.

OCL BVH traversal in branch.

For reference the OCL BVH can render the Havoc scene, as seen above, at elapsed time: 0.09 sec vs the 4.20 sec it took with the brute force code. i.e. it is around 45x faster for this scene. The advantage should increase for scenes with more solids.

The HLBVH code has stabilized enough that I replaced the grids code with it.

Integrated OCL rendering with rt (command line option "-z") and mged (diffuse and surface normals light models). Currently it is fill rate limited. Pixel pushing is done with view_pixel on a single CPU core. This should be done on the GPU. The framebuffer outputs should also support writing blocks of pixels. Currently they use line oriented output. Doing these changes would require breaking API compatibility.

Do heavy duty pixel pushing with the GPU. This speeds up rendering of Havok around 2-3x on my system. It should make even more of a difference in simpler scenes which are more fillrate than geometry performance limited. I figured out a way to do the code for this without actually breaking the API. I used a callback to get the framebuffer pointer.

I redid the accuracy tests after reimplementing the raster parts of the code in OCL to check the accuracy. I got the same accuracy in surface normals mode as when we only computed the hit results in OCL with one kernel invocation per ray-solid intersection.

RT Hyperboloid

OCL Hyperboloid

PIXDIFF Hyperboloid

elapsed time @ 972x956: 0.35 sec

elapsed time @ 972x956: 0.06 sec

This was the one primitive which had the most differences last time so I ran the test again. ehy: pixdiff bytes: 760757 matching, 25663 off by 1, 12 off by many. I got similar results. So the pixel engine shouldn't be more innacurate than the regular one. What I did find out in surface normals mode was that the CPU code actually is showing hits with the side of the hyperboloid (see the blue dots in the figure at the left). Despite this view being top down. So maybe the GPU version is actually more accurate? The differences show a nice noisy pattern without obvious banding or moire so there don't seem to be any major issues with the hits, normals, and raster.

Show -z OpenCL command line option when running rt -h.

Rename table.cl to rt.cl.

Replace branches in pixel writing with conditional moves.

Refactor sub buffer code.

Write depth buffer in network byte order.

Removed scan code from PyOpenCL because of licensing issues. Good thing it wasn't being used anywhere yet.

Remove malloc inside framebuffer grabber routine.

Require OpenCL 1.2 or greater.

Change OCL primitive packing routines to use memory pools.

Initial bot, ars implementation. It just intersects all the triangles. No acceleration.

Added material colors to OCL render. The colors are kind of buggy because there is no easy way, that I know of, getting the actual material associated with a solid in the table. The materials are in regions and regions are the ones with materials. Any solid may be in a number of regions. Figuring out the material without consulting the actual CSG tree which has the regions is hence non-trivial.

Added a lightmodel with transparent multi-hit rendering to show the multi-hit facilities.

Golliath (OCL)

elapsed time @ 972x956: 0.33 sec

Fix linking errors in AMD OCL SDK.

Fix issues with OCL color render.

Fix issue when doing a render with nothing on view.

Set the local workgroup size when rendering to use subgrids up to 8x8 size to maximize coherency of accesses. speeds up things like 2x.

Tested an adaptation of Understanding the Efficiency of Ray Traversal on GPUs. Timo Aila and Samuli Laine, Proc. High-Performance Graphics 2009. Was not significantly better on the GTX TITAN compared with just shooting rays in 8x8 blocks. You can read more about it here:

Use less memory to store solid ids and materials. Eliminate some more branches and simplify logic in solver.

Compute transparency using attenuation.

bool.c cleanups. If we ever are to port the standard BRL-CAD CSG evaluator algorithm to OpenCL C, given that there seem to be no other major viable options which give sufficiently correct results for our project's purposes, this code must be brought to heel. Such a task would be immense. I hope I helped this with a series of patches to: remove goto (not available in OpenCL C), to re-compile the bool trees (binary tree of pointers) to a linear postfix array form. This form is easier to parse and eval during the rendering stage. I did those tasks in these stages:

eliminated all gotos in rt_default_multioverlap().

eliminated all gotos in rt_boolweave().

produced a patch to use the postfix linear tree. I uses a lot less memory (64-bits per node) and the traversal is more cache coherent. The CSG inference engine supports these operators: UNION, INTERSECT, DIFFERENCE, XOR, NOT, SOLID, NOP.

It might require re-interfacing with db code in particular for the way XOR operations used to be treated. I reimplemented these functions to use the postfix bool tree:

Process segments instead of hit points. Use registers to store segments. Make all available rendering modes (full, diffuse, normals, multi-hit transparent) work in a single pass. This speeds up the full and transparent modes like 2-3x.

Also updated the multiple-kernel launch renderer code to work with the segment list approach. It might be slower than the single-kernel launch renderer but we might eventually need the whole segment list in memory at the same time to perform more advanced rendering.

Fixed the ocl material colors. It seems a solid's basic material color is in the end rather than the beginning of the regions list it has...

Well folks GSoC 2015 is finally over! Mission complete! I thank everyone who made this possible:

Google: Carol Smith

BRL-CAD: brlcad (Sean), Stragus, ``Erik, starseeker.

These were the most notable task supporters to list. The deepest thanks go to my parents for tirelessly supporting me during this code marathon.