मैं टाइल-आधारित ओपनजीएल, सी ++ एप्लिकेशन पर काम कर रहा हूं। मैं आवेदन से नमूना स्क्रीन जोड़ रहा है, ताकि इसे और अधिक स्पष्ट हो जाएगा:प्राइमेटिव ड्राइंग के अप्रचलित विधि से धीमी गति से वीबीओ - क्यों?
मैं Tile
वर्ग जो Object
रों की एक सरणी शामिल है। प्रत्येक टाइल 15 ऑब्जेक्ट्स तक स्टोर कर सकती है - इसका उदाहरण Tile
पर हरा और पीला वर्ग (दो ऑब्जेक्ट्स) है, इसलिए यह 10x10x15 = 1500 Object
एस ड्रॉ करने के लिए है (सबसे खराब मामले में, क्योंकि मैं खाली नहीं कर रहा हूं 'खाली है 'वाले)। आम तौर पर यह कम है, मेरे परीक्षण में मैं उनमें से 600 का उपयोग करता हूं। Object
में इसका अपना ग्राफिक है, जिसे खींचा जा सकता है। प्रत्येक Object
एक समय में एक Tile
से संबंधित है, लेकिन इसे स्थानांतरित किया जा सकता है (उदाहरण के लिए चित्र में लाल वर्ग)।
Object
की पृष्ठभूमि में सीमा होगी और उन्हें अच्छी तरह से स्केलेबल होने की आवश्यकता है, इसलिए मैं उन्हें आकर्षित करने के लिए 9-पैच पैटर्न का उपयोग कर रहा हूं (वे 9 क्वाड से बने हैं)।
ड्राइंग Tile
एस (उनके Object
एस सटीक होने के बिना), मेरे आवेदन के पास लगभग 600 fps
है।
सबसे पहले, मैं अप्रचलित विधि का उपयोग किया गया है उन Tile
रों आकर्षित करने के लिए - का उपयोग कर glBegin(GL_QUADS)
/glEnd()
और glDisplayList
रों। उस ड्राइंग के कारण प्रदर्शन की एक बड़ी बूंद थी - 600
से 320 fps
तक। इस प्रकार मैं उन्हें चित्रित कर रहा हूं:
bool Background::draw(const TPoint& pos, int width, int height)
{
if(width <= 0 || height <= 0)
return false;
//glFrontFace(GL_CW);
glPushMatrix();
glTranslatef((GLfloat)pos.x, (GLfloat)pos.y, 0.0f); // Move background to right direction
if((width != m_savedWidth) || (height != m_savedHeight)) // If size to draw is different than the one saved in display list,
// then recalculate everything and save in display list
{
// That size will be now saved in display list
m_savedWidth = width;
m_savedHeight = height;
// If this background doesn't have unique display list id specified yet,
// then let OpenGL generate one
if(m_displayListId == NO_DISPLAY_LIST_ID)
{
GLuint displayList;
displayList = glGenLists(1);
m_displayListId = displayList;
}
glNewList(m_displayListId, GL_COMPILE);
GLfloat texelCentersOffsetX = (GLfloat)1/(2*m_width);
// Instead of coordinates range 0..1 we need to specify new ones
GLfloat maxTexCoordWidth = m_bTiling ? (GLfloat)width/m_width : 1.0;
GLfloat maxTexCoordHeight = m_bTiling ? (GLfloat)height/m_height : 1.0;
GLfloat maxTexCoordBorderX = (GLfloat)m_borderWidth/m_width;
GLfloat maxTexCoordBorderY = (GLfloat)m_borderWidth/m_height;
/* 9-cell-pattern
-------------------
| 1 | 2 | 3 |
-------------------
| | | |
| 4 | 9 | 5 |
| | | |
-------------------
| 6 | 7 | 8 |
-------------------
*/
glBindTexture(GL_TEXTURE_2D, m_texture); // Select Our Texture
// Top left quad [1]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(0.0, maxTexCoordBorderY);
glVertex2i(0, 0 + m_borderWidth);
// Top left
glTexCoord2f(0.0, 0.0);
glVertex2i(0, 0);
// Top right
glTexCoord2f(maxTexCoordBorderX, 0.0);
glVertex2i(0 + m_borderWidth, 0);
// Bottom right
glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(0 + m_borderWidth, 0 + m_borderWidth);
glEnd();
// Top middle quad [2]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(maxTexCoordBorderX + texelCentersOffsetX, maxTexCoordBorderY);
glVertex2i(0 + m_borderWidth, 0 + m_borderWidth);
// Top left
glTexCoord2f(maxTexCoordBorderX + texelCentersOffsetX, 0.0);
glVertex2i(0 + m_borderWidth, 0);
// Top right
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX - texelCentersOffsetX, 0.0);
glVertex2i(0 + width - m_borderWidth, 0);
// Bottom right
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX - texelCentersOffsetX, maxTexCoordBorderY);
glVertex2i(0 + width - m_borderWidth, 0 + m_borderWidth);
glEnd();
// Top right quad [3]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(0 + width - m_borderWidth, 0 + m_borderWidth);
// Top left
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, 0.0);
glVertex2i(0 + width - m_borderWidth, 0);
// Top right
glTexCoord2f(1.0, 0.0);
glVertex2i(0 + width, 0);
// Bottom right
glTexCoord2f(1.0, maxTexCoordBorderY);
glVertex2i(0 + width, 0 + m_borderWidth);
glEnd();
// Middle left quad [4]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(0.0, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0, 0 + height - m_borderWidth);
// Top left
glTexCoord2f(0.0, maxTexCoordBorderY);
glVertex2i(0, 0 + m_borderWidth);
// Top right
glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(0 + m_borderWidth, 0 + m_borderWidth);
// Bottom right
glTexCoord2f(maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0 + m_borderWidth, 0 + height - m_borderWidth);
glEnd();
// Middle right quad [5]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0 + width - m_borderWidth, 0 + height - m_borderWidth);
// Top left
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(0 + width - m_borderWidth, 0 + m_borderWidth);
// Top right
glTexCoord2f(1.0, maxTexCoordBorderY);
glVertex2i(0 + width, 0 + m_borderWidth);
// Bottom right
glTexCoord2f(1.0, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0 + width, 0 + height - m_borderWidth);
glEnd();
// Bottom left quad [6]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(0.0f, 1.0);
glVertex2i(0, 0 + height);
// Top left
glTexCoord2f(0.0f, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0, 0 + height - m_borderWidth);
// Top right
glTexCoord2f(maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0 + m_borderWidth, 0 + height - m_borderWidth);
// Bottom right
glTexCoord2f(maxTexCoordBorderX, 1.0);
glVertex2i(0 + m_borderWidth, 0 + height);
glEnd();
// Bottom middle quad [7]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(maxTexCoordBorderX + texelCentersOffsetX, 1.0);
glVertex2i(0 + m_borderWidth, 0 + height);
// Top left
glTexCoord2f(maxTexCoordBorderX + texelCentersOffsetX, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0 + m_borderWidth, 0 + height - m_borderWidth);
// Top right
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX - texelCentersOffsetX, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0 + width - m_borderWidth, 0 + height - m_borderWidth);
// Bottom right
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX - texelCentersOffsetX, 1.0);
glVertex2i(0 + width - m_borderWidth, 0 + height);
glEnd();
// Bottom right quad [8]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, 1.0);
glVertex2i(0 + width - m_borderWidth, 0 + height);
// Top left
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0 + width - m_borderWidth, 0 + height - m_borderWidth);
// Top right
glTexCoord2f(1.0, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(0 + width, 0 + height - m_borderWidth);
// Bottom right
glTexCoord2f(1.0, 1.0);
glVertex2i(0 + width, 0 + height);
glEnd();
GLfloat xTexOffset;
GLfloat yTexOffset;
if(m_borderWidth > 0)
{
glBindTexture(GL_TEXTURE_2D, m_centerTexture); // If there's a border, we have to use
// second texture now for middle quad
xTexOffset = 0.0; // We are using another texture, so middle middle quad
yTexOffset = 0.0; // has to be texture with a whole texture
}
else
{
// Don't bind any texture here - we're still using the same one
xTexOffset = maxTexCoordBorderX; // But it implies using offset which equals
yTexOffset = maxTexCoordBorderY; // maximum texture coordinates
}
// Middle middle quad [9]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(xTexOffset, maxTexCoordHeight - yTexOffset);
glVertex2i(0 + m_borderWidth, 0 + height - m_borderWidth);
// Top left
glTexCoord2f(xTexOffset, yTexOffset);
glVertex2i(0 + m_borderWidth, 0 + m_borderWidth);
// Top right
glTexCoord2f(maxTexCoordWidth - xTexOffset, yTexOffset);
glVertex2i(0 + width - m_borderWidth, 0 + m_borderWidth);
// Bottom right
glTexCoord2f(maxTexCoordWidth - xTexOffset, maxTexCoordHeight - yTexOffset);
glVertex2i(0 + width - m_borderWidth, 0 + height - m_borderWidth);
glEnd();
glEndList();
}
glCallList(m_displayListId); // Now we can call earlier or now created display list
glPopMatrix();
return true;
}
शायद वहां बहुत अधिक कोड है, लेकिन मैं सब कुछ दिखाना चाहता था। इस संस्करण के बारे में मुख्य बात डिस्प्ले सूचियों और glVertex2i
का उपयोग है जो बहिष्कृत हैं।
मैंने सोचा कि इस तरह की धीमी गति की समस्या इस अप्रचलित विधि का उपयोग था जो मैंने पढ़ा है, काफी धीमी है, इसलिए मैंने VBO
के लिए जाने का फैसला किया। मैं का उपयोग किया है this tutorial और यह के अनुसार मैं इस तरह मेरी पद्धति को बदल:
bool Background::draw(const TPoint& pos, int width, int height)
{
if(width <= 0 || height <= 0)
return false;
glPushMatrix();
glTranslatef((GLfloat)pos.x, (GLfloat)pos.y, 0.0f); // Move background to right direction
if((width != m_savedWidth) || (height != m_savedHeight)) // If size to draw is different than the one saved in display list,
// then recalculate everything and save in display list
{
// That size will be now saved in display list
m_savedWidth = width;
m_savedHeight = height;
GLfloat texelCentersOffsetX = (GLfloat)1/(2*m_width);
// Instead of coordinates range 0..1 we need to specify new ones
GLfloat maxTexCoordWidth = m_bTiling ? (GLfloat)width/m_width : 1.0;
GLfloat maxTexCoordHeight = m_bTiling ? (GLfloat)height/m_height : 1.0;
GLfloat maxTexCoordBorderX = (GLfloat)m_borderWidth/m_width;
GLfloat maxTexCoordBorderY = (GLfloat)m_borderWidth/m_height;
/* 9-cell-pattern, each number represents one quad
-------------------
| 1 | 2 | 3 |
-------------------
| | | |
| 4 | 9 | 5 |
| | | |
-------------------
| 6 | 7 | 8 |
-------------------
*/
/* How vertices are distributed on one quad made of two triangles
v1 ------ v0
| /|
| / |
|/ |
v2 ------ v3
*/
GLfloat vertices[] = {
// Top left quad [1]
m_borderWidth, 0, 0, // v0
0, 0, 0, // v1
0, m_borderWidth, 0, // v2
0, m_borderWidth, 0, // v2
m_borderWidth, m_borderWidth, 0, // v3
m_borderWidth, 0, 0, // v0
// Top middle quad [2]
width-m_borderWidth, 0, 0, // v0
m_borderWidth, 0, 0, // v1
m_borderWidth, m_borderWidth, 0, // v2
m_borderWidth, m_borderWidth, 0, // v2
width-m_borderWidth, m_borderWidth, 0, // v3
width-m_borderWidth, 0, 0, // v0
// Top right quad [3]
width, 0, 0, // v0
width-m_borderWidth, 0, 0, // v1
width-m_borderWidth, m_borderWidth, 0, // v2
width-m_borderWidth, m_borderWidth, 0, // v2
width, m_borderWidth, 0, // v3
width, 0, 0, // v0
// Middle left quad [4]
m_borderWidth, m_borderWidth, 0, // v0
0, m_borderWidth, 0, // v1
0, height-m_borderWidth, 0, // v2
0, height-m_borderWidth, 0, // v2
m_borderWidth, height-m_borderWidth, 0, // v3
m_borderWidth, m_borderWidth, 0, // v0
// Middle right quad [5]
width, m_borderWidth, 0, // v0
width-m_borderWidth, m_borderWidth, 0, // v1
width-m_borderWidth, height-m_borderWidth, 0, // v2
width-m_borderWidth, height-m_borderWidth, 0, // v2
width, height-m_borderWidth, 0, // v3
width, m_borderWidth, 0, // v0
// Bottom left quad [6]
m_borderWidth, height-m_borderWidth, 0, // v0
0, height-m_borderWidth, 0, // v1
0, height, 0, // v2
0, height, 0, // v2
m_borderWidth, height, 0, // v3
m_borderWidth, height-m_borderWidth, 0, // v0
// Bottom middle quad [7]
width-m_borderWidth, height-m_borderWidth, 0, // v0
m_borderWidth, height-m_borderWidth, 0, // v1
m_borderWidth, height, 0, // v2
m_borderWidth, height, 0, // v2
width-m_borderWidth, height, 0, // v3
width-m_borderWidth, height-m_borderWidth, 0, // v0
// Bottom right quad [8]
width, height-m_borderWidth, 0, // v0
width-m_borderWidth, height-m_borderWidth, 0, // v1
width-m_borderWidth, height, 0, // v2
width-m_borderWidth, height, 0, // v2
width, height, 0, // v3
width, height-m_borderWidth, 0, // v0
// Middle middle quad [9]
width-m_borderWidth, m_borderWidth, 0, // v0
m_borderWidth, m_borderWidth, 0, // v1
m_borderWidth, height-m_borderWidth, 0, // v2
m_borderWidth, height-m_borderWidth, 0, // v2
width-m_borderWidth, height-m_borderWidth, 0, // v3
width-m_borderWidth, m_borderWidth, 0 // v0
};
copy(vertices, vertices + 162, m_vCoords); // 162, because we have 162 coordinates
int dataSize = 162 * sizeof(GLfloat);
m_vboId = createVBO(m_vCoords, dataSize);
}
// bind VBOs for vertex array
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_vboId); // for vertex coordinates
glEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords array
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 162);
glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex array
// bind with 0, so, switch back to normal pointer operation
glBindBufferARB(GL_ARRAY_BUFFER_ARB, NO_VBO_ID);
glPopMatrix();
return true;
}
यह काफी पिछले संस्करण में समान है, लेकिन glDisplayList
और glVertex2i()
मैं VBO
इस्तेमाल किया जो एक सरणी में संग्रहीत डेटा से बनाया जा रहा है के बजाय ।
लेकिन परिणाम, मुझे निराश है क्योंकि मैं बढ़ावा के बजाय प्रदर्शन ड्रॉप मिल गया, मैं मुश्किल से ~260 fps
मिला है और मैं ध्यान दें चाहिए कि इस विधि संस्करण मैं अभी तक बनावट के उपयोग को लागू नहीं किया है, तो वहाँ अब बिना के लिए केवल quads हैं किसी भी बनावट से बंधे हैं।
मैंने कुछ लेख पढ़े हैं ताकि यह पता चल सके कि इतनी धीमी गति का कारण क्या हो सकता है और पता चला है कि शायद यह VBO
एस की बड़ी मात्रा के कारण है और मेरे पास शायद VBO
होना चाहिए जिसमें सभी पृष्ठभूमि डेटा हैं प्रत्येक पृष्ठभूमि के लिए VBO
अलग करें। लेकिन समस्या यह है कि Object
एस चारों ओर स्थानांतरित हो सकते हैं और उनके पास अलग-अलग बनावट हैं (और बनावट एटलस मेरे लिए एक अच्छा समाधान नहीं है), इसलिए उन लोगों के लिए उन परिवर्तनों को अपडेट करना मुश्किल होगा जो Object
एस ने अपना राज्य बदल दिया। अभी के लिए, जब Object
एस बदल रहा है, तो मैं इसे VBO
फिर से बना देता हूं और शेष VBO
एस बिना छूटे रहते हैं।
तो मेरा सवाल है - मैं क्या गलत कर रहा हूं?क्या VBO
एस की बड़ी (~ 600) संख्या का उपयोग glVertex2i
के साथ ड्राइंग की अप्रचलित विधि से वास्तव में धीमा है? और क्या हो सकता है - शायद मेरे मामले में सबसे अच्छा, लेकिन बेहतर नहीं - समाधान?
फ्रेम्स-प्रति-सेकंड एक [भयानक तुलनात्मक मीट्रिक] है (http://www.mvps.org/directx/articles/fps_versus_frame_time.htm)। प्रति फ्रेम (मिली-सेकंड सेकंड) पर स्विच करें। – genpfault
@genpfault धन्यवाद, यह जानना निश्चित रूप से अच्छा है। तथ्य यह है कि उस मामले में वीबीओ धीमा है, हालांकि। –
कुछ ड्राइवर वास्तव में प्रदर्शन सूचियों को संकलित करने में बहुत अच्छे हैं। – JasonD