//// GLBackend.cpp// interface/src/gpu//// Created by Sam Gateau on 10/27/2014.// Copyright 2014 High Fidelity, Inc.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html//#include "GLBackend.h" #include <QDebug> #include "gpu/Batch.h" using namespace gpu; GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = { (&::gpu::GLBackend::do_draw), (&::gpu::GLBackend::do_drawIndexed), (&::gpu::GLBackend::do_drawInstanced), (&::gpu::GLBackend::do_drawIndexedInstanced), (&::gpu::GLBackend::do_setInputFormat), (&::gpu::GLBackend::do_setInputBuffer), (&::gpu::GLBackend::do_setIndexBuffer), (&::gpu::GLBackend::do_setModelTransform), (&::gpu::GLBackend::do_setViewTransform), (&::gpu::GLBackend::do_setProjectionTransform), (&::gpu::GLBackend::do_glEnable), (&::gpu::GLBackend::do_glDisable), (&::gpu::GLBackend::do_glEnableClientState), (&::gpu::GLBackend::do_glDisableClientState), (&::gpu::GLBackend::do_glCullFace), (&::gpu::GLBackend::do_glAlphaFunc), (&::gpu::GLBackend::do_glDepthFunc), (&::gpu::GLBackend::do_glDepthMask), (&::gpu::GLBackend::do_glDepthRange), (&::gpu::GLBackend::do_glBindBuffer), (&::gpu::GLBackend::do_glBindTexture), (&::gpu::GLBackend::do_glActiveTexture), (&::gpu::GLBackend::do_glDrawBuffers), (&::gpu::GLBackend::do_glUseProgram), (&::gpu::GLBackend::do_glUniform1f), (&::gpu::GLBackend::do_glUniform2f), (&::gpu::GLBackend::do_glUniformMatrix4fv), (&::gpu::GLBackend::do_glMatrixMode), (&::gpu::GLBackend::do_glPushMatrix), (&::gpu::GLBackend::do_glPopMatrix), (&::gpu::GLBackend::do_glMultMatrixf), (&::gpu::GLBackend::do_glLoadMatrixf), (&::gpu::GLBackend::do_glLoadIdentity), (&::gpu::GLBackend::do_glRotatef), (&::gpu::GLBackend::do_glScalef), (&::gpu::GLBackend::do_glTranslatef), (&::gpu::GLBackend::do_glDrawArrays), (&::gpu::GLBackend::do_glDrawRangeElements), (&::gpu::GLBackend::do_glColorPointer), (&::gpu::GLBackend::do_glNormalPointer), (&::gpu::GLBackend::do_glTexCoordPointer), (&::gpu::GLBackend::do_glVertexPointer), (&::gpu::GLBackend::do_glVertexAttribPointer), (&::gpu::GLBackend::do_glEnableVertexAttribArray), (&::gpu::GLBackend::do_glDisableVertexAttribArray), (&::gpu::GLBackend::do_glColor4f), (&::gpu::GLBackend::do_glMaterialf), (&::gpu::GLBackend::do_glMaterialfv),}; static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_QUADS,}; static const GLenum _elementTypeToGLType[NUM_TYPES]= { GL_FLOAT, GL_INT, GL_UNSIGNED_INT, GL_HALF_FLOAT, GL_SHORT, GL_UNSIGNED_SHORT, GL_BYTE, GL_UNSIGNED_BYTE, GL_FLOAT, GL_INT, GL_UNSIGNED_INT, GL_HALF_FLOAT, GL_SHORT, GL_UNSIGNED_SHORT, GL_BYTE, GL_UNSIGNED_BYTE}; GLBackend::GLBackend() : _input(), _transform(){ } GLBackend::~GLBackend() { } void GLBackend::renderBatch(Batch& batch) { uint32 numCommands = batch.getCommands().size(); const Batch::Commands::value_type* command = batch.getCommands().data(); const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data(); GLBackend backend; for (unsigned int i = 0; i < numCommands; i++) { CommandCall call = _commandCalls[(*command)]; (backend.*(call))(batch, *offset); command++; offset++; }} void GLBackend::checkGLError() { GLenum error = glGetError(); if (!error) { return; } else { switch (error) { case GL_INVALID_ENUM: qDebug() << "An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag."; break; case GL_INVALID_VALUE: qDebug() << "A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag"; break; case GL_INVALID_OPERATION: qDebug() << "The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag.."; break; case GL_INVALID_FRAMEBUFFER_OPERATION: qDebug() << "The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag."; break; case GL_OUT_OF_MEMORY: qDebug() << "There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded."; break; case GL_STACK_UNDERFLOW: qDebug() << "An attempt has been made to perform an operation that would cause an internal stack to underflow."; break; case GL_STACK_OVERFLOW: qDebug() << "An attempt has been made to perform an operation that would cause an internal stack to overflow."; break; } }} //#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError()#define CHECK_GL_ERROR() void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { updateInput(); updateTransform(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; uint32 numVertices = batch._params[paramOffset + 1]._uint; uint32 startVertex = batch._params[paramOffset + 0]._uint; glDrawArrays(mode, startVertex, numVertices); CHECK_GL_ERROR();} void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { updateInput(); updateTransform(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; uint32 numIndices = batch._params[paramOffset + 1]._uint; uint32 startIndex = batch._params[paramOffset + 0]._uint; GLenum glType = _elementTypeToGLType[_input._indexBufferType]; glDrawElements(mode, numIndices, glType, reinterpret_cast<GLvoid*>(startIndex + _input._indexBufferOffset)); CHECK_GL_ERROR();} void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR();} void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR();} void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) { Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint); if (format != _input._format) { _input._format = format; _input._invalidFormat = true; }} void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) { Offset stride = batch._params[paramOffset + 0]._uint; Offset offset = batch._params[paramOffset + 1]._uint; BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); uint32 channel = batch._params[paramOffset + 3]._uint; if (channel < getNumInputBuffers()) { _input._buffers[channel] = buffer; _input._bufferOffsets[channel] = offset; _input._bufferStrides[channel] = stride; _input._buffersState.set(channel); }} #define SUPPORT_LEGACY_OPENGL#if defined(SUPPORT_LEGACY_OPENGL)static const int NUM_CLASSIC_ATTRIBS = Stream::TANGENT;static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = { GL_VERTEX_ARRAY, GL_NORMAL_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY};#endif void GLBackend::updateInput() { if (_input._invalidFormat || _input._buffersState.any()) { if (_input._invalidFormat) { InputStageState::ActivationCache newActivation; // Check expected activation if (_input._format) { const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) { const Stream::Attribute& attrib = (*it).second; newActivation.set(attrib._slot); } } // Manage Activation what was and what is expected now for (unsigned int i = 0; i < newActivation.size(); i++) { bool newState = newActivation[i]; if (newState != _input._attributeActivation[i]) {#if defined(SUPPORT_LEGACY_OPENGL) if (i < NUM_CLASSIC_ATTRIBS) { if (newState) { glEnableClientState(attributeSlotToClassicAttribName[i]); } else { glDisableClientState(attributeSlotToClassicAttribName[i]); } } else {#else {#endif if (newState) { glEnableVertexAttribArray(i); } else { glDisableVertexAttribArray(i); } } CHECK_GL_ERROR(); _input._attributeActivation.flip(i); } } } // now we need to bind the buffers and assign the attrib pointers if (_input._format) { const Buffers& buffers = _input._buffers; const Offsets& offsets = _input._bufferOffsets; const Offsets& strides = _input._bufferStrides; const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); for (Stream::Format::ChannelMap::const_iterator channelIt = _input._format->getChannels().begin(); channelIt != _input._format->getChannels().end(); channelIt++) { const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second; if ((*channelIt).first < buffers.size()) { int bufferNum = (*channelIt).first; if (_input._buffersState.test(bufferNum) || _input._invalidFormat) { GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum])); glBindBuffer(GL_ARRAY_BUFFER, vbo); CHECK_GL_ERROR(); _input._buffersState[bufferNum] = false; for (unsigned int i = 0; i < channel._slots.size(); i++) { const Stream::Attribute& attrib = attributes.at(channel._slots[i]); GLuint slot = attrib._slot; GLuint count = attrib._element.getDimensionCount(); GLenum type = _elementTypeToGLType[attrib._element.getType()]; GLuint stride = strides[bufferNum]; GLuint pointer = attrib._offset + offsets[bufferNum]; #if defined(SUPPORT_LEGACY_OPENGL) if (slot < NUM_CLASSIC_ATTRIBS) { switch (slot) { case Stream::POSITION: glVertexPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer)); break; case Stream::NORMAL: glNormalPointer(type, stride, reinterpret_cast<GLvoid*>(pointer)); break; case Stream::COLOR: glColorPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer)); break; case Stream::TEXCOORD: glTexCoordPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer)); break; }; } else { #else { #endif GLboolean isNormalized = attrib._element.isNormalized(); glVertexAttribPointer(slot, count, type, isNormalized, stride, reinterpret_cast<GLvoid*>(pointer)); } CHECK_GL_ERROR(); } } } } } // everything format related should be in sync now _input._invalidFormat = false; } /* TODO: Fancy version GL4.4 if (_needInputFormatUpdate) { InputActivationCache newActivation; // Assign the vertex format required if (_inputFormat) { const StreamFormat::AttributeMap& attributes = _inputFormat->getAttributes(); for (StreamFormat::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) { const StreamFormat::Attribute& attrib = (*it).second; newActivation.set(attrib._slot); glVertexAttribFormat( attrib._slot, attrib._element.getDimensionCount(), _elementTypeToGLType[attrib._element.getType()], attrib._element.isNormalized(), attrib._stride); } CHECK_GL_ERROR(); } // Manage Activation what was and what is expected now for (int i = 0; i < newActivation.size(); i++) { bool newState = newActivation[i]; if (newState != _inputAttributeActivation[i]) { if (newState) { glEnableVertexAttribArray(i); } else { glDisableVertexAttribArray(i); } _inputAttributeActivation.flip(i); } } CHECK_GL_ERROR(); _needInputFormatUpdate = false; } if (_needInputStreamUpdate) { if (_inputStream) { const Stream::Buffers& buffers = _inputStream->getBuffers(); const Stream::Offsets& offsets = _inputStream->getOffsets(); const Stream::Strides& strides = _inputStream->getStrides(); for (int i = 0; i < buffers.size(); i++) { GLuint vbo = gpu::GLBackend::getBufferID((*buffers[i])); glBindVertexBuffer(i, vbo, offsets[i], strides[i]); } CHECK_GL_ERROR(); } _needInputStreamUpdate = false; }*/} void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { _input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint; BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint); _input._indexBufferOffset = batch._params[paramOffset + 0]._uint; _input._indexBuffer = indexBuffer; if (indexBuffer) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer)); } else { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } CHECK_GL_ERROR();} // Transform Stage void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { _transform._model = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidModel = true;} void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { _transform._view = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidView = true;} void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { _transform._projection = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidProj = true;} void GLBackend::updateTransform() { if (_transform._invalidProj) { // TODO: implement the projection matrix assignment to gl state /* if (_transform._lastMode != GL_PROJECTION) { glMatrixMode(GL_PROJECTION); _transform._lastMode = GL_PROJECTION; } CHECK_GL_ERROR();*/ } if (_transform._invalidModel || _transform._invalidView) { if (!_transform._model.isIdentity()) { if (_transform._lastMode != GL_MODELVIEW) { glMatrixMode(GL_MODELVIEW); _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; if (!_transform._view.isIdentity()) { Transform mvx; Transform::inverseMult(mvx, _transform._view, _transform._model); mvx.getMatrix(modelView); } else { _transform._model.getMatrix(modelView); } glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { if (!_transform._view.isIdentity()) { if (_transform._lastMode != GL_MODELVIEW) { glMatrixMode(GL_MODELVIEW); _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; _transform._view.getInverseMatrix(modelView); glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { // TODO: eventually do something about the matrix when neither view nor model is specified? // glLoadIdentity(); } } CHECK_GL_ERROR(); _transform._invalidModel = false; _transform._invalidView = false; }} // TODO: As long as we have gl calls explicitely issued from interface// code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API #define ADD_COMMAND_GL(call) _commands.push_back(COMMAND_##call); _commandOffsets.push_back(_params.size()); //#define DO_IT_NOW(call, offset) runLastCommand();#define DO_IT_NOW(call, offset) void Batch::_glEnable(GLenum cap) { ADD_COMMAND_GL(glEnable); _params.push_back(cap); Lines 1–500 of 1111. Load more
// // GLBackend.cpp // interface/src/gpu // // Created by Sam Gateau on 10/27/2014. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "GLBackend.h" #include <QDebug> #include "gpu/Batch.h" using namespace gpu; GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = { (&::gpu::GLBackend::do_draw), (&::gpu::GLBackend::do_drawIndexed), (&::gpu::GLBackend::do_drawInstanced), (&::gpu::GLBackend::do_drawIndexedInstanced), (&::gpu::GLBackend::do_setInputFormat), (&::gpu::GLBackend::do_setInputBuffer), (&::gpu::GLBackend::do_setIndexBuffer), (&::gpu::GLBackend::do_setModelTransform), (&::gpu::GLBackend::do_setViewTransform), (&::gpu::GLBackend::do_setProjectionTransform), (&::gpu::GLBackend::do_glEnable), (&::gpu::GLBackend::do_glDisable), (&::gpu::GLBackend::do_glEnableClientState), (&::gpu::GLBackend::do_glDisableClientState), (&::gpu::GLBackend::do_glCullFace), (&::gpu::GLBackend::do_glAlphaFunc), (&::gpu::GLBackend::do_glDepthFunc), (&::gpu::GLBackend::do_glDepthMask), (&::gpu::GLBackend::do_glDepthRange), (&::gpu::GLBackend::do_glBindBuffer), (&::gpu::GLBackend::do_glBindTexture), (&::gpu::GLBackend::do_glActiveTexture), (&::gpu::GLBackend::do_glDrawBuffers), (&::gpu::GLBackend::do_glUseProgram), (&::gpu::GLBackend::do_glUniform1f), (&::gpu::GLBackend::do_glUniform2f), (&::gpu::GLBackend::do_glUniformMatrix4fv), (&::gpu::GLBackend::do_glMatrixMode), (&::gpu::GLBackend::do_glPushMatrix), (&::gpu::GLBackend::do_glPopMatrix), (&::gpu::GLBackend::do_glMultMatrixf), (&::gpu::GLBackend::do_glLoadMatrixf), (&::gpu::GLBackend::do_glLoadIdentity), (&::gpu::GLBackend::do_glRotatef), (&::gpu::GLBackend::do_glScalef), (&::gpu::GLBackend::do_glTranslatef), (&::gpu::GLBackend::do_glDrawArrays), (&::gpu::GLBackend::do_glDrawRangeElements), (&::gpu::GLBackend::do_glColorPointer), (&::gpu::GLBackend::do_glNormalPointer), (&::gpu::GLBackend::do_glTexCoordPointer), (&::gpu::GLBackend::do_glVertexPointer), (&::gpu::GLBackend::do_glVertexAttribPointer), (&::gpu::GLBackend::do_glEnableVertexAttribArray), (&::gpu::GLBackend::do_glDisableVertexAttribArray), (&::gpu::GLBackend::do_glColor4f), (&::gpu::GLBackend::do_glMaterialf), (&::gpu::GLBackend::do_glMaterialfv), }; static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_QUADS, }; static const GLenum _elementTypeToGLType[NUM_TYPES]= { GL_FLOAT, GL_INT, GL_UNSIGNED_INT, GL_HALF_FLOAT, GL_SHORT, GL_UNSIGNED_SHORT, GL_BYTE, GL_UNSIGNED_BYTE, GL_FLOAT, GL_INT, GL_UNSIGNED_INT, GL_HALF_FLOAT, GL_SHORT, GL_UNSIGNED_SHORT, GL_BYTE, GL_UNSIGNED_BYTE }; GLBackend::GLBackend() : _input(), _transform() { } GLBackend::~GLBackend() { } void GLBackend::renderBatch(Batch& batch) { uint32 numCommands = batch.getCommands().size(); const Batch::Commands::value_type* command = batch.getCommands().data(); const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data(); GLBackend backend; for (unsigned int i = 0; i < numCommands; i++) { CommandCall call = _commandCalls[(*command)]; (backend.*(call))(batch, *offset); command++; offset++; } } void GLBackend::checkGLError() { GLenum error = glGetError(); if (!error) { return; } else { switch (error) { case GL_INVALID_ENUM: qDebug() << "An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag."; break; case GL_INVALID_VALUE: qDebug() << "A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag"; break; case GL_INVALID_OPERATION: qDebug() << "The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag.."; break; case GL_INVALID_FRAMEBUFFER_OPERATION: qDebug() << "The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag."; break; case GL_OUT_OF_MEMORY: qDebug() << "There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded."; break; case GL_STACK_UNDERFLOW: qDebug() << "An attempt has been made to perform an operation that would cause an internal stack to underflow."; break; case GL_STACK_OVERFLOW: qDebug() << "An attempt has been made to perform an operation that would cause an internal stack to overflow."; break; } } } //#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError() #define CHECK_GL_ERROR() void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { updateInput(); updateTransform(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; uint32 numVertices = batch._params[paramOffset + 1]._uint; uint32 startVertex = batch._params[paramOffset + 0]._uint; glDrawArrays(mode, startVertex, numVertices); CHECK_GL_ERROR(); } void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { updateInput(); updateTransform(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; uint32 numIndices = batch._params[paramOffset + 1]._uint; uint32 startIndex = batch._params[paramOffset + 0]._uint; GLenum glType = _elementTypeToGLType[_input._indexBufferType]; glDrawElements(mode, numIndices, glType, reinterpret_cast<GLvoid*>(startIndex + _input._indexBufferOffset)); CHECK_GL_ERROR(); } void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR(); } void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR(); } void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) { Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint); if (format != _input._format) { _input._format = format; _input._invalidFormat = true; } } void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) { Offset stride = batch._params[paramOffset + 0]._uint; Offset offset = batch._params[paramOffset + 1]._uint; BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); uint32 channel = batch._params[paramOffset + 3]._uint; if (channel < getNumInputBuffers()) { _input._buffers[channel] = buffer; _input._bufferOffsets[channel] = offset; _input._bufferStrides[channel] = stride; _input._buffersState.set(channel); } } #define SUPPORT_LEGACY_OPENGL #if defined(SUPPORT_LEGACY_OPENGL) static const int NUM_CLASSIC_ATTRIBS = Stream::TANGENT; static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = { GL_VERTEX_ARRAY, GL_NORMAL_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY }; #endif void GLBackend::updateInput() { if (_input._invalidFormat || _input._buffersState.any()) { if (_input._invalidFormat) { InputStageState::ActivationCache newActivation; // Check expected activation if (_input._format) { const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) { const Stream::Attribute& attrib = (*it).second; newActivation.set(attrib._slot); } } // Manage Activation what was and what is expected now for (unsigned int i = 0; i < newActivation.size(); i++) { bool newState = newActivation[i]; if (newState != _input._attributeActivation[i]) { #if defined(SUPPORT_LEGACY_OPENGL) if (i < NUM_CLASSIC_ATTRIBS) { if (newState) { glEnableClientState(attributeSlotToClassicAttribName[i]); } else { glDisableClientState(attributeSlotToClassicAttribName[i]); } } else { #else { #endif if (newState) { glEnableVertexAttribArray(i); } else { glDisableVertexAttribArray(i); } } CHECK_GL_ERROR(); _input._attributeActivation.flip(i); } } } // now we need to bind the buffers and assign the attrib pointers if (_input._format) { const Buffers& buffers = _input._buffers; const Offsets& offsets = _input._bufferOffsets; const Offsets& strides = _input._bufferStrides; const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); for (Stream::Format::ChannelMap::const_iterator channelIt = _input._format->getChannels().begin(); channelIt != _input._format->getChannels().end(); channelIt++) { const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second; if ((*channelIt).first < buffers.size()) { int bufferNum = (*channelIt).first; if (_input._buffersState.test(bufferNum) || _input._invalidFormat) { GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum])); glBindBuffer(GL_ARRAY_BUFFER, vbo); CHECK_GL_ERROR(); _input._buffersState[bufferNum] = false; for (unsigned int i = 0; i < channel._slots.size(); i++) { const Stream::Attribute& attrib = attributes.at(channel._slots[i]); GLuint slot = attrib._slot; GLuint count = attrib._element.getDimensionCount(); GLenum type = _elementTypeToGLType[attrib._element.getType()]; GLuint stride = strides[bufferNum]; GLuint pointer = attrib._offset + offsets[bufferNum]; #if defined(SUPPORT_LEGACY_OPENGL) if (slot < NUM_CLASSIC_ATTRIBS) { switch (slot) { case Stream::POSITION: glVertexPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer)); break; case Stream::NORMAL: glNormalPointer(type, stride, reinterpret_cast<GLvoid*>(pointer)); break; case Stream::COLOR: glColorPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer)); break; case Stream::TEXCOORD: glTexCoordPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer)); break; }; } else { #else { #endif GLboolean isNormalized = attrib._element.isNormalized(); glVertexAttribPointer(slot, count, type, isNormalized, stride, reinterpret_cast<GLvoid*>(pointer)); } CHECK_GL_ERROR(); } } } } } // everything format related should be in sync now _input._invalidFormat = false; } /* TODO: Fancy version GL4.4 if (_needInputFormatUpdate) { InputActivationCache newActivation; // Assign the vertex format required if (_inputFormat) { const StreamFormat::AttributeMap& attributes = _inputFormat->getAttributes(); for (StreamFormat::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) { const StreamFormat::Attribute& attrib = (*it).second; newActivation.set(attrib._slot); glVertexAttribFormat( attrib._slot, attrib._element.getDimensionCount(), _elementTypeToGLType[attrib._element.getType()], attrib._element.isNormalized(), attrib._stride); } CHECK_GL_ERROR(); } // Manage Activation what was and what is expected now for (int i = 0; i < newActivation.size(); i++) { bool newState = newActivation[i]; if (newState != _inputAttributeActivation[i]) { if (newState) { glEnableVertexAttribArray(i); } else { glDisableVertexAttribArray(i); } _inputAttributeActivation.flip(i); } } CHECK_GL_ERROR(); _needInputFormatUpdate = false; } if (_needInputStreamUpdate) { if (_inputStream) { const Stream::Buffers& buffers = _inputStream->getBuffers(); const Stream::Offsets& offsets = _inputStream->getOffsets(); const Stream::Strides& strides = _inputStream->getStrides(); for (int i = 0; i < buffers.size(); i++) { GLuint vbo = gpu::GLBackend::getBufferID((*buffers[i])); glBindVertexBuffer(i, vbo, offsets[i], strides[i]); } CHECK_GL_ERROR(); } _needInputStreamUpdate = false; } */ } void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { _input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint; BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint); _input._indexBufferOffset = batch._params[paramOffset + 0]._uint; _input._indexBuffer = indexBuffer; if (indexBuffer) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer)); } else { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } CHECK_GL_ERROR(); } // Transform Stage void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { _transform._model = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidModel = true; } void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { _transform._view = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidView = true; } void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { _transform._projection = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidProj = true; } void GLBackend::updateTransform() { if (_transform._invalidProj) { // TODO: implement the projection matrix assignment to gl state /* if (_transform._lastMode != GL_PROJECTION) { glMatrixMode(GL_PROJECTION); _transform._lastMode = GL_PROJECTION; } CHECK_GL_ERROR();*/ } if (_transform._invalidModel || _transform._invalidView) { if (!_transform._model.isIdentity()) { if (_transform._lastMode != GL_MODELVIEW) { glMatrixMode(GL_MODELVIEW); _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; if (!_transform._view.isIdentity()) { Transform mvx; Transform::inverseMult(mvx, _transform._view, _transform._model); mvx.getMatrix(modelView); } else { _transform._model.getMatrix(modelView); } glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { if (!_transform._view.isIdentity()) { if (_transform._lastMode != GL_MODELVIEW) { glMatrixMode(GL_MODELVIEW); _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; _transform._view.getInverseMatrix(modelView); glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { // TODO: eventually do something about the matrix when neither view nor model is specified? // glLoadIdentity(); } } CHECK_GL_ERROR(); _transform._invalidModel = false; _transform._invalidView = false; } } // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API #define ADD_COMMAND_GL(call) _commands.push_back(COMMAND_##call); _commandOffsets.push_back(_params.size()); //#define DO_IT_NOW(call, offset) runLastCommand(); #define DO_IT_NOW(call, offset) void Batch::_glEnable(GLenum cap) { ADD_COMMAND_GL(glEnable); _params.push_back(cap);