I have a python application. I need to render with panda3d inside a thread in this application. I do the rendering on the cpp side. I transfer the render data to the python side using ctypes. However, I am facing a problem. On the Python side, if I do these operations without opening a thread, it works smoothly. I get the render image I want, but when I run the same function in the thread, I get a segmentation error. How can I solve this problem?
I am rendering on a headless server. I built panda3d without x11 support with
“python3 makepanda/makepanda.py --everything --installer --threads 16 --no-x11”.
“sudo dpkg -i panda3d*.deb”
My python code:
from ctypes import cdll
import time
# import threading
# from direct.stdpy import threading
from direct.stdpy import threading2 as threading
import datetime
import numpy as np
import matplotlib.pyplot as plt
import ctypes
import cv2
def process_render():
camera_values = np.array([0.5555,-114.92007343418689, -8.148216295002753, 16.654022979044203, -179.98575181566176, -55.97798890611995, 0.006786534125852574],np.float32)
model_path = "model_path.egg"
encoded_model_path = model_path.encode('utf-8')
liblr = cdll.LoadLibrary('so_file_path/librender.so')
liblr.RenderFunc.restype = ctypes.c_void_p
liblr.Render.argtypes = [ctypes.c_void_p]
render = liblr.Render(encoded_model_path)
render_result = liblr.RenderFunc(render, camera_values.ctypes)
buffer_as_ctypes_array = ctypes.cast(render_result, ctypes.POINTER(ctypes.c_void_p*(1920*1080*4//8)))[0]
image_anim = np.frombuffer(buffer_as_ctypes_array, np.uint8).reshape(1080,1920,4)
image_anim = np.flipud(image_anim)
# cv2.imwrite("render_res_cpp.png",image_anim) ## I process the image later on. I don't need to save image to disk. debug purposes only.
if __name__ == "__main__":
process_render() # this works completely fine.
# t = threading.Thread(target=process_render, args=()) ## if i run this. I get segmentation fault.
# t.start()
My cpp code:
#include "displayRegion.h"
#include <chrono>
#include "texture.h"
#include "frameBufferProperties.h"
#include "graphicsOutput.h"
#include "graphicsEngine.h"
#include "graphicsPipe.h"
#include "graphicsPipeSelection.h"
#include "camera.h"
#include "windowProperties.h"
#include "nodePath.h"
#include "pandaNode.h"
#include "loader.h"
class cpp_Render{
public:
PT(GraphicsOutput) mybuffer;
PT(Texture) mytexture;
PT(Camera) mycamera;
PT(DisplayRegion) region;
NodePath mycameraNP;
FrameBufferProperties fb_prop;
PT(GraphicsPipe) pipe;
PT(GraphicsEngine) engine;
WindowProperties win_prop;
NodePath altRender = NodePath("render");
NodePath model;
PT(Loader) loader;
cpp_Render(char* model_path);
void* render_function(float* camera_values);
};
cpp_Render::cpp_Render(char * model_path){
engine = GraphicsEngine::get_global_ptr();
pipe = GraphicsPipeSelection::get_global_ptr()->make_module_pipe("pandagl");
loader = Loader::get_global_ptr();
fb_prop.set_rgb_color(true);
fb_prop.set_rgba_bits(8, 8, 8, 8);
win_prop.set_size(1920,1080);
mytexture = new Texture("texture");
mycamera = new Camera("new_camera");
mycameraNP = NodePath(mycamera) ;
mycameraNP.reparent_to(altRender);
mycamera->get_lens()->set_film_size( 1.0,0.5625);
mycamera->get_lens()->set_focal_length(0.5);
mycameraNP.set_pos(0, 0, 0);
mycameraNP.set_hpr(0, 0, 0);
int flags = pipe->BF_refuse_window;
mybuffer = engine->make_output(pipe, "buffer", -100, fb_prop, win_prop, flags);
mybuffer->set_clear_color_active(true);
mybuffer->set_clear_depth_active(true);
mybuffer->set_clear_depth(1.0);
mybuffer->set_clear_color(LColor(0,0,0,0));
mybuffer->add_render_texture(mytexture, GraphicsOutput::RTM_copy_ram);
model = NodePath(loader->load_sync(model_path));
model.flatten_light();
model.reparent_to(altRender);
region = mybuffer->make_display_region();
region->set_camera(mycameraNP);
mybuffer->get_engine()->render_frame();
mybuffer->get_engine()->render_frame();
};
void* cpp_Render::render_function(float * camera_values){
mycamera->get_lens()->set_focal_length(*camera_values);
mycameraNP.set_pos(*(camera_values+1),*(camera_values+2),*(camera_values+3));
mycameraNP.set_hpr(*(camera_values+4),*(camera_values+5),*(camera_values+6));
mybuffer->get_engine()->render_frame();
mytexture = mybuffer->get_texture();
CPTA_uchar data = mytexture->get_ram_image();
void* data_ptr = (void*)data.p();
return data_ptr;
};
extern "C" {
cpp_Render* Render(char * model_path){
return new cpp_Render(model_path);
}
void* RenderFunc(cpp_Render* Render, float* camera_values ){
return Render -> render_function(camera_values);
}
}
Cpp Compile Flags
g++ -std=c++11 -c -w -Wall -fpic render.cpp -I/home/ubuntu/cpp_panda/panda3d/built/include -I/usr/include/eigen3 -I/usr/include/bullet
g++ -std=c++11 -shared render.o -o librender.so -L/usr/lib/x86_64-linux-gnu -L/home/ubuntu/cpp_panda/panda3d/built/lib -lp3direct -lp3dtool -lp3dtoolconfig -lp3framework -lp3interrogatedb -lp3vision -lpanda -lpandaai -lpandabullet -lpandaegg -lpandaexpress -lpandafx -lpandafx -lpandaode -lpandaphysics -lpandaskel -lBullet3Common -lBulletDynamics -lBullet3Dynamics -lBullet3Geometry -lpthread -lLinearMath -Wl,–no-undefined