mirror of
https://github.com/libretro/cpp-cheat.git
synced 2025-04-04 12:01:41 +00:00
245 lines
6.3 KiB
C
245 lines
6.3 KiB
C
#ifndef COMMON_H
|
|
#define COMMON_H
|
|
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
/* http://stackoverflow.com/questions/28500496/opencl-function-found-deprecated-by-visual-studio */
|
|
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS
|
|
#include <CL/cl.h>
|
|
|
|
/* Encapsulates objects that we use the same on most programs.
|
|
* This excludes, notably, buffers. */
|
|
typedef struct {
|
|
cl_command_queue command_queue;
|
|
cl_context context;
|
|
cl_device_id device;
|
|
cl_kernel kernel;
|
|
cl_program program;
|
|
} Common;
|
|
|
|
void common_assert_success(cl_int ret) {
|
|
assert(ret == CL_SUCCESS);
|
|
}
|
|
|
|
char* common_read_file(const char *path, long *length_out) {
|
|
char *buffer;
|
|
FILE *f;
|
|
long length;
|
|
|
|
f = fopen(path, "r");
|
|
assert(NULL != f);
|
|
fseek(f, 0, SEEK_END);
|
|
length = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
buffer = (char *)malloc(length);
|
|
if (fread(buffer, 1, length, f) < (size_t)length) {
|
|
return NULL;
|
|
}
|
|
fclose(f);
|
|
if (NULL != length_out) {
|
|
*length_out = length;
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
char* common_read_file_null(const char *path) {
|
|
char *f;
|
|
long length;
|
|
f = common_read_file(path, &length);
|
|
f = (char *)realloc(f, length + 1);
|
|
f[length] = '\0';
|
|
return f;
|
|
}
|
|
|
|
void common_build_program(
|
|
Common *common,
|
|
const char *options,
|
|
cl_program *program
|
|
) {
|
|
char *err;
|
|
cl_int ret;
|
|
size_t err_len;
|
|
ret = clBuildProgram(*program, 1, &(common->device), options, NULL, NULL);
|
|
if (CL_SUCCESS != ret) {
|
|
clGetProgramBuildInfo(*program, common->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &err_len);
|
|
err = (char *)malloc(err_len);
|
|
clGetProgramBuildInfo(*program, common->device, CL_PROGRAM_BUILD_LOG, err_len, err, NULL);
|
|
fprintf(stderr, "error: clBuildProgram:\n%s\n", err);
|
|
free(err);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
void common_create_program(
|
|
Common *common,
|
|
const char *source,
|
|
const char *options,
|
|
cl_program *program
|
|
) {
|
|
*program = clCreateProgramWithSource(common->context, 1, &source, NULL, NULL);
|
|
common_build_program(common, options, program);
|
|
}
|
|
|
|
void common_create_kernel(
|
|
Common *common,
|
|
const char *source,
|
|
const char *options
|
|
) {
|
|
if (NULL != source) {
|
|
common_create_program(common, source, options, &common->program);
|
|
common->kernel = clCreateKernel(common->program, "kmain", NULL);
|
|
assert(NULL != common->kernel);
|
|
} else {
|
|
common->kernel = NULL;
|
|
common->program = NULL;
|
|
}
|
|
}
|
|
|
|
void common_create_kernel_file(
|
|
Common *common,
|
|
const char *source_path,
|
|
const char *options
|
|
) {
|
|
char *source;
|
|
source = common_read_file_null(source_path);
|
|
common_create_kernel(common, source, options);
|
|
free(source);
|
|
}
|
|
|
|
/*
|
|
* @param[in] source: if NULL, kernel and program are left to NULL on common
|
|
**/
|
|
void common_init_options(
|
|
Common *common,
|
|
const char *source,
|
|
const char *options
|
|
) {
|
|
cl_platform_id platform;
|
|
|
|
clGetPlatformIDs(1, &platform, NULL);
|
|
clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 1, &(common->device), NULL);
|
|
common->context = clCreateContext(NULL, 1, &(common->device), NULL, NULL, NULL);
|
|
common->command_queue = clCreateCommandQueue(common->context, common->device, 0, NULL);
|
|
common_create_kernel(common, source, options);
|
|
}
|
|
|
|
void common_init(
|
|
Common *common,
|
|
const char *source
|
|
) {
|
|
common_init_options(common, source, "");
|
|
}
|
|
|
|
void common_init_file_options(
|
|
Common *common,
|
|
const char *source_path,
|
|
const char *options
|
|
) {
|
|
char *source;
|
|
source = common_read_file_null(source_path);
|
|
common_init_options(common, source, options);
|
|
free(source);
|
|
}
|
|
|
|
void common_init_file(
|
|
Common *common,
|
|
const char *source_path
|
|
) {
|
|
common_init_file_options(common, source_path, "");
|
|
}
|
|
|
|
void common_deinit_kernel_and_program(cl_kernel kernel, cl_program program) {
|
|
if (NULL != kernel) {
|
|
clReleaseKernel(kernel);
|
|
}
|
|
if (NULL != program) {
|
|
clReleaseProgram(program);
|
|
}
|
|
}
|
|
|
|
void common_deinit(
|
|
Common *common
|
|
) {
|
|
clReleaseCommandQueue(common->command_queue);
|
|
common_deinit_kernel_and_program(common->kernel, common->program);
|
|
clReleaseContext(common->context);
|
|
#ifdef CL_1_2
|
|
clReleaseDevice(common->device);
|
|
#endif
|
|
}
|
|
|
|
void common_create_kernel_or_use_cache(
|
|
Common *common,
|
|
int use_cache,
|
|
char *source_path,
|
|
char *bin_path
|
|
) {
|
|
FILE *f;
|
|
char *binary;
|
|
cl_int errcode_ret, binary_status;
|
|
cl_kernel kernel;
|
|
cl_program program;
|
|
long length;
|
|
size_t binary_size;
|
|
|
|
if (use_cache) {
|
|
common_init(common, NULL);
|
|
binary = common_read_file(bin_path, &length);
|
|
binary_size = length;
|
|
} else {
|
|
common_init_file(common, source_path);
|
|
clGetProgramInfo(common->program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binary_size, NULL);
|
|
binary = (char *)malloc(binary_size);
|
|
clGetProgramInfo(common->program, CL_PROGRAM_BINARIES, binary_size, &binary, NULL);
|
|
f = fopen(bin_path, "w");
|
|
fwrite(binary, binary_size, 1, f);
|
|
fclose(f);
|
|
}
|
|
program = clCreateProgramWithBinary(
|
|
common->context, 1, &common->device, &binary_size,
|
|
(const unsigned char **)&binary, &binary_status, &errcode_ret
|
|
);
|
|
assert(NULL != program);
|
|
common_assert_success(binary_status);
|
|
common_assert_success(errcode_ret);
|
|
free(binary);
|
|
common_build_program(common, NULL, &program);
|
|
kernel = clCreateKernel(program, "kmain", &errcode_ret);
|
|
assert(NULL != kernel);
|
|
common_assert_success(errcode_ret);
|
|
/* Cleanup kernel and program if they were created from source. */
|
|
common_deinit_kernel_and_program(common->kernel, common->program);
|
|
common->kernel = kernel;
|
|
common->program = program;
|
|
}
|
|
|
|
double common_get_nanos(void) {
|
|
struct timespec ts;
|
|
timespec_get(&ts, TIME_UTC);
|
|
return ts.tv_sec + ts.tv_nsec / 1000000000.0;
|
|
}
|
|
|
|
void common_vec_print_i(int *vec, size_t n) {
|
|
size_t i;
|
|
for (i = 0; i < n; ++i) {
|
|
printf("%d\n", vec[i]);
|
|
}
|
|
}
|
|
|
|
void common_vec_assert_eq_i(int *vec1, int *vec2, size_t n) {
|
|
if (memcmp(vec1, vec2, n * sizeof(*vec1)) != 0) {
|
|
common_vec_print_i(vec1, n);
|
|
puts("");
|
|
common_vec_print_i(vec2, n);
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
#endif
|