2017-04-26 4 views
1

Je veux avoir des particules qui vont augmenter à la fois. J'ai eu advice qui a placé la valeur de tampon plus haut de sorte que je puisse jouer avec la quantité de particules. ce que je pense est que je vais avoir une taille de compte maximale fixée au tampon, puis en shader, je vais avoir un struct avec tableau pour prendre l'attribut de particules.Métal Shading Language - buffer binding

J'ai dans mon 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! 

Puis je me inscrire le buffer:

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

et mettre à jour le buffer en conséquence:

... 
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() 

et essayer de l'obtenir à partir metal fichier:

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]]) { 
... 
} 

et je suis une erreur:

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

Il est indiqué la ligne command_encoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount) me donner l'erreur. Je lis un peu à propos de buffer binding et je pense que c'est la façon dont j'envoie le threadGroupCounts ou le ThreadGroup qui me pose problème. Si je change float3 position[100]; en float3 position[7];, cela fonctionne toujours. Quelque chose de plus que 7 obtiendra l'erreur similaire.

Comment puis-je résoudre ce problème?

Et y a-t-il une bonne formule pour estimer threadGroups et threadGroupCount? Même la règle du pouce pour le faire?

Update01

Sur la base de la réponse de Ken Thomases, je changer mon code pour:

rapide:

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

métal:

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

Il fonctionne pour l'instant . Mais comment puis-je allouer plus de mémoire tampon qui doit encore être utilisé plus tard dans l'application comme this post mentionné?

Répondre

1

Il y a plusieurs problèmes ici.

Vous définissez Vects avec une taille spécifique. Cela permet à Metal de vérifier si la taille de la mémoire tampon à l'index 2 est assez grande pour correspondre à la taille de votre variable vects. Il se plaint parce que ce n'est pas assez grand. (Il ne serait pas en mesure de le faire vérifier si vects ont été déclarés comme constant float3 *vects [[buffer(2)]], par exemple.)

Deuxièmement, la taille de votre tampon - MemoryLayout<float3>.size * vectMaxCount - est incorrect. Il ne prend pas en compte l'alignement de float3 et donc le remplissage qui existe entre les éléments de votre tableau [float3].Comme indiqué dans le documentation for MemoryLayout, vous devez toujours utiliser stride, et non size, lors du calcul des tailles d'allocation.

C'est pourquoi la panne survient lorsque Vects::position a une longueur de 8 éléments ou plus. Vous vous attendez à ce qu'il commence à 11 éléments car vectMaxCount est 10, mais votre tampon est plus court qu'un tableau de vectMaxCountfloat3 s. Pour être précis, votre tampon est de 10 * 12 == 120 octets de long. La foulée de float3 est 16 et 120/16 == 7,5.

Si vous passez size-stride lors de l'attribution de votre tampon et de modifier le nombre d'éléments de Vects::position à 10 pour correspondre vectMaxCount, alors vous aurez passé cette question immédiatement. Cependant, il y a d'autres problèmes qui se cachent.

Votre fonction de calcul telle qu'elle est actuellement ne sait pas combien d'éléments de vects.position sont effectivement remplis. Vous devez transmettre le nombre réel d'éléments.

Cette ligne:

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

est incorrect (même après avoir remplacé size avec stride). Il lit après la fin de metalvects. C'est parce que le nombre d'éléments dans metalvects est inférieur à vectMaxCount. Vous devez utiliser metalvects.count au lieu de vectMaxCount.

+0

Veuillez vérifier la mise à jour01. Je suis pris référence d'un autre poste que vous avez répondu. – sooon

+0

Vous pouvez et devriez continuer à utiliser 'vextMaxCount' quand * allouer * le tampon. C'est juste l'appel à 'memcpy()' où vous devriez utiliser 'metalvects.count'. –

+0

Ouais, ça marche. J'ai besoin de lire plus sur la «disposition de la mémoire» et autres. Avez-vous de bonnes recommandations? – sooon