2013-03-22 8 views
5

में बैच कॉल करने का सबसे तेज़ तरीका मैं अपने 2 डी गेम इंजन के लिए अपने कैनवास-आधारित प्रतिपादन को फिर से लिखने की कोशिश कर रहा हूं। मैंने अच्छी प्रगति की है और वेबलॉग संदर्भ ठीक करने के लिए बनावट प्रस्तुत कर सकते हैं, स्केलिंग, रोटेशन और ब्लेंडिंग के साथ पूरा करें। लेकिन मेरा प्रदर्शन बेकार है। मेरे टेस्ट लैपटॉप पर, मैं एक बार में स्क्रीन पर 1,000 इकाइयों के साथ वेनिला 2 डी कैनवास में 30 एफपीएस प्राप्त कर सकता हूं; वेबजीएल में, मुझे स्क्रीन पर 500 इकाइयों के साथ 30 एफपीएस मिलते हैं। मैं स्थिति को विपरीत होने की उम्मीद करता हूं!वेबजीएल

मुझे एक झुकाव संदेह है कि अपराधी यह सब Float32Array बफर कचरा है जो मैं चारों ओर फेंक रहा हूं। यहां मेरे साधारण परीक्षण shaders (इन सम्मिश्रण याद कर रहे हैं, & रोटेशन स्केलिंग) है

// boilerplate code and obj coordinates 

// grab gl context 
var canvas = sys.canvas; 
var gl = sys.webgl; 
var program = sys.glProgram; 

// width and height 
var scale = sys.scale; 
var tileWidthScaled = Math.floor(tileWidth * scale); 
var tileHeightScaled = Math.floor(tileHeight * scale); 
var normalizedWidth = tileWidthScaled/this.width; 
var normalizedHeight = tileHeightScaled/this.height; 

var worldX = targetX * scale; 
var worldY = targetY * scale; 

this.bindGLBuffer(gl, this.vertexBuffer, sys.glWorldLocation); 
this.bufferGLRectangle(gl, worldX, worldY, tileWidthScaled, tileHeightScaled); 

gl.activeTexture(gl.TEXTURE0); 
gl.bindTexture(gl.TEXTURE_2D, this.texture); 

var frameX = (Math.floor(tile * tileWidth) % this.width) * scale; 
var frameY = (Math.floor(tile * tileWidth/this.width) * tileHeight) * scale; 

// fragment (texture) shader 
this.bindGLBuffer(gl, this.textureBuffer, sys.glTextureLocation); 
this.bufferGLRectangle(gl, frameX, frameY, normalizedWidth, normalizedHeight); 

gl.drawArrays(gl.TRIANGLES, 0, 6); 

bufferGLRectangle: function (gl, x, y, width, height) { 
    var left = x; 
    var right = left + width; 
    var top = y; 
    var bottom = top + height; 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
     left, top, 
     right, top, 
     left, bottom, 
     left, bottom, 
     right, top, 
     right, bottom 
    ]), gl.STATIC_DRAW); 
}, 

bindGLBuffer: function (gl, buffer, location) { 
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 
    gl.vertexAttribPointer(location, 2, gl.FLOAT, false, 0, 0); 
}, 

और::

// fragment (texture) shader 
precision mediump float; 
uniform sampler2D image; 
varying vec2 texturePosition; 

void main() { 
    gl_FragColor = texture2D(image, texturePosition); 
} 

// vertex shader 
attribute vec2 worldPosition; 
attribute vec2 vertexPosition; 

uniform vec2 canvasResolution; 
varying vec2 texturePosition; 

void main() { 
    vec2 zeroToOne = worldPosition/canvasResolution; 
    vec2 zeroToTwo = zeroToOne * 2.0; 
    vec2 clipSpace = zeroToTwo - 1.0; 

    gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); 
    texturePosition = vertexPosition; 
} 

कैसे बेहतर प्रदर्शन प्राप्त करने के बारे में कोई भी विचार यहाँ मेरी प्रस्तुत करना कोड है? क्या मेरे drawArrays बैच करने का कोई तरीका है? क्या बफर कचरे पर कटौती करने का कोई तरीका है?

धन्यवाद!

+1

अधिक आंतों को आकर्षित करने के लिए मेरा सुझाव है कि आप अपने प्रश्न का शीर्षक दें "वेबजीएल पर ड्रैए आरेज़ को बैच करने का सबसे तेज़ तरीका" –

+0

@Mikko हो गया। धन्यवाद! –

+0

@AbrahamWalters: क्या आप प्रत्येक फ्रेम के लिए प्रत्येक इकाई के लिए सटीक रेंडर कोड चला रहे हैं? (उर्फ 500 * 30 = प्रति सेकंड 1500 बार) यदि ऐसा है, तो मुझे लगता है कि टैब/ब्राउज़र एक घंटे के भीतर मेमोरी से बाहर हो जाएगा (यदि दस मिनट नहीं है) यदि आप इसे बस बैठते हैं। –

उत्तर

7

यहां दो बड़े मुद्दे हैं जो मैं देख सकता हूं जो आपके प्रदर्शन पर प्रतिकूल प्रभाव डालेंगे।

आप बहुत सारे अस्थायी Float32Arrays बना रहे हैं, जो वर्तमान में निर्माण करने के लिए महंगे हैं (यह भविष्य में बेहतर होना चाहिए)। यह कहीं इस मामले में बेहतर हो एक सारिणी बना सकते हैं और कोने इसलिए की तरह हर बार स्थापित करने के लिए होगा:

verts[0] = left; verts[1] = top; 
verts[2] = right; verts[3] = top; 
// etc... 
gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW); 

अब तक का बड़ा मुद्दा यह है कि आप केवल एक समय में एक ही ट्रैक्टर ड्राइंग कर रहे है । 3 डी एपीआई बस इसे कुशलतापूर्वक करने के लिए डिज़ाइन नहीं किए गए हैं। आप जो करना चाहते हैं, वह है कि प्रत्येक ड्राअरेज़/ड्राइलेमेंट्स कॉल में जितना संभव हो सके उतने त्रिभुजों को निचोड़ें और निचोड़ें।

ऐसा करने के कई तरीके हैं, एक ही बनावट के साथ एक बफर भरने के लिए सबसे सरल तरीका है, जैसा कि आप वही बनावट साझा कर सकते हैं, फिर उन्हें एक ही बार में खींचें। psuedocode में:

var MAX_QUADS_PER_BATCH = 100; 
var VERTS_PER_QUAD = 6; 
var FLOATS_PER_VERT = 2; 
var verts = new Float32Array(MAX_QUADS_PER_BATCH * VERTS_PER_QUAD * FLOATS_PER_VERT); 

var quadCount = 0; 
function addQuad(left, top, bottom, right) { 
    var offset = quadCount * VERTS_PER_QUAD * FLOATS_PER_VERT; 

    verts[offset] = left; verts[offset+1] = top; 
    verts[offset+2] = right; verts[offset+3] = top; 
    // etc... 

    quadCount++; 

    if(quadCount == MAX_QUADS_PER_BATCH) { 
     flushQuads(); 
    } 
} 

function flushQuads() { 
    gl.bindBuffer(gl.ARRAY_BUFFER, vertsBuffer); 
    gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW); // Copy the buffer we've been building to the GPU. 

    // Make sure vertexAttribPointers are set, etc... 

    gl.drawArrays(gl.TRIANGLES, 0, quadCount + VERTS_PER_QUAD); 
} 

// In your render loop 

for(sprite in spriteTypes) { 
    gl.bindTexture(gl.TEXTURE_2D, sprite.texture); 

    for(instance in sprite.instances) { 
     addQuad(instance.left, instance.top, instance.right, instance.bottom); 
    } 

    flushQuads(); 
} 

से एक अति कि आप कैसे बेहतर प्रदर्शन के लिए अपने कॉल batching शुरू करने के लिए की एक विचार देता है कि, और वहाँ बैच के तरीके है और भी अधिक है, लेकिन उम्मीद है कि।

+0

यह बहुत समझ में आता है। मैं निश्चित रूप से मैप टाइल्स और कणों जैसी चीजों को बैच कर सकता हूं, लेकिन दिन के अंत में, मैं बांधने वाला हूं प्रत्येक फ्रेम को बहुत अधिक करता है। क्या बनावट एटलस के बिना इसके आसपास कोई रास्ता है? –

2

यदि आप वेबजीएल इंस्पेक्टर का उपयोग करते हैं तो आप ट्रेस में देखेंगे यदि आप कोई अनावश्यक जीएल निर्देश (वे चमकदार पीले रंग की पृष्ठभूमि के साथ चिह्नित हैं)। यह आपको आपके प्रतिपादन को अनुकूलित करने के बारे में एक विचार दे सकता है।

आम तौर पर बोलते हुए, अपने ड्रॉ कॉल को सॉर्ट करें ताकि सभी एक ही प्रोग्राम का उपयोग कर सकें, फिर विशेषताओं, फिर बनावट और फिर वर्दी क्रमबद्ध हो जाएं। इस तरह आपके पास जितना संभव हो उतने जीएल निर्देश (और जेएस निर्देश) होंगे।

संबंधित मुद्दे