mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-15 20:36:50 +02:00
279 lines
10 KiB
C++
279 lines
10 KiB
C++
//
|
|
// 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) {
|
|
bool hasColorAttribute{ false };
|
|
|
|
_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();
|
|
|
|
hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR);
|
|
|
|
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
|
|
}
|
|
|
|
if (_input._hadColorAttribute && !hasColorAttribute) {
|
|
// The previous input stage had a color attribute but this one doesn't so reset
|
|
// color to pure white.
|
|
const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
|
glVertexAttrib4fv(Stream::COLOR, &white.r);
|
|
_input._colorAttribute = white;
|
|
}
|
|
_input._hadColorAttribute = hasColorAttribute;
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
}
|
|
|