2017-04-26 11 views
1

Ich möchte Partikel haben, die mit der Zeit zunehmen werden. Ich habe advice, die den Pufferwert höher einstellen, damit ich mit der Menge der Partikel herumspielen kann. Was ich denke ist, dass ich eine maximale Zählgröße auf den Puffer gesetzt habe, dann werde ich in shader eine struct mit Array haben, um das Partikel-Attribut zu nehmen.Metal Shading Language - Pufferbindung

Ich habe dies in meinem swift:

var vectMaxCount = 10 
var metalvects = [float3(0.0,0.0,0.0),float3(1.0,0.0,0.0),float3(2.0,0.0,0.0)] 
var vectBuffer: MTLBuffer! 

Dann melde ich mich an die buffer:

vectBuffer = device!.makeBuffer(length: MemoryLayout<float3>.size * vectMaxCount, options: []) 

und aktualisieren Sie die buffer entsprechend:

... 
command_encoder.setBuffer(vectBuffer, offset: 0, at: 2) 
var bufferPointer = vectBuffer.contents() 
memcpy(bufferPointer, &metalvects, MemoryLayout<float3>.size * vectMaxCount) 

let threadGroupCount = MTLSizeMake(8, 8, 1) 
let threadGroups = MTLSizeMake(drawable.texture.width/threadGroupCount.width, drawable.texture.height/threadGroupCount.height, 1) 
command_encoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount) 
command_encoder.endEncoding() 
command_buffer.present(drawable) 
command_buffer.commit() 

und versuchen, es zu bekommen aus metal Datei:

struct Vects 
{ 
    float3 position[100]; 
}; 

kernel void compute(texture2d<float, access::write> output [[texture(0)]], 
        constant Vects &vects [[buffer(2)]], 
        uint2 gid [[thread_position_in_grid]]) { 
... 
} 

und ich habe einen Fehler:

validateComputeFunctionArguments:727: failed assertion `(length - offset)(160) must be >= 1600 at buffer binding at index 2 for vects[0].'

Sie die Linie angezeigt command_encoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount) mir Fehler geben. Ich lese ein wenig über buffer binding und ich denke, ist die Art, wie ich die threadGroupCounts oder ThreadGroup senden, die mir Problem geben.

Wenn ich float3 position[100]; zu float3 position[7]; ändere, funktioniert es immer noch. Irgendetwas mehr als 7 wird den ähnlichen Fehler bekommen.

Wie kann ich das beheben?

Und gibt es eine gute Formel zu schätzen threadGroups und threadGroupCount? Auch Faustregel, das zu tun?

swift:

Update01

Basierend auf Ken Thomases Antwort, ich meinen Code ändern

vectBuffer = device!.makeBuffer(length: MemoryLayout<float3>.stride * metalvects.count, options: []) 
... 
memcpy(bufferPointer, &metalvects, MemoryLayout<float3>.stride * metalvects.count) 
... 

Metall:

struct Vects 
{ 
    float3 position[3]; 
}; 
... 

Es funktioniert jetzt . Aber wie kann ich höheren Pufferspeicher zuweisen, der später in der App noch zu verwenden ist wie this post?

Antwort

1

Es gibt mehrere Probleme hier.

Sie definieren Vects mit einer bestimmten Größe. Dadurch kann Metal überprüfen, ob die Größe des Puffers bei Index 2 groß genug ist, um der Größe Ihrer vects-Variablen zu entsprechen. Es beschwert sich, weil es nicht groß genug ist. (Es würde diese Prüfung nicht in der Lage sein zu tun, wenn vects als constant float3 *vects [[buffer(2)]] erklärt wurden, zum Beispiel.)

Zweitens, die Größe des Puffers - MemoryLayout<float3>.size * vectMaxCount - ist falsch. Es berücksichtigt nicht die Ausrichtung von float3 und daher die Auffüllung, die zwischen Elementen in Ihrem Array [float3] besteht.Wie in der documentation for MemoryLayout erwähnt, sollten Sie immer stride, nicht size verwenden, wenn Sie die Zuweisungsgrößen berechnen.

Aus diesem Grund tritt der Fehler auf, wenn Vects::position 8 oder mehr Elemente lang ist. Sie würden erwarten, dass es bei 11 Elementen beginnt, weil vectMaxCount 10 ist, aber Ihr Puffer ist kürzer als ein Array von vectMaxCountfloat3 s. Um genau zu sein, Ihr Puffer ist 10 * 12 = 120 Bytes lang. Der Schritt von float3 ist 16 und 120/16 == 7.5.

Wenn Sie size-stride wechseln, wenn Ihre Puffer Aufteilung und die Elementanzahl von Vects::position bis 10 vectMaxCount passen ändern, dann werden Sie über dieses unmittelbare Problem zu bekommen. Allerdings lauern zusätzliche Probleme.

Ihre Rechenfunktion, wie sie derzeit steht, weiß nicht, wie viele Elemente von vects.position tatsächlich gefüllt sind. Sie müssen die tatsächliche Anzahl der Elemente eingeben.

Diese Zeile:

memcpy(bufferPointer, &metalvects, MemoryLayout<float3>.size * vectMaxCount) 

falsch ist (auch nach size mit stride ersetzen). Es liest sich über das Ende metalvects hinaus. Das liegt daran, dass die Anzahl der Elemente in metalvects weniger als vectMaxCount ist. Sie sollten metalvects.count anstelle von vectMaxCount verwenden.

+0

Bitte überprüfen update01. Ich nehme Bezug auf einen anderen Beitrag, den Sie beantwortet haben. – sooon

+0

Sie können und sollten weiterhin 'vextMaxCount' verwenden, wenn * der * Puffer zugewiesen wird. Es ist nur der Aufruf von 'memcpy()', wo Sie 'metalvects.count' verwenden sollten. –

+0

Yup, es funktioniert. Ich muss mehr über das "Memory Layout" und so lesen. Haben Sie gute Empfehlungen? – sooon