265 lines · 9.7 KB · C++
RawDownload
////  GLBackendInput.cpp//  libraries/gpu/src/gpu////  Created by Sam Gateau on 3/8/2015.//  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 "GLShared.h"#include "GLInputFormat.h"#include "GLBuffer.h" using namespace gpu;using namespace gpu::gl; void GLBackend::do_setInputFormat(const Batch& batch, size_t paramOffset) {    const auto& format = batch._streamFormats.get(batch._params[paramOffset]._uint);    if (!compare(_input._format, format)) {        if (format) {            assign(_input._format, format);            auto inputFormat = GLInputFormat::sync((*format));            assert(inputFormat);            if (_input._formatKey != inputFormat->key) {                _input._formatKey = inputFormat->key;                _input._invalidFormat = true;            }        } else {            reset(_input._format);            _input._formatKey.clear();            _input._invalidFormat = true;        }    }} void GLBackend::do_setInputBuffer(const Batch& batch, size_t paramOffset) {    Offset stride = batch._params[paramOffset + 0]._uint;    Offset offset = batch._params[paramOffset + 1]._uint;    const auto& buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);    uint32 channel = batch._params[paramOffset + 3]._uint;     if (channel < getNumInputBuffers()) {        bool isModified = false;        if (!compare(_input._buffers[channel], buffer)) {            assign(_input._buffers[channel], buffer);            _input._bufferVBOs[channel] = getBufferIDUnsynced((*buffer));            isModified = true;        }         if (_input._bufferOffsets[channel] != offset) {            _input._bufferOffsets[channel] = offset;            isModified = true;        }         if (_input._bufferStrides[channel] != stride) {            _input._bufferStrides[channel] = stride;            isModified = true;        }         if (isModified) {            _input._invalidBuffers.set(channel);        }    }} void GLBackend::initInput() {    if(!_input._defaultVAO) {        glGenVertexArrays(1, &_input._defaultVAO);    }    glBindVertexArray(_input._defaultVAO);    (void) CHECK_GL_ERROR();} void GLBackend::killInput() {    glBindVertexArray(0);        if(_input._defaultVAO) {        glDeleteVertexArrays(1, &_input._defaultVAO);    }    (void) CHECK_GL_ERROR();} void GLBackend::syncInputStateCache() {    for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) {        GLint active = 0;        glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &active);        _input._attributeActivation[i] = active;    }    //_input._defaultVAO    glBindVertexArray(_input._defaultVAO);} void GLBackend::resetInputStage() {    // Reset index buffer    _input._indexBufferType = UINT32;    _input._indexBufferOffset = 0;    reset(_input._indexBuffer);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);    (void) CHECK_GL_ERROR();     // Reset vertex buffer and format    reset(_input._format);    _input._formatKey.clear();    _input._invalidFormat = false;    _input._attributeActivation.reset();     for (uint32_t i = 0; i < _input._buffers.size(); i++) {        reset(_input._buffers[i]);        _input._bufferOffsets[i] = 0;        _input._bufferStrides[i] = 0;        _input._bufferVBOs[i] = 0;    }    _input._invalidBuffers.reset();     // THe vertex array binding MUST be reset in the specific Backend versions as they use different techniques} void GLBackend::do_setIndexBuffer(const Batch& batch, size_t paramOffset) {    _input._indexBufferType = (Type)batch._params[paramOffset + 2]._uint;    _input._indexBufferOffset = batch._params[paramOffset + 0]._uint;     const auto& indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);    if (!compare(_input._indexBuffer, indexBuffer)) {        assign(_input._indexBuffer, indexBuffer);        if (indexBuffer) {            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferIDUnsynced(*indexBuffer));        } else {            // FIXME do we really need this?  Is there ever a draw call where we care that the element buffer is null?            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);        }    }    (void) CHECK_GL_ERROR();} void GLBackend::do_setIndirectBuffer(const Batch& batch, size_t paramOffset) {    _input._indirectBufferOffset = batch._params[paramOffset + 1]._uint;    _input._indirectBufferStride = batch._params[paramOffset + 2]._uint;     const auto& buffer = batch._buffers.get(batch._params[paramOffset]._uint);    if (!compare(_input._indirectBuffer, buffer)) {        assign(_input._indirectBuffer, buffer);        if (buffer) {            glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferIDUnsynced(*buffer));        } else {            // FIXME do we really need this?  Is there ever a draw call where we care that the element buffer is null?            glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);        }    }     (void)CHECK_GL_ERROR();} void GLBackend::updateInput() {    bool isStereoNow = isStereo();    // track stereo state change potentially happening without changing the input format    // this is a rare case requesting to invalid the format#ifdef GPU_STEREO_DRAWCALL_INSTANCED    _input._invalidFormat |= (isStereoNow != _input._lastUpdateStereoState);#endif    _input._lastUpdateStereoState = isStereoNow;     if (_input._invalidFormat) {        InputStageState::ActivationCache newActivation;         // Assign the vertex format required        auto format = acquire(_input._format);        if (format) {            _input._attribBindingBuffers.reset();             const auto& attributes = format->getAttributes();            const auto& inputChannels = format->getChannels();            for (auto& channelIt : inputChannels) {                auto bufferChannelNum = (channelIt).first;                const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second;                _input._attribBindingBuffers.set(bufferChannelNum);                 GLuint frequency = 0;                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.getLocationScalarCount();                    uint8_t locationCount = attrib._element.getLocationCount();                    GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()];                     GLuint offset = (GLuint)attrib._offset;                    GLboolean isNormalized = attrib._element.isNormalized();                     GLenum perLocationSize = attrib._element.getLocationSize();                     for (GLuint locNum = 0; locNum < locationCount; ++locNum) {                        GLuint attriNum = (GLuint)(slot + locNum);                        newActivation.set(attriNum);                        if (!_input._attributeActivation[attriNum]) {                            _input._attributeActivation.set(attriNum);                            glEnableVertexAttribArray(attriNum);                        }                        if (attrib._element.isInteger()) {                            glVertexAttribIFormat(attriNum, count, type, offset + locNum * perLocationSize);                        } else {                            glVertexAttribFormat(attriNum, count, type, isNormalized, offset + locNum * perLocationSize);                        }                        glVertexAttribBinding(attriNum, attrib._channel);                    }                     if (i == 0) {                        frequency = attrib._frequency;                    } else {                        assert(frequency == attrib._frequency);                    }                      (void)CHECK_GL_ERROR();                }#ifdef GPU_STEREO_DRAWCALL_INSTANCED                glVertexBindingDivisor(bufferChannelNum, frequency * (isStereoNow ? 2 : 1));#else                glVertexBindingDivisor(bufferChannelNum, frequency);#endif            }        }         // Manage Activation what was and what is expected now        // This should only disable VertexAttribs since the one needed by the vertex format (if it exists) have been enabled above        for (GLuint i = 0; i < (GLuint)newActivation.size(); i++) {            bool newState = newActivation[i];            if (newState != _input._attributeActivation[i]) {                if (newState) {                    glEnableVertexAttribArray(i);                } else {                    glDisableVertexAttribArray(i);                }                _input._attributeActivation.flip(i);            }        }        (void)CHECK_GL_ERROR();         _input._invalidFormat = false;        _stats._ISNumFormatChanges++;    }     if (_input._invalidBuffers.any()) {        auto vbo = _input._bufferVBOs.data();        auto offset = _input._bufferOffsets.data();        auto stride = _input._bufferStrides.data();         // Profile the count of buffers to update and use it to short cut the for loop        int numInvalids = (int) _input._invalidBuffers.count();        _stats._ISNumInputBufferChanges += numInvalids;         for (GLuint buffer = 0; buffer < _input._buffers.size(); buffer++, vbo++, offset++, stride++) {            if (_input._invalidBuffers.test(buffer)) {                glBindVertexBuffer(buffer, (*vbo), (*offset), (GLsizei)(*stride));                numInvalids--;                if (numInvalids <= 0) {                    break;                }            }        }         _input._invalidBuffers.reset();        (void)CHECK_GL_ERROR();    }}