In the source of SFML 2.0, in void RenderTarget::draw(...), I see this code:
void RenderTarget::draw(const Vertex* vertices, unsigned int vertexCount,
PrimitiveType type, const RenderStates& states)
{
// Nothing to draw?
if (!vertices || (vertexCount == 0))
return;
if (activate(true))
{
// First set the persistent OpenGL states if it's the very first call
if (!m_cache.glStatesSet)
resetGLStates();
// Check if the vertex count is low enough so that we can pre-transform them
bool useVertexCache = (vertexCount <= StatesCache::VertexCacheSize);
if (useVertexCache)
{
// Pre-transform the vertices and store them into the vertex cache
for (unsigned int i = 0; i < vertexCount; ++i)
{
Vertex& vertex = m_cache.vertexCache[i];
vertex.position = states.transform * vertices[i].position;
vertex.color = vertices[i].color;
vertex.texCoords = vertices[i].texCoords;
}
// Since vertices are transformed, we must use an identity transform to render them
if (!m_cache.useVertexCache)
applyTransform(Transform::Identity);
}
else
{
applyTransform(states.transform);
}
// Apply the view
if (m_cache.viewChanged)
applyCurrentView();
// Apply the blend mode
if (states.blendMode != m_cache.lastBlendMode)
applyBlendMode(states.blendMode);
// Apply the texture
Uint64 textureId = states.texture ? states.texture->m_cacheId : 0;
if (textureId != m_cache.lastTextureId)
applyTexture(states.texture);
// Apply the shader
if (states.shader)
applyShader(states.shader);
// If we pre-transform the vertices, we must use our internal vertex cache
if (useVertexCache)
{
// ... and if we already used it previously, we don't need to set the pointers again
if (!m_cache.useVertexCache)
vertices = m_cache.vertexCache;
else
vertices = NULL;
}
// Setup the pointers to the vertices' components
if (vertices)
{
const char* data = reinterpret_cast<const char*>(vertices);
glCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), data + 0));
glCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), data + 8));
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
}
// Find the OpenGL primitive type
static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
GLenum mode = modes[type];
// Draw the primitives
glCheck(glDrawArrays(mode, 0, vertexCount));
// Unbind the shader, if any
if (states.shader)
applyShader(NULL);
// Update the cache
m_cache.useVertexCache = useVertexCache;
}
}
That makes me curious. If it's bad for performance to change shaders and textures, so developers try to reduce those calls as much as possible, why does SFML unbind the shader after every draw call?
Is this a precaution incase the user of SFML lets the sf::Shader go out of scope?
Does the unbinding and then rebinding of the same shader cause a small hit to the performance?
I also noticed the sf::Texture getting bound, but not later unbound. Why is the sf::Shader unbound after the call, but not the sf::Texture?
I use SFML alot, and I'm an OpenGL noob trying to learn it, and I just encountered this in SFML's source and was curious.
If my code is entirely positive that the sf::Shader won't get destructed between two draw calls, do I still have to unbind it between them?
Also, do shaders ever need to be unbound when the program ends, or can I leave the last used shader bound? e.g. is it like calling delete() on what you new(), and important unbinding-processes are occuring, or is 'unbinding' just saying, "use the default shader" and not actually required to clean up when the program is exiting?