Files
TheRock/rocm-libraries/projects/hipthreads/examples/InOneWeekendRaytracer/hip-variant/main.hip
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

230 lines
8.6 KiB
C++

#include "hip/hip_runtime.h"
#include <iostream>
#include <time.h>
#include <float.h>
#include <hiprand/hiprand_kernel.h>
#include "vec3.h"
#include "ray.h"
#include "sphere.h"
#include "hitable_list.h"
#include "camera.h"
#include "material.h"
// limited version of checkCudaErrors from hip/hip_runtime_api.h in CUDA examples
#define checkCudaErrors(val) check_cuda( (val), #val, __FILE__, __LINE__ )
void check_cuda(hipError_t result, char const *const func, const char *const file, int const line) {
if (result) {
std::cerr << "CUDA error = " << static_cast<unsigned int>(result) << " at " <<
file << ":" << line << " '" << func << "' \n";
// Make sure we call CUDA Device Reset before exiting
hipDeviceReset();
exit(99);
}
}
// Matching the C++ code would recurse enough into color() calls that
// it was blowing up the stack, so we have to turn this into a
// limited-depth loop instead. Later code in the book limits to a max
// depth of 50, so we adapt this a few chapters early on the GPU.
__host__ __device__ vec3 color(const ray& r, hittable **world, hiprandState *state) {
ray cur_ray = r;
vec3 cur_attenuation = vec3(1.0,1.0,1.0);
for(int i = 0; i < 50; i++) {
hit_record rec;
if ((*world)->hit(cur_ray, 0.001f, FLT_MAX, rec)) {
ray scattered;
vec3 attenuation;
if(rec.mat_ptr->scatter(cur_ray, rec, attenuation, scattered, state)) {
cur_attenuation *= attenuation;
cur_ray = scattered;
}
else {
return vec3(0.0,0.0,0.0);
}
}
else {
vec3 unit_direction = unit_vector(cur_ray.direction());
float t = 0.5f*(unit_direction.y() + 1.0f);
vec3 c = (1.0f-t)*vec3(1.0, 1.0, 1.0) + t*vec3(0.5, 0.7, 1.0);
return cur_attenuation * c;
}
}
return vec3(0.0,0.0,0.0); // exceeded recursion
}
__global__ void rand_init(hiprandState *rand_state) {
if (threadIdx.x == 0 && blockIdx.x == 0) {
hiprand_init(1984, 0, 0, rand_state);
}
}
__global__ void render_init(int max_x, int max_y, hiprandState *rand_state) {
int i = threadIdx.x + blockIdx.x * blockDim.x;
int j = threadIdx.y + blockIdx.y * blockDim.y;
if((i >= max_x) || (j >= max_y)) return;
int pixel_index = j*max_x + i;
// Original: Each thread gets same seed, a different sequence number, no offset
// hiprand_init(1984, pixel_index, 0, &rand_state[pixel_index]);
// BUGFIX, see Issue#2: Each thread gets different seed, same sequence for
// performance improvement of about 2x!
hiprand_init(1984+pixel_index, 0, 0, &rand_state[pixel_index]);
}
__global__ void render(vec3 *fb, int max_x, int max_y, int ns, camera **cam, hittable **world, hiprandState *rand_state) {
int i = threadIdx.x + blockIdx.x * blockDim.x;
int j = threadIdx.y + blockIdx.y * blockDim.y;
if((i >= max_x) || (j >= max_y)) return;
int pixel_index = j*max_x + i;
hiprandState local_rand_state = rand_state[pixel_index];
vec3 col(0,0,0);
for(int s=0; s < ns; s++) {
float u = float(i + hiprand_uniform(&local_rand_state)) / float(max_x);
float v = float(j + hiprand_uniform(&local_rand_state)) / float(max_y);
ray r = (*cam)->get_ray(u, v, &local_rand_state);
col += color(r, world, &local_rand_state);
}
rand_state[pixel_index] = local_rand_state;
col /= float(ns);
col[0] = sqrt(col[0]);
col[1] = sqrt(col[1]);
col[2] = sqrt(col[2]);
fb[pixel_index] = col;
}
#define RND (hiprand_uniform(&local_rand_state))
__global__ void create_world(hittable **d_list, hittable **d_world, camera **d_camera, int nx, int ny, hiprandState *rand_state) {
if (threadIdx.x == 0 && blockIdx.x == 0) {
hiprandState local_rand_state = *rand_state;
d_list[0] = new sphere(vec3(0,-1000.0,-1), 1000,
new lambertian(vec3(0.5, 0.5, 0.5)));
int i = 1;
for(int a = -11; a < 11; a++) {
for(int b = -11; b < 11; b++) {
float choose_mat = RND;
vec3 center(a+RND,0.2,b+RND);
if(choose_mat < 0.8f) { // diffuse
d_list[i++] = new sphere(center, 0.2,
new lambertian(vec3(RND*RND, RND*RND, RND*RND)));
}
else if(choose_mat < 0.95f) { // metal
d_list[i++] = new sphere(center, 0.2,
new metal(vec3(0.5f*(1.0f+RND), 0.5f*(1.0f+RND), 0.5f*(1.0f+RND)), 0.5f*RND));
}
else { // glass
d_list[i++] = new sphere(center, 0.2, new dielectric(1.5));
}
}
}
d_list[i++] = new sphere(vec3(0, 1,0), 1.0, new dielectric(1.5));
d_list[i++] = new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)));
d_list[i++] = new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));
*rand_state = local_rand_state;
*d_world = new hittable_list(d_list, 22*22+1+3);
vec3 lookfrom(13,2,3);
vec3 lookat(0,0,0);
float dist_to_focus = 10.0; (lookfrom-lookat).length();
float aperture = 0.1;
*d_camera = new camera(lookfrom,
lookat,
vec3(0,1,0),
30.0,
float(nx)/float(ny),
aperture,
dist_to_focus);
}
}
__global__ void free_world(hittable **d_list, hittable **d_world, camera **d_camera) {
for(int i=0; i < 22*22+1+3; i++) {
delete ((sphere *)d_list[i])->mat_ptr;
delete d_list[i];
}
delete *d_world;
delete *d_camera;
}
int main() {
int nx = 1200;
int ny = 800;
int ns = 10;
int tx = 8;
int ty = 8;
std::cerr << "Rendering a " << nx << "x" << ny << " image with " << ns << " samples per pixel ";
std::cerr << "in " << tx << "x" << ty << " blocks.\n";
int num_pixels = nx*ny;
size_t fb_size = num_pixels*sizeof(vec3);
// allocate FB
vec3 *fb;
checkCudaErrors(hipMallocManaged((void **)&fb, fb_size));
// allocate random state
hiprandState *d_rand_state;
checkCudaErrors(hipMalloc((void **)&d_rand_state, num_pixels*sizeof(hiprandState)));
hiprandState *d_rand_state2;
checkCudaErrors(hipMalloc((void **)&d_rand_state2, 1*sizeof(hiprandState)));
// we need that 2nd random state to be initialized for the world creation
rand_init<<<1,1>>>(d_rand_state2);
checkCudaErrors(hipGetLastError());
checkCudaErrors(hipDeviceSynchronize());
// make our world of hittables & the camera
hittable **d_list;
int num_hittables = 22*22+1+3;
checkCudaErrors(hipMalloc((void **)&d_list, num_hittables*sizeof(hittable *)));
hittable **d_world;
checkCudaErrors(hipMalloc((void **)&d_world, sizeof(hittable *)));
camera **d_camera;
checkCudaErrors(hipMalloc((void **)&d_camera, sizeof(camera *)));
create_world<<<1,1>>>(d_list, d_world, d_camera, nx, ny, d_rand_state2);
checkCudaErrors(hipGetLastError());
checkCudaErrors(hipDeviceSynchronize());
clock_t start, stop;
start = clock();
// Render our buffer
dim3 blocks(nx/tx+1,ny/ty+1);
dim3 threads(tx,ty);
render_init<<<blocks, threads>>>(nx, ny, d_rand_state);
checkCudaErrors(hipGetLastError());
checkCudaErrors(hipDeviceSynchronize());
render<<<blocks, threads>>>(fb, nx, ny, ns, d_camera, d_world, d_rand_state);
checkCudaErrors(hipGetLastError());
checkCudaErrors(hipDeviceSynchronize());
stop = clock();
double timer_seconds = ((double)(stop - start)) / CLOCKS_PER_SEC;
std::cerr << "took " << timer_seconds << " seconds.\n";
// Output FB as Image
std::cout << "P3\n" << nx << " " << ny << "\n255\n";
for (int j = ny-1; j >= 0; j--) {
for (int i = 0; i < nx; i++) {
size_t pixel_index = j*nx + i;
int ir = int(255.99*fb[pixel_index].r());
int ig = int(255.99*fb[pixel_index].g());
int ib = int(255.99*fb[pixel_index].b());
std::cout << ir << " " << ig << " " << ib << "\n";
}
}
// clean up
checkCudaErrors(hipDeviceSynchronize());
free_world<<<1,1>>>(d_list,d_world,d_camera);
checkCudaErrors(hipGetLastError());
checkCudaErrors(hipFree(d_camera));
checkCudaErrors(hipFree(d_world));
checkCudaErrors(hipFree(d_list));
checkCudaErrors(hipFree(d_rand_state));
checkCudaErrors(hipFree(d_rand_state2));
checkCudaErrors(hipFree(fb));
hipDeviceReset();
}