首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当使用太多制服时,着色器无法编译

当使用太多制服时,着色器无法编译
EN

Stack Overflow用户
提问于 2022-03-10 02:01:35
回答 1查看 169关注 0票数 1

我会说这是我第一次接触着色器代码,所以我肯定我的措辞会有很多错误。

我正在开发一个SpriteKit游戏,希望能够生成精灵,而不是手动创建/更改/添加资产。我的想法是拥有一个“基本”资产,记下资产中存在的所有不同颜色,然后以编程方式创建表示资产颜色和我希望用它们替换的颜色的制服。在那里,我的着色器可以将每个rgb值与表示资产颜色的制服进行比较,并确定用哪种颜色替换它。本质上,我正在构建一个从旧颜色到新颜色的映射,并执行颜色交换。

这很好,只要我在我的“映射”中使用不到30套制服。当我超过30时,我会得到以下错误(请注意,"u_base_“和"u_new_”名称是我生成的制服):

program_source:49:1883:错误:“缓冲区”属性参数超出界限:必须介于0到30段float4 SKShader_FragFunc( texture2d u_texture [纹理(0)]、const设备浮点数*u_time [buffer(0)]、const device float *u_path_length [buffer(1)]、const device float4 * u_base_skinDark [buffer(2)]、const device float4 * u_base_eyesColor [缓冲区(3)]、const device float4 * u_new_shirtMediumLight [buffer(4)],const device float4 * u_base_eyesDark [buffer(5)],const device float4 * u_new_shoes [buffer(6)],const device float4 * u_new_hairDark [buffer(7)],const device float4 * u_new_eyesWhite [buffer(8)],const device float4 * u_new_skinMediumDark [buffer(9)],const device float4 * u_base_skinMediumLight [buffer(10)],const device float2 * u_sprite_size [buffer(11)],const device float4 * u_base_shirtMediumLight [buffer(12)],const device float4 * u_new_eyesColor [buffer(13)],const device float4 * u_base_shirtDark [buffer(14)],const device float4 * u_base_shirtMediumDark [buffer(15)],const device float4 * u_new_hairMedium [buffer(16)],const device float4 * u_base_eyesBrow [buffer(17)],const device float4 * u_base_hairDark [buffer(18)],const device float4 * u_new_shirtMediumDark [buffer(19)],const device float4 * u_new_skinDark [buffer(20)],const device float4 * u_new_eyesDark [buffer(21)],const device float4 * u_new_eyesBrow [buffer(22)],const device float4 * u_new_hairLight [buffer(23)],const device float4 * u_new_skinLight [buffer(24)],const device float4 * u_base_skinLight [buffer(25)],const device float4 * u_new_skinMediumLight [buffer(26)],const device float4 * u_base_hairLight [buffer(27)],const device float4 * u_base_shoes [buffer(28)],const device float4 * u_base_eyesWhite [buffer(29)],const device float4 * u_new_shirtDark [buffer(30)],const device float4 * u_base_skinMediumDark [buffer(31)],const device float4 * u_base_hairMedium [buffer(32)],SKShader_VertexOut插值[stage_in]) {

我几乎没有发现对错误消息的引用,所以很难找到一个修复程序。从那以后,我发现这并不是使用着色器的正确方法,因为这些类型的比较并不是很好的表现,但我仍然想了解这个错误。是否要增加缓冲区的大小?这仅仅是SpriteKit的一个限制吗?另外,使用“交换纹理”来完成这个颜色交换是唯一的方法吗?

EN

回答 1

Stack Overflow用户

发布于 2022-04-12 13:51:56

我无法回答您关于SpriteKit的具体问题,但在处理金属项目时也遇到了同样的错误。

根据硬件的不同,您可以通过使用参数缓冲区(例如用于第1层(来自缓冲器))使用超过31个缓冲区(即所遇到的限制):

一级限制 以下资源限制被定义为在参数缓冲区内设置并单独设置的资源的最大组合数,每个图形或计算函数。例如,如果一个内核函数使用4个单独的纹理和一个包含8个纹理的参数缓冲区,则该内核函数的纹理总数为12。 在iOS和tvOS中,每个函数参数表中的最大条目是: 31个缓冲区(在A11和更高版本的96个缓冲器上) 31个纹理*(在A11及以后的96个纹理中) 16个取样器 *参数缓冲区中不支持可写纹理。 在macOS中,每个函数参数表中的最大条目是: 64个缓冲区 128个纹理 16个取样器

例如,对于第1层macOS (例如在M1上),通过使用参数缓冲区,您应该能够总共使用64个缓冲区。

示例.metal着色器代码:

代码语言:javascript
复制
#include <metal_stdlib>
using namespace metal;

struct DataBuffers {
    const device float* buffer0 [[ id(0) ]];
    const device float* buffer1 [[ id(1) ]];
    const device float* buffer2 [[ id(2) ]];
    const device float* buffer3 [[ id(3) ]];
    const device float* buffer4 [[ id(4) ]];
    const device float* buffer5 [[ id(5) ]];
    const device float* buffer6 [[ id(6) ]];
    const device float* buffer7 [[ id(7) ]];
    const device float* buffer8 [[ id(8) ]];
    const device float* buffer9 [[ id(9) ]];
    const device float* buffer10 [[ id(10) ]];
    const device float* buffer11 [[ id(11) ]];
    const device float* buffer12 [[ id(12) ]];
    const device float* buffer13 [[ id(13) ]];
    const device float* buffer14 [[ id(14) ]];
    const device float* buffer15 [[ id(15) ]];
    const device float* buffer16 [[ id(16) ]];
    const device float* buffer17 [[ id(17) ]];
    const device float* buffer18 [[ id(18) ]];
    const device float* buffer19 [[ id(19) ]];
    const device float* buffer20 [[ id(20) ]];
    const device float* buffer21 [[ id(21) ]];
    const device float* buffer22 [[ id(22) ]];
    const device float* buffer23 [[ id(23) ]];
    const device float* buffer24 [[ id(24) ]];
    const device float* buffer25 [[ id(25) ]];
    const device float* buffer26 [[ id(26) ]];
    const device float* buffer27 [[ id(27) ]];
    const device float* buffer28 [[ id(28) ]];
    const device float* buffer29 [[ id(29) ]];
    const device float* buffer30 [[ id(30) ]];
    const device float* buffer31 [[ id(31) ]];
    const device float* buffer32 [[ id(32) ]];
    const device float* buffer33 [[ id(33) ]];
    const device float* buffer34 [[ id(34) ]];
    const device float* buffer35 [[ id(35) ]];
    const device float* buffer36 [[ id(36) ]];
    const device float* buffer37 [[ id(37) ]];
    const device float* buffer38 [[ id(38) ]];
    const device float* buffer39 [[ id(39) ]];
};

kernel void argument_buffer_test(
    device float* out [[ buffer(0) ]],
    const device DataBuffers& data_buffers [[ buffer(1) ]],
    uint id [[ thread_position_in_grid ]]
) {
    // Simply copy one of the input buffers.
    out[id] = data_buffers.buffer11[id];
}

对应.swift文件

代码语言:javascript
复制
import Foundation
import MetalKit

// Number of samples.
let N = 10
// Number of buffers in the struct as defined in the .metal file.
let structBuffers = 40

// Setup.
let device = MTLCreateSystemDefaultDevice()!
let commandQueue = device.makeCommandQueue()!
let library = device.makeDefaultLibrary()!

let function = library.makeFunction(name: "argument_buffer_test")!
let pipeline = try! device.makeComputePipelineState(function: function)

let threadsPerThreadgroup = MTLSize(width: pipeline.threadExecutionWidth, height: 1, depth: 1)

let argumentEncoder = function.makeArgumentEncoder(bufferIndex: 1)
let argumentBuffer = device.makeBuffer(length: argumentEncoder.encodedLength, options: [])
argumentEncoder.setArgumentBuffer(argumentBuffer, offset: 0)

// Dummy data.
var inputBuffer: MTLBuffer
var inputBuffers = [MTLBuffer]()
var dummyData: [CFloat]
for i in 0..<structBuffers {
    dummyData = Array<CFloat>(repeating: Float(i), count: N)
    inputBuffer = device.makeBuffer(
        bytes: &dummyData,
        length: MemoryLayout<CFloat>.stride * dummyData.count,
        options: []
    )!
    inputBuffers.append(inputBuffer)
    argumentEncoder.setBuffer(inputBuffer, offset: 0, index: i)
}

let outputBuffer = device.makeBuffer(length: MemoryLayout<CFloat>.stride * N, options: [])!

// Encode commands.
let commandBuffer = commandQueue.makeCommandBuffer()!
let encoder = commandBuffer.makeComputeCommandEncoder()!
encoder.setComputePipelineState(pipeline)

encoder.setBuffer(outputBuffer, offset: 0, index: 0)
// The argument buffer is represented as a single buffer here,
// with references to the individual input buffers created above.
encoder.setBuffer(argumentBuffer, offset: 0, index: 1)
// When using argument buffers, the underlying buffers have to be marked like so
for i in 0..<inputBuffers.count {
    encoder.useResource(inputBuffers[i], usage: .read)
}

let threadsPerGrid = MTLSize(width: N, height: 1, depth: 1)

encoder.dispatchThreads(threadsPerGrid, threadsPerThreadgroup: threadsPerThreadgroup)
encoder.endEncoding()

commandBuffer.commit()
commandBuffer.waitUntilCompleted()

// Print output.
print(Array(
    UnsafeBufferPointer<CFloat>(
        start: outputBuffer.contents().bindMemory(to: CFloat.self, capacity: N),
        count: N
    )
))

另一个很好的资源是来自金属用教程https://github.com/raywenderlich/met-materials/tree/editions/3.0的第26章。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71418012

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档