kernel的ti.template() 参数导致帧率下降

如下的代码中,在kernel中建立了一个100^3的点,并投影回相机平面。

render_proj(param)这个kernel接受一个完全没用到的ti.template()参数。
当这个param是一个field时,帧率在显示器上限165 FPS。
当这个param是field[0]时,帧率降到10FPS。

请问为什么会这样…
ti.template() 如果不能接受 filed[n] ,是不是应该有一些提示…
如果能接受,为什么速度差别这么大。。

import taichi as ti

@ti.func
def vec3_x_mat4(vec: ti.template(), mat: ti.template()):
    rst0 = mat[0,0] * vec[0] + mat[0,1] * vec[1] + mat[0,2] * vec[2] + mat[0,3]
    rst1 = mat[1,0] * vec[0] + mat[1,1] * vec[1] + mat[1,2] * vec[2] + mat[1,3]
    rst2 = mat[2,0] * vec[0] + mat[2,1] * vec[1] + mat[2,2] * vec[2] + mat[2,3]
    rst3 = mat[3,0] * vec[0] + mat[3,1] * vec[1] + mat[3,2] * vec[2] + mat[3,3]
    return ti.Vector([rst0, rst1, rst2, rst3])

@ti.func
def vec4_x_mat4(vec: ti.template(), mat: ti.template()):
    rst0 = mat[0,0] * vec[0] + mat[0,1] * vec[1] + mat[0,2] * vec[2] + mat[0,3] * vec[3]
    rst1 = mat[1,0] * vec[0] + mat[1,1] * vec[1] + mat[1,2] * vec[2] + mat[1,3] * vec[3]
    rst2 = mat[2,0] * vec[0] + mat[2,1] * vec[1] + mat[2,2] * vec[2] + mat[2,3] * vec[3]
    rst3 = mat[3,0] * vec[0] + mat[3,1] * vec[1] + mat[3,2] * vec[2] + mat[3,3] * vec[3]
    return ti.Vector([rst0, rst1, rst2, rst3])

@ti.data_oriented
class Viewer:
    def __init__(self) -> None:
        self.window = ti.ui.Window("Viewer", (1080, 720))
        self.gui = self.window.get_gui()
        self.canvas = self.window.get_canvas()
        # camera settings
        self.camera = ti.ui.Camera() # by default, look at (0, 0, 1)
        self.camera.position(1000, 1000, 1000)
        self.camera.lookat(50, 50, 50)
        self._img = ti.Vector.field(3, ti.f32, (1080, 720))
        self._mat_view = ti.Matrix.field(4,4, ti.f32, shape=())
        self._mat_proj = ti.Matrix.field(4,4, ti.f32, shape=())

        ############## dummy param for test
        self.param = ti.Vector.field(3, ti.f64, 1000)
        ############## 
    
    def render_proj(self):
        self._mat_view.from_numpy(self.camera.get_view_matrix().T)
        self._mat_proj.from_numpy(self.camera.get_projection_matrix(1080/720))
        # self._render_k(self.param[0])           ###### 10 FPS
        self._render_k(self.param)              ###### 165 FPS

    def run(self):
        while self.window.running:
            # gui
            self.render_proj()
            self.canvas.set_image(self._img)
            self.window.show()

    @ti.kernel
    def _render_k(self,
            p1: ti.template(),
            ):
        for i,j,k in ti.ndrange(100, 100, 100):
            x_w = i
            y_w = j
            z_w = k
            # projection to self._img
            xyz_w = ti.Vector([x_w, y_w, z_w])
            xyzw_e = vec3_x_mat4(xyz_w, self._mat_view[None])
            xyzw_c = vec4_x_mat4(xyzw_e, self._mat_proj[None])
            # culling
            x_c = xyzw_c[0]
            y_c = xyzw_c[1]
            z_c = xyzw_c[2]
            w_c = xyzw_c[3]
            x_c /= w_c
            y_c /= w_c
            z_c /= w_c
            if x_c < -1 or x_c > 1 or y_c < -1 or y_c > 1 or z_c < -1 or z_c > 1:
                continue
            # project to camera plane
            row = y_c * 360 + 360
            col = x_c * 540 + 540
            rowi = ti.i32(row)
            coli = ti.i32(col)

            self._img[coli, rowi][0] = 1.0
            self._img[coli, rowi][1] = 1.0
            self._img[coli, rowi][2] = 1.0

ti.init(ti.cuda)
viewer = Viewer()
viewer.run()

另外想问一下关于ti.ui.camera.get_view_matrix()函数
doc 说是row-major,但实际格式如下,我理解这个实际是row-major的 M^T_{view} ? 感觉文档不是很清楚…

R R R 0
R R R 0
R R R 0
X Y Z 1

抱歉回复的有点晚,我试了一下是因为ti.template()在这里没有完全地确定元素的类型。一般最好不要这样用template,直接传ndarray或者field,然后把offset也传进去再访问比较好

好的,谢谢。
还是希望这里能有一些warning之类的提示,或者直接报错。
花了很久才找到原来是这里使用方法的差别造成到的性能差别…

请问这里说的直接传field是怎样操作的?

直接从在定义成python global variable,在kernel中直接用,比如:

x = ti.field(...)

@ti.kernel
def test():
  x[0] = 100

类似这样