英文:
opencl - using image multiple times
问题
所以,我想制作一个应用程序,显示一些图像,并且当窗口调整大小时,将所有图像按比例缩放以适应屏幕。
我的策略如下:
- 对于每个原始图像,调用
clCreateImage
并将cl_mem
指针存储在全局映射中(类似于:文件名->cl_mem
)。 - 调用
scale(cl_mem img, int width, int height)
,该函数调用一个内核并读取输出图像数据。然后显示缩放后的图像。 - 当窗口调整大小事件发生时:删除所有缩放后的图像,并再次调用
scale(...)
,使用映射中存储的cl_mem
指针。
我在小规模上尝试了一下,只创建了一个图像,并调用了两次scale
。第一次是正常的,并且进行了缩放,但第二次却损坏了。我不知道为什么,源图像是CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR
,输出图像是在scale
函数中创建的。
原始图像:https://ibb.co/pQDwScW
第一次缩放(适应300x300):https://ibb.co/nnN9kTY
第二次尝试(适应500x500):https://ibb.co/561SkSn
但是,即使我只尝试300x300,然后再尝试300x300,它也会损坏。
是否有一个规则,即图像不能在内核中多次使用?还是我漏掉了什么?
编辑:
C代码在这里:https://pastebin.com/NpSaxRyT
它是从使用cgo的golang中使用的,因此createImage
将cl_mem
作为void*
返回,以便Go部分不需要包含cl.h
。
init()
函数在Go程序启动时调用。createImage
函数从Go中使用像素数据调用。
因此,图像指针(cl_mem
指针)在Go中,然后调用resize
(scale
)函数。它接受void*
指针和缓冲区指针,用于传输像素数据。
缓冲区也是由Go分配的,但是对于第一个图像,它是正常的,我认为垃圾回收没有启动(还尝试禁用了整个垃圾回收)。
示例代码如下:
outData := make([]byte, outWidth*outHeight*ir.pixelSize)
ret := C.resize(
cl_mem_img_pointer, //unsafe.Pointer (void*)
C.int(origWidth),
C.int(origHeight),
C.int(outWidth),
C.int(outHeight),
C.int(rowPitch),
C.uint(image_channel_order),
C.uint(image_channel_data_type),
unsafe.Pointer(&outData[0]),
)
英文:
So I want to make a app that shows some images and when the window resizes, it scales also all images to fit on the screen.
My strategy is this:
- call clCreateImage for every original image and store the
cl_mem
pointers in a global map (something like:filename -> cl_mem
) - call
scale(cl_mem img, int width, int height)
, that calls a kernel and reads the output image data. Then show the scaled images. - when the a window resize event occures: drop all scaled images and call
scale(...)
another time, with thecl_mem
pointers stored in the map
I tried it on a small scale where I just create one image, and call scale
two times. The first is OK and scaled, but the second is corrupted. I don't know why, the src image is CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR
, the out image is created in scale
function.
original: https://ibb.co/pQDwScW
first time scaled (to fit in 300x300): https://ibb.co/nnN9kTY
second try (to fit in 500x500): https://ibb.co/561SkSn
But also when I try just 300x300 and then also 300x300 it is corrupted.
Is there a rule, that images can't be used in a kernel multiple times? Or im just missing something?
EDIT:
C code is here: https://pastebin.com/NpSaxRyT
It is used from golang with cgo, so the createImage
returns the cl_mem
as void*
, so that the Go part doesn't need to include cl.h
.
init()
function is called on startup of the Go program. createImage
function is called from Go with pixel data.
So the image pointers (cl_mem
pointers) are in Go and then the resize
(scale
) function is called. It takes the void*
pointer and buffer pointer where the pixel data will be transfered.
Also the buffer is allocated by Go, but with the first image it is OK and I think that the GC doesn't kick in (also tried to disable GC entirely).
like so:
outData := make([]byte, outWidth*outHeight*ir.pixelSize)
ret := C.resize(
cl_mem_img_pointer, //unsafe.Pointer (void*)
C.int(origWidth),
C.int(origHeight),
C.int(outWidth),
C.int(outHeight),
C.int(rowPitch),
C.uint(image_channel_order),
C.uint(image_channel_data_type),
unsafe.Pointer(&outData[0]),
)
答案1
得分: 1
在第一次调整大小操作之后,你正在释放资源。
if err := ir.Release(); err != nil {
t.Fatal(err)
}
img2, err := ir.Resize(200, 200)
if err != nil {
t.Fatal(err)
}
200x200 的调整大小操作失败,因为它找不到已释放的 img 组件。
在退出程序之前,所有的 OpenCL 对象都是可重用的。在退出之前,只需按照它们分配的相反顺序释放资源。
如果你在所有任务中只使用相同的内核,你可以只使用一个全局内核对象来处理所有的调整大小调用。只需要重新设置在调用之间发生变化的内核参数,例如输出图像的大小、图像缓冲本身等。
英文:
You are releasing right after the first resize operation
if err := ir.Release(); err != nil {
t.Fatal(err)
}
img2, err := ir.Resize(200, 200)
if err != nil {
t.Fatal(err)
}
and the 200x200 resize failes as it can not find the img component that was released.
All of OpenCL objects are re-usable until you exit the program. Before exiting, just don't forget to release the resources in the reverse-order they were allocated.
If you are using only same kernel for all tasks, you can use just one global kernel object to be used for all resize calls. It only needs re-setting kernel arguments which are changed between calls. For example, changing sizes of output image, image buffer itself, etc.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论