parent
3444349242
commit
0df47e8325
3 changed files with 0 additions and 350 deletions
@ -1,111 +0,0 @@ |
|||||||
#include <assert.h> |
|
||||||
#include <stdio.h> |
|
||||||
#include <string.h> |
|
||||||
|
|
||||||
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS |
|
||||||
#ifdef __APPLE__ |
|
||||||
#include <OpenCL/cl.h> |
|
||||||
#else |
|
||||||
#include <CL/cl.h> |
|
||||||
#endif |
|
||||||
|
|
||||||
#include "selfdrive/common/clutil.h" |
|
||||||
#include "selfdrive/modeld/transforms/transform.h" |
|
||||||
|
|
||||||
typedef struct { |
|
||||||
int disable_model; |
|
||||||
Transform transform; |
|
||||||
|
|
||||||
int in_width; |
|
||||||
int in_height; |
|
||||||
int out_width; |
|
||||||
int out_height; |
|
||||||
|
|
||||||
cl_context context; |
|
||||||
cl_command_queue command_queue; |
|
||||||
cl_device_id device_id; |
|
||||||
|
|
||||||
size_t in_yuv_size; |
|
||||||
cl_mem in_yuv_cl; |
|
||||||
|
|
||||||
cl_mem out_y_cl, out_u_cl, out_v_cl; |
|
||||||
} VisionTest; |
|
||||||
|
|
||||||
void initialize_opencl(VisionTest* visiontest) { |
|
||||||
// init cl
|
|
||||||
cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_CPU); |
|
||||||
visiontest->context = CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, NULL, NULL, &err)); |
|
||||||
visiontest->device_id = device_id; |
|
||||||
} |
|
||||||
|
|
||||||
VisionTest* visiontest_create(int temporal_model, int disable_model, |
|
||||||
int input_width, int input_height, |
|
||||||
int model_input_width, int model_input_height) { |
|
||||||
VisionTest* const vt = calloc(1, sizeof(*vt)); |
|
||||||
assert(vt); |
|
||||||
|
|
||||||
vt->disable_model = disable_model; |
|
||||||
vt->in_width = input_width; |
|
||||||
vt->in_height = input_height; |
|
||||||
vt->out_width = model_input_width; |
|
||||||
vt->out_height = model_input_height; |
|
||||||
|
|
||||||
initialize_opencl(vt); |
|
||||||
|
|
||||||
transform_init(&vt->transform, vt->context, vt->device_id); |
|
||||||
|
|
||||||
|
|
||||||
assert((vt->in_width%2) == 0 && (vt->in_height%2) == 0); |
|
||||||
vt->in_yuv_size = vt->in_width*vt->in_height*3/2; |
|
||||||
vt->in_yuv_cl = CL_CHECK_ERR(clCreateBuffer(vt->context, CL_MEM_READ_WRITE, |
|
||||||
vt->in_yuv_size, NULL, &err)); |
|
||||||
vt->out_y_cl = CL_CHECK_ERR(clCreateBuffer(vt->context, CL_MEM_READ_WRITE, |
|
||||||
vt->out_width*vt->out_width, NULL, &err)); |
|
||||||
vt->out_u_cl = CL_CHECK_ERR(clCreateBuffer(vt->context, CL_MEM_READ_WRITE, |
|
||||||
vt->out_width*vt->out_width/4, NULL, &err)); |
|
||||||
vt->out_v_cl = CL_CHECK_ERR(clCreateBuffer(vt->context, CL_MEM_READ_WRITE, |
|
||||||
vt->out_width*vt->out_width/4, NULL, &err)); |
|
||||||
vt->command_queue = CL_CHECK_ERR(clCreateCommandQueue(vt->context, vt->device_id, 0, &err)); |
|
||||||
return vt; |
|
||||||
} |
|
||||||
|
|
||||||
void visiontest_destroy(VisionTest* vt) { |
|
||||||
transform_destroy(&vt->transform); |
|
||||||
|
|
||||||
CL_CHECK(clReleaseMemObject(vt->in_yuv_cl)); |
|
||||||
CL_CHECK(clReleaseMemObject(vt->out_y_cl)); |
|
||||||
CL_CHECK(clReleaseMemObject(vt->out_u_cl)); |
|
||||||
CL_CHECK(clReleaseMemObject(vt->out_v_cl)); |
|
||||||
CL_CHECK(clReleaseCommandQueue(vt->command_queue)); |
|
||||||
CL_CHECK(clReleaseContext(vt->context)); |
|
||||||
|
|
||||||
free(vt); |
|
||||||
} |
|
||||||
|
|
||||||
void visiontest_transform(VisionTest* vt, const uint8_t* yuv_data, |
|
||||||
uint8_t* out_y, uint8_t* out_u, uint8_t* out_v, |
|
||||||
const float* transform) { |
|
||||||
CL_CHECK(clEnqueueWriteBuffer(vt->command_queue, vt->in_yuv_cl, CL_FALSE, |
|
||||||
0, vt->in_yuv_size, yuv_data, 0, NULL, NULL)); |
|
||||||
|
|
||||||
mat3 transform_m = *(const mat3*)transform; |
|
||||||
|
|
||||||
transform_queue(&vt->transform, vt->command_queue, |
|
||||||
vt->in_yuv_cl, vt->in_width, vt->in_height, |
|
||||||
vt->out_y_cl, vt->out_u_cl, vt->out_v_cl, |
|
||||||
vt->out_width, vt->out_height, |
|
||||||
transform_m); |
|
||||||
|
|
||||||
CL_CHECK(clEnqueueReadBuffer(vt->command_queue, vt->out_y_cl, CL_FALSE, |
|
||||||
0, vt->out_width*vt->out_height, out_y, |
|
||||||
0, NULL, NULL)); |
|
||||||
CL_CHECK(clEnqueueReadBuffer(vt->command_queue, vt->out_u_cl, CL_FALSE, |
|
||||||
0, vt->out_width*vt->out_height/4, out_u, |
|
||||||
0, NULL, NULL)); |
|
||||||
CL_CHECK(clEnqueueReadBuffer(vt->command_queue, vt->out_v_cl, CL_FALSE, |
|
||||||
0, vt->out_width*vt->out_height/4, out_v, |
|
||||||
0, NULL, NULL)); |
|
||||||
|
|
||||||
clFinish(vt->command_queue); |
|
||||||
} |
|
||||||
|
|
@ -1,104 +0,0 @@ |
|||||||
CC:=clang
|
|
||||||
CXX:=clang++
|
|
||||||
OPT_FLAGS:=-O2 -g -ggdb3
|
|
||||||
|
|
||||||
UNAME_S := $(shell uname -s)
|
|
||||||
ifeq ($(UNAME_S),Linux) |
|
||||||
SHARED_FLAGS=-Wl,--whole-archive $^ -Wl,--no-whole-archive
|
|
||||||
endif |
|
||||||
ifeq ($(UNAME_S),Darwin) |
|
||||||
SHARED_FLAGS=-Wl,-force_load $^
|
|
||||||
endif |
|
||||||
|
|
||||||
PHONELIBS := ../../third_party
|
|
||||||
BASEDIR := ../..
|
|
||||||
|
|
||||||
WARN_FLAGS = -Werror=implicit-function-declaration \
|
|
||||||
-Werror=incompatible-pointer-types \
|
|
||||||
-Werror=int-conversion \
|
|
||||||
-Werror=return-type \
|
|
||||||
-Werror=format-extra-args
|
|
||||||
|
|
||||||
CFLAGS = -std=gnu11 -g -fPIC $(OPT_FLAGS) $(WARN_FLAGS)
|
|
||||||
CXXFLAGS = -std=c++1z -fPIC $(OPT_FLAGS) $(WARN_FLAGS)
|
|
||||||
|
|
||||||
EIGEN_FLAGS = -I$(PHONELIBS)/eigen
|
|
||||||
|
|
||||||
CEREAL_LIBS = $(BASEDIR)/cereal/libmessaging.a
|
|
||||||
|
|
||||||
OPENCV_LIBS = -lopencv_video -lopencv_core -lopencv_imgproc
|
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin) |
|
||||||
VT_LDFLAGS += $(PHONELIBS)/capnp-c/mac/lib/libcapnp_c.a \
|
|
||||||
$(PHONELIBS)/zmq/mac/lib/libzmq.a \
|
|
||||||
-framework OpenCL
|
|
||||||
|
|
||||||
OPENCV_LIBS += -L/usr/local/opt/opencv@2/lib
|
|
||||||
OPENCV_FLAGS += -I/usr/local/opt/opencv@2/include
|
|
||||||
|
|
||||||
else |
|
||||||
VT_LDFLAGS += $(CEREAL_LIBS) \
|
|
||||||
-L/system/vendor/lib64 \
|
|
||||||
-L$(BASEDIR)/external/zmq/lib/ \
|
|
||||||
-l:libzmq.a \
|
|
||||||
-lOpenCL
|
|
||||||
endif |
|
||||||
|
|
||||||
.PHONY: all visiontest clean test |
|
||||||
all: visiontest |
|
||||||
|
|
||||||
libvisiontest_inputs := visiontest.c \
|
|
||||||
transforms/transform.cc \
|
|
||||||
transforms/loadyuv.cc \
|
|
||||||
../common/clutil.cc \
|
|
||||||
$(BASEDIR)/selfdrive/common/util.c \
|
|
||||||
$(CEREAL_OBJS)
|
|
||||||
|
|
||||||
visiontest: libvisiontest.so |
|
||||||
all-tests := $(addsuffix .test, $(basename $(wildcard test_*)))
|
|
||||||
|
|
||||||
%.o: %.cc |
|
||||||
@echo "[ CXX ] $@"
|
|
||||||
$(CXX) $(CXXFLAGS) -MMD \
|
|
||||||
-I. -I.. -I../.. \
|
|
||||||
-Wall \
|
|
||||||
-I$(BASEDIR)/ -I$(BASEDIR)/selfdrive -I$(BASEDIR)/selfdrive/common \
|
|
||||||
$(EIGEN_FLAGS) \
|
|
||||||
$(OPENCV_FLAGS) \
|
|
||||||
$(CEREAL_CXXFLAGS) \
|
|
||||||
-c -o '$@' '$<'
|
|
||||||
|
|
||||||
%.o: %.c |
|
||||||
@echo "[ CXX ] $@"
|
|
||||||
$(CC) $(CFLAGS) -MMD \
|
|
||||||
-I. -I.. -I../.. \
|
|
||||||
-Wall \
|
|
||||||
-I$(BASEDIR)/ -I$(BASEDIR)/selfdrive -I$(BASEDIR)/selfdrive/common \
|
|
||||||
$(CEREAL_CFLAGS) \
|
|
||||||
-c -o '$@' '$<'
|
|
||||||
|
|
||||||
libvisiontest.so: $(libvisiontest_inputs) |
|
||||||
$(eval $@_TMP := $(shell mktemp))
|
|
||||||
$(CC) -std=gnu11 -shared -fPIC -O2 -g \
|
|
||||||
-Werror=implicit-function-declaration -Werror=incompatible-pointer-types \
|
|
||||||
-Werror=int-conversion -Wno-pointer-to-int-cast \
|
|
||||||
-I. \
|
|
||||||
$^ -o $($@_TMP) \
|
|
||||||
-I$(PHONELIBS)/opencl/include \
|
|
||||||
-I$(BASEDIR)/selfdrive/common \
|
|
||||||
$(CEREAL_CXXFLAGS) \
|
|
||||||
$(CEREAL_CFLAGS) \
|
|
||||||
-I$(BASEDIR)/external/zmq/include \
|
|
||||||
-I$(BASEDIR)/ -I$(BASEDIR)/selfdrive \
|
|
||||||
-lstdc++ \
|
|
||||||
$(VT_LDFLAGS) \
|
|
||||||
-lm -lpthread
|
|
||||||
mv $($@_TMP) $@
|
|
||||||
|
|
||||||
test : $(all-tests) |
|
||||||
|
|
||||||
test_%.test : test_% |
|
||||||
@./'$<' || echo FAIL
|
|
||||||
|
|
||||||
clean: |
|
||||||
rm -rf *.o *.so *.a
|
|
@ -1,135 +0,0 @@ |
|||||||
import os |
|
||||||
import subprocess |
|
||||||
from cffi import FFI |
|
||||||
from common.basedir import BASEDIR |
|
||||||
|
|
||||||
# Initialize visiontest. Ignore output. |
|
||||||
_visiond_dir = os.path.dirname(os.path.abspath(__file__)) |
|
||||||
_libvisiontest = "libvisiontest.so" |
|
||||||
try: # because this crashes sometimes when running pipeline |
|
||||||
subprocess.check_output(["make", "-C", _visiond_dir, "-f", |
|
||||||
os.path.join(_visiond_dir, "visiontest.mk"), |
|
||||||
_libvisiontest]) |
|
||||||
except Exception: |
|
||||||
pass |
|
||||||
|
|
||||||
|
|
||||||
class VisionTest(): |
|
||||||
"""A version of the vision model that can be run on a desktop. |
|
||||||
|
|
||||||
WARNING: This class is not thread safe. VisionTest objects cannot be |
|
||||||
created or used on multiple threads simultaneously. |
|
||||||
""" |
|
||||||
|
|
||||||
ffi = FFI() |
|
||||||
ffi.cdef(""" |
|
||||||
typedef unsigned char uint8_t; |
|
||||||
|
|
||||||
struct VisionTest; |
|
||||||
typedef struct VisionTest VisionTest; |
|
||||||
|
|
||||||
VisionTest* visiontest_create(int temporal_model, int disable_model, |
|
||||||
int input_width, int input_height, |
|
||||||
int model_input_width, int model_input_height); |
|
||||||
void visiontest_destroy(VisionTest* visiontest); |
|
||||||
|
|
||||||
void visiontest_transform(VisionTest* vt, const uint8_t* yuv_data, |
|
||||||
uint8_t* out_y, uint8_t* out_u, uint8_t* out_v, |
|
||||||
const float* transform); |
|
||||||
""") |
|
||||||
|
|
||||||
clib = ffi.dlopen(os.path.join(_visiond_dir, _libvisiontest)) |
|
||||||
|
|
||||||
def __init__(self, input_size, model_input_size, model): |
|
||||||
"""Create a wrapper around visiond for off-device python code. |
|
||||||
|
|
||||||
Inputs: |
|
||||||
input_size: The size of YUV images passed to transform. |
|
||||||
model_input_size: The size of YUV images passed to the model. |
|
||||||
model: The name of the model to use. "temporal", "yuv", or None to disable the |
|
||||||
model (used to disable OpenCL). |
|
||||||
""" |
|
||||||
self._input_size = input_size |
|
||||||
self._model_input_size = model_input_size |
|
||||||
|
|
||||||
if model is None: |
|
||||||
disable_model = 1 |
|
||||||
temporal_model = 0 |
|
||||||
elif model == "yuv": |
|
||||||
disable_model = 0 |
|
||||||
temporal_model = 0 |
|
||||||
elif model == "temporal": |
|
||||||
disable_model = 0 |
|
||||||
temporal_model = 1 |
|
||||||
else: |
|
||||||
raise ValueError(f"Bad model name: {model}") |
|
||||||
|
|
||||||
prevdir = os.getcwd() |
|
||||||
os.chdir(_visiond_dir) # tmp hack to find kernels |
|
||||||
os.environ['BASEDIR'] = BASEDIR |
|
||||||
self._visiontest_c = self.clib.visiontest_create( |
|
||||||
temporal_model, disable_model, self._input_size[0], self._input_size[1], |
|
||||||
self._model_input_size[0], self._model_input_size[1]) |
|
||||||
os.chdir(prevdir) |
|
||||||
|
|
||||||
@property |
|
||||||
def input_size(self): |
|
||||||
return self._input_size |
|
||||||
|
|
||||||
@property |
|
||||||
def model_input_size(self): |
|
||||||
return self._model_input_size |
|
||||||
|
|
||||||
def transform(self, yuv_data, transform): |
|
||||||
y_len = self.model_input_size[0] * self.model_input_size[1] |
|
||||||
t_y_ptr = bytearray(y_len) |
|
||||||
t_u_ptr = bytearray(y_len // 4) |
|
||||||
t_v_ptr = bytearray(y_len // 4) |
|
||||||
|
|
||||||
self.transform_output_buffer(yuv_data, t_y_ptr, t_u_ptr, t_v_ptr, |
|
||||||
transform) |
|
||||||
|
|
||||||
return t_y_ptr, t_u_ptr, t_v_ptr |
|
||||||
|
|
||||||
def transform_contiguous(self, yuv_data, transform): |
|
||||||
y_ol = self.model_input_size[0] * self.model_input_size[1] |
|
||||||
uv_ol = y_ol // 4 |
|
||||||
result = bytearray(y_ol * 3 // 2) |
|
||||||
result_view = memoryview(result) |
|
||||||
t_y_ptr = result_view[:y_ol] |
|
||||||
t_u_ptr = result_view[y_ol:y_ol + uv_ol] |
|
||||||
t_v_ptr = result_view[y_ol + uv_ol:] |
|
||||||
|
|
||||||
self.transform_output_buffer(yuv_data, t_y_ptr, t_u_ptr, t_v_ptr, |
|
||||||
transform) |
|
||||||
return result |
|
||||||
|
|
||||||
def transform_output_buffer(self, yuv_data, y_out, u_out, v_out, |
|
||||||
transform): |
|
||||||
assert len(yuv_data) == self.input_size[0] * self.input_size[1] * 3 / 2 |
|
||||||
|
|
||||||
cast = self.ffi.cast |
|
||||||
from_buffer = self.ffi.from_buffer |
|
||||||
yuv_ptr = cast("unsigned char*", from_buffer(yuv_data)) |
|
||||||
transform_ptr = self.ffi.new("float[]", transform) |
|
||||||
|
|
||||||
y_out_ptr = cast("unsigned char*", from_buffer(y_out)) |
|
||||||
u_out_ptr = cast("unsigned char*", from_buffer(u_out)) |
|
||||||
v_out_ptr = cast("unsigned char*", from_buffer(v_out)) |
|
||||||
|
|
||||||
self.clib.visiontest_transform(self._visiontest_c, yuv_ptr, y_out_ptr, |
|
||||||
u_out_ptr, v_out_ptr, transform_ptr) |
|
||||||
|
|
||||||
def close(self): |
|
||||||
self.clib.visiontest_destroy(self._visiontest_c) |
|
||||||
self._visiontest_c = None |
|
||||||
|
|
||||||
def __enter__(self): |
|
||||||
return self |
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback): |
|
||||||
self.close() |
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__": |
|
||||||
VisionTest((560, 304), (320, 160), "temporal") |
|
Loading…
Reference in new issue