Compare commits

...

2 Commits

Author SHA1 Message Date
377582c833 make it compile with cmake. 2025-09-23 19:08:56 +02:00
59411ea4ce good import. 2025-09-08 13:20:35 +02:00
26 changed files with 56925 additions and 93 deletions

7
.gitignore vendored
View File

@ -3,3 +3,10 @@
/docs/2025
/CMakeCache.txt
*.zip
/build/
/.cache/
/.ccls-cache/
/Debug/
/refs/
*.clbin
/.julia/

View File

@ -1,8 +1,66 @@
cmake_minimum_required(VERSION 3.0)
cmake_policy(VERSION 3.0...3.18.4)
project(proj)
add_executable(app src/main.cpp)
find_package(OpenCLHeaders REQUIRED)
find_package(OpenCLICDLoader REQUIRED)
find_package(OpenCLHeadersCpp REQUIRED)
target_link_libraries(app PRIVATE OpenCL::Headers OpenCL::OpenCL OpenCL::HeadersCpp)
cmake_minimum_required(VERSION 3.15...4.0)
project(
simulator
VERSION 0.0.1
DESCRIPTION "Simulation of Ground Fertility, 1 tick every time it is ran."
LANGUAGES CXX)
# Only do these if this is the main project, and not if it is included through add_subdirectory
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
# Optionally set things like CMAKE_CXX_STANDARD, CMAKE_POSITION_INDEPENDENT_CODE here
# Let's ensure -std=c++xx instead of -std=g++xx
set(CMAKE_CXX_EXTENSIONS OFF)
# Let's nicely support folders in IDEs
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Testing only available if this is the main app
# Note this needs to be done in the main CMakeLists
# since it calls enable_testing, which must be in the
# main CMakeLists.
include(CTest)
# Docs only available if this is the main app
find_package(Doxygen)
if(Doxygen_FOUND)
add_subdirectory(docs)
else()
message(STATUS "Doxygen not found, not building docs")
endif()
endif()
# FetchContent added in CMake 3.11, downloads during the configure step
# FetchContent_MakeAvailable was added in CMake 3.14; simpler usage
include(FetchContent)
# Accumulator library
# This is header only, so could be replaced with git submodules or FetchContent
find_package(OpenCL REQUIRED)
link_directories(libs)
#kernel code compiled
add_subdirectory(kernels)
# The compiled library code is here
add_subdirectory(src)
# The executable code is here
add_subdirectory(simulation)
# Testing only available if this is the main app
# Emergency override MODERN_CMAKE_BUILD_TESTING provided as well
if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR MODERN_CMAKE_BUILD_TESTING)
AND BUILD_TESTING)
add_subdirectory(tests)
endif()
#add_library(duckdb SHARED "libs/libduckdb.so" "include/duckdb/duckdb.h")
#target_include_directories(base PUBLIC HEADER_LIST)
#add_executable(simulator src/main.cpp)
#target_link_libraries(simulator OpenCL::OpenCL duckdb)

View File

@ -12,7 +12,7 @@ GLSLS := $(shell find $(SHADER_DIR) -name '*.cl')
# Prepends BUILD_DIR and appends .o to every src file
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
SPIRVS := $(GLSLS:%.$(SHADER_EXT)=$(BUILD_DIR)/%.sphv)
spirvs := $(glsls:%.$(shader_ext)=$(build_dir)/%.sphv)
# String substitution (suffix version without %).
DEPS := $(OBJS:.o=.d)
@ -27,7 +27,7 @@ LIBS := OpenCL
LDFLAGS := $(addprefix -l,$(LIBS))
# The -MMD and -MP flags together generate Makefiles for us! we use c++ 26
CPPFLAGS := -Wall -Wextra $(INC_FLAGS) -MMD -MP -std=c++20
CPPFLAGS := -Wall -Wextra $(INC_FLAGS) -L/libs -MMD -MP -std=c++20
#set flags for kernel compiling
GPU_VENDOR := glxinfo | grep -E "OpenGL vendor | OpenGL renderer" | cut -d" " -f4
@ -42,7 +42,7 @@ else
CLFLAGS := --target=spirv32
endif
CXX := clang
CXX := clang -v
# The final build step.
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)

1
compile_commands.json Symbolic link
View File

@ -0,0 +1 @@
Debug/compile_commands.json

182
compile_test.cpp Normal file
View File

@ -0,0 +1,182 @@
// opencl_cache.cpp
#include <CL/opencl.hpp> // OpenCL C++ bindings
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <filesystem> // C++17
#include <stdexcept>
// -------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------
// Read a text file into a string
std::string read_file(const std::string &path)
{
std::ifstream f(path, std::ios::in | std::ios::binary);
if (!f) throw std::runtime_error("Cannot open file: " + path);
std::ostringstream ss;
ss << f.rdbuf();
return ss.str();
}
// Read a binary file into a std::vector<uint8_t>
std::vector<uint8_t> read_binary(const std::string &path)
{
std::ifstream f(path, std::ios::binary);
if (!f) throw std::runtime_error("Cannot open binary file: " + path);
return std::vector<uint8_t>(std::istreambuf_iterator<char>(f),
std::istreambuf_iterator<char>());
}
// Write a binary buffer to file
void write_binary(const std::string &path, const std::vector<uint8_t> &data)
{
std::ofstream f(path, std::ios::binary);
if (!f) throw std::runtime_error("Cannot write binary file: " + path);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
}
// Create a unique key for the device (vendor + name + global mem size)
std::string device_key(const cl::Device &dev)
{
std::ostringstream ss;
ss << dev.getInfo<CL_DEVICE_VENDOR>()
<< "-" << dev.getInfo<CL_DEVICE_NAME>()
<< "-" << dev.getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>();
return ss.str();
}
// -------------------------------------------------------------------
// Main
// -------------------------------------------------------------------
int main()
{
try
{
// 1) Pick the first GPU device on the first platform
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
throw std::runtime_error("No OpenCL platforms found");
cl::Platform platform = platforms[0];
std::vector<cl::Device> devices;
platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
if (devices.empty())
throw std::runtime_error("No GPU devices on the platform");
cl::Device device = devices[0];
std::cout << "Using platform: "
<< platform.getInfo<CL_PLATFORM_NAME>() << '\n';
std::cout << "Using device : "
<< device.getInfo<CL_DEVICE_NAME>() << '\n';
// 2) Context & cache file name
cl::Context ctx(device);
std::string bin_file = device_key(device) + ".bin";
std::filesystem::path bin_path = std::filesystem::current_path() / bin_file;
cl::Program program;
// 3) If we already have a binary, load it
if (std::filesystem::exists(bin_path))
{
std::cout << "Loading binary from " << bin_path << '\n';
std::vector<uint8_t> bin = read_binary(bin_path.string());
// OpenCL expects an array of *unsigned char* pointers, one per
// device. We are using only one device here.
std::vector<const unsigned char*> binaries(1, bin.data());
std::vector<size_t> lengths(1, bin.size());
std::vector<cl::Program> progs(1);
cl_int err = ctx.createProgramWithBinary(devices,
lengths,
binaries.data(),
nullptr,
&progs[0]);
if (err != CL_SUCCESS)
throw std::runtime_error("clCreateProgramWithBinary failed");
program = progs[0];
}
else
{
// 4) Compile from source, extract the binary, save it
std::cout << "Compiling source (first run)...\n";
std::string src = read_file("example.cl");
cl::Program::Sources srcs(1, { src.c_str(), src.length() + 1 });
program = cl::Program(ctx, srcs);
cl_int err = program.build(devices);
if (err != CL_SUCCESS)
{
std::string log = program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device);
throw std::runtime_error("Program build failed: " + log);
}
// Retrieve the binary
std::vector<unsigned char> bin;
std::vector<size_t> lengths;
program.getInfo(CL_PROGRAM_BINARY_SIZES, &lengths);
program.getInfo(CL_PROGRAM_BINARIES, &bin);
// Save it for next run
write_binary(bin_path.string(), std::vector<uint8_t>(bin.begin(), bin.end()));
std::cout << "Saved binary to " << bin_path << '\n';
}
// -------------------------------------------------------------------
// 5) Demo: add two float vectors
// -------------------------------------------------------------------
size_t N = 1024;
std::vector<float> a(N, 1.0f), b(N, 2.0f), c(N, 0.0f);
// Allocate device buffers
cl::Buffer bufA(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
sizeof(float) * N, a.data());
cl::Buffer bufB(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
sizeof(float) * N, b.data());
cl::Buffer bufC(ctx, CL_MEM_WRITE_ONLY,
sizeof(float) * N);
// Create kernel
cl::Kernel kernel(program, "add_vectors");
// Set arguments
kernel.setArg(0, bufA);
kernel.setArg(1, bufB);
kernel.setArg(2, bufC);
// Launch
cl::CommandQueue queue(ctx, device);
queue.enqueueNDRangeKernel(kernel, cl::NullRange,
cl::NDRange(N), cl::NullRange);
queue.finish();
// Read back
queue.enqueueReadBuffer(bufC, CL_TRUE, 0,
sizeof(float) * N, c.data());
// Verify a few elements
bool ok = true;
for (size_t i = 0; i < N; ++i)
{
if (c[i] != a[i] + b[i]) { ok = false; break; }
}
std::cout << "Demo " << (ok ? "succeeded" : "failed") << '\n';
}
catch (const std::exception &e)
{
std::cerr << "ERROR: " << e.what() << '\n';
return 1;
}
return 0;
}

5
docs/CMakeLists.txt Normal file
View File

@ -0,0 +1,5 @@
set(DOXYGEN_EXTRACT_ALL YES)
set(DOXYGEN_BUILTIN_STL_SUPPORT YES)
doxygen_add_docs(docs opencl_helper.hpp "${CMAKE_CURRENT_SOURCE_DIR}/mainpage.md"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/include")

4752
include/duckdb/duckdb.h Normal file

File diff suppressed because it is too large Load Diff

51649
include/duckdb/duckdb.hpp Normal file

File diff suppressed because it is too large Load Diff

11
include/opencl_helper.hpp Normal file
View File

@ -0,0 +1,11 @@
#ifndef OPENCL_HELPER_H_
#define OPENCL_HELPER_H_
#include <CL/opencl.hpp>
namespace OpenCL{
cl::Device select_devices();
}
#endif // OPENCL_HELPER_H_

11
include/simulation.hpp Normal file
View File

@ -0,0 +1,11 @@
#ifndef SIMULATION_H_
#define SIMULATION_H_
#include <CL/opencl.hpp>
// duckdb
#include "duckdb/duckdb.hpp"
void run_simulation(duckdb_connection dbcon, cl::Device cl_device, cl::Context cl_context);
#endif // SIMULATION_H_

View File

@ -1,38 +0,0 @@
using OpenCL, pocl_jll
function vadd(a, b, c)
gid = get_global_id(1)
@inbounds c[gid] = a[gid] + b[gid]
return
end
a = rand(Float32, 50_000)
b = rand(Float32, 50_000)
d_a = CLArray(a)
d_b = CLArray(b)
d_c = similar(d_a)
@opencl global_size=size(a) vadd(d_a, d_b, d_c)
c = Array(d_c)
@assert a + b c
using OpenCL, pocl_jll
function vadd(a, b, c)
gid = get_global_id(1)
@inbounds c[gid] = a[gid] + b[gid]
return
end
a = rand(Float32, 50_000)
b = rand(Float32, 50_000)
d_a = CLArray(a)
d_b = CLArray(b)
d_c = similar(d_a)
@opencl global_size=size(a) vadd(d_a, d_b, d_c)
c = Array(d_c)

39
kernels/CMakeLists.txt Normal file
View File

@ -0,0 +1,39 @@
find_package(Vulkan REQUIRED)
function(add_shaders TARGET_NAME)
set(SHADER_SOURCE_FILES ${ARGN}) # the rest of arguments to this function will be assigned as shader source files
# Validate that source files have been passed
list(LENGTH SHADER_SOURCE_FILES FILE_COUNT)
if(FILE_COUNT EQUAL 0)
message(FATAL_ERROR "Cannot create a shaders target without any source files")
endif()
set(SHADER_COMMANDS)
set(SHADER_PRODUCTS)
foreach(SHADER_SOURCE IN LISTS SHADER_SOURCE_FILES)
cmake_path(ABSOLUTE_PATH SHADER_SOURCE NORMALIZE)
cmake_path(GET SHADER_SOURCE FILENAME SHADER_NAME)
# Build command
list(APPEND SHADER_COMMAND COMMAND)
list(APPEND SHADER_COMMAND Vulkan::glslc)
list(APPEND SHADER_COMMAND "${SHADER_SOURCE}")
list(APPEND SHADER_COMMAND "-o")
list(APPEND SHADER_COMMAND "${CMAKE_CURRENT_BINARY_DIR}/${SHADER_NAME}.spv")
# Add product
list(APPEND SHADER_PRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/${SHADER_NAME}.spv")
endforeach()
add_custom_target(${TARGET_NAME} ALL
${SHADER_COMMAND}
COMMENT "Compiling Shaders [${TARGET_NAME}]"
SOURCES ${SHADER_SOURCE_FILES}
BYPRODUCTS ${SHADER_PRODUCTS}
)
endfunction()
add_shaders(kernels test.cl)

30
kernels/Makefile Normal file
View File

@ -0,0 +1,30 @@
##
# compile kernels
#
# @file
# @version 0.1
GLSL := $(shell find -name '*.cl')
SPHV := $(GLSL:.cl=.clbin)
#set flags for kernel compiling
GPU_VENDOR := glxinfo | grep -E "OpenGL vendor | OpenGL renderer" | cut -d" " -f4
ARCH := uname -m
ifeq ($(GPU_VENDOR),"AMD")
CLFLAGS := --target=amdgcn-amd-amdhsa -mcpu=gfx900
else ifeq ($(GPU_VENDOR),"NVIDIA")
CLFLAGS := --target=nvtpx64-unkown-unkown
else ifeq ($(ARCH), "x86_64")
CLFLAGS := --target=spirv64
else
CLFLAGS := --target=spirv32
endif
CXX := clang
$(SPHV): $(GLSL)
$(CXX) -cl-std=CL2.0 $(CLFLAGS) $< -o $@
# end

View File

@ -1 +1,3 @@
#version 460 core
kernel void k(){}

BIN
libs/libduckdb.so Executable file

Binary file not shown.

BIN
libs/libduckdb_static.a Normal file

Binary file not shown.

BIN
simulation.duckdb Normal file

Binary file not shown.

4
simulation/.ccls Normal file
View File

@ -0,0 +1,4 @@
%compile_commands.json
%c -std=c11
%cpp -std=c++17
-Iinc

View File

@ -0,0 +1,3 @@
add_executable(sim main.cpp)
target_compile_features(sim PRIVATE cxx_std_17)
target_link_libraries(sim PRIVATE inc duckdb OpenCL::OpenCL)

44
simulation/main.cpp Normal file
View File

@ -0,0 +1,44 @@
#include <print>
#include <iostream>
// opencl
#include <CL/opencl.hpp>
// duckdb
#include "duckdb/duckdb.hpp"
#include "opencl_helper.hpp"
#include "simulation.hpp"
#define DB_FILE "../simulation.duckdb"
#define KERNEL_DIR "../kernels/"
#define SQLCMD_DIR "../sqlcmd/"
int main(){
// open database
duckdb_database db;
duckdb_connection dbcon;
if (duckdb_open(DB_FILE, &db) == DuckDBError) {
std::cout << "DB file can not be found" << std::endl;
exit(1);
}
if (duckdb_connect(db, &dbcon) == DuckDBError) {
std::cout << ("DB NOT Connected") << std::endl;
exit(1);
}
std::cout << "DB Connected" << std::endl;
// Setup OpenCL
cl::Device cl_device = OpenCL::select_devices();
cl::Context cl_context ({cl_device});
run_simulation(dbcon, cl_device , cl_context);
duckdb_disconnect(&dbcon);
duckdb_close(&db);
return 0;
}

28
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,28 @@
# Note that headers are optional, and do not affect add_library, but they will not
# show up in IDEs unless they are listed in add_library.
file(GLOB HEADERS_LIST "include/*.hpp" "include/*.h")
file(GLOB SRC_LIST "src/*.cpp")
# Optionally glob, but only for CMake 3.12 or later:
# file(GLOB HEADER_LIST CONFIGURE_DEPENDS "${ModernCMakeExample_SOURCE_DIR}/include/modern/*.hpp")
# Make an automatic library - will be static or dynamic based on user setting
add_library(inc opencl_helper.cpp simulation.cpp ${HEADER_LIST})
# We need this directory, and users of our library will need it too
target_include_directories(inc PUBLIC ../include)
# This depends on (header only) boost
target_link_libraries(inc PRIVATE OpenCL::OpenCL)
# All users of this library will need at least C++11
target_compile_features(inc PUBLIC cxx_std_17)
# IDEs should put the headers in a nice place
source_group(
TREE "${PROJECT_SOURCE_DIR}/include"
PREFIX "Header Files"
FILES ${HEADER_LIST})

View File

@ -1,43 +0,0 @@
#include <iostream>
#include <vector>
// opencl
#include <CL/cl.hpp>
// raylib
// #include <raylib.h>
// sqllite
//#include <sqlite3.h>
//#include "include/layers.hpp"
int main(){
// import data
cl::Platform default_platform=select_platform();
std::cout << "Using platform: "<<default_platform.getInfo<CL_PLATFORM_NAME>()<<"\n";
return 0;
// setup raylib env
//while loop
// raylib thread (60fps)
// opencl sim (every 15 seconds) swap data every 15 seconds
}
cl::Platform select_platform (){
std::vector<cl::Platform> all_platforms;
cl::Platform::get(&all_platforms);
if(all_platforms.size() == 0)
{
std::cout << "No Platforms found. Check OpenCl installation!\n";
exit(1);
}
return all_platforms[0]
}

42
src/opencl_helper.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "opencl_helper.hpp"
#include <CL/cl.h>
#include <CL/cl_gl.h>
#include <ostream>
#include <vector>
#include <iostream>
#include <CL/opencl.hpp>
namespace OpenCL{
cl::Platform select_platform (){
std::vector<cl::Platform> all_platforms;
cl::Platform::get(&all_platforms);
if(all_platforms.size() == 0)
{
std::cout << " No platforms found. Check OpenCL installation!\n";
exit(1);
}
return all_platforms[0];
}
cl::Device select_device(cl::Platform platform){
std::vector<cl::Device> all_devices;
//first select GPU if it is there
platform.getDevices(CL_DEVICE_TYPE_GPU, &all_devices);
if(all_devices.size()!=0){
return all_devices[0];
}
platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices);
if(all_devices.size()!=0){
return all_devices[0];
}
std::cout << "No, Devices found!" << std::endl;
exit(1);
}
cl::Device select_devices(){
return select_device(select_platform());
}
}

23
src/simulation.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "simulation.hpp"
#include "plants.hpp"
void run_simulation(duckdb_connection dbcon, cl::Device cl_device, cl::Context cl_context){
//Data Preparation
//Apply Actions
//Top layer
//All layers
//Safe Data
return;
}

21
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,21 @@
# Testing library
FetchContent_Declare(
catch
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.13.6)
FetchContent_MakeAvailable(catch)
# Adds Catch2::Catch2
# Tests need to be added as executables first
add_executable(testlib tests.cpp)
# I'm using C++17 in the test
target_compile_features(testlib PRIVATE cxx_std_17)
# Should be linked to the main library, as well as the Catch2 testing library
target_link_libraries(testlib PRIVATE inc Catch2::Catch2)
# If you register a test, then ctest and make test will run it.
# You can also run examples and check the output, as well.
add_test(NAME testlibtest COMMAND testlib) # Command can be a target

View File

@ -1 +1,2 @@
#include "tests.h"
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>