2015-07-21 23 views
5

Sto cercando di eseguire una funzione C++ per moltiplicare le matrici 4x4. Dopo 2 giorni finalmente funziona, ma non come previsto.Emscripten Uncaught RangeError: Source is too large, multiple Float32Arrays

Spesso i parametri vengono ritrasmessi alla funzione e quindi questa linea:

dataHeap2.set(new Uint8Array(data2.buffer)); 

produce un errore "RangeError Uncaught: Fonte è troppo grande"

A prima vista sembra che solo un normale Float32Array con 16 elementi, ma dopo aver guardato dentro è la dimensione del buffer sembra essere diverso

console.log(data2.buffer.bufferLength); 

Il risultato non ci si aspetta 64 byte, ma enorme num bers come 3342345. È questo il problema? Ho trovato una soluzione alternativa copiando manualmente i valori (come sotto), restituendoli e quindi il problema scompare. Sfortunatamente rende il mio codice molto più lento di quello operativo direttamente sui buffer.

// bad solution - which works 
    for(var i = 0; i < 16; i++) { 
     dataTarget[i] = result[i]; 
    } 

Speriamo che questa notte mi troverò una soluzione migliore e voglio continuare a utilizzare questa funzione come viene utilizzato un codice compilato C++ utilizzando ASM.JS + SIMD per aninmating più personaggi. In puro JavaScript è ancora troppo lento. Ecco l'intera funzione. Sono abbastanza sicuro che data2 stia prendendo l'HEAP di Emscripten con esso e voglio farlo.

matrix4multiply = function(data, data2) { 
    // Import function from Emscripten generated file 
    var mmul_vec4 = Module.cwrap(
     'mmul_vec4', 'number', ['number', 'number', 'number'] 
    ); 

    var dataTarget = new Float32Array(16); 

    // Get data byte size, allocate memory on Emscripten heap, and get pointer 
    var nDataBytes = dataTarget.length * dataTarget.BYTES_PER_ELEMENT; 

    // First matrix copy data to Emscripten heap 
    var dataPtr = Module._malloc(nDataBytes); 
    var dataPtr2 = Module._malloc(nDataBytes); 
    var dataPtr3 = Module._malloc(nDataBytes); 

    var dataHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr, nDataBytes); 
    dataHeap.set(new Uint8Array(data.buffer)); 

    // second matrix allocate and copy to emscripten's heap 
    var dataHeap2 = new Uint8Array(Module.HEAPU8.buffer, dataPtr2, nDataBytes); 
    dataHeap2.set(new Uint8Array(data2.buffer)); 

    // target heap 
    var targetHeap = new Uint8Array(Module.HEAPU8.buffer, dataPtr3, nDataBytes); 
    targetHeap.set(new Uint8Array(dataTarget.buffer)); 

    // Call the function by passing a number pointing to the byte location of 
    // the array of pointers on the Emscripten heap. Emscripten knows what to do! 
    mmul_vec4(dataHeap.byteOffset, dataHeap2.byteOffset, targetHeap.byteOffset); 

    // get result 
    var result = new Float32Array(targetHeap.buffer, targetHeap.byteOffset, 16); 

    // bad solution - which works 
    //for(var i = 0; i < 16; i++) { 
    // dataTarget[i] = result[i]; 
    //} 

    // Free memory 
    Module._free(dataHeap.byteOffset); 
    Module._free(dataHeap2.byteOffset); 
    Module._free(targetHeap.byteOffset); 

    return result; 
} 

Edit: semplificata versione non preoccuparti di malloc ecc

new Uint8Array(Module.HEAPU8.buffer, this.dataPtr, 64).set(new Uint8Array(data.buffer, data.byteOffset, 64)); 

    // second matrix allocate and copy to emscripten's heap 
    new Uint8Array(Module.HEAPU8.buffer, this.dataPtr + 72, 64).set(new Uint8Array(data2.buffer, data2.byteOffset, 64)); 

    // multiply first two parameters and return in the last one 
    this.mmul_vec4(this.dataPtr, this.dataPtr + 72, this.dataPtr + 144); 

    // like that it works, unfotunately copying is being made here 
    return new Float32Array(Module.HEAPU8.buffer.slice(this.dataPtr + 144, this.dataPtr + 208)); 
    // with this version (if uncommented) there's just white screen(but it looks like the game is working. 
    //return new Float32Array(Module.HEAPU8.buffer, this.dataPtr + 144, 16); 
+0

Asm.js sembra richiedere buffer di heap singolo. forse è necessaria la copia o la gestione malloc/gratuita. http://asmjs.org/spec/latest/#validatemodule-f – zakki

+0

@zakki ok quindi penso che la copia passata su targetFloat32 funzionerà, ma non vedo come alimentare questo Module.HEAPU8.buffer, this.dataPtr + 144, 16 in Float32Array esistente senza creare una nuova istanza in questo modo: nuovo Float32Array (Module.HEAPU8.buffer, this.dataPtr + 144, 16). È troppo lento. – Pawel

+0

Il problema analogo si è verificato essere il buffer inizializzato su un valore inferiore rispetto alla dimensione dei dati impostati. – vatsa

risposta

2

Per usare la testa 64 byte di data2, specificare offset e lunghezza.

dataHeap2.set(new Uint8Array(data2.buffer, data2.byteOffset, nDataBytes)); 
+0

Grazie, ci ho già provato. Ottenere "RangeError: Start offset è troppo grande:" – Pawel

+0

In realtà non c'erano errori. Solo uno schermo bianco nel mio gioco. – Pawel

0

Questo sembra risolvere il problema, ma ho paura che i dati solo .set funzione copia e non è una vera e propria soluzione di allora. Almeno un po 'più elegante di un loop cloning (ma è meglio di "Module.HEAPU8.buffer.slice")?

matrix4multiplyBlocking = function(data, data2, dataTarget) { 
    //console.log(new Float32Array(data2.buffer, data2.byteOffset, 16)); 
    // Copy data to Emscripten heap 
    new Uint8Array(Module.HEAPU8.buffer, this.dataPtr, 64).set(new Uint8Array(data.buffer, data.byteOffset, 64)); 

    // second matrix allocate and copy to emscripten's heap 
    new Uint8Array(Module.HEAPU8.buffer, this.dataPtr + 72, 64).set(new Uint8Array(data2.buffer, data2.byteOffset, 64)); 

    // multiply first two parameters and return in the last one 
    this.mmul_vec4(this.dataPtr, this.dataPtr + 72, this.dataPtr + 144); 
    // Free memory 
    //Module._free(this.dataPtr); 

    dataTarget.set(new Float32Array(Module.HEAPU8.buffer, this.dataPtr + 144, 16)); 
}; 

Anche io odio il fatto di creare nuova istanza Float32Array perché rallenta tutto

Problemi correlati