开发者社区 问答 正文

写入MTLTexture会导致致命错误

给出MTLTexture,定义如下。

// Create device.
id<MTLDevice> dev = MTLCreateDefaultSystemDevice();

// Size of texture.
const unsigned int W = 640;
const unsigned int H = 480;

// Define texture.
MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init];
desc.pixelFormat = MTLPixelFormatBGRA8Unorm;
desc.width = W;
desc.height = H;

// Create texture.
id<MTLTexture> tex = [device newTextureWithDescriptor:desc];

据我所知,在这一点上应中定义的纹理desc在设备上分配dev并可通过tex.

现在,给出另一种纹理tex2(已知分配和访问)和金属计算内核定义如下。

kernel void foo(texture2d<float, access::read> in [[texture(0)]],
                texture2d<float, access::write> out [[texture(1)]],
                uint2 pix [[thread_position_in_grid]]) {
    // Out of bounds check.
    if (pix.x >= out.get_width() || pix.y >= out.get_height()) {
        return;
    }

    // Do some processing on the input texture.
    // ... All fine up to here.

    // Write out a pixel to the output buffer.
    const float4 p = abc; // abc is computed above.
    out.write(p, pix);
}

据我所知,当像素p写成out的价值p将转换为符合tex,在这种情况下MTLPixelFormatBGRA8Unorm.

但是,在按如下方式启动内核时,p写成out(以上定义为tex)触发一个关键错误(SIGABRT).

// Create a Metal library.
id<MTLLibrary> lib = [dev newDefaultLibrary];

// Load the kernel.
id<MTLFunction> kernel = [lib newFunctionWithName:@"foo"];

// Create a pipeline state.
id<MTLComputePipelineState> pipelineState = [dev newComputePipelineStateWithFunction:kernel error:NULL];

// Create a command queue.
id<MTLCommandQueue> cmdQueue = [dev newCommandQueue];

// Create command buffer.
id<MTLCommandBuffer> cmdBuff = [cmdQueue commandBuffer];

// Create compute encoder.
id<MTLComputeCommandEncoder> enc = [cmdBuff computeCommandEncoder];

// Set the pipeline state.
[enc setComputePipelineState:pipelineState];

// Set the input textures (tex2 is read only in the kernel, as above).
[enc setTexture:tex2 atIndex:0];
[enc setTexture:tex atIndex:1];

// 2D launch configuration.
const MTLSize groupDim = MTLSizeMake(16, 16, 1);
const MTLSize gridDim = MTLSizeMake((int)ceil((float)(W / (float)groupDim.width)),
                                    (int)ceil((float)(H / (float)groupDim.height)),
                                    1);

// Launch kernel.
[enc dispatchThreadgroups:gridDim threadsPerThreadgroup:groupDim];
[enc endEncoding];
[enc commit];
[cmdBuff waitUntilCompleted];

我的问题是,在上述情况下,我是否理解如何分配MTLTexture对,是这样?或者,上面的示例仅仅定义了包装器围绕一些纹理,我需要分开分配?

展开
收起
游客5akardh5cojhg 2019-12-19 21:10:31 1044 分享 版权
阿里云 AI 助理回答

在您的代码示例中,您正确地创建并分配了MTLTexture对象。当您使用[device newTextureWithDescriptor:desc]时,确实是在设备上为纹理分配了内存,并且这个操作是正确的。所以,textex2(假设它也是通过类似方式创建的)都是有效分配的纹理资源。

关于您遇到的SIGABRT错误,这通常意味着在执行Metal代码时发生了严重的错误,但具体原因需要进一步调查。基于您提供的信息,这里有几个可能的问题点和解决思路:

  1. 纹理格式兼容性:确保写入操作与输出纹理tex的像素格式兼容。虽然您已经定义了desc.pixelFormat = MTLPixelFormatBGRA8Unorm;,但在内核函数中处理数据时,如果计算出的float4 p不符合该格式的要求(例如,超出颜色范围或不正确的通道顺序),可能会导致问题。请检查abc的计算逻辑以确保其符合BGRA8Unorm的预期输入。

  2. 资源状态或生命周期管理:确认textex2在被命令编码器使用时没有被意外释放或者处于不可用状态。虽然您的代码片段未显示这一点,但在实际应用中,资源管理不当可能导致访问冲突或无效状态。

  3. 线程越界:尽管您有边界检查,但请再次确认计算网格尺寸和线程组大小的逻辑是否完全无误,避免任何潜在的越界情况。

  4. 错误处理:在创建pipeline state时,您忽略了错误返回值。尝试添加错误处理逻辑,如:

    NSError *error;
    id pipelineState = [dev newComputePipelineStateWithFunction:kernel error:&error];
    if (!pipelineState) {
       NSLog(@"Failed to create compute pipeline state: %@", error);
    }
    

    这可以帮助诊断是否有问题发生在pipeline state的创建过程中。

  5. 硬件或驱动限制:有时,特定的硬件或驱动程序可能对某些操作有限制或bug。确保您的开发环境和目标设备的驱动是最新的。

综上所述,根据您提供的代码,纹理应该是正确分配的。问题可能在于纹理数据处理、资源管理或Metal API调用的其他方面。建议按照上述方向进行排查。

有帮助
无帮助
AI 助理回答生成答案可能存在不准确,仅供参考
0 条回答
写回答
取消 提交回答
问答地址: