mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 21:36:47 +02:00
325 lines
12 KiB
C++
325 lines
12 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"
|
|
|
|
using namespace gpu;
|
|
using namespace gpu::gl;
|
|
|
|
void GLBackend::do_setInputFormat(Batch& batch, size_t 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, size_t 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()) {
|
|
bool isModified = false;
|
|
if (_input._buffers[channel] != buffer) {
|
|
_input._buffers[channel] = buffer;
|
|
|
|
GLuint vbo = 0;
|
|
if (buffer) {
|
|
vbo = getBufferID((*buffer));
|
|
}
|
|
_input._bufferVBOs[channel] = vbo;
|
|
|
|
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;
|
|
_input._indexBuffer.reset();
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
(void) CHECK_GL_ERROR();
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
|
|
for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) {
|
|
glDisableVertexAttribArray(i);
|
|
glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
|
}
|
|
|
|
// Reset vertex buffer and format
|
|
_input._format.reset();
|
|
_input._invalidFormat = false;
|
|
_input._attributeActivation.reset();
|
|
|
|
for (uint32_t i = 0; i < _input._buffers.size(); i++) {
|
|
_input._buffers[i].reset();
|
|
_input._bufferOffsets[i] = 0;
|
|
_input._bufferStrides[i] = 0;
|
|
_input._bufferVBOs[i] = 0;
|
|
}
|
|
_input._invalidBuffers.reset();
|
|
|
|
}
|
|
|
|
void GLBackend::do_setIndexBuffer(Batch& batch, size_t paramOffset) {
|
|
_input._indexBufferType = (Type)batch._params[paramOffset + 2]._uint;
|
|
_input._indexBufferOffset = batch._params[paramOffset + 0]._uint;
|
|
|
|
BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
|
|
if (indexBuffer != _input._indexBuffer) {
|
|
_input._indexBuffer = indexBuffer;
|
|
if (indexBuffer) {
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*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(Batch& batch, size_t paramOffset) {
|
|
_input._indirectBufferOffset = batch._params[paramOffset + 1]._uint;
|
|
_input._indirectBufferStride = batch._params[paramOffset + 2]._uint;
|
|
|
|
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset]._uint);
|
|
if (buffer != _input._indirectBuffer) {
|
|
_input._indirectBuffer = buffer;
|
|
if (buffer) {
|
|
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferID(*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();
|
|
}
|
|
|
|
|
|
// Core 41 doesn't expose the features to really separate the vertex format from the vertex buffers binding
|
|
// Core 43 does :)
|
|
// FIXME crashing problem with glVertexBindingDivisor / glVertexAttribFormat
|
|
// Once resolved, break this up into the GL 4.1 and 4.5 backends
|
|
#if 1 || (GPU_INPUT_PROFILE == GPU_CORE_41)
|
|
#define NO_SUPPORT_VERTEX_ATTRIB_FORMAT
|
|
#else
|
|
#define SUPPORT_VERTEX_ATTRIB_FORMAT
|
|
#endif
|
|
|
|
void GLBackend::updateInput() {
|
|
#if defined(SUPPORT_VERTEX_ATTRIB_FORMAT)
|
|
if (_input._invalidFormat) {
|
|
|
|
InputStageState::ActivationCache newActivation;
|
|
|
|
// Assign the vertex format required
|
|
if (_input._format) {
|
|
for (auto& it : _input._format->getAttributes()) {
|
|
const Stream::Attribute& attrib = (it).second;
|
|
|
|
GLuint slot = attrib._slot;
|
|
GLuint count = attrib._element.getLocationScalarCount();
|
|
uint8_t locationCount = attrib._element.getLocationCount();
|
|
GLenum type = _elementTypeToGL41Type[attrib._element.getType()];
|
|
GLuint offset = attrib._offset;;
|
|
GLboolean isNormalized = attrib._element.isNormalized();
|
|
|
|
GLenum perLocationSize = attrib._element.getLocationSize();
|
|
|
|
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
|
|
newActivation.set(slot + locNum);
|
|
glVertexAttribFormat(slot + locNum, count, type, isNormalized, offset + locNum * perLocationSize);
|
|
glVertexAttribBinding(slot + locNum, attrib._channel);
|
|
}
|
|
glVertexBindingDivisor(attrib._channel, attrib._frequency);
|
|
}
|
|
(void)CHECK_GL_ERROR();
|
|
}
|
|
|
|
// Manage Activation what was and what is expected now
|
|
for (size_t i = 0; i < 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()) {
|
|
int numBuffers = _input._buffers.size();
|
|
auto buffer = _input._buffers.data();
|
|
auto vbo = _input._bufferVBOs.data();
|
|
auto offset = _input._bufferOffsets.data();
|
|
auto stride = _input._bufferStrides.data();
|
|
|
|
for (int bufferNum = 0; bufferNum < numBuffers; bufferNum++) {
|
|
if (_input._invalidBuffers.test(bufferNum)) {
|
|
glBindVertexBuffer(bufferNum, (*vbo), (*offset), (*stride));
|
|
}
|
|
buffer++;
|
|
vbo++;
|
|
offset++;
|
|
stride++;
|
|
}
|
|
_input._invalidBuffers.reset();
|
|
(void)CHECK_GL_ERROR();
|
|
}
|
|
#else
|
|
if (_input._invalidFormat || _input._invalidBuffers.any()) {
|
|
|
|
if (_input._invalidFormat) {
|
|
InputStageState::ActivationCache newActivation;
|
|
|
|
_stats._ISNumFormatChanges++;
|
|
|
|
// Check expected activation
|
|
if (_input._format) {
|
|
for (auto& it : _input._format->getAttributes()) {
|
|
const Stream::Attribute& attrib = (it).second;
|
|
uint8_t locationCount = attrib._element.getLocationCount();
|
|
for (int i = 0; i < locationCount; ++i) {
|
|
newActivation.set(attrib._slot + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 (newState) {
|
|
glEnableVertexAttribArray(i);
|
|
} else {
|
|
glDisableVertexAttribArray(i);
|
|
}
|
|
(void)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();
|
|
auto& inputChannels = _input._format->getChannels();
|
|
_stats._ISNumInputBufferChanges++;
|
|
|
|
GLuint boundVBO = 0;
|
|
for (auto& channelIt : inputChannels) {
|
|
const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second;
|
|
if ((channelIt).first < buffers.size()) {
|
|
int bufferNum = (channelIt).first;
|
|
|
|
if (_input._invalidBuffers.test(bufferNum) || _input._invalidFormat) {
|
|
// GLuint vbo = gpu::GL41Backend::getBufferID((*buffers[bufferNum]));
|
|
GLuint vbo = _input._bufferVBOs[bufferNum];
|
|
if (boundVBO != vbo) {
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
(void)CHECK_GL_ERROR();
|
|
boundVBO = vbo;
|
|
}
|
|
_input._invalidBuffers[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.getLocationScalarCount();
|
|
uint8_t locationCount = attrib._element.getLocationCount();
|
|
GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()];
|
|
// GLenum perLocationStride = strides[bufferNum];
|
|
GLenum perLocationStride = attrib._element.getLocationSize();
|
|
GLuint stride = (GLuint)strides[bufferNum];
|
|
GLuint pointer = (GLuint)(attrib._offset + offsets[bufferNum]);
|
|
GLboolean isNormalized = attrib._element.isNormalized();
|
|
|
|
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
|
|
glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride,
|
|
reinterpret_cast<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
|
|
glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency);
|
|
}
|
|
|
|
// TODO: Support properly the IAttrib version
|
|
|
|
(void)CHECK_GL_ERROR();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// everything format related should be in sync now
|
|
_input._invalidFormat = false;
|
|
}
|
|
#endif
|
|
}
|
|
|