参数缓冲区的金属采样纹理会生成 GPU 地址错误

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

我有一个片段着色器函数,可以对立方体贴图纹理(texturecube)进行采样。它工作得很好,直到我决定通过参数缓冲区传递这个纹理和其他参数:

#ifdef __METAL_VERSION__
struct SkyParams {
    vector_float3 ambientRadiance;
    texturecube <float,access::sample> cubeMap;
    texture2d <float,access::sample> lutMap;
};
#endif

我的着色器函数如下所示(我已尽可能简化它):

float4 enlight(PixelData pixel, constant SkyParams &sky) {
    constexpr sampler sam(mip_filter::linear, mag_filter::linear, min_filter::linear, address::repeat);
    float3 irradiance = sky.cubeMap.sample(sam, pixel.normal, level(4)).rgb;
    float3 diffuse = pixel.albedo * mix(pow(irradiance, 0.2), irradiance, pixel.metalness);
    float3 ambient = diffuse * pixel.ao * sky.ambientRadiance;
    return float4(ambient, 1.0);
}

它会生成 GPU 错误:由于执行期间出现错误,命令缓冲区的执行被中止。导致GPU地址错误错误(0000000b:kIOGPUCommandBufferCallbackErrorPageFault)

奇怪的是,如果我只是更改返回值,甚至不注释纹理采样,错误就会消失:

float4 enlight(PixelData pixel, constant SkyParams &sky) {
    constexpr sampler sam(mip_filter::linear, mag_filter::linear, min_filter::linear, address::repeat);
    float3 irradiance = sky.cubeMap.sample(sam, pixel.normal, level(4)).rgb;
    float3 diffuse = pixel.albedo * mix(pow(irradiance, 0.2), irradiance, pixel.metalness);
    float3 ambient = diffuse * pixel.ao * sky.ambientRadiance;
    return float4(pixel.albedo, 1.0);
}

我该如何调试这个?有什么想法吗?

请注意,我的参数缓冲区似乎已正确编码:

metal
1个回答
0
投票

kIOGPUCommandBufferCallbackErrorPageFault
表示 GPU 在尝试读取或写入某些内容时出现页面错误,因为它无法找到从虚拟内存到物理内存的映射。具有此映射的资源被称为“常驻”。

当您在执行读取(或写入)的相应命令编码器中缺少

useResource
useHeap
调用时,通常会发生这种情况。这适用于纹理以及其他资源。每个资源都会占用一定范围的虚拟内存,需要 GPU 映射,当您在命令缓冲区中提交具有
useResource
调用的命令编码器时,就会“创建”该映射。

当您不使用参数缓冲区时,驻留通常不是问题,因为 API 可以显式地查看您正在使用哪些资源,并且可以使它们隐式地为您驻留。但是对于参数缓冲区,它并不真正知道您到底使用了哪些资源,因此 API 需要您告诉它。

如果您的资源实际上存在,但您大大超出了它的长度(通常超过虚拟内存页面的长度),也可能会发生这种情况。例如,如果您有一个长度为 1024 字节的缓冲区,但您正在以大于 16 的偏移量读取该缓冲区 384,您可能会进入其他未映射的页面并出现页面错误。

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