t113全志g2d应用,解析摄像头数据
// g2d 解析时用到的东西
注意不同版本的sdk对应的 g2d_driver.h 中的宏定义值可能不一样,注意区分,eg: T113S3 和T113S4的就不一样,文件位置位于 kernel/linux-5.4/include/linuxs/g2d_driver.h
my_ion_lib.h #ifndef __MY_ION_LIB_H__ #define __MY_ION_LIB_H__ #ifdef __cplusplus extern "C" { #endif struct ion_memory { unsigned int size; int fd; void* virt_addr; //虚拟地址 unsigned int phy_addr; //物理地址 }; // 注意使用前,请确认,有 /dev/ion 和 /dev/cedar_dev int my_ion_init(void); int my_ion_release(void); int my_ion_alloc(struct ion_memory* mem,unsigned int size); int my_ion_free(struct ion_memory* mem); int my_ion_flush(struct ion_memory* mem); #ifdef __cplusplus } //extern "C" #endif #endif //__MY_ION_LIB_H__ /* date -s 2023-06-13 date -s 9:33:30 hwclock -w */ /* # gcc head.h method_1.c method_2.c -fPIC -shared -o method.so # aarch64-linux-gnu-gcc -lstdc++ -fPIC -shared -o libai_dface.so ai_dface_check.cpp feature_memory_database.cpp movingaverage.cpp -I. -I./include -I/opt/EmbedSky/TQT507/CoreA/longan//platform/framework/auto/sdk_lib/include -I/opt/install/include cp ./libai_dface.so /opt/EmbedSky/TQT507/CoreA/longan/out/t507/evb/longan/buildroot/target/usr/lib/ */ my_ion_lib.c #include "my_ion_lib.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> #include <time.h> #include <sys/mman.h> #include <pthread.h> #include <asm-generic/ioctl.h> // package/allwinner/libuapi/src/ion_alloc_5.4.h #define __u64 unsigned long long #define __u32 unsigned long struct aw_ion_new_alloc_data { __u64 len; __u32 heap_id_mask; __u32 flags; __u32 fd; __u32 unused; }; #define SZ_64M 0x04000000 #define SZ_4M 0x00400000 #define SZ_1M 0x00100000 #define SZ_64K 0x00010000 #define SZ_4k 0x00001000 #define SZ_1k 0x00000400 enum ion_heap_type { AW_ION_SYSTEM_HEAP_TYPE, AW_ION_SYSTEM_CONTIG_HEAP_TYPE, AW_ION_CARVEOUT_HEAP_TYPE, AW_ION_TYPE_HEAP_CHUNK, AW_ION_TYPE_HEAP_DMA, AW_ION_TYPE_HEAP_CUSTOM, AW_ION_TYPE_HEAP_SECURE, AW_ION_NUM_HEAPS = 16, }; #define AW_MEM_ENGINE_REQ 0x206 #define AW_MEM_ENGINE_REL 0x207 #define AW_MEM_GET_IOMMU_ADDR 0x502 #define AW_MEM_FREE_IOMMU_ADDR 0x503 #define AW_ION_CACHED_FLAG 1 #define AW_ION_CACHED_NEEDS_SYNC_FLAG 2 #define ION_IOC_SUNXI_FLUSH_RANGE 5 #define ION_IOC_SUNXI_FLUSH_ALL 6 #define ION_IOC_SUNXI_PHYS_ADDR 7 #define ION_IOC_SUNXI_DMA_COPY 8 #define ION_IOC_SUNXI_TEE_ADDR 17 #define AW_ION_SYSTEM_HEAP_MASK (1 << AW_ION_SYSTEM_HEAP_TYPE) #define AW_ION_SYSTEM_CONTIG_HEAP_MASK (1 << AW_ION_SYSTEM_CONTIG_HEAP_TYPE) #define AW_ION_CARVEOUT_HEAP_MASK (1 << AW_ION_CARVEOUT_HEAP_TYPE) #define AW_ION_DMA_HEAP_MASK (1 << AW_ION_TYPE_HEAP_DMA) #define AW_ION_SECURE_HEAP_MASK (1 << AW_ION_TYPE_HEAP_SECURE) #define AW_MEM_ION_IOC_MAGIC 'I' #define AW_ION_IOC_NEW_ALLOC _IOWR(AW_MEM_ION_IOC_MAGIC, 0, struct aw_ion_new_alloc_data) // lichee/linux-5.4/drivers/media/cedar-ve/cedar_ve.h enum IOCTL_CMD { IOCTL_UNKOWN = 0x100, IOCTL_GET_ENV_INFO, IOCTL_WAIT_VE_DE, IOCTL_WAIT_VE_EN, IOCTL_RESET_VE, IOCTL_ENABLE_VE, IOCTL_DISABLE_VE, IOCTL_SET_VE_FREQ, IOCTL_CONFIG_AVS2 = 0x200, IOCTL_GETVALUE_AVS2, IOCTL_PAUSE_AVS2, IOCTL_START_AVS2, IOCTL_RESET_AVS2, IOCTL_ADJUST_AVS2, IOCTL_ENGINE_REQ, IOCTL_ENGINE_REL, IOCTL_ENGINE_CHECK_DELAY, IOCTL_GET_IC_VER, IOCTL_ADJUST_AVS2_ABS, IOCTL_FLUSH_CACHE, IOCTL_SET_REFCOUNT, IOCTL_FLUSH_CACHE_ALL, IOCTL_TEST_VERSION, IOCTL_GET_LOCK = 0x310, IOCTL_RELEASE_LOCK, IOCTL_SET_VOL = 0x400, IOCTL_WAIT_JPEG_DEC = 0x500, /*for get the ve ref_count for ipc to delete the semphore*/ IOCTL_GET_REFCOUNT, /*for iommu*/ IOCTL_GET_IOMMU_ADDR, IOCTL_FREE_IOMMU_ADDR, /* map/unmap dma buffer to get/free phyaddr by dma fd */ /* get/free iommu addr will not use since kernel 5.4 */ IOCTL_MAP_DMA_BUF, IOCTL_UNMAP_DMA_BUF, /*for fush cache range since kernel 5.4*/ IOCTL_FLUSH_CACHE_RANGE, /*for debug*/ IOCTL_SET_PROC_INFO, IOCTL_STOP_PROC_INFO, IOCTL_COPY_PROC_INFO, IOCTL_SET_DRAM_HIGH_CHANNAL = 0x600, /* debug for decoder and encoder*/ IOCTL_PROC_INFO_COPY = 0x610, IOCTL_PROC_INFO_STOP, IOCTL_POWER_SETUP = 0x700, IOCTL_POWER_SHUTDOWN, }; #define VE_LOCK_VDEC 0x01 #define VE_LOCK_VENC 0x02 #define VE_LOCK_JDEC 0x04 #define VE_LOCK_00_REG 0x08 #define VE_LOCK_04_REG 0x10 #define VE_LOCK_ERR 0x80 #define VE_LOCK_PROC_INFO 0x1000 // prebuilt/gcc/linux-x86/riscv/toolchain-thead-glibc/riscv64-glibc-gcc-thead_20200702/sysroot/usr/include/linux/dma-buf.h:41 struct dma_buf_sync { __u64 flags; }; #define DMA_BUF_SYNC_READ (1 << 0) #define DMA_BUF_SYNC_WRITE (2 << 0) #define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE) #define DMA_BUF_SYNC_START (0 << 2) #define DMA_BUF_SYNC_END (1 << 2) #define DMA_BUF_SYNC_VALID_FLAGS_MASK \ (DMA_BUF_SYNC_RW | DMA_BUF_SYNC_END) #define DMA_BUF_NAME_LEN 32 #define DMA_BUF_BASE 'b' #define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync) #define DMA_BUF_SET_NAME _IOW(DMA_BUF_BASE, 1, const char *) // package/allwinner/tina_multimedia/libcedarc/include/veInterface.h struct user_iommu_param { int fd; unsigned int iommu_addr; }; static int ion_fd = -1; static int cedar_fd = -1; int my_ion_init(void){ my_ion_release(); ion_fd = open("/dev/ion", O_RDWR); cedar_fd = open("/dev/cedar_dev", O_RDONLY); ioctl(cedar_fd, IOCTL_ENGINE_REQ, 0); return 0; } int my_ion_release(void){ if (cedar_fd != -1) { ioctl(cedar_fd, IOCTL_ENGINE_REL, 0); close(cedar_fd); cedar_fd = -1; } if (ion_fd != -1) { close(ion_fd); ion_fd = -1; } return 0; } int my_ion_alloc(struct ion_memory* mem,unsigned int size){ struct aw_ion_new_alloc_data alloc_data; alloc_data.len = size; alloc_data.heap_id_mask = AW_ION_SYSTEM_HEAP_MASK; alloc_data.flags = AW_ION_CACHED_FLAG | AW_ION_CACHED_NEEDS_SYNC_FLAG; alloc_data.fd = 0; alloc_data.unused = 0; ioctl(ion_fd, AW_ION_IOC_NEW_ALLOC, &alloc_data); void* virt_addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, alloc_data.fd, 0); struct user_iommu_param iommu_param; iommu_param.fd = alloc_data.fd; iommu_param.iommu_addr = 0; ioctl(cedar_fd, IOCTL_GET_IOMMU_ADDR, &iommu_param); mem->size = size; mem->fd = alloc_data.fd; mem->virt_addr = virt_addr; mem->phy_addr = iommu_param.iommu_addr; return 0; } int my_ion_free(struct ion_memory* mem){ if (mem->fd == -1) return 0; struct user_iommu_param iommu_param; iommu_param.fd = mem->fd; ioctl(cedar_fd, IOCTL_FREE_IOMMU_ADDR, &iommu_param); munmap(mem->virt_addr, mem->size); close(mem->fd); mem->size = 0; mem->fd = -1; mem->virt_addr = 0; mem->phy_addr = 0; return 0; } int my_ion_flush(struct ion_memory* mem){ struct dma_buf_sync sync; sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW; ioctl(mem->fd, DMA_BUF_IOCTL_SYNC, &sync); return 0; } /* // g2d 显示 // 步骤1 ion_allocator ion; ion.open(); struct ion_memory yuv_ion; ion.alloc(rgb_size, &rgb_ion); struct ion_memory rgb_ion; ion.alloc(yuv_size, &yuv_ion); int g2d_fd = ::open("/dev/g2d", O_RDWR); // 步骤2 memcpy((unsigned char*)yuv_ion.virt_addr, yuv420sp, yuv_size); ion.flush(&yuv_ion); // 步骤3 g2d_blt_h blit; memset(&blit, 0, sizeof(blit)); blit.flag_h = G2D_BLT_NONE_H; blit.src_image_h.format = G2D_FORMAT_YUV420UVC_V1U1V0U0; blit.src_image_h.width = width; blit.src_image_h.height = height; blit.src_image_h.align[0] = 0; blit.src_image_h.align[1] = 0; blit.src_image_h.clip_rect.x = 0; blit.src_image_h.clip_rect.y = 0; blit.src_image_h.clip_rect.w = width; blit.src_image_h.clip_rect.h = height; blit.src_image_h.gamut = G2D_BT601; blit.src_image_h.bpremul = 0; blit.src_image_h.mode = G2D_PIXEL_ALPHA; blit.src_image_h.use_phy_addr = 0; blit.src_image_h.fd = yuv_ion.fd; blit.dst_image_h.format = G2D_FORMAT_RGB888; blit.dst_image_h.width = width; blit.dst_image_h.height = height; blit.dst_image_h.align[0] = 0; blit.dst_image_h.clip_rect.x = 0; blit.dst_image_h.clip_rect.y = 0; blit.dst_image_h.clip_rect.w = width; blit.dst_image_h.clip_rect.h = height; blit.dst_image_h.gamut = G2D_BT601; blit.dst_image_h.bpremul = 0; blit.dst_image_h.mode = G2D_PIXEL_ALPHA; blit.dst_image_h.use_phy_addr = 0; blit.dst_image_h.fd = rgb_ion.fd; ioctl(g2d_fd, G2D_CMD_BITBLT_H, &blit); // 步骤4 ion.flush(&rgb_ion); memcpy(rgb, (const unsigned char*)rgb_ion.virt_addr, rgb_size); // 步骤5 ion.free(&rgb_ion); ion.free(&yuv_ion); ion.close(); ::close(g2d_fd); */ my_g2d_lib.h #ifndef __MY_G2D_LIB_H__ #define __MY_G2D_LIB_H__ #ifdef __cplusplus extern "C" { #endif #include "g2d_driver.h" #include "my_ion_lib.h" enum { MY_G2D_ROT_NONE = 0, MY_G2D_ROT_90 = 0x00000100, MY_G2D_ROT_180 = 0x00000200, MY_G2D_ROT_270 = 0x00000300, MY_G2D_ROT_H = 0x00001000, MY_G2D_ROT_V = 0x00002000, }; int my_g2d_init(void); int my_g2d_release(void); int my_g2d_type_transe(struct ion_memory* inbuf,unsigned int intype,int inw,int inh,struct ion_memory* outbuf,unsigned int outtype,int outw,int outh); int my_g2d_type_rotate(int rotate,struct ion_memory* inbuf,struct ion_memory* outbuf,unsigned int outtype,int outw,int outh); #ifdef __cplusplus } //extern "C" #endif #endif // __MY_G2D_LIB_H__ /* #include "my_g2d_lib.h" #include "my_ion_lib.h" struct ion_memory inbuf; struct ion_memory outbuf; #include <fcntl.h> // for open #include <stdio.h> #include <unistd.h> // for close #include <sys/ioctl.h> #include <linux/i2c-dev.h> #include <linux/i2c.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <pthread.h> int stopflag=0; void sigintHandler(int signum) { if(stopflag>0){return ;} stopflag=1; my_ion_free(&inbuf); my_ion_free(&outbuf); my_g2d_release(); my_ion_release(); usleep(1000*200);//等待退出 printf("waitfor normal exit!!!\n"); exit(0); } int main(int argc, char **argv){ // 注册SIGINT信号处理函数 signal(SIGINT, sigintHandler); signal(SIGSEGV, sigintHandler); // 初始化 my_g2d_init(); my_ion_init(); my_ion_alloc(&inbuf,CAM_WIDTH * CAM_HEIGHT * 4); my_ion_alloc(&outbuf,SCREEN_WIDTH * SCREEN_HEIGHT * 4); while(!stopflag){ // 获取数据 param,paramlen // 转化数据 if(CAM_FORMAT==V4L2_PIX_FMT_YUYV){ memcpy(inbuf.virt_addr,param,paramlen);// G2D_FORMAT_BGRA8888 my_g2d_type_transe(&inbuf,G2D_FORMAT_IYUV422_V0Y1U0Y0,video_width,video_height,&outbuf,G2D_FORMAT_ARGB8888,video_width,video_height); memcpy(yuv_buffer,outbuf.virt_addr,CAM_WIDTH * CAM_HEIGHT * 4); } else if(CAM_FORMAT==V4L2_PIX_FMT_NV21){ memcpy(inbuf.virt_addr,param,paramlen); my_g2d_type_transe(&inbuf,G2D_FORMAT_YUV420UVC_U1V1U0V0,video_width,video_height,&outbuf,G2D_FORMAT_ARGB8888,video_width,video_height); memcpy(yuv_buffer,outbuf.virt_addr,CAM_WIDTH * CAM_HEIGHT * 4); } // 显示数据 lcd_image(0, CAM_WIDTH, 0, CAM_HEIGHT, yuv_buffer); } // 资源回收 sigintHandler(0); } */ my_g2d_lib.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> #include <time.h> #include <sys/mman.h> #include <pthread.h> #include <asm-generic/ioctl.h> #include <sys/ioctl.h> #include "my_g2d_lib.h" #include "my_ion_lib.h" static int g2d_fd =0; int my_g2d_init(void){ g2d_fd = open("/dev/g2d", O_RDWR); return 0; } int my_g2d_release(void){ close(g2d_fd); return 0; } int my_g2d_type_transe(struct ion_memory* inbuf,unsigned int intype,int inw,int inh,struct ion_memory* outbuf,unsigned int outtype,int outw,int outh){ my_ion_flush(inbuf); // G2D_FORMAT_YUV420UVC_V1U1V0U0 G2D_FORMAT_BGRA8888 g2d_blt_h blit; memset(&blit, 0, sizeof(blit)); blit.flag_h = G2D_BLT_NONE_H; blit.src_image_h.format = intype; blit.src_image_h.width = inw; blit.src_image_h.height = inh; blit.src_image_h.align[0] = 0; blit.src_image_h.align[1] = 0; blit.src_image_h.clip_rect.x = 0; blit.src_image_h.clip_rect.y = 0; blit.src_image_h.clip_rect.w = outw; blit.src_image_h.clip_rect.h = outh; blit.src_image_h.gamut = G2D_BT601; blit.src_image_h.bpremul = 0; blit.src_image_h.mode = G2D_PIXEL_ALPHA; blit.src_image_h.use_phy_addr = 0; blit.src_image_h.fd = inbuf->fd; blit.dst_image_h.format = outtype; blit.dst_image_h.width = outw; blit.dst_image_h.height = outh; blit.dst_image_h.align[0] = 0; blit.dst_image_h.clip_rect.x = 0; blit.dst_image_h.clip_rect.y = 0; blit.dst_image_h.clip_rect.w = outw; blit.dst_image_h.clip_rect.h = outh; blit.dst_image_h.gamut = G2D_BT601; blit.dst_image_h.bpremul = 0; blit.dst_image_h.mode = G2D_PIXEL_ALPHA; blit.dst_image_h.use_phy_addr = 0; blit.dst_image_h.fd = outbuf->fd; ioctl(g2d_fd, G2D_CMD_BITBLT_H, &blit); my_ion_flush(outbuf); return 0; } int my_g2d_type_rotate(int rotate,struct ion_memory* inbuf,struct ion_memory* outbuf,unsigned int outtype,int outw,int outh){ if(rotate==0){return 0;} if(rotate==0||rotate==G2D_ROT_90||rotate==G2D_ROT_180||rotate==G2D_ROT_270||rotate==G2D_ROT_H||rotate==G2D_ROT_V){ }else{return -1;} my_ion_flush(inbuf); // G2D_FORMAT_YUV420UVC_V1U1V0U0 G2D_FORMAT_BGRA8888 // g2d_blt_h 方案有噪声 g2d_blt_h blit; memset(&blit, 0, sizeof(blit)); blit.flag_h = rotate; blit.src_image_h.format = outtype; blit.src_image_h.width = outw; blit.src_image_h.height = outh; blit.src_image_h.align[0] = 0; blit.src_image_h.align[1] = 0; blit.src_image_h.clip_rect.x = 0; blit.src_image_h.clip_rect.y = 0; blit.src_image_h.clip_rect.w = outw; blit.src_image_h.clip_rect.h = outh; blit.src_image_h.gamut = G2D_BT601; blit.src_image_h.bpremul = 0; blit.src_image_h.mode = G2D_PIXEL_ALPHA; blit.src_image_h.use_phy_addr = 0; blit.src_image_h.fd = inbuf->fd; blit.dst_image_h.format = outtype; blit.dst_image_h.width = outw; blit.dst_image_h.height = outh; blit.dst_image_h.align[0] = 0; blit.dst_image_h.clip_rect.x = 0; blit.dst_image_h.clip_rect.y = 0; blit.dst_image_h.clip_rect.w = outw; blit.dst_image_h.clip_rect.h = outh; blit.dst_image_h.gamut = G2D_BT601; blit.dst_image_h.bpremul = 0; blit.dst_image_h.mode = G2D_PIXEL_ALPHA; blit.dst_image_h.use_phy_addr = 0; blit.dst_image_h.fd = outbuf->fd; ioctl(g2d_fd, G2D_CMD_BITBLT_H, &blit); // if(rotate==G2D_ROT_90){rotate=G2D_BLT_ROTATE90;} // else if(rotate==G2D_ROT_180){rotate=G2D_BLT_ROTATE180;} // else if(rotate==G2D_ROT_270){rotate=G2D_BLT_ROTATE270;} // else if(rotate==G2D_ROT_H){rotate=G2D_BLT_FLIP_HORIZONTAL;} // else if(rotate==G2D_ROT_V){rotate=G2D_BLT_FLIP_VERTICAL;} // else {return -1;} // g2d_blt blit; // memset(&blit, 0, sizeof(blit)); // blit.flag = rotate; // blit.src_image.format = outtype; // blit.src_image.w = outw; // blit.src_image.h = outh; // blit.src_image.align[0] = 0; // blit.src_image.align[1] = 0; // blit.src_image.clip_rect.x = 0; // blit.src_image.clip_rect.y = 0; // blit.src_image.clip_rect.w = outw; // blit.src_image.clip_rect.h = outh; // blit.src_image.gamut = G2D_BT601; // blit.src_image.bpremul = 0; // blit.src_image.mode = G2D_PIXEL_ALPHA; // blit.src_image.use_phy_addr = 0; // blit.src_image.fd = inbuf->fd; // blit.dst_image_h.format = outtype; // blit.dst_image_h.width = outw; // blit.dst_image_h.height = outh; // blit.dst_image_h.align[0] = 0; // blit.dst_image_h.clip_rect.x = 0; // blit.dst_image_h.clip_rect.y = 0; // blit.dst_image_h.clip_rect.w = outw; // blit.dst_image_h.clip_rect.h = outh; // blit.dst_image_h.gamut = G2D_BT601; // blit.dst_image_h.bpremul = 0; // blit.dst_image_h.mode = G2D_PIXEL_ALPHA; // blit.dst_image_h.use_phy_addr = 0; // blit.dst_image_h.fd = outbuf->fd; // ioctl(g2d_fd, G2D_CMD_BITBLT_H, &blit); my_ion_flush(outbuf); return 0; }
T113S3 g2d_driver.h文件(添加了部分注解) 在 kernel/linux-5.4/include/linux/g2d_driver.h
/* g2d_driver.h * * Copyright (c) 2011 xxxx Electronics * 2011 Yupu Tang * * @ F23 G2D driver * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * GNU General Public License for more details. */ #ifndef __G2D_DRIVER_H #define __G2D_DRIVER_H #include <linux/types.h> #include <linux/ioctl.h> #include <stdbool.h> /* data format */ typedef enum { G2D_FORMAT_ARGB8888, G2D_FORMAT_ABGR8888, G2D_FORMAT_RGBA8888, G2D_FORMAT_BGRA8888, G2D_FORMAT_XRGB8888, G2D_FORMAT_XBGR8888, G2D_FORMAT_RGBX8888, G2D_FORMAT_BGRX8888, G2D_FORMAT_RGB888, G2D_FORMAT_BGR888, G2D_FORMAT_RGB565, G2D_FORMAT_BGR565, G2D_FORMAT_ARGB4444, G2D_FORMAT_ABGR4444, G2D_FORMAT_RGBA4444, G2D_FORMAT_BGRA4444, G2D_FORMAT_ARGB1555, G2D_FORMAT_ABGR1555, G2D_FORMAT_RGBA5551, G2D_FORMAT_BGRA5551, G2D_FORMAT_ARGB2101010, G2D_FORMAT_ABGR2101010, G2D_FORMAT_RGBA1010102, G2D_FORMAT_BGRA1010102, /* invailed for UI channel */ G2D_FORMAT_IYUV422_V0Y1U0Y0 = 0x20,//YUYV G2D_FORMAT_IYUV422_Y1V0Y0U0, G2D_FORMAT_IYUV422_U0Y1V0Y0, G2D_FORMAT_IYUV422_Y1U0Y0V0, G2D_FORMAT_YUV422UVC_V1U1V0U0, G2D_FORMAT_YUV422UVC_U1V1U0V0, G2D_FORMAT_YUV422_PLANAR, G2D_FORMAT_YUV420UVC_V1U1V0U0 = 0x28, // NV12 G2D_FORMAT_YUV420UVC_U1V1U0V0,//NV21 G2D_FORMAT_YUV420_PLANAR, G2D_FORMAT_YUV411UVC_V1U1V0U0 = 0x2c, G2D_FORMAT_YUV411UVC_U1V1U0V0, G2D_FORMAT_YUV411_PLANAR, G2D_FORMAT_Y8 = 0x30, /* YUV 10bit format */ G2D_FORMAT_YVU10_P010 = 0x34, G2D_FORMAT_YVU10_P210 = 0x36, G2D_FORMAT_YVU10_444 = 0x38, G2D_FORMAT_YUV10_444 = 0x39, G2D_FORMAT_MAX, } g2d_fmt_enh;// 用于描述 G2D 模块支持的格式 /* mixer data format */ typedef enum { /* share data format */ G2D_FMT_ARGB_AYUV8888 = (0x0), G2D_FMT_BGRA_VUYA8888 = (0x1), G2D_FMT_ABGR_AVUY8888 = (0x2), G2D_FMT_RGBA_YUVA8888 = (0x3), G2D_FMT_XRGB8888 = (0x4), G2D_FMT_BGRX8888 = (0x5), G2D_FMT_XBGR8888 = (0x6), G2D_FMT_RGBX8888 = (0x7), G2D_FMT_ARGB4444 = (0x8), G2D_FMT_ABGR4444 = (0x9), G2D_FMT_RGBA4444 = (0xA), G2D_FMT_BGRA4444 = (0xB), G2D_FMT_ARGB1555 = (0xC), G2D_FMT_ABGR1555 = (0xD), G2D_FMT_RGBA5551 = (0xE), G2D_FMT_BGRA5551 = (0xF), G2D_FMT_RGB565 = (0x10), G2D_FMT_BGR565 = (0x11), G2D_FMT_IYUV422 = (0x12),// Interleaved YUV422 G2D_FMT_8BPP_MONO = (0x13),// 8bit per pixel mono G2D_FMT_4BPP_MONO = (0x14), G2D_FMT_2BPP_MONO = (0x15), G2D_FMT_1BPP_MONO = (0x16), G2D_FMT_PYUV422UVC = (0x17), G2D_FMT_PYUV420UVC = (0x18), G2D_FMT_PYUV411UVC = (0x19), /* just for output format */ G2D_FMT_PYUV422 = (0x1A), G2D_FMT_PYUV420 = (0x1B), G2D_FMT_PYUV411 = (0x1C), /* just for input format */ G2D_FMT_8BPP_PALETTE = (0x1D), G2D_FMT_4BPP_PALETTE = (0x1E), G2D_FMT_2BPP_PALETTE = (0x1F), G2D_FMT_1BPP_PALETTE = (0x20), G2D_FMT_PYUV422UVC_MB16 = (0x21), G2D_FMT_PYUV420UVC_MB16 = (0x22), G2D_FMT_PYUV411UVC_MB16 = (0x23), G2D_FMT_PYUV422UVC_MB32 = (0x24), G2D_FMT_PYUV420UVC_MB32 = (0x25), G2D_FMT_PYUV411UVC_MB32 = (0x26), G2D_FMT_PYUV422UVC_MB64 = (0x27), G2D_FMT_PYUV420UVC_MB64 = (0x28), G2D_FMT_PYUV411UVC_MB64 = (0x29), G2D_FMT_PYUV422UVC_MB128 = (0x2A), G2D_FMT_PYUV420UVC_MB128 = (0x2B), G2D_FMT_PYUV411UVC_MB128 = (0x2C), } g2d_data_fmt;//用于描述像素格式。 /* pixel sequence in double word */ typedef enum { G2D_SEQ_NORMAL = 0x0, /* for interleaved yuv422 */ G2D_SEQ_VYUY = 0x1, /* pixel 0在低16位 */ G2D_SEQ_YVYU = 0x2, /* pixel 1在低16位 */ /* for uv_combined yuv420 */ G2D_SEQ_VUVU = 0x3, /* for 16bpp rgb */ G2D_SEQ_P10 = 0x4, /* pixel 0在低16位 */ G2D_SEQ_P01 = 0x5, /* pixel 1在低16位 */ /* planar format or 8bpp rgb */ G2D_SEQ_P3210 = 0x6, /* pixel 0在低8位 */ G2D_SEQ_P0123 = 0x7, /* pixel 3在低8位 */ /* for 4bpp rgb */ G2D_SEQ_P76543210 = 0x8, /* 7,6,5,4,3,2,1,0 */ G2D_SEQ_P67452301 = 0x9, /* 6,7,4,5,2,3,0,1 */ G2D_SEQ_P10325476 = 0xA, /* 1,0,3,2,5,4,7,6 */ G2D_SEQ_P01234567 = 0xB, /* 0,1,2,3,4,5,6,7 */ /* for 2bpp rgb */ /* 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 */ G2D_SEQ_2BPP_BIG_BIG = 0xC, /* 12,13,14,15,8,9,10,11,4,5,6,7,0,1,2,3 */ G2D_SEQ_2BPP_BIG_LITTER = 0xD, /* 3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12 */ G2D_SEQ_2BPP_LITTER_BIG = 0xE, /* 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 */ G2D_SEQ_2BPP_LITTER_LITTER = 0xF, /* for 1bpp rgb */ /* 31,30,29,28,27,26,25,24,23,22,21,20, * 19,18,17,16,15,14,13,12,11,10,9,8,7, * 6,5,4,3,2,1,0 */ G2D_SEQ_1BPP_BIG_BIG = 0x10, /* 24,25,26,27,28,29,30,31,16,17, * 18,19,20,21,22,23,8,9,10,11,12, * 13,14,15,0,1,2,3,4,5,6,7 */ G2D_SEQ_1BPP_BIG_LITTER = 0x11, /* 7,6,5,4,3,2,1,0,15,14,13,12,11, * 10,9,8,23,22,21,20,19,18,17,16, * 31,30,29,28,27,26,25,24 */ G2D_SEQ_1BPP_LITTER_BIG = 0x12, /* 0,1,2,3,4,5,6,7,8,9,10,11,12,13, * 14,15,16,17,18,19,20,21,22,23,24, * 25,26,27,28,29,30,31 */ G2D_SEQ_1BPP_LITTER_LITTER = 0x13, } g2d_pixel_seq;// 用于描述像素序列。 /* */ typedef enum { G2D_BLT_NONE_H = 0x0,//单个源操作 G2D_BLT_BLACKNESS,//使用与物理调色板的索引0相关的色彩来填充目标矩形区域,(对缺省的物理调色板,该颜色为黑色) G2D_BLT_NOTMERGEPEN,//dst = ~(dst+src) G2D_BLT_MASKNOTPEN,// dst =~src&dst G2D_BLT_NOTCOPYPEN,// dst =~src G2D_BLT_MASKPENNOT,// dst =src&~dst G2D_BLT_NOT,// dst =~dst G2D_BLT_XORPEN,// dst =src^dst G2D_BLT_NOTMASKPEN,// dst =~(src&dst) G2D_BLT_MASKPEN,// dst =src&dst G2D_BLT_NOTXORPEN,// dst =~(src^dst) G2D_BLT_NOP,// dst =dst G2D_BLT_MERGENOTPEN,// dst =~src+dst G2D_BLT_COPYPEN,// dst =src G2D_BLT_MERGEPENNOT,// dst =src+~dst G2D_BLT_MERGEPEN,// dst =src+dst G2D_BLT_WHITENESS = 0x000000ff,//使用与物理调色板中索引1有关的颜色填充目标矩形区域(对于缺省物理调色板来说,这个颜色为白色) G2D_ROT_90 = 0x00000100, G2D_ROT_180 = 0x00000200, G2D_ROT_270 = 0x00000300, G2D_ROT_0 = 0x00000400, G2D_ROT_H = 0x00001000, G2D_ROT_V = 0x00002000, /* G2D_SM_TDLR_1 = 0x10000000, */ G2D_SM_DTLR_1 = 0x10000000, /* G2D_SM_TDRL_1 = 0x20000000, */ /* G2D_SM_DTRL_1 = 0x30000000, */ } g2d_blt_flags_h;//定义二元光栅操作码 /* ROP3 command */ typedef enum { G2D_ROP3_BLACKNESS = 0x00,// dst = BLACK G2D_ROP3_NOTSRCERASE = 0x11,// dst = (NOT src) AND (NOT dst) G2D_ROP3_NOTSRCCOPY = 0x33,// dst = (NOT src) :将源矩形区域颜色取反,拷贝到目标矩形区域 G2D_ROP3_SRCERASE = 0x44,// dst = src AND (NOT dst ) G2D_ROP3_DSTINVERT = 0x55,// dst = (NOT dst) G2D_ROP3_PATINVERT = 0x5A,// dst = pattern XOR dst :通过使用布尔型的异或(XOR)操作符将特定模式和目标矩形区域颜色合并 G2D_ROP3_SRCINVERT = 0x66,// dst = src XOR dst :通过使用布尔型的异或(XOR)操作符将源和目标矩形区域颜色合并 G2D_ROP3_SRCAND = 0x88,// dst = src AND dst :通过使用与操作符将源和目标矩形区域颜色值合并 G2D_ROP3_MERGEPAINT = 0xBB,// dst = (NOT src) OR dst :通过使用布尔型的或(OR)操作符将反向的源矩形区域的颜色与目标矩形区域颜色合并 G2D_ROP3_MERGECOPY = 0xC0,// dst = (src AND pattern) G2D_ROP3_SRCCOPY = 0xCC,// dst = src :将源矩形区域直接拷贝到目标矩形区域 G2D_ROP3_SRCPAINT = 0xEE,//dst = src OR dst :通过使用布尔型的或(OR)操作符将源和目标矩形区域颜色合并 G2D_ROP3_PATCOPY = 0xF0,//dst = pattern G2D_ROP3_PATPAINT = 0xFB,//dst = DPSnoo :通过使用布尔型的或(OR)操作符将源矩形区域取反后的颜色值与特定模式的颜色合并,然后使用OR操作符与该操作的结果与目标矩形区域内的颜色合并 G2D_ROP3_WHITENESS = 0xFF,//dst = WHITE } g2d_rop3_cmd_flag;//用于定义三元光栅操作码。 typedef enum { G2D_FIL_NONE = 0x00000000,//纯填充 G2D_FIL_PIXEL_ALPHA = 0x00000001,//填充区域和目标做点alpha G2D_FIL_PLANE_ALPHA = 0x00000002,//面 G2D_FIL_MULTI_ALPHA = 0x00000004,//填充区域的alpha值*面alpha值后再和目标做alpha } g2d_fillrect_flags;//用于描述一个 fillrect 属性信息 typedef enum { G2D_BLT_NONE = 0x00000000,//纯拷贝 G2D_BLT_PIXEL_ALPHA = 0x00000001,//点alpha标志 G2D_BLT_PLANE_ALPHA = 0x00000002,//面 G2D_BLT_MULTI_ALPHA = 0x00000004,//混合 G2D_BLT_SRC_COLORKEY = 0x00000008,//源colorkey标志 G2D_BLT_DST_COLORKEY = 0x00000010,//目标colorkey标志 G2D_BLT_FLIP_HORIZONTAL = 0x00000020,//水平翻转 G2D_BLT_FLIP_VERTICAL = 0x00000040,//垂直翻转 G2D_BLT_ROTATE90 = 0x00000080,//逆时针旋转90度 G2D_BLT_ROTATE180 = 0x00000100, G2D_BLT_ROTATE270 = 0x00000200, G2D_BLT_MIRROR45 = 0x00000400,//镜像45度 G2D_BLT_MIRROR135 = 0x00000800, G2D_BLT_SRC_PREMULTIPLY = 0x00001000, G2D_BLT_DST_PREMULTIPLY = 0x00002000, } g2d_blt_flags;// g2d_blt_flags 用于描述一个 bitblt 和 stretchblt 的 flag 属性信息 /* BLD LAYER ALPHA MODE*/ typedef enum { G2D_PIXEL_ALPHA,//点alpha G2D_GLOBAL_ALPHA,//面alpha G2D_MIXER_ALPHA,//混合alpha } g2d_alpha_mode_enh;// 定义进行 alpha blend 操作时,选择的 alpha mode。 /* flip rectangle struct */ typedef struct { __s32 x; /* left top point coordinate x */ __s32 y; /* left top point coordinate y */ __u32 w; /* rectangle width */ __u32 h; /* rectangle height */ } g2d_rect; /* g2d color gamut */ typedef enum { G2D_BT601, G2D_BT709, G2D_BT2020, } g2d_color_gmt;//定义进行位操作时,选择的颜色空间。 /* image struct */ typedef struct { __u32 addr[3];/* base addr of image frame buffer in byte */ __u32 w; /* width of image frame buffer in pixel */ __u32 h; /* height of image frame buffer in pixel */ g2d_data_fmt format; /* pixel format of image frame buffer */ g2d_pixel_seq pixel_seq;/* pixel sequence of image frame buffer */ } g2d_image;//用于描述 image 属性信息(V1.0) // addr[3] 图像帧的基地址, // 对于UV combined,addr[0,1]有效,planar类型addr[0,1,2]有效,其他addr[0]有效。 // 在linux5.10版本及以后的版本中, addr[0]形式参数接收的实际参数是上层应用程序通过dma_buf_heap相关接口申请到的内存句柄fd,addr[1]和addr[2]废弃 typedef struct { /* left point coordinate x of dst rect */ unsigned int x; /* top point coordinate y of dst rect */ unsigned int y; } g2d_coor; enum color_range { COLOR_RANGE_0_255 = 0, COLOR_RANGE_16_235 = 1, }; /* image struct */ typedef struct { int bbuff; __u32 color; g2d_fmt_enh format; __u32 laddr[3];//起始低位地址 __u32 haddr[3];//起始高位地址 __u32 width; __u32 height; __u32 align[3]; g2d_rect clip_rect;//ROI矩形 g2d_coor coor; g2d_color_gmt gamut;//图的色域 int bpremul;//是否为预乘 __u8 alpha;//面alpha值 g2d_alpha_mode_enh mode;// alpha模式设置 int fd; __u32 use_phy_addr; enum color_range color_range; } g2d_image_enh;//主要描述图片的宽高、存放地址、是否做 Clip 处理,是否为预乘等。 /* * 0:Top to down, Left to right * 1:Top to down, Right to left * 2:Down to top, Left to right * 3:Down to top, Right to left */ enum g2d_scan_order {//定义进行 alpha blend 操作时,选择的图像扫行模式。(V1.0) G2D_SM_TDLR = 0x00000000, G2D_SM_TDRL = 0x00000001, G2D_SM_DTLR = 0x00000002, G2D_SM_DTRL = 0x00000003, }; typedef struct { g2d_fillrect_flags flag;//填充矩形标志, g2d_image dst_image;//目标图像信息 g2d_rect dst_rect;//目标矩形信息,x/y/w/h-左上角x/左上角y/宽/高 __u32 color; /* fill color */ __u32 alpha; /* plane alpha value */ } g2d_fillrect; //用于描述一个 fill rectangle 参数信息(V1.0) typedef struct { g2d_image_enh dst_image_h; } g2d_fillrect_h;//实现带透明度的颜色填充。 其中color成员用于传递填充的颜色参数,各个分量:A[31:24] R[23:16] G[15:8] B[7:0] typedef struct { g2d_blt_flags flag; g2d_image src_image;//源图像信息,详见g2d_image g2d_rect src_rect; g2d_image dst_image;//目标图像信息 /* left top point coordinate x of dst rect */ __s32 dst_x;//目标矩形左上角x /* left top point coordinate y of dst rect */ __s32 dst_y; __u32 color; /* colorkey color */ //colorkey颜色 __u32 alpha; /* plane alpha value */ //面alpha值 } g2d_blt;//用于一个源和目标做 blt 的信息(V1.0) typedef struct { g2d_blt_flags_h flag_h;//定义二元光栅操作码 g2d_image_enh src_image_h;//源图像信息 g2d_image_enh dst_image_h;//目标 } g2d_blt_h;//实现对 foreground 带缩放的 ROP2 处理 typedef struct { g2d_blt_h blt; __u32 lbc_cmp_ratio; bool enc_is_lossy; bool dec_is_lossy; } g2d_lbc_rot; typedef struct { g2d_blt_flags flag; g2d_image src_image;//源图像信息 g2d_rect src_rect;//源矩形信息,x/y/w/h-左上角x/左上角y/宽/高 g2d_image dst_image; g2d_rect dst_rect; __u32 color; /* colorkey color */ __u32 alpha; /* plane alpha value */ } g2d_stretchblt;//用于描述一个 stretchblt 参数信息。(V1.0) typedef struct { g2d_rop3_cmd_flag back_flag; g2d_rop3_cmd_flag fore_flag; g2d_image_enh dst_image_h; g2d_image_enh src_image_h; g2d_image_enh ptn_image_h; g2d_image_enh mask_image_h; } g2d_maskblt; /* Porter Duff BLD command*/ typedef enum { G2D_BLD_CLEAR = 0x00000001,//清除source和destination图像,也即result图像为空 G2D_BLD_COPY = 0x00000002,//result = source :result图像为source图像 G2D_BLD_DST = 0x00000003,//result = destination G2D_BLD_SRCOVER = 0x00000004,// result = (1 - As) * destination + source :As为Alpha source参数 G2D_BLD_DSTOVER = 0x00000005,//result = (1 - Ad) * source + destination :Ad为Alpha destination参数 G2D_BLD_SRCIN = 0x00000006,//result = Ad * source G2D_BLD_DSTIN = 0x00000007,//result = As * destination G2D_BLD_SRCOUT = 0x00000008,// result = (1 - Ad) * source G2D_BLD_DSTOUT = 0x00000009,// result = (1 - As) * destination G2D_BLD_SRCATOP = 0x0000000a,// result = (1 - As) * destination + Ad * source G2D_BLD_DSTATOP = 0x0000000b,//result = As * destination + (1 - Ad) * source G2D_BLD_XOR = 0x0000000c,//result = (1 - As) * destination + (1 - Ad) * source G2D_CK_SRC = 0x00010000,//when the pixel value matches destination images, it displays the pixel from source image G2D_CK_DST = 0x00020000,//when the pixel value matches source images, it displays the pixel from destination image } g2d_bld_cmd_flag;//定义 BLD 操作命令 (alpha blend) 不同的图层之间可以做 alpha blending。Alpha 分为 pixel alpha、plane alpha、multi alpha三种: typedef struct { __u32 *pbuffer; __u32 size; } g2d_palette; typedef struct { long start; long end; } g2d_cache_range; /* CK PARA struct */ typedef struct { bool match_rule;//当match_rule为假时,Color Min=<Color<=Color Max表示满足匹配条件, //当match_rule为真时,Color>Color Max or Color <Color Min表示满足匹配条件 /* int match_rule; */ __u32 max_color;//Color Max __u32 min_color;//Color Min } g2d_ck;//定义了 colorkey 操作的参数 typedef struct { g2d_bld_cmd_flag bld_cmd;//定义 BLD 操作命令 g2d_image_enh dst_image; g2d_image_enh src_image[4];/*now only ch0 and ch3*/ g2d_ck ck_para;//colorkey参数 } g2d_bld; /* blending enhance */ //实现两幅图的 BLD 和 colorkey 操作。(V1.0) typedef enum { OP_FILLRECT = 0x1, OP_BITBLT = 0x2, OP_BLEND = 0x4, OP_MASK = 0x8, OP_SPLIT_MEM = 0x10, } g2d_operation_flag; /** * mixer_para RCQ 批处理的核心结构体。 */ struct mixer_para { g2d_operation_flag op_flag; g2d_blt_flags_h flag_h; g2d_rop3_cmd_flag back_flag; g2d_rop3_cmd_flag fore_flag; g2d_bld_cmd_flag bld_cmd; g2d_image_enh src_image_h; g2d_image_enh dst_image_h; g2d_image_enh ptn_image_h; g2d_image_enh mask_image_h; g2d_ck ck_para; }; #define SUNXI_G2D_IOC_MAGIC 'G' #define SUNXI_G2D_IO(nr) _IO(SUNXI_G2D_IOC_MAGIC, nr) #define SUNXI_G2D_IOR(nr, size) _IOR(SUNXI_G2D_IOC_MAGIC, nr, size) #define SUNXI_G2D_IOW(nr, size) _IOW(SUNXI_G2D_IOC_MAGIC, nr, size) #define SUNXI_G2D_IOWR(nr, size) _IOWR(SUNXI_G2D_IOC_MAGIC, nr, size) typedef enum { G2D_CMD_BITBLT = 0x50,//BITBLT 函数实现的是两个图层的运算,比如源拷贝到目标;源旋转放入目标;源和目标做 alpha blending/colorkey 后拷贝到目标( arg 为 g2d_blt 结构体指针) G2D_CMD_FILLRECT = 0x51,//用一种颜色的画点画直线及矩形填充,同时也能实现填充颜色和目标做 alpha blend-ing。(arg 为 g2d_fillrect 结构体指针) G2D_CMD_STRETCHBLT = 0x52,//STRETCHBLT 函数实现的是两个图层的运算,比如源缩放到目标大小后拷贝到目标;源缩放到目标大小旋转放入目标;源缩放到目标大小后和目标做alpha blending/colorkey拷贝到目标( arg 为 g2d_stretchblt 结构体指针。) G2D_CMD_PALETTE_TBL = 0x53,//PALETTE_TAL 函数实现的是把查找表写入硬件 SDRAM,也只有在前面接口的源数据format 设置为 palette 模式时才需要先使用这条命令(arg 为 g2d_palette 结构体指针) G2D_CMD_QUEUE = 0x54,// G2D_CMD_BITBLT_H = 0x55,//实现单幅图的缩放、格式转换等。实现对 foreground 带缩放的 ROP2 处理。 (g2d_blt_h) G2D_CMD_FILLRECT_H = 0x56,//向目标图像填充颜色矩形(arg为g2d_fillrect_h结构体指针) G2D_CMD_BLD_H = 0x57,//实现两幅图的 BLD(porter-duff) 操作 (g2d_bld) G2D_CMD_MASK_H = 0x58,//根据掩膜图和光栅操作码对 src、pattern 和 dst 进行操作,并将结果保存到 dst 中(arg为g2d_maskblt结构体指针) G2D_CMD_MEM_REQUEST = 0x59, G2D_CMD_MEM_RELEASE = 0x5A, G2D_CMD_MEM_GETADR = 0x5B, G2D_CMD_MEM_SELIDX = 0x5C, G2D_CMD_MEM_FLUSH_CACHE = 0x5D, G2D_CMD_INVERTED_ORDER = 0x5E, G2D_CMD_MIXER_TASK = 0x5F,//批处理,mixer_para的构造 arg[0]设备文件标识符arg指向mixer_para指针,批处理的话就是数组指针。 arg[1]: 指针需要处理的帧的数量,大于等于1 G2D_CMD_LBC_ROT = 0x60, G2D_CMD_CREATE_TASK = SUNXI_G2D_IOW(0x1, struct mixer_para),//该 ioctl 命令用于创建新的批处理实例,但不做硬件处理, 只是准备好软件 G2D_CMD_TASK_APPLY = SUNXI_G2D_IOW(0x2, struct mixer_para),//该 ioctl 命令的作用是执行批处理的硬件操作(值得注意 arg[1] 中的 mixer_para,必须是 G2D_CMD_CREATE_TASK 之后返回的mixer_para 或 者 是 通 过 另 外 一 个 ioctl 命 令 G2D_CMD_TASK_GET_PARA 才 行,这里不需要制定帧数的原因是前面的 G2D_CMD_CREATE_TASK 已经指定好帧数,而G2D_CMD_TASK_APPLY 是基于 task id 来执行的) G2D_CMD_TASK_DESTROY = SUNXI_G2D_IOW(0x3, unsigned int),//该 ioctl 命令的作用是销毁指定 task id 的批处理实例。 G2D_CMD_TASK_GET_PARA = SUNXI_G2D_IOR(0x4, struct mixer_para),//该 ioctl 命令的作用是获取指定 task id 的 mixer para。 } g2d_cmd; #endif /* __G2D_DRIVER_H */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
2022-07-05 qt使用qwt 跟随鼠标显示坐标