我有一个片段着色器函数,可以对立方体贴图纹理(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);
}
我该如何调试这个?有什么想法吗?
kIOGPUCommandBufferCallbackErrorPageFault
表示 GPU 在尝试读取或写入某些内容时出现页面错误,因为它无法找到从虚拟内存到物理内存的映射。具有此映射的资源被称为“常驻”。
当您在执行读取(或写入)的相应命令编码器中缺少
useResource
或 useHeap
调用时,通常会发生这种情况。这适用于纹理以及其他资源。每个资源都会占用一定范围的虚拟内存,需要 GPU 映射,当您在命令缓冲区中提交具有 useResource
调用的命令编码器时,就会“创建”该映射。
当您不使用参数缓冲区时,驻留通常不是问题,因为 API 可以显式地查看您正在使用哪些资源,并且可以使它们隐式地为您驻留。但是对于参数缓冲区,它并不真正知道您到底使用了哪些资源,因此 API 需要您告诉它。
如果您的资源实际上存在,但您大大超出了它的长度(通常超过虚拟内存页面的长度),也可能会发生这种情况。例如,如果您有一个长度为 1024 字节的缓冲区,但您正在以大于 16 的偏移量读取该缓冲区 384,您可能会进入其他未映射的页面并出现页面错误。