如何正确地一起使用mmap()和newBufferWithBytesNoCopy?

问题描述 投票:0回答:1

在通过

MTLBuffer
mmap()
 创建的 
newBufferWithBytesNoCopy
生成纹理时,如果
len
参数请求的页数大于文件大小的页数,
mmap
调用成功,并且
mmap
消息不会导致
newBufferWithBytesNoCopy
返回或错误,但是当我将缓冲区传递给 GPU 以将数据复制到
nil
时,会打印以下内容控制台,所有 GPU 命令无法执行任何操作:

由于执行期间出现错误,命令缓冲区的执行被中止。内部错误(IOAF 代码 -536870211)

这是演示问题的代码:

MTLTexture

在这种情况下,如果实际 
static id<MTLDevice> Device; static id<MTLCommandQueue> Queue; static id<MTLTexture> BlockTexture[3]; #define TEX_LEN_1 1 // These are all made 1 in this question for simplicity #define TEX_LEN_2 1 #define TEX_LEN_4 1 #define TEX_SIZE ((TEX_LEN_1<<10)+(TEX_LEN_2<<11)+(TEX_LEN_4<<12)) #define PAGE_ALIGN(S) ((S)+PAGE_SIZE-1&~(PAGE_SIZE-1)) int main(void) { if (!(Queue = [Device = MTLCreateSystemDefaultDevice() newCommandQueue])) return EXIT_FAILURE; @autoreleasepool { const id<MTLBuffer> data = ({ void *const map = ({ NSFileHandle *const file = [NSFileHandle fileHandleForReadingAtPath:[NSBundle.mainBundle pathForResource:@"Content" ofType:nil]]; if (!file) return EXIT_FAILURE; mmap(NULL, TEX_SIZE, PROT_READ, MAP_SHARED, file.fileDescriptor, 0); }); if (map == MAP_FAILED) return errno; [Device newBufferWithBytesNoCopy:map length:PAGE_ALIGN(TEX_SIZE) options:MTLResourceStorageModeShared deallocator:^(void *const ptr, const NSUInteger len){ munmap(ptr, len); }]; }); if (!data) return EXIT_FAILURE; const id<MTLCommandBuffer> buffer = [Queue commandBuffer]; const id<MTLBlitCommandEncoder> encoder = [buffer blitCommandEncoder]; if (!encoder) return EXIT_FAILURE; { MTLTextureDescriptor *const descriptor = [MTLTextureDescriptor new]; descriptor.width = descriptor.height = 32; descriptor.mipmapLevelCount = 6; descriptor.textureType = MTLTextureType2DArray; descriptor.storageMode = MTLStorageModePrivate; const enum MTLPixelFormat format[] = {MTLPixelFormatR8Unorm, MTLPixelFormatRG8Unorm, MTLPixelFormatRGBA8Unorm}; const NSUInteger len[] = {TEX_LEN_1, TEX_LEN_2, TEX_LEN_4}; for (NSUInteger i = 3, off = 0; i--;) { descriptor.pixelFormat = format[i]; const NSUInteger l = descriptor.arrayLength = len[i]; const id<MTLTexture> texture = [Device newTextureWithDescriptor:descriptor]; if (!texture) return EXIT_FAILURE; const NSUInteger br = 32<<i, bi = 1024<<i; for (NSUInteger j = 0; j < l; off += bi) [encoder copyFromBuffer:data sourceOffset:off sourceBytesPerRow:br sourceBytesPerImage:bi sourceSize:(const MTLSize){32, 32, 1} toTexture:texture destinationSlice:j++ destinationLevel:0 destinationOrigin:(const MTLOrigin){0}]; [encoder generateMipmapsForTexture:BlockTexture[i] = texture]; } } [encoder endEncoding]; [buffer commit]; } // Rest of code to initialize application (omitted) }

文件的大小小于 4097 字节(假设页面大小为 4096),则该命令将失败。最奇怪的是,在这种情况下,

Content
mmap()
都没有失败,并且任何/所有后续 GPU 调用也会失败。
我以为文件之外的

newBufferWithBytesNoCopy

空间只是有效的0内存。如果 GPU 使用该空间,为什么情况显然并非如此?至少,除了手动检查文件是否太小之外,我如何检测 GPU 执行错误或像这样的无效缓冲区以优雅地处理它们?这是操作系统的错误还是功能使用不当?

    

gpu posix metal mmap mtlbuffer
1个回答
0
投票
mmap()

的使用没有任何问题。问题在于,根据设计,映射文件中超出文件末尾的页面如果被访问,将导致 SIGBUS。

    

© www.soinside.com 2019 - 2024. All rights reserved.