1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
#include <cstdint>
#include <cstdio>
#include <cstdlib>
struct Pixel {
uint8_t r, g, b;
};
struct Complex {
float r, i;
__device__ float norm2() const { return r * r + i * i; }
};
__device__ Complex operator*(Complex a, Complex b) {
return Complex{(a.r * b.r) - (a.i * b.i), (a.i * b.r) + (a.r * b.i)};
}
__device__ Complex operator+(Complex a, Complex b) {
return Complex{a.r + b.r, a.i + b.i};
}
__device__ int julia(int width, int height, int x, int y) {
constexpr float scale = 1.5;
constexpr int N = 200;
const float jx = scale * (width / 2 - x) / (width / 2);
const float jy = scale * (height / 2 - y) / (height / 2);
const Complex c{-0.8, 0.156};
Complex a{jx, jy};
for (int i = 0; i < N; ++i) {
a = a * a + c;
if (a.norm2() > 1000) {
return 0;
}
}
return 1;
}
__global__ void juliaMain(Pixel* image) {
const int x = blockIdx.x;
const int y = blockIdx.y;
constexpr Pixel background{41, 95, 152};
constexpr Pixel juliaColour{228, 192, 135};
const Pixel pixel =
julia(gridDim.x, gridDim.y, x, y) == 1 ? juliaColour : background;
image[y * gridDim.x + x] = pixel;
}
bool write_pbm(const Pixel* image, int width, int height, const char* path) {
const size_t num_pixels = width * height;
FILE* file = fopen(path, "wb");
if (!file) {
return false;
}
fprintf(file, "P6\n%d %d\n255\n", width, height);
if (fwrite(image, sizeof(Pixel), num_pixels, file) != num_pixels) {
fclose(file);
return false;
}
fclose(file);
return true;
}
int main(int argc, const char** argv) {
const int width = argc > 1 ? atoi(argv[1]) : 1920;
const int height = argc > 2 ? atoi(argv[2]) : 1080;
bool success = false;
const dim3 dim(width, height);
const int image_size_bytes = width * height * sizeof(Pixel);
auto image_host = new Pixel[width * height];
Pixel* image_dev = nullptr;
if (cudaMalloc(&image_dev, image_size_bytes) != cudaSuccess) {
goto cleanup;
}
juliaMain<<<dim, 1>>>(image_dev);
if (cudaMemcpy(
image_host, image_dev, image_size_bytes, cudaMemcpyDeviceToHost) !=
cudaSuccess) {
goto cleanup;
}
if (!write_pbm(image_host, width, height, "julia.pbm")) {
goto cleanup;
}
success = true;
cleanup:
delete[] image_host;
if (image_dev) {
cudaFree(image_dev);
}
return success ? 0 : 1;
}
|