Skip to content

Commit b1e9696

Browse files
committed
binary_shader
1 parent 203bf34 commit b1e9696

File tree

5 files changed

+101
-38
lines changed

5 files changed

+101
-38
lines changed

opencl/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
1. [Write buffer](write_buffer.c)
1414
1. [Multi-kernel](multi_kernel.c)
1515
1. [Benchmark examples](benchmark-examples.md)
16-
1. [Interactive](interactive)
16+
1. [Binary shader](binary_shader)
17+
1. [Interactive](interactive/)
1718
1. Tools
1819
1. [clinfo](clinfo.md)
1920
1. [Benchmarks](benchmarks.md)

opencl/binary_shader.c

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,78 @@
1-
/*
1+
/*Let's play with clCreateProgramWithBinary.
2+
3+
Compile the "inc.cl" CL C shader to binary, save the binary to a file, and load the shader from the binary:
4+
5+
./prog
6+
7+
Ignore the CL C shader, load binary from a file, and run it:
8+
9+
./prog 0
10+
11+
Use another shader instead:
12+
13+
./prog 1 dec.cl
14+
15+
The name "binary" is a possible lie: NVIDIA Linux driver 375.39
16+
just dumps PTX human readable assembly, which we can modify without
17+
reverse engineering. Hurray!
218
*/
319

20+
#define BIN_PATH __FILE__ ".bin.tmp"
21+
422
#include "common.h"
523

6-
int main(void) {
7-
const char *source =
8-
"__kernel void kmain(__global int *out) {\n"
9-
" out[get_global_id(0)]++;\n"
10-
"}\n"
11-
;
12-
cl_int input[] = {1, 2};
24+
int main(int argc, char **argv) {
25+
Common common;
26+
FILE *f;
27+
char *binary, *source_path;
28+
cl_int input[] = {1, 2}, errcode_ret, binary_status;
1329
cl_kernel kernel;
1430
cl_mem buffer;
1531
cl_program program;
16-
Common common;
1732
const size_t global_work_size = sizeof(input) / sizeof(input[0]);
18-
19-
/* Run kernel. */
20-
common_init(&common, source);
21-
22-
unsigned char *binary;
33+
int use_cache;
34+
long lenght;
2335
size_t binary_size;
24-
FILE *f;
2536

26-
clGetProgramInfo(common.program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binary_size, NULL);
27-
binary = malloc(binary_size);
28-
clGetProgramInfo(common.program, CL_PROGRAM_BINARIES, binary_size, binary, NULL);
37+
if (argc > 1) {
38+
use_cache = !strcmp(argv[1], "0");
39+
} else {
40+
use_cache = 0;
41+
}
42+
if (argc > 2) {
43+
source_path = argv[2];
44+
} else {
45+
source_path = "inc.cl";
46+
}
2947

30-
/* Not mandatory, but fun to reverse engineer their format later on. */
31-
f = fopen("a.bin.tmp", "w");
32-
fwrite(binary, binary_size, 1, f);
33-
fclose(f);
34-
35-
program = clCreateProgramWithBinary(common.context, 1, &common.device, &binary_size, (const unsigned char **)&binary, NULL, NULL);
36-
kernel = clCreateKernel(program, "kmain", NULL);
48+
/* Get the binary, and create a kernel with it. */
49+
if (use_cache) {
50+
common_init(&common, NULL);
51+
binary = common_read_file(BIN_PATH, &lenght);
52+
binary_size = lenght;
53+
} else {
54+
common_init_file(&common, source_path);
55+
clGetProgramInfo(common.program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binary_size, NULL);
56+
binary = malloc(binary_size);
57+
clGetProgramInfo(common.program, CL_PROGRAM_BINARIES, binary_size, &binary, NULL);
58+
f = fopen(BIN_PATH, "w");
59+
fwrite(binary, binary_size, 1, f);
60+
fclose(f);
61+
}
62+
program = clCreateProgramWithBinary(
63+
common.context, 1, &common.device, &binary_size,
64+
(const unsigned char **)&binary, &binary_status, &errcode_ret
65+
);
66+
assert(NULL != program);
67+
common_assert_success(binary_status);
68+
common_assert_success(errcode_ret);
3769
free(binary);
70+
common_build_program(&common, NULL, &program);
71+
kernel = clCreateKernel(program, "kmain", &errcode_ret);
72+
assert(NULL != kernel);
73+
common_assert_success(errcode_ret);
3874

39-
75+
/* Run the kernel created from the binary. */
4076
buffer = clCreateBuffer(common.context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeof(input), input, NULL);
4177
clSetKernelArg(kernel, 0, sizeof(buffer), &buffer);
4278
clEnqueueNDRangeKernel(common.command_queue, kernel, 1, NULL, &global_work_size, NULL, 0, NULL, NULL);

opencl/common.h

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ typedef struct {
2323
cl_program program;
2424
} Common;
2525

26-
char* common_read_file(const char *path) {
26+
void common_assert_success(cl_int ret) {
27+
assert(ret == CL_SUCCESS);
28+
}
29+
30+
char* common_read_file(const char *path, long *length_out) {
2731
char *buffer;
2832
FILE *f;
2933
long length;
@@ -33,37 +37,55 @@ char* common_read_file(const char *path) {
3337
fseek(f, 0, SEEK_END);
3438
length = ftell(f);
3539
fseek(f, 0, SEEK_SET);
36-
buffer = malloc(length + 1);
40+
buffer = malloc(length);
3741
if (fread(buffer, 1, length, f) < (size_t)length) {
3842
return NULL;
3943
}
4044
fclose(f);
41-
buffer[length] = '\0';
45+
if (NULL != length_out) {
46+
*length_out = length;
47+
}
4248
return buffer;
4349
}
4450

45-
void common_create_program(
51+
char* common_read_file_null(const char *path) {
52+
char *f;
53+
long length;
54+
f = common_read_file(path, &length);
55+
f = realloc(f, length + 1);
56+
f[length] = '\0';
57+
return f;
58+
}
59+
60+
void common_build_program(
4661
Common *common,
47-
const char *source,
4862
const char *options,
4963
cl_program *program
5064
) {
5165
char *err;
5266
cl_int ret;
5367
size_t err_len;
54-
55-
*program = clCreateProgramWithSource(common->context, 1, &source, NULL, NULL);
5668
ret = clBuildProgram(*program, 1, &(common->device), options, NULL, NULL);
5769
if (CL_SUCCESS != ret) {
5870
clGetProgramBuildInfo(*program, common->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &err_len);
5971
err = malloc(err_len);
6072
clGetProgramBuildInfo(*program, common->device, CL_PROGRAM_BUILD_LOG, err_len, err, NULL);
61-
fprintf(stderr, "error: clCreateProgramWithSource:\n%s\n", err);
73+
fprintf(stderr, "error: clBuildProgram:\n%s\n", err);
6274
free(err);
6375
exit(EXIT_FAILURE);
6476
}
6577
}
6678

79+
void common_create_program(
80+
Common *common,
81+
const char *source,
82+
const char *options,
83+
cl_program *program
84+
) {
85+
*program = clCreateProgramWithSource(common->context, 1, &source, NULL, NULL);
86+
common_build_program(common, options, program);
87+
}
88+
6789
void common_create_kernel(
6890
Common *common,
6991
const char *source,
@@ -85,7 +107,7 @@ void common_create_kernel_file(
85107
const char *options
86108
) {
87109
char *source;
88-
source = common_read_file(source_path);
110+
source = common_read_file_null(source_path);
89111
common_create_kernel(common, source, options);
90112
free(source);
91113
}
@@ -117,7 +139,7 @@ void common_init_file_options(
117139
const char *options
118140
) {
119141
char *source;
120-
source = common_read_file(source_path);
142+
source = common_read_file_null(source_path);
121143
common_init_options(common, source, options);
122144
free(source);
123145
}

opencl/inc.cl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__kernel void kmain(__global int *out) {
2+
out[get_global_id(0)]++;
3+
}

opencl/inc_vector.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ int main(void) {
1515
const char *source =
1616
"__kernel void kmain(__global int *out) {\n"
1717
" out[get_global_id(0)]++;\n"
18-
"}\n";
18+
"}\n"
19+
;
1920
cl_int input[] = {1, 2};
2021
cl_mem buffer;
2122
Common common;

0 commit comments

Comments
 (0)