diff --git a/CMakeLists.txt b/CMakeLists.txt index aa2c353453..406fb5aeb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,6 +210,7 @@ endforeach() file(GLOB_RECURSE JS_SRC scripts/*.js) add_custom_target(js SOURCES ${JS_SRC}) +GroupSources("scripts") if (UNIX) install( diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index ac44be18f2..0006bdd778 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -65,6 +65,7 @@ set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") file(GLOB_RECURSE QML_SRC resources/qml/*.qml resources/qml/*.js) add_custom_target(qml SOURCES ${QML_SRC}) +GroupSources("resources/qml") if (UNIX) install( diff --git a/interface/resources/sounds/snap.wav b/interface/resources/sounds/snap.wav index bb562e1db9..e5b86c0c71 100644 Binary files a/interface/resources/sounds/snap.wav and b/interface/resources/sounds/snap.wav differ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d7005f2c0d..fbf28a8d99 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -594,7 +594,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _aboutToQuit(false), _notifiedPacketVersionMismatchThisDomain(false), _maxOctreePPS(maxOctreePacketsPerSecond.get()), - _lastFaceTrackerUpdate(0) + _lastFaceTrackerUpdate(0), + _snapshotSound(nullptr) { auto steamClient = PluginManager::getInstance()->getSteamClientPlugin(); setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); @@ -1454,6 +1455,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return entityServerNode && !isPhysicsEnabled(); }); + QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); + _snapshotSound = DependencyManager::get()->getSound(QUrl::fromLocalFile(inf.absoluteFilePath())); + QVariant testProperty = property(hifi::properties::TEST); qDebug() << testProperty; if (testProperty.isValid()) { @@ -1776,12 +1780,17 @@ void Application::cleanupBeforeQuit() { // stop QML DependencyManager::destroy(); + if (_snapshotSoundInjector != nullptr) { + _snapshotSoundInjector->stop(); + } + // stop audio after QML, as there are unexplained audio crashes originating in qtwebengine // stop the AudioClient, synchronously QMetaObject::invokeMethod(DependencyManager::get().data(), "stop", Qt::BlockingQueuedConnection); + // destroy Audio so it and its threads have a chance to go down safely DependencyManager::destroy(); DependencyManager::destroy(); @@ -6406,15 +6415,24 @@ void Application::loadAddAvatarBookmarkDialog() const { } void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio) { - postLambdaEvent([notify, includeAnimated, aspectRatio, this] { - QMediaPlayer* player = new QMediaPlayer(); - QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); - player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath())); - player->play(); + + //keep sound thread out of event loop scope + AudioInjectorOptions options; + options.localOnly = true; + options.stereo = true; + + if (_snapshotSoundInjector) { + _snapshotSoundInjector->setOptions(options); + _snapshotSoundInjector->restart(); + } else { + QByteArray samples = _snapshotSound->getByteArray(); + _snapshotSoundInjector = AudioInjector::playSound(samples, options); + } + + postLambdaEvent([notify, includeAnimated, aspectRatio, this] { // Get a screenshot and save it QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio)); - // If we're not doing an animated snapshot as well... if (!includeAnimated || !(SnapshotAnimated::alsoTakeAnimatedSnapshot.get())) { // Tell the dependency manager that the capture of the still snapshot has taken place. @@ -6425,6 +6443,7 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa } }); } + void Application::shareSnapshot(const QString& path, const QUrl& href) { postLambdaEvent([path, href] { // not much to do here, everything is done in snapshot code... diff --git a/interface/src/Application.h b/interface/src/Application.h index 55c8303905..dff1de2860 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -73,6 +73,7 @@ #include #include +#include "Sound.h" class OffscreenGLCanvas; class GLCanvas; @@ -80,6 +81,7 @@ class FaceTracker; class MainWindow; class AssetUpload; class CompositorHelper; +class AudioInjector; namespace controller { class StateController; @@ -683,6 +685,8 @@ private: QTimer _addAssetToWorldErrorTimer; FileScriptingInterface* _fileDownload; + AudioInjector* _snapshotSoundInjector { nullptr }; + SharedSoundPointer _snapshotSound; }; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 0c11fa456d..81a5bf38dc 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -242,7 +242,7 @@ void SkeletonModel::updateAttitude() { void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { updateAttitude(); if (fullUpdate) { - setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); + setBlendshapeCoefficients(_owningAvatar->getHead()->getSummedBlendshapeCoefficients()); Model::simulate(deltaTime, fullUpdate); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9802630cf5..20894104ff 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -967,6 +967,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { const int coefficientsSize = sizeof(float) * numCoefficients; PACKET_READ_CHECK(FaceTrackerCoefficients, coefficientsSize); _headData->_blendshapeCoefficients.resize(numCoefficients); // make sure there's room for the copy! + _headData->_baseBlendshapeCoefficients.resize(numCoefficients); memcpy(_headData->_blendshapeCoefficients.data(), sourceBuffer, coefficientsSize); sourceBuffer += coefficientsSize; int numBytesRead = sourceBuffer - startSection; diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index 909c6a613e..271ce133a2 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -38,6 +39,8 @@ HeadData::HeadData(AvatarData* owningAvatar) : _rightEyeBlink(0.0f), _averageLoudness(0.0f), _browAudioLift(0.0f), + _baseBlendshapeCoefficients(QVector(0, 0.0f)), + _currBlendShapeCoefficients(QVector(0, 0.0f)), _owningAvatar(owningAvatar) { @@ -86,6 +89,24 @@ static const QMap& getBlendshapesLookupMap() { return blendshapeLookupMap; } +const QVector& HeadData::getSummedBlendshapeCoefficients() { + int maxSize = std::max(_baseBlendshapeCoefficients.size(), _blendshapeCoefficients.size()); + if (_currBlendShapeCoefficients.size() != maxSize) { + _currBlendShapeCoefficients.resize(maxSize); + } + + for (int i = 0; i < maxSize; i++) { + if (i >= _baseBlendshapeCoefficients.size()) { + _currBlendShapeCoefficients[i] = _blendshapeCoefficients[i]; + } else if (i >= _blendshapeCoefficients.size()) { + _currBlendShapeCoefficients[i] = _baseBlendshapeCoefficients[i]; + } else { + _currBlendShapeCoefficients[i] = _baseBlendshapeCoefficients[i] + _blendshapeCoefficients[i]; + } + } + + return _currBlendShapeCoefficients; +} void HeadData::setBlendshape(QString name, float val) { const auto& blendshapeLookupMap = getBlendshapesLookupMap(); @@ -96,7 +117,10 @@ void HeadData::setBlendshape(QString name, float val) { if (_blendshapeCoefficients.size() <= it.value()) { _blendshapeCoefficients.resize(it.value() + 1); } - _blendshapeCoefficients[it.value()] = val; + if (_baseBlendshapeCoefficients.size() <= it.value()) { + _baseBlendshapeCoefficients.resize(it.value() + 1); + } + _baseBlendshapeCoefficients[it.value()] = val; } } diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index 6c468daefd..dbed0a6a65 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -59,6 +59,7 @@ public: void setBlendshape(QString name, float val); const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + const QVector& getSummedBlendshapeCoefficients(); void setBlendshapeCoefficients(const QVector& blendshapeCoefficients) { _blendshapeCoefficients = blendshapeCoefficients; } const glm::vec3& getLookAtPosition() const { return _lookAtPosition; } @@ -92,6 +93,8 @@ protected: float _browAudioLift; QVector _blendshapeCoefficients; + QVector _baseBlendshapeCoefficients; + QVector _currBlendShapeCoefficients; AvatarData* _owningAvatar; private: diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 52c689ec00..4c9e53c037 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -592,7 +592,7 @@ void HmdDisplayPlugin::OverlayRenderer::updatePipeline() { auto ps = gpu::Shader::createPixel(fsSource.toLocal8Bit().toStdString()); auto program = gpu::Shader::createProgram(vs, ps); gpu::gl::GLBackend::makeProgram(*program, gpu::Shader::BindingSet()); - this->uniformsLocation = program->getBuffers().findLocation("overlayBuffer"); + this->uniformsLocation = program->getUniformBuffers().findLocation("overlayBuffer"); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(gpu::State::DepthTest(false)); diff --git a/libraries/gl/src/gl/GLShaders.cpp b/libraries/gl/src/gl/GLShaders.cpp index 3487ae5d25..fd0c6788cb 100644 --- a/libraries/gl/src/gl/GLShaders.cpp +++ b/libraries/gl/src/gl/GLShaders.cpp @@ -6,9 +6,9 @@ namespace gl { #ifdef SEPARATE_PROGRAM - bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject) { + bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error) { #else - bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject) { + bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error) { #endif if (shaderSource.empty()) { qCDebug(glLogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create"; @@ -69,6 +69,8 @@ namespace gl { } qCWarning(glLogging) << "GLShader::compileShader - errors:"; qCWarning(glLogging) << temp; + + error = std::string(temp); delete[] temp; glDeleteShader(glshader); @@ -130,7 +132,7 @@ namespace gl { return true; } -GLuint compileProgram(const std::vector& glshaders) { +GLuint compileProgram(const std::vector& glshaders, std::string& error) { // A brand new program: GLuint glprogram = glCreateProgram(); if (!glprogram) { @@ -170,6 +172,9 @@ GLuint compileProgram(const std::vector& glshaders) { qCDebug(glLogging) << "GLShader::compileProgram - failed to LINK the gl program object :"; qCDebug(glLogging) << temp; + error = std::string(temp); + delete[] temp; + /* filestream.open("debugshader.glsl.info.txt"); if (filestream.is_open()) { diff --git a/libraries/gl/src/gl/GLShaders.h b/libraries/gl/src/gl/GLShaders.h index b8c8b6770b..a6213fd280 100644 --- a/libraries/gl/src/gl/GLShaders.h +++ b/libraries/gl/src/gl/GLShaders.h @@ -17,12 +17,12 @@ namespace gl { #ifdef SEPARATE_PROGRAM - bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject); + bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error); #else - bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject); + bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error); #endif - GLuint compileProgram(const std::vector& glshaders); + GLuint compileProgram(const std::vector& glshaders, std::string& error); } diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index d0db376a9d..1210112a78 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -101,6 +101,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_setStateScissorRect), (&::gpu::gl::GLBackend::do_setUniformBuffer), + (&::gpu::gl::GLBackend::do_setResourceBuffer), (&::gpu::gl::GLBackend::do_setResourceTexture), (&::gpu::gl::GLBackend::do_setFramebuffer), diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 76c950ec2b..1c6cffb575 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -93,6 +93,8 @@ public: // this is the maximum per shader stage on the low end apple // TODO make it platform dependant at init time + static const int MAX_NUM_RESOURCE_BUFFERS = 16; + size_t getMaxNumResourceBuffers() const { return MAX_NUM_RESOURCE_BUFFERS; } static const int MAX_NUM_RESOURCE_TEXTURES = 16; size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } @@ -122,6 +124,7 @@ public: virtual void do_setUniformBuffer(const Batch& batch, size_t paramOffset) final; // Resource Stage + virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final; // Pipeline Stage @@ -357,13 +360,19 @@ protected: void releaseUniformBuffer(uint32_t slot); void resetUniformStage(); - + + // update resource cache and do the gl bind/unbind call with the current gpu::Buffer cached at slot s + // This is using different gl object depending on the gl version + virtual bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) = 0; + virtual void releaseResourceBuffer(uint32_t slot) = 0; + // update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s void releaseResourceTexture(uint32_t slot); void resetResourceStage(); struct ResourceStageState { + std::array _buffers; std::array _textures; //Textures _textures { { MAX_NUM_RESOURCE_TEXTURES } }; int findEmptyTextureSlot() const; @@ -400,6 +409,28 @@ protected: } } _pipeline; + // Backend dependant compilation of the shader + virtual GLShader* compileBackendProgram(const Shader& program); + virtual GLShader* compileBackendShader(const Shader& shader); + virtual std::string getBackendShaderHeader() const; + virtual void makeProgramBindings(ShaderObject& shaderObject); + class ElementResource { + public: + gpu::Element _element; + uint16 _resource; + ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {} + }; + ElementResource getFormatFromGLUniform(GLenum gltype); + static const GLint UNUSED_SLOT {-1}; + static bool isUnusedSlot(GLint binding) { return (binding == UNUSED_SLOT); } + virtual int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, + Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers); + virtual int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers); + virtual int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& resourceBuffers) = 0; + virtual int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs); + virtual int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs); + + // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncOutputStateCache(); void resetOutputStage(); @@ -425,6 +456,7 @@ protected: static CommandCall _commandCalls[Batch::NUM_COMMANDS]; friend class GLState; friend class GLTexture; + friend class GLShader; }; } } diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp index 1dad72dbc1..1d1f92b297 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp @@ -191,11 +191,45 @@ void GLBackend::releaseResourceTexture(uint32_t slot) { } void GLBackend::resetResourceStage() { + for (uint32_t i = 0; i < _resource._buffers.size(); i++) { + releaseResourceBuffer(i); + } for (uint32_t i = 0; i < _resource._textures.size(); i++) { releaseResourceTexture(i); } } + +void GLBackend::do_setResourceBuffer(const Batch& batch, size_t paramOffset) { + GLuint slot = batch._params[paramOffset + 1]._uint; + if (slot >= (GLuint)MAX_NUM_RESOURCE_BUFFERS) { + // "GLBackend::do_setResourceBuffer: Trying to set a resource Buffer at slot #" + slot + " which doesn't exist. MaxNumResourceBuffers = " + getMaxNumResourceBuffers()); + return; + } + + auto resourceBuffer = batch._buffers.get(batch._params[paramOffset + 0]._uint); + + if (!resourceBuffer) { + releaseResourceBuffer(slot); + return; + } + // check cache before thinking + if (_resource._buffers[slot] == resourceBuffer) { + return; + } + + // One more True Buffer bound + _stats._RSNumResourceBufferBounded++; + + // If successful bind then cache it + if (bindResourceBuffer(slot, resourceBuffer)) { + _resource._buffers[slot] = resourceBuffer; + } else { // else clear slot and cache + releaseResourceBuffer(slot); + return; + } +} + void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) { GLuint slot = batch._params[paramOffset + 1]._uint; if (slot >= (GLuint) MAX_NUM_RESOURCE_TEXTURES) { diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp new file mode 100644 index 0000000000..ffc8140b25 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp @@ -0,0 +1,517 @@ +// +// Created by Sam Gateau on 2017/04/13 +// Copyright 2013-2017 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 "GLShader.h" +#include + +using namespace gpu; +using namespace gpu::gl; + +// GLSL version +std::string GLBackend::getBackendShaderHeader() const { + return std::string("#version 410 core"); +} + +// Shader domain +static const size_t NUM_SHADER_DOMAINS = 3; + +// GL Shader type enums +// Must match the order of type specified in gpu::Shader::Type +static const std::array SHADER_DOMAINS { { + GL_VERTEX_SHADER, + GL_FRAGMENT_SHADER, + GL_GEOMETRY_SHADER, +} }; + +// Domain specific defines +// Must match the order of type specified in gpu::Shader::Type +static const std::array DOMAIN_DEFINES { { + "#define GPU_VERTEX_SHADER", + "#define GPU_PIXEL_SHADER", + "#define GPU_GEOMETRY_SHADER", +} }; + +// Stereo specific defines +static const std::string stereoVersion { +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + "#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED\n#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN" +#endif +#ifdef GPU_STEREO_DRAWCALL_DOUBLED +#ifdef GPU_STEREO_CAMERA_BUFFER + "#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED" +#else + "#define GPU_TRANSFORM_IS_STEREO" +#endif +#endif +}; + +// Versions specific of the shader +static const std::array VERSION_DEFINES { { + "", + stereoVersion +} }; + +GLShader* GLBackend::compileBackendShader(const Shader& shader) { + // Any GLSLprogram ? normally yes... + const std::string& shaderSource = shader.getSource().getCode(); + GLenum shaderDomain = SHADER_DOMAINS[shader.getType()]; + GLShader::ShaderObjects shaderObjects; + + for (int version = 0; version < GLShader::NumVersions; version++) { + auto& shaderObject = shaderObjects[version]; + + std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version]; + std::string error; + +#ifdef SEPARATE_PROGRAM + bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram, error); +#else + bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, error); +#endif + if (!result) { + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << error.c_str(); + return nullptr; + } + } + + // So far so good, the shader is created successfully + GLShader* object = new GLShader(this->shared_from_this()); + object->_shaderObjects = shaderObjects; + + return object; +} + +GLShader* GLBackend::compileBackendProgram(const Shader& program) { + if (!program.isProgram()) { + return nullptr; + } + + GLShader::ShaderObjects programObjects; + + for (int version = 0; version < GLShader::NumVersions; version++) { + auto& programObject = programObjects[version]; + + // Let's go through every shaders and make sure they are ready to go + std::vector< GLuint > shaderGLObjects; + for (auto subShader : program.getShaders()) { + auto object = GLShader::sync((*this), *subShader); + if (object) { + shaderGLObjects.push_back(object->_shaderObjects[version].glshader); + } else { + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?"; + return nullptr; + } + } + + std::string error; + GLuint glprogram = ::gl::compileProgram(shaderGLObjects, error); + if (glprogram == 0) { + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << error.c_str(); + return nullptr; + } + + programObject.glprogram = glprogram; + + makeProgramBindings(programObject); + } + + // So far so good, the program versions have all been created successfully + GLShader* object = new GLShader(this->shared_from_this()); + object->_shaderObjects = programObjects; + + return object; +} + +GLBackend::ElementResource GLBackend::getFormatFromGLUniform(GLenum gltype) { + switch (gltype) { + case GL_FLOAT: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); + /* + case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); + */ + case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER); + case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER); + case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER); + case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER); + + case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER); +#if defined(Q_OS_WIN) + case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER); + case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER); + case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER); +#endif + + case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER); + case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER); + case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER); + case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER); + + + case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER); + case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER); + + /* {GL_FLOAT_MAT2x3 mat2x3}, + {GL_FLOAT_MAT2x4 mat2x4}, + {GL_FLOAT_MAT3x2 mat3x2}, + {GL_FLOAT_MAT3x4 mat3x4}, + {GL_FLOAT_MAT4x2 mat4x2}, + {GL_FLOAT_MAT4x3 mat4x3}, + {GL_DOUBLE_MAT2 dmat2}, + {GL_DOUBLE_MAT3 dmat3}, + {GL_DOUBLE_MAT4 dmat4}, + {GL_DOUBLE_MAT2x3 dmat2x3}, + {GL_DOUBLE_MAT2x4 dmat2x4}, + {GL_DOUBLE_MAT3x2 dmat3x2}, + {GL_DOUBLE_MAT3x4 dmat3x4}, + {GL_DOUBLE_MAT4x2 dmat4x2}, + {GL_DOUBLE_MAT4x3 dmat4x3}, + */ + + case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D); + case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D); + + case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D); + case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE); + +#if defined(Q_OS_WIN) + case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY); + case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY); + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); +#endif + + case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D); +#if defined(Q_OS_WIN) + case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE); + + case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY); +#endif + + // {GL_SAMPLER_1D_SHADOW sampler1DShadow}, + // {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow}, + + case GL_SAMPLER_BUFFER: return ElementResource(Element(SCALAR, gpu::FLOAT, RESOURCE_BUFFER), Resource::BUFFER); + + // {GL_SAMPLER_2D_RECT sampler2DRect}, + // {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow}, + +#if defined(Q_OS_WIN) + case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D); + case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D); + case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D); + case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE); + + case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); + case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); + + // {GL_INT_SAMPLER_BUFFER isamplerBuffer}, + // {GL_INT_SAMPLER_2D_RECT isampler2DRect}, + + case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D); + case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D); + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); + case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D); + case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE); + + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); +#endif + // {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer}, + // {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect}, + /* + {GL_IMAGE_1D image1D}, + {GL_IMAGE_2D image2D}, + {GL_IMAGE_3D image3D}, + {GL_IMAGE_2D_RECT image2DRect}, + {GL_IMAGE_CUBE imageCube}, + {GL_IMAGE_BUFFER imageBuffer}, + {GL_IMAGE_1D_ARRAY image1DArray}, + {GL_IMAGE_2D_ARRAY image2DArray}, + {GL_IMAGE_2D_MULTISAMPLE image2DMS}, + {GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray}, + {GL_INT_IMAGE_1D iimage1D}, + {GL_INT_IMAGE_2D iimage2D}, + {GL_INT_IMAGE_3D iimage3D}, + {GL_INT_IMAGE_2D_RECT iimage2DRect}, + {GL_INT_IMAGE_CUBE iimageCube}, + {GL_INT_IMAGE_BUFFER iimageBuffer}, + {GL_INT_IMAGE_1D_ARRAY iimage1DArray}, + {GL_INT_IMAGE_2D_ARRAY iimage2DArray}, + {GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS}, + {GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray}, + {GL_UNSIGNED_INT_IMAGE_1D uimage1D}, + {GL_UNSIGNED_INT_IMAGE_2D uimage2D}, + {GL_UNSIGNED_INT_IMAGE_3D uimage3D}, + {GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect}, + {GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot + + {GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer}, + {GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray}, + {GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray}, + {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS}, + {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray}, + {GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint} + */ + default: + return ElementResource(Element(), Resource::BUFFER); + } + +}; + +int GLBackend::makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, + Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { + GLint uniformsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount); + + for (int i = 0; i < uniformsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + GLint location = glGetUniformLocation(glprogram, name); + const GLint INVALID_UNIFORM_LOCATION = -1; + + // Try to make sense of the gltype + auto elementResource = getFormatFromGLUniform(type); + + // The uniform as a standard var type + if (location != INVALID_UNIFORM_LOCATION) { + // Let's make sure the name doesn't contains an array element + std::string sname(name); + auto foundBracket = sname.find_first_of('['); + if (foundBracket != std::string::npos) { + // std::string arrayname = sname.substr(0, foundBracket); + + if (sname[foundBracket + 1] == '0') { + sname = sname.substr(0, foundBracket); + } else { + // skip this uniform since it's not the first element of an array + continue; + } + } + + if (elementResource._resource == Resource::BUFFER) { + uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource)); + } else { + // For texture/Sampler, the location is the actual binding value + GLint binding = -1; + glGetUniformiv(glprogram, location, &binding); + + auto requestedBinding = slotBindings.find(std::string(sname)); + if (requestedBinding != slotBindings.end()) { + if (binding != (*requestedBinding)._location) { + binding = (*requestedBinding)._location; + glProgramUniform1i(glprogram, location, binding); + } + } + + textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); + samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); + } + } + } + + return uniformsCount; +} + +int GLBackend::makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) { + GLint buffersCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount); + + // fast exit + if (buffersCount == 0) { + return 0; + } + + GLint maxNumUniformBufferSlots = 0; + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots); + std::vector uniformBufferSlotMap(maxNumUniformBufferSlots, -1); + + struct UniformBlockInfo { + using Vector = std::vector; + const GLuint index{ 0 }; + const std::string name; + GLint binding{ -1 }; + GLint size{ 0 }; + + static std::string getName(GLuint glprogram, GLuint i) { + static const GLint NAME_LENGTH = 256; + GLint length = 0; + GLchar nameBuffer[NAME_LENGTH]; + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); + glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, nameBuffer); + return std::string(nameBuffer); + } + + UniformBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) { + glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_BINDING, &binding); + glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size); + } + }; + + UniformBlockInfo::Vector uniformBlocks; + uniformBlocks.reserve(buffersCount); + for (int i = 0; i < buffersCount; i++) { + uniformBlocks.push_back(UniformBlockInfo(glprogram, i)); + } + + for (auto& info : uniformBlocks) { + auto requestedBinding = slotBindings.find(info.name); + if (requestedBinding != slotBindings.end()) { + info.binding = (*requestedBinding)._location; + glUniformBlockBinding(glprogram, info.index, info.binding); + uniformBufferSlotMap[info.binding] = info.index; + } + } + + for (auto& info : uniformBlocks) { + if (slotBindings.count(info.name)) { + continue; + } + + // If the binding is 0, or the binding maps to an already used binding + if (info.binding == 0 || !isUnusedSlot(uniformBufferSlotMap[info.binding])) { + // If no binding was assigned then just do it finding a free slot + auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), GLBackend::isUnusedSlot); + if (slotIt != uniformBufferSlotMap.end()) { + info.binding = slotIt - uniformBufferSlotMap.begin(); + glUniformBlockBinding(glprogram, info.index, info.binding); + } else { + // This should neve happen, an active ubo cannot find an available slot among the max available?! + info.binding = -1; + } + } + + uniformBufferSlotMap[info.binding] = info.index; + } + + for (auto& info : uniformBlocks) { + static const Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER); + buffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size)); + } + return buffersCount; +} + +int GLBackend::makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) { + GLint inputsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount); + + for (int i = 0; i < inputsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + + GLint binding = glGetAttribLocation(glprogram, name); + + auto elementResource = getFormatFromGLUniform(type); + inputs.insert(Shader::Slot(name, binding, elementResource._element, -1)); + } + + return inputsCount; +} + +int GLBackend::makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) { + /* GLint outputsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount); + + for (int i = 0; i < inputsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + + auto element = getFormatFromGLUniform(type); + outputs.insert(Shader::Slot(name, i, element)); + } + */ + return 0; //inputsCount; +} + +void GLBackend::makeProgramBindings(ShaderObject& shaderObject) { + if (!shaderObject.glprogram) { + return; + } + GLuint glprogram = shaderObject.glprogram; + GLint loc = -1; + + //Check for gpu specific attribute slotBindings + loc = glGetAttribLocation(glprogram, "inPosition"); + if (loc >= 0 && loc != gpu::Stream::POSITION) { + glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition"); + } + + loc = glGetAttribLocation(glprogram, "inNormal"); + if (loc >= 0 && loc != gpu::Stream::NORMAL) { + glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal"); + } + + loc = glGetAttribLocation(glprogram, "inColor"); + if (loc >= 0 && loc != gpu::Stream::COLOR) { + glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor"); + } + + loc = glGetAttribLocation(glprogram, "inTexCoord0"); + if (loc >= 0 && loc != gpu::Stream::TEXCOORD) { + glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0"); + } + + loc = glGetAttribLocation(glprogram, "inTangent"); + if (loc >= 0 && loc != gpu::Stream::TANGENT) { + glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent"); + } + + loc = glGetAttribLocation(glprogram, "inTexCoord1"); + if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) { + glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1"); + } + + loc = glGetAttribLocation(glprogram, "inSkinClusterIndex"); + if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) { + glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex"); + } + + loc = glGetAttribLocation(glprogram, "inSkinClusterWeight"); + if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) { + glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight"); + } + + loc = glGetAttribLocation(glprogram, "_drawCallInfo"); + if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) { + glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo"); + } + + // Link again to take into account the assigned attrib location + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + if (!linked) { + qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?"; + } +} + diff --git a/libraries/gpu-gl/src/gpu/gl/GLPipeline.cpp b/libraries/gpu-gl/src/gpu/gl/GLPipeline.cpp index bcc8e70c89..ebf1a55232 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLPipeline.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLPipeline.cpp @@ -51,7 +51,7 @@ GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) { // Special case for view correction matrices, any pipeline that declares the correction buffer // uniform will automatically have it provided without any client code necessary. // Required for stable lighting in the HMD. - object->_cameraCorrection = shader->getBuffers().findLocation("cameraCorrectionBuffer"); + object->_cameraCorrection = shader->getUniformBuffers().findLocation("cameraCorrectionBuffer"); object->_program = programObject; object->_state = stateObject; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp index 5020ad38a4..7ed9121978 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp @@ -30,117 +30,6 @@ GLShader::~GLShader() { } } -// GLSL version -static const std::string glslVersion { - "#version 410 core" -}; - -// Shader domain -static const size_t NUM_SHADER_DOMAINS = 3; - -// GL Shader type enums -// Must match the order of type specified in gpu::Shader::Type -static const std::array SHADER_DOMAINS { { - GL_VERTEX_SHADER, - GL_FRAGMENT_SHADER, - GL_GEOMETRY_SHADER, -} }; - -// Domain specific defines -// Must match the order of type specified in gpu::Shader::Type -static const std::array DOMAIN_DEFINES { { - "#define GPU_VERTEX_SHADER", - "#define GPU_PIXEL_SHADER", - "#define GPU_GEOMETRY_SHADER", -} }; - -// Stereo specific defines -static const std::string stereoVersion { -#ifdef GPU_STEREO_DRAWCALL_INSTANCED - "#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED\n#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN" -#endif -#ifdef GPU_STEREO_DRAWCALL_DOUBLED -#ifdef GPU_STEREO_CAMERA_BUFFER - "#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED" -#else - "#define GPU_TRANSFORM_IS_STEREO" -#endif -#endif -}; - -// Versions specific of the shader -static const std::array VERSION_DEFINES { { - "", - stereoVersion -} }; - -GLShader* compileBackendShader(GLBackend& backend, const Shader& shader) { - // Any GLSLprogram ? normally yes... - const std::string& shaderSource = shader.getSource().getCode(); - GLenum shaderDomain = SHADER_DOMAINS[shader.getType()]; - GLShader::ShaderObjects shaderObjects; - - for (int version = 0; version < GLShader::NumVersions; version++) { - auto& shaderObject = shaderObjects[version]; - - std::string shaderDefines = glslVersion + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version]; - -#ifdef SEPARATE_PROGRAM - bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram); -#else - bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader); -#endif - if (!result) { - return nullptr; - } - } - - // So far so good, the shader is created successfully - GLShader* object = new GLShader(backend.shared_from_this()); - object->_shaderObjects = shaderObjects; - - return object; -} - -GLShader* compileBackendProgram(GLBackend& backend, const Shader& program) { - if (!program.isProgram()) { - return nullptr; - } - - GLShader::ShaderObjects programObjects; - - for (int version = 0; version < GLShader::NumVersions; version++) { - auto& programObject = programObjects[version]; - - // Let's go through every shaders and make sure they are ready to go - std::vector< GLuint > shaderGLObjects; - for (auto subShader : program.getShaders()) { - auto object = GLShader::sync(backend, *subShader); - if (object) { - shaderGLObjects.push_back(object->_shaderObjects[version].glshader); - } else { - qCWarning(gpugllogging) << "GLShader::compileBackendProgram - One of the shaders of the program is not compiled?"; - return nullptr; - } - } - - GLuint glprogram = ::gl::compileProgram(shaderGLObjects); - if (glprogram == 0) { - return nullptr; - } - - programObject.glprogram = glprogram; - - makeProgramBindings(programObject); - } - - // So far so good, the program versions have all been created successfully - GLShader* object = new GLShader(backend.shared_from_this()); - object->_shaderObjects = programObjects; - - return object; -} - GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) { GLShader* object = Backend::getGPUObject(shader); @@ -150,13 +39,13 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) { } // need to have a gpu object? if (shader.isProgram()) { - GLShader* tempObject = compileBackendProgram(backend, shader); + GLShader* tempObject = backend.compileBackendProgram(shader); if (tempObject) { object = tempObject; Backend::setGPUObject(shader, object); } } else if (shader.isDomain()) { - GLShader* tempObject = compileBackendShader(backend, shader); + GLShader* tempObject = backend.compileBackendShader(shader); if (tempObject) { object = tempObject; Backend::setGPUObject(shader, object); @@ -180,22 +69,25 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin auto& shaderObject = object->_shaderObjects[version]; if (shaderObject.glprogram) { Shader::SlotSet buffers; - makeUniformBlockSlots(shaderObject.glprogram, slotBindings, buffers); + backend.makeUniformBlockSlots(shaderObject.glprogram, slotBindings, buffers); Shader::SlotSet uniforms; Shader::SlotSet textures; Shader::SlotSet samplers; - makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers); + backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers); + + Shader::SlotSet resourceBuffers; + backend.makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers); Shader::SlotSet inputs; - makeInputSlots(shaderObject.glprogram, slotBindings, inputs); + backend.makeInputSlots(shaderObject.glprogram, slotBindings, inputs); Shader::SlotSet outputs; - makeOutputSlots(shaderObject.glprogram, slotBindings, outputs); + backend.makeOutputSlots(shaderObject.glprogram, slotBindings, outputs); // Define the public slots only from the default version if (version == 0) { - shader.defineSlots(uniforms, buffers, textures, samplers, inputs, outputs); + shader.defineSlots(uniforms, buffers, resourceBuffers, textures, samplers, inputs, outputs); } // else { GLShader::UniformMapping mapping; @@ -210,3 +102,5 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin return true; } + + diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h index e03b487a60..dcf2dc330d 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h @@ -12,6 +12,13 @@ namespace gpu { namespace gl { +struct ShaderObject { + GLuint glshader { 0 }; + GLuint glprogram { 0 }; + GLint transformCameraSlot { -1 }; + GLint transformObjectSlot { -1 }; +}; + class GLShader : public GPUObject { public: static GLShader* sync(GLBackend& backend, const Shader& shader); diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp index 7acdc0ec79..7f46a0aa2b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp @@ -356,432 +356,6 @@ void getCurrentGLState(State::Data& state) { (void)CHECK_GL_ERROR(); } - -class ElementResource { -public: - gpu::Element _element; - uint16 _resource; - - ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {} -}; - -ElementResource getFormatFromGLUniform(GLenum gltype) { - switch (gltype) { - case GL_FLOAT: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); - /* - case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER); - */ - case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER); - case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER); - case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER); - case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER); - - case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER); -#if defined(Q_OS_WIN) - case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER); - case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER); - case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER); -#endif - - case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER); - case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER); - case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER); - case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER); - - - case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER); - case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER); - - /* {GL_FLOAT_MAT2x3 mat2x3}, - {GL_FLOAT_MAT2x4 mat2x4}, - {GL_FLOAT_MAT3x2 mat3x2}, - {GL_FLOAT_MAT3x4 mat3x4}, - {GL_FLOAT_MAT4x2 mat4x2}, - {GL_FLOAT_MAT4x3 mat4x3}, - {GL_DOUBLE_MAT2 dmat2}, - {GL_DOUBLE_MAT3 dmat3}, - {GL_DOUBLE_MAT4 dmat4}, - {GL_DOUBLE_MAT2x3 dmat2x3}, - {GL_DOUBLE_MAT2x4 dmat2x4}, - {GL_DOUBLE_MAT3x2 dmat3x2}, - {GL_DOUBLE_MAT3x4 dmat3x4}, - {GL_DOUBLE_MAT4x2 dmat4x2}, - {GL_DOUBLE_MAT4x3 dmat4x3}, - */ - - case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D); - case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D); - - case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D); - case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE); - -#if defined(Q_OS_WIN) - case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); - case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY); - case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY); - case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); -#endif - - case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D); -#if defined(Q_OS_WIN) - case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE); - - case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY); -#endif - - // {GL_SAMPLER_1D_SHADOW sampler1DShadow}, - // {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow}, - - // {GL_SAMPLER_BUFFER samplerBuffer}, - // {GL_SAMPLER_2D_RECT sampler2DRect}, - // {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow}, - -#if defined(Q_OS_WIN) - case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D); - case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D); - case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); - case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D); - case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE); - - case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); - case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); - - // {GL_INT_SAMPLER_BUFFER isamplerBuffer}, - // {GL_INT_SAMPLER_2D_RECT isampler2DRect}, - - case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D); - case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D); - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D); - case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D); - case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE); - - case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY); - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY); - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY); -#endif - // {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer}, - // {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect}, - /* - {GL_IMAGE_1D image1D}, - {GL_IMAGE_2D image2D}, - {GL_IMAGE_3D image3D}, - {GL_IMAGE_2D_RECT image2DRect}, - {GL_IMAGE_CUBE imageCube}, - {GL_IMAGE_BUFFER imageBuffer}, - {GL_IMAGE_1D_ARRAY image1DArray}, - {GL_IMAGE_2D_ARRAY image2DArray}, - {GL_IMAGE_2D_MULTISAMPLE image2DMS}, - {GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray}, - {GL_INT_IMAGE_1D iimage1D}, - {GL_INT_IMAGE_2D iimage2D}, - {GL_INT_IMAGE_3D iimage3D}, - {GL_INT_IMAGE_2D_RECT iimage2DRect}, - {GL_INT_IMAGE_CUBE iimageCube}, - {GL_INT_IMAGE_BUFFER iimageBuffer}, - {GL_INT_IMAGE_1D_ARRAY iimage1DArray}, - {GL_INT_IMAGE_2D_ARRAY iimage2DArray}, - {GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS}, - {GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray}, - {GL_UNSIGNED_INT_IMAGE_1D uimage1D}, - {GL_UNSIGNED_INT_IMAGE_2D uimage2D}, - {GL_UNSIGNED_INT_IMAGE_3D uimage3D}, - {GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect}, - {GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot - - {GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer}, - {GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray}, - {GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray}, - {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS}, - {GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray}, - {GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint} - */ - default: - return ElementResource(Element(), Resource::BUFFER); - } - -}; - -int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, - Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { - GLint uniformsCount = 0; - - glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount); - - for (int i = 0; i < uniformsCount; i++) { - const GLint NAME_LENGTH = 256; - GLchar name[NAME_LENGTH]; - GLint length = 0; - GLint size = 0; - GLenum type = 0; - glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name); - GLint location = glGetUniformLocation(glprogram, name); - const GLint INVALID_UNIFORM_LOCATION = -1; - - // Try to make sense of the gltype - auto elementResource = getFormatFromGLUniform(type); - - // The uniform as a standard var type - if (location != INVALID_UNIFORM_LOCATION) { - // Let's make sure the name doesn't contains an array element - std::string sname(name); - auto foundBracket = sname.find_first_of('['); - if (foundBracket != std::string::npos) { - // std::string arrayname = sname.substr(0, foundBracket); - - if (sname[foundBracket + 1] == '0') { - sname = sname.substr(0, foundBracket); - } else { - // skip this uniform since it's not the first element of an array - continue; - } - } - - if (elementResource._resource == Resource::BUFFER) { - uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource)); - } else { - // For texture/Sampler, the location is the actual binding value - GLint binding = -1; - glGetUniformiv(glprogram, location, &binding); - - auto requestedBinding = slotBindings.find(std::string(sname)); - if (requestedBinding != slotBindings.end()) { - if (binding != (*requestedBinding)._location) { - binding = (*requestedBinding)._location; - glProgramUniform1i(glprogram, location, binding); - } - } - - textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); - samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); - } - } - } - - return uniformsCount; -} - -const GLint UNUSED_SLOT = -1; -bool isUnusedSlot(GLint binding) { - return (binding == UNUSED_SLOT); -} - -int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) { - GLint buffersCount = 0; - - glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount); - - // fast exit - if (buffersCount == 0) { - return 0; - } - - GLint maxNumUniformBufferSlots = 0; - glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots); - std::vector uniformBufferSlotMap(maxNumUniformBufferSlots, -1); - - struct UniformBlockInfo { - using Vector = std::vector; - const GLuint index{ 0 }; - const std::string name; - GLint binding{ -1 }; - GLint size{ 0 }; - - static std::string getName(GLuint glprogram, GLuint i) { - static const GLint NAME_LENGTH = 256; - GLint length = 0; - GLchar nameBuffer[NAME_LENGTH]; - glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); - glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, nameBuffer); - return std::string(nameBuffer); - } - - UniformBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) { - glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_BINDING, &binding); - glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size); - } - }; - - UniformBlockInfo::Vector uniformBlocks; - uniformBlocks.reserve(buffersCount); - for (int i = 0; i < buffersCount; i++) { - uniformBlocks.push_back(UniformBlockInfo(glprogram, i)); - } - - for (auto& info : uniformBlocks) { - auto requestedBinding = slotBindings.find(info.name); - if (requestedBinding != slotBindings.end()) { - info.binding = (*requestedBinding)._location; - glUniformBlockBinding(glprogram, info.index, info.binding); - uniformBufferSlotMap[info.binding] = info.index; - } - } - - for (auto& info : uniformBlocks) { - if (slotBindings.count(info.name)) { - continue; - } - - // If the binding is 0, or the binding maps to an already used binding - if (info.binding == 0 || uniformBufferSlotMap[info.binding] != UNUSED_SLOT) { - // If no binding was assigned then just do it finding a free slot - auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), isUnusedSlot); - if (slotIt != uniformBufferSlotMap.end()) { - info.binding = slotIt - uniformBufferSlotMap.begin(); - glUniformBlockBinding(glprogram, info.index, info.binding); - } else { - // This should neve happen, an active ubo cannot find an available slot among the max available?! - info.binding = -1; - } - } - - uniformBufferSlotMap[info.binding] = info.index; - } - - for (auto& info : uniformBlocks) { - static const Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER); - buffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size)); - } - return buffersCount; -} - -int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) { - GLint inputsCount = 0; - - glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount); - - for (int i = 0; i < inputsCount; i++) { - const GLint NAME_LENGTH = 256; - GLchar name[NAME_LENGTH]; - GLint length = 0; - GLint size = 0; - GLenum type = 0; - glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); - - GLint binding = glGetAttribLocation(glprogram, name); - - auto elementResource = getFormatFromGLUniform(type); - inputs.insert(Shader::Slot(name, binding, elementResource._element, -1)); - } - - return inputsCount; -} - -int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) { - /* GLint outputsCount = 0; - - glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount); - - for (int i = 0; i < inputsCount; i++) { - const GLint NAME_LENGTH = 256; - GLchar name[NAME_LENGTH]; - GLint length = 0; - GLint size = 0; - GLenum type = 0; - glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); - - auto element = getFormatFromGLUniform(type); - outputs.insert(Shader::Slot(name, i, element)); - } - */ - return 0; //inputsCount; -} - -void makeProgramBindings(ShaderObject& shaderObject) { - if (!shaderObject.glprogram) { - return; - } - GLuint glprogram = shaderObject.glprogram; - GLint loc = -1; - - //Check for gpu specific attribute slotBindings - loc = glGetAttribLocation(glprogram, "inPosition"); - if (loc >= 0 && loc != gpu::Stream::POSITION) { - glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition"); - } - - loc = glGetAttribLocation(glprogram, "inNormal"); - if (loc >= 0 && loc != gpu::Stream::NORMAL) { - glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal"); - } - - loc = glGetAttribLocation(glprogram, "inColor"); - if (loc >= 0 && loc != gpu::Stream::COLOR) { - glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor"); - } - - loc = glGetAttribLocation(glprogram, "inTexCoord0"); - if (loc >= 0 && loc != gpu::Stream::TEXCOORD) { - glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0"); - } - - loc = glGetAttribLocation(glprogram, "inTangent"); - if (loc >= 0 && loc != gpu::Stream::TANGENT) { - glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent"); - } - - loc = glGetAttribLocation(glprogram, "inTexCoord1"); - if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) { - glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1"); - } - - loc = glGetAttribLocation(glprogram, "inSkinClusterIndex"); - if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) { - glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex"); - } - - loc = glGetAttribLocation(glprogram, "inSkinClusterWeight"); - if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) { - glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight"); - } - - loc = glGetAttribLocation(glprogram, "_drawCallInfo"); - if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) { - glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo"); - } - - // Link again to take into account the assigned attrib location - glLinkProgram(glprogram); - - GLint linked = 0; - glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); - if (!linked) { - qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?"; - } - - // now assign the ubo binding, then DON't relink! - - //Check for gpu specific uniform slotBindings -#ifdef GPU_SSBO_DRAW_CALL_INFO - loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer"); - if (loc >= 0) { - glShaderStorageBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); - shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT; - } -#else - loc = glGetUniformLocation(glprogram, "transformObjectBuffer"); - if (loc >= 0) { - glProgramUniform1i(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); - shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT; - } -#endif - - loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer"); - if (loc >= 0) { - glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT); - shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT; - } - - (void)CHECK_GL_ERROR(); -} - void serverWait() { auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); assert(fence); diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.h b/libraries/gpu-gl/src/gpu/gl/GLShared.h index b0eec23448..22f63363d1 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShared.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShared.h @@ -34,20 +34,6 @@ State::BlendOp blendOpFromGL(GLenum blendOp); State::BlendArg blendArgFromGL(GLenum blendArg); void getCurrentGLState(State::Data& state); -struct ShaderObject { - GLuint glshader { 0 }; - GLuint glprogram { 0 }; - GLint transformCameraSlot { -1 }; - GLint transformObjectSlot { -1 }; -}; - -int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, - Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers); -int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers); -int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs); -int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs); -void makeProgramBindings(ShaderObject& shaderObject); - enum GLSyncState { // The object is currently undergoing no processing, although it's content // may be out of date, or it's storage may be invalid relative to the @@ -150,6 +136,8 @@ class GLQuery; class GLState; class GLShader; class GLTexture; +struct ShaderObject; + } } // namespace gpu::gl diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 0c3c70dbb8..545279627a 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -35,6 +35,11 @@ class GL41Backend : public GLBackend { friend class Context; public: + static const GLint TRANSFORM_OBJECT_SLOT { 31 }; + static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 }; + static const GLint RESOURCE_BUFFER_TEXBUF_TEX_UNIT { 33 }; + static const GLint RESOURCE_BUFFER_SLOT0_TEX_UNIT { 34 }; + explicit GL41Backend(bool syncCache) : Parent(syncCache) {} GL41Backend() : Parent() {} @@ -119,6 +124,7 @@ protected: GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; GLuint getBufferID(const Buffer& buffer) override; + GLuint getResourceBufferID(const Buffer& buffer); GLBuffer* syncGPUObject(const Buffer& buffer) override; GLTexture* syncGPUObject(const TexturePointer& texture) override; @@ -143,8 +149,17 @@ protected: void initTransform() override; void updateTransform(const Batch& batch) override; + // Resource Stage + bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) override; + void releaseResourceBuffer(uint32_t slot) override; + // Output stage void do_blit(const Batch& batch, size_t paramOffset) override; + + std::string getBackendShaderHeader() const override; + void makeProgramBindings(ShaderObject& shaderObject) override; + int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override; + }; } } diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendBuffer.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendBuffer.cpp index b739bfaf89..eb66cc4544 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendBuffer.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendBuffer.cpp @@ -18,11 +18,17 @@ namespace gpu { return result; } + ~GL41Buffer() { + if (_texBuffer) { + glDeleteTextures(1, &_texBuffer); + } + } + public: GL41Buffer(const std::weak_ptr& backend, const Buffer& buffer, GL41Buffer* original) : Parent(backend, buffer, allocate()) { - glBindBuffer(GL_ARRAY_BUFFER, _buffer); - glBufferData(GL_ARRAY_BUFFER, _size, nullptr, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer); + glBufferData(GL_COPY_WRITE_BUFFER, _size, nullptr, GL_DYNAMIC_DRAW); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); if (original && original->_size) { glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer); @@ -36,20 +42,34 @@ namespace gpu { } void transfer() override { - glBindBuffer(GL_ARRAY_BUFFER, _buffer); + glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer); (void)CHECK_GL_ERROR(); Size offset; Size size; Size currentPage { 0 }; auto data = _gpuObject._renderSysmem.readData(); while (_gpuObject._renderPages.getNextTransferBlock(offset, size, currentPage)) { - glBufferSubData(GL_ARRAY_BUFFER, offset, size, data + offset); + glBufferSubData(GL_COPY_WRITE_BUFFER, offset, size, data + offset); (void)CHECK_GL_ERROR(); } - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); (void)CHECK_GL_ERROR(); _gpuObject._renderPages._flags &= ~PageManager::DIRTY; } + + // REsource BUffer are implemented with TextureBuffer + GLuint _texBuffer { 0 }; + GLuint getTexBufferId() { + if (!_texBuffer) { + glGenTextures(1, &_texBuffer); + glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_BUFFER_TEXBUF_TEX_UNIT); + glBindTexture(GL_TEXTURE_BUFFER, _texBuffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _buffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + (void)CHECK_GL_ERROR(); + } + return _texBuffer; + } }; } } @@ -63,6 +83,40 @@ GLuint GL41Backend::getBufferID(const Buffer& buffer) { return GL41Buffer::getId(*this, buffer); } +GLuint GL41Backend::getResourceBufferID(const Buffer& buffer) { + auto* object = GL41Buffer::sync(*this, buffer); + if (object) { + return object->getTexBufferId(); + } else { + return 0; + } +} + GLBuffer* GL41Backend::syncGPUObject(const Buffer& buffer) { return GL41Buffer::sync(*this, buffer); } + +bool GL41Backend::bindResourceBuffer(uint32_t slot, BufferPointer& buffer) { + GLuint texBuffer = GL41Backend::getResourceBufferID((*buffer)); + if (texBuffer) { + glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT + slot); + glBindTexture(GL_TEXTURE_BUFFER, texBuffer); + + (void)CHECK_GL_ERROR(); + + _resource._buffers[slot] = buffer; + + return true; + } + + return false; +} + +void GL41Backend::releaseResourceBuffer(uint32_t slot) { + auto& buf = _resource._buffers[slot]; + if (buf) { + glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT + slot); + glBindTexture(GL_TEXTURE_BUFFER, 0); + buf.reset(); + } +} diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp index 51a24563f3..43b48f721f 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp @@ -112,9 +112,6 @@ void GL41Backend::updateInput() { glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency); #endif } - - // TODO: Support properly the IAttrib version - (void)CHECK_GL_ERROR(); } } diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp new file mode 100644 index 0000000000..b5a8dcb7a9 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp @@ -0,0 +1,113 @@ +// +// Created by Sam Gateau on 2017/04/13 +// Copyright 2013-2017 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 "GL41Backend.h" +#include "../gl/GLShader.h" +//#include + +using namespace gpu; +using namespace gpu::gl41; + +// GLSL version +std::string GL41Backend::getBackendShaderHeader() const { + return std::string("#version 410 core\n#define GPU_GL410 1"); +} + +int GL41Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) { + GLint ssboCount = 0; + GLint uniformsCount = 0; + + glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount); + + for (int i = 0; i < uniformsCount; i++) { + const GLint NAME_LENGTH = 256; + GLchar name[NAME_LENGTH]; + GLint length = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name); + GLint location = glGetUniformLocation(glprogram, name); + const GLint INVALID_UNIFORM_LOCATION = -1; + + // Try to make sense of the gltype + auto elementResource = getFormatFromGLUniform(type); + + // The uniform as a standard var type + if (location != INVALID_UNIFORM_LOCATION) { + + if (elementResource._resource == Resource::BUFFER) { + if (elementResource._element.getSemantic() == gpu::RESOURCE_BUFFER) { + // Let's make sure the name doesn't contains an array element + std::string sname(name); + auto foundBracket = sname.find_first_of('['); + if (foundBracket != std::string::npos) { + // std::string arrayname = sname.substr(0, foundBracket); + + if (sname[foundBracket + 1] == '0') { + sname = sname.substr(0, foundBracket); + } else { + // skip this uniform since it's not the first element of an array + continue; + } + } + + // For texture/Sampler, the location is the actual binding value + GLint binding = -1; + glGetUniformiv(glprogram, location, &binding); + + if (binding == GL41Backend::TRANSFORM_OBJECT_SLOT) { + continue; + } + + auto requestedBinding = slotBindings.find(std::string(sname)); + if (requestedBinding != slotBindings.end()) { + GLint requestedLoc = (*requestedBinding)._location + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT; + if (binding != requestedLoc) { + binding = requestedLoc; + } + } else { + binding += GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT; + } + glProgramUniform1i(glprogram, location, binding); + + ssboCount++; + resourceBuffers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource)); + } + } + } + } + + return ssboCount; +} + +void GL41Backend::makeProgramBindings(gl::ShaderObject& shaderObject) { + if (!shaderObject.glprogram) { + return; + } + GLuint glprogram = shaderObject.glprogram; + GLint loc = -1; + + GLBackend::makeProgramBindings(shaderObject); + + // now assign the ubo binding, then DON't relink! + + //Check for gpu specific uniform slotBindings + loc = glGetUniformLocation(glprogram, "transformObjectBuffer"); + if (loc >= 0) { + glProgramUniform1i(glprogram, loc, GL41Backend::TRANSFORM_OBJECT_SLOT); + shaderObject.transformObjectSlot = GL41Backend::TRANSFORM_OBJECT_SLOT; + } + + loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT); + shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT; + } + + (void)CHECK_GL_ERROR(); +} + diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 1e02b3a385..fe01284446 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -77,8 +77,7 @@ GLuint GL41Texture::allocate(const Texture& texture) { void GL41Texture::withPreservedTexture(std::function f) const { - const GLint TRANSFER_TEXTURE_UNIT = 32; - glActiveTexture(GL_TEXTURE0 + TRANSFER_TEXTURE_UNIT); + glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_TRANSFER_TEX_UNIT); glBindTexture(_target, _texture); (void)CHECK_GL_ERROR(); diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTransform.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTransform.cpp index 526bac9ec8..41a3c5cf25 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTransform.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTransform.cpp @@ -38,15 +38,9 @@ void GL41Backend::transferTransformState(const Batch& batch) const { } if (!batch._objects.empty()) { -#ifdef GPU_SSBO_DRAW_CALL_INFO - glBindBuffer(GL_SHADER_STORAGE_BUFFER, _transform._objectBuffer); - glBufferData(GL_SHADER_STORAGE_BUFFER, sysmem.getSize(), sysmem.readData(), GL_STREAM_DRAW); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); -#else glBindBuffer(GL_TEXTURE_BUFFER, _transform._objectBuffer); glBufferData(GL_TEXTURE_BUFFER, batch._objects.size() * sizeof(Batch::TransformObject), batch._objects.data(), GL_DYNAMIC_DRAW); glBindBuffer(GL_TEXTURE_BUFFER, 0); -#endif } if (!batch._namedData.empty()) { @@ -64,15 +58,11 @@ void GL41Backend::transferTransformState(const Batch& batch) const { glBindBuffer(GL_ARRAY_BUFFER, 0); } -#ifdef GPU_SSBO_DRAW_CALL_INFO - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._objectBuffer); -#else - glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT); + glActiveTexture(GL_TEXTURE0 + GL41Backend::TRANSFORM_OBJECT_SLOT); glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture); if (!batch._objects.empty()) { glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer); } -#endif CHECK_GL_ERROR(); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 152d4cfec5..d80a70cfd1 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -18,6 +18,7 @@ #define INCREMENTAL_TRANSFER 0 #define THREADED_TEXTURE_BUFFERING 1 +#define GPU_SSBO_TRANSFORM_OBJECT 1 namespace gpu { namespace gl45 { @@ -30,6 +31,13 @@ class GL45Backend : public GLBackend { friend class Context; public: + +#ifdef GPU_SSBO_TRANSFORM_OBJECT + static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot +#else + static const GLint TRANSFORM_OBJECT_SLOT { 31 }; // TBO binding slot +#endif + explicit GL45Backend(bool syncCache) : Parent(syncCache) {} GL45Backend() : Parent() {} @@ -177,9 +185,18 @@ protected: void initTransform() override; void updateTransform(const Batch& batch) override; + // Resource Stage + bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) override; + void releaseResourceBuffer(uint32_t slot) override; + // Output stage void do_blit(const Batch& batch, size_t paramOffset) override; + // Shader Stage + std::string getBackendShaderHeader() const override; + void makeProgramBindings(ShaderObject& shaderObject) override; + int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override; + // Texture Management Stage void initTextureManagementStage() override; }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp index cd69c03691..b4a6410612 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp @@ -54,3 +54,29 @@ GLuint GL45Backend::getBufferID(const Buffer& buffer) { GLBuffer* GL45Backend::syncGPUObject(const Buffer& buffer) { return GL45Buffer::sync(*this, buffer); } + + +bool GL45Backend::bindResourceBuffer(uint32_t slot, BufferPointer& buffer) { + GLBuffer* object = syncGPUObject((*buffer)); + if (object) { + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, object->_id); + + (void)CHECK_GL_ERROR(); + + _resource._buffers[slot] = buffer; + + return true; + } + + return false; +} + +void GL45Backend::releaseResourceBuffer(uint32_t slot) { + auto& buf = _resource._buffers[slot]; + if (buf) { + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, 0); + buf.reset(); + } +} + + diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp new file mode 100644 index 0000000000..8a5e8d0064 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp @@ -0,0 +1,169 @@ +// +// Created by Sam Gateau on 2017/04/13 +// Copyright 2013-2017 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 "GL45Backend.h" +#include "../gl/GLShader.h" +//#include + +using namespace gpu; +using namespace gpu::gl45; + +// GLSL version +std::string GL45Backend::getBackendShaderHeader() const { + const char header[] = +R"GLSL(#version 450 core +#define GPU_GL450 +)GLSL" +#ifdef GPU_SSBO_TRANSFORM_OBJECT + R"GLSL(#define GPU_SSBO_TRANSFORM_OBJECT 1)GLSL" +#endif + ; + return std::string(header); +} + +int GL45Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) { + GLint buffersCount = 0; + glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &buffersCount); + + // fast exit + if (buffersCount == 0) { + return 0; + } + + GLint maxNumResourceBufferSlots = 0; + glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxNumResourceBufferSlots); + std::vector resourceBufferSlotMap(maxNumResourceBufferSlots, -1); + + struct ResourceBlockInfo { + using Vector = std::vector; + const GLuint index{ 0 }; + const std::string name; + GLint binding{ -1 }; + GLint size{ 0 }; + + static std::string getName(GLuint glprogram, GLuint i) { + static const GLint NAME_LENGTH = 256; + GLint length = 0; + GLchar nameBuffer[NAME_LENGTH]; + glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, i, NAME_LENGTH, &length, nameBuffer); + return std::string(nameBuffer); + } + + ResourceBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) { + GLenum props[2] = { GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE}; + glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, i, 2, props, 2, nullptr, &binding); + } + }; + + ResourceBlockInfo::Vector resourceBlocks; + resourceBlocks.reserve(buffersCount); + for (int i = 0; i < buffersCount; i++) { + resourceBlocks.push_back(ResourceBlockInfo(glprogram, i)); + } + + for (auto& info : resourceBlocks) { + auto requestedBinding = slotBindings.find(info.name); + if (requestedBinding != slotBindings.end()) { + info.binding = (*requestedBinding)._location; + glUniformBlockBinding(glprogram, info.index, info.binding); + resourceBufferSlotMap[info.binding] = info.index; + } + } + + for (auto& info : resourceBlocks) { + if (slotBindings.count(info.name)) { + continue; + } + + // If the binding is -1, or the binding maps to an already used binding + if (info.binding == -1 || !isUnusedSlot(resourceBufferSlotMap[info.binding])) { + // If no binding was assigned then just do it finding a free slot + auto slotIt = std::find_if(resourceBufferSlotMap.begin(), resourceBufferSlotMap.end(), GLBackend::isUnusedSlot); + if (slotIt != resourceBufferSlotMap.end()) { + info.binding = slotIt - resourceBufferSlotMap.begin(); + glUniformBlockBinding(glprogram, info.index, info.binding); + } else { + // This should never happen, an active ssbo cannot find an available slot among the max available?! + info.binding = -1; + } + } + + resourceBufferSlotMap[info.binding] = info.index; + } + + for (auto& info : resourceBlocks) { + static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER); + resourceBuffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size)); + } + return buffersCount; +/* + GLint ssboCount = 0; + glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssboCount); + if (ssboCount > 0) { + GLint maxNameLength = 0; + glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &maxNameLength); + std::vector nameBytes(maxNameLength); + + for (GLint b = 0; b < ssboCount; b++) { + GLint length; + glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, b, maxNameLength, &length, nameBytes.data()); + std::string bufferName(nameBytes.data()); + + GLenum props = GL_BUFFER_BINDING; + GLint binding = -1; + glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, b, 1, &props, 1, nullptr, &binding); + + auto requestedBinding = slotBindings.find(std::string(bufferName)); + if (requestedBinding != slotBindings.end()) { + if (binding != (*requestedBinding)._location) { + binding = (*requestedBinding)._location; + glShaderStorageBlockBinding(glprogram, b, binding); + } + } + + static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER); + resourceBuffers.insert(Shader::Slot(bufferName, binding, element, -1)); + } + } + return ssboCount;*/ +} + +void GL45Backend::makeProgramBindings(gl::ShaderObject& shaderObject) { + if (!shaderObject.glprogram) { + return; + } + GLuint glprogram = shaderObject.glprogram; + GLint loc = -1; + + GLBackend::makeProgramBindings(shaderObject); + + // now assign the ubo binding, then DON't relink! + + //Check for gpu specific uniform slotBindings +#ifdef GPU_SSBO_TRANSFORM_OBJECT + loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer"); + if (loc >= 0) { + glShaderStorageBlockBinding(glprogram, loc, GL45Backend::TRANSFORM_OBJECT_SLOT); + shaderObject.transformObjectSlot = GL45Backend::TRANSFORM_OBJECT_SLOT; + } +#else + loc = glGetUniformLocation(glprogram, "transformObjectBuffer"); + if (loc >= 0) { + glProgramUniform1i(glprogram, loc, GL45Backend::TRANSFORM_OBJECT_SLOT); + shaderObject.transformObjectSlot = GL45Backend::TRANSFORM_OBJECT_SLOT; + } +#endif + + loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT); + shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT; + } + + (void)CHECK_GL_ERROR(); +} + diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp index 57862eb983..ae323612c4 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp @@ -19,7 +19,10 @@ void GL45Backend::initTransform() { _transform._objectBuffer = transformBuffers[0]; _transform._cameraBuffer = transformBuffers[1]; _transform._drawCallInfoBuffer = transformBuffers[2]; +#ifdef GPU_SSBO_TRANSFORM_OBJECT +#else glCreateTextures(GL_TEXTURE_BUFFER, 1, &_transform._objectBufferTexture); +#endif size_t cameraSize = sizeof(TransformStageState::CameraBufferElement); while (_transform._cameraUboSize < cameraSize) { _transform._cameraUboSize += _uboAlignment; @@ -53,10 +56,10 @@ void GL45Backend::transferTransformState(const Batch& batch) const { glNamedBufferData(_transform._drawCallInfoBuffer, bufferData.size(), bufferData.data(), GL_STREAM_DRAW); } -#ifdef GPU_SSBO_DRAW_CALL_INFO - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._objectBuffer); +#ifdef GPU_SSBO_TRANSFORM_OBJECT + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, GL45Backend::TRANSFORM_OBJECT_SLOT, _transform._objectBuffer); #else - glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT); + glActiveTexture(GL_TEXTURE0 + GL45Backend::TRANSFORM_OBJECT_SLOT); glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture); glTextureBuffer(_transform._objectBufferTexture, GL_RGBA32F, _transform._objectBuffer); #endif diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index f822da129b..0d5036c202 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -292,8 +292,16 @@ void Batch::setUniformBuffer(uint32 slot, const BufferView& view) { setUniformBuffer(slot, view._buffer, view._offset, view._size); } +void Batch::setResourceBuffer(uint32 slot, const BufferPointer& buffer) { + ADD_COMMAND(setResourceBuffer); + + _params.emplace_back(_buffers.cache(buffer)); + _params.emplace_back(slot); +} + void Batch::setResourceTexture(uint32 slot, const TexturePointer& texture) { ADD_COMMAND(setResourceTexture); + _params.emplace_back(_textures.cache(texture)); _params.emplace_back(slot); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 598680a745..85e99951cb 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -30,12 +30,6 @@ class QDebug; namespace gpu { enum ReservedSlot { - -#ifdef GPU_SSBO_DRAW_CALL_INFO - TRANSFORM_OBJECT_SLOT = 14, -#else - TRANSFORM_OBJECT_SLOT = 31, -#endif TRANSFORM_CAMERA_SLOT = 15, }; @@ -189,9 +183,12 @@ public: void setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size); void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView - void setResourceTexture(uint32 slot, const TexturePointer& view); + void setResourceBuffer(uint32 slot, const BufferPointer& buffer); + + void setResourceTexture(uint32 slot, const TexturePointer& texture); void setResourceTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView + // Ouput Stage void setFramebuffer(const FramebufferPointer& framebuffer); @@ -290,6 +287,7 @@ public: COMMAND_setStateScissorRect, COMMAND_setUniformBuffer, + COMMAND_setResourceBuffer, COMMAND_setResourceTexture, COMMAND_setFramebuffer, diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 102c754cd7..b56255f862 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -34,6 +34,7 @@ public: int _ISNumInputBufferChanges = 0; int _ISNumIndexBufferChanges = 0; + int _RSNumResourceBufferBounded = 0; int _RSNumTextureBounded = 0; int _RSAmountTextureMemoryBounded = 0; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 4114ccb15c..58115edca0 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -178,6 +178,7 @@ enum Semantic { UNIFORM, UNIFORM_BUFFER, + RESOURCE_BUFFER, SAMPLER, SAMPLER_MULTISAMPLE, SAMPLER_SHADOW, diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp index a044e4845e..398a269f3f 100755 --- a/libraries/gpu/src/gpu/Shader.cpp +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -72,9 +72,10 @@ Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer return Pointer(); } -void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) { +void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers, const SlotSet& resourceBuffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) { _uniforms = uniforms; - _buffers = buffers; + _uniformBuffers = uniformBuffers; + _resourceBuffers = resourceBuffers; _textures = textures; _samplers = samplers; _inputs = inputs; diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index ebe0bc83df..181c9b5e78 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -134,10 +134,11 @@ public: // Access the exposed uniform, input and output slot const SlotSet& getUniforms() const { return _uniforms; } - const SlotSet& getBuffers() const { return _buffers; } + const SlotSet& getUniformBuffers() const { return _uniformBuffers; } + const SlotSet& getResourceBuffers() const { return _resourceBuffers; } const SlotSet& getTextures() const { return _textures; } const SlotSet& getSamplers() const { return _samplers; } - + const SlotSet& getInputs() const { return _inputs; } const SlotSet& getOutputs() const { return _outputs; } @@ -146,7 +147,13 @@ public: // to correctly bind resource to the shader. // These can be build "manually" from knowledge of the atual shader code // or automatically by calling "makeShader()", this is the preferred way - void defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs); + void defineSlots(const SlotSet& uniforms, + const SlotSet& uniformBuffers, + const SlotSet& resourceBuffers, + const SlotSet& textures, + const SlotSet& samplers, + const SlotSet& inputs, + const SlotSet& outputs); // makeProgram(...) make a program shader ready to be used in a Batch. // It compiles the sub shaders, link them and defines the Slots and their bindings. @@ -181,7 +188,8 @@ protected: // List of exposed uniform, input and output slots SlotSet _uniforms; - SlotSet _buffers; + SlotSet _uniformBuffers; + SlotSet _resourceBuffers; SlotSet _textures; SlotSet _samplers; SlotSet _inputs; diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 06672a2dd0..b786222198 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -119,15 +119,15 @@ struct TransformObject { layout(location=15) in ivec2 _drawCallInfo; -<@if FALSE @> -// Disable SSBOs for now +#if defined(GPU_SSBO_TRANSFORM_OBJECT) layout(std140) buffer transformObjectBuffer { TransformObject _object[]; }; TransformObject getTransformObject() { - return _object[_drawCallInfo.x]; + TransformObject transformObject = _object[_drawCallInfo.x]; + return transformObject; } -<@else@> +#else uniform samplerBuffer transformObjectBuffer; TransformObject getTransformObject() { @@ -145,7 +145,8 @@ TransformObject getTransformObject() { return object; } -<@endif@> +#endif + <@endfunc@> diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 83122578e7..0275a875ec 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -59,7 +59,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, auto& procedural = skybox._procedural; procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat()); auto textureSlot = procedural.getShader()->getTextures().findLocation("cubeMap"); - auto bufferSlot = procedural.getShader()->getBuffers().findLocation("skyboxBuffer"); + auto bufferSlot = procedural.getShader()->getUniformBuffers().findLocation("skyboxBuffer"); skybox.prepare(batch, textureSlot, bufferSlot); batch.draw(gpu::TRIANGLE_STRIP, 4); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 7167e8cba8..34fd481c44 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -259,12 +259,12 @@ static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* f locations->texcoordFrameTransform = program->getUniforms().findLocation("texcoordFrameTransform"); - locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - locations->ambientBufferUnit = program->getBuffers().findLocation("lightAmbientBuffer"); - locations->lightIndexBufferUnit = program->getBuffers().findLocation("lightIndexBuffer"); - locations->deferredFrameTransformBuffer = program->getBuffers().findLocation("deferredFrameTransformBuffer"); - locations->subsurfaceScatteringParametersBuffer = program->getBuffers().findLocation("subsurfaceScatteringParametersBuffer"); - locations->shadowTransformBuffer = program->getBuffers().findLocation("shadowTransformBuffer"); + locations->lightBufferUnit = program->getUniformBuffers().findLocation("lightBuffer"); + locations->ambientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer"); + locations->lightIndexBufferUnit = program->getUniformBuffers().findLocation("lightIndexBuffer"); + locations->deferredFrameTransformBuffer = program->getUniformBuffers().findLocation("deferredFrameTransformBuffer"); + locations->subsurfaceScatteringParametersBuffer = program->getUniformBuffers().findLocation("subsurfaceScatteringParametersBuffer"); + locations->shadowTransformBuffer = program->getUniformBuffers().findLocation("shadowTransformBuffer"); return program; } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index e0dee7b953..f1c995b943 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1686,7 +1686,7 @@ void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bo auto ps = gpu::Shader::createPixel(std::string(grid_frag)); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); - _gridSlot = program->getBuffers().findLocation("gridBuffer"); + _gridSlot = program->getUniformBuffers().findLocation("gridBuffer"); auto stateLayered = std::make_shared(); stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index ed9975e2e5..b6f3440d5c 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -148,8 +148,6 @@ const gpu::PipelinePointer DrawBounds::getPipeline() { gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); - _cornerLocation = program->getUniforms().findLocation("inBoundPos"); - _scaleLocation = program->getUniforms().findLocation("inBoundDim"); _colorLocation = program->getUniforms().findLocation("inColor"); auto state = std::make_shared(); @@ -167,6 +165,18 @@ void DrawBounds::run(const RenderContextPointer& renderContext, const Inputs& items) { RenderArgs* args = renderContext->args; + uint32_t numItems = (uint32_t) items.size(); + if (numItems == 0) { + return; + } + + static const uint32_t sizeOfItemBound = sizeof(ItemBound); + if (!_drawBuffer) { + _drawBuffer = std::make_shared(sizeOfItemBound); + } + + _drawBuffer->setData(numItems * sizeOfItemBound, (const gpu::Byte*) items.data()); + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -181,22 +191,13 @@ void DrawBounds::run(const RenderContextPointer& renderContext, // Bind program batch.setPipeline(getPipeline()); - assert(_cornerLocation >= 0); - assert(_scaleLocation >= 0); - // Render bounds - float numItems = (float) items.size(); - float itemNum = 0.0f; - for (const auto& item : items) { - glm::vec4 color(glm::vec3(itemNum / numItems), 1.0f); - batch._glUniform3fv(_cornerLocation, 1, (const float*)(&item.bound.getCorner())); - batch._glUniform3fv(_scaleLocation, 1, (const float*)(&item.bound.getScale())); - batch._glUniform4fv(_colorLocation, 1, (const float*)(&color)); + glm::vec4 color(glm::vec3(0.0f), -(float) numItems); + batch._glUniform4fv(_colorLocation, 1, (const float*)(&color)); + batch.setResourceBuffer(0, _drawBuffer); - static const int NUM_VERTICES_PER_CUBE = 24; - batch.draw(gpu::LINES, NUM_VERTICES_PER_CUBE, 0); - itemNum += 1.0f; - } + static const int NUM_VERTICES_PER_CUBE = 24; + batch.draw(gpu::LINES, NUM_VERTICES_PER_CUBE * numItems, 0); }); } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 317aaf1e25..896ccef842 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -65,8 +65,8 @@ public: private: const gpu::PipelinePointer getPipeline(); gpu::PipelinePointer _boundsPipeline; - int _cornerLocation { -1 }; - int _scaleLocation { -1 }; + gpu::BufferPointer _drawBuffer; + int _colorLocation { -1 }; }; diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 551b48fd7d..b0d84d5379 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -227,6 +227,7 @@ class ItemBound { ItemID id; AABox bound; + uint32_t padding; }; // many Item Bounds in a vector diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 1c8e73f5d7..d51d7f8cb6 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -80,12 +80,12 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->metallicTextureUnit = program->getTextures().findLocation("metallicMap"); locations->emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); locations->occlusionTextureUnit = program->getTextures().findLocation("occlusionMap"); - locations->lightingModelBufferUnit = program->getBuffers().findLocation("lightingModelBuffer"); - locations->skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); - locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); - locations->texMapArrayBufferUnit = program->getBuffers().findLocation("texMapArrayBuffer"); - locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - locations->lightAmbientBufferUnit = program->getBuffers().findLocation("lightAmbientBuffer"); + locations->lightingModelBufferUnit = program->getUniformBuffers().findLocation("lightingModelBuffer"); + locations->skinClusterBufferUnit = program->getUniformBuffers().findLocation("skinClusterBuffer"); + locations->materialBufferUnit = program->getUniformBuffers().findLocation("materialBuffer"); + locations->texMapArrayBufferUnit = program->getUniformBuffers().findLocation("texMapArrayBuffer"); + locations->lightBufferUnit = program->getUniformBuffers().findLocation("lightBuffer"); + locations->lightAmbientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer"); locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap"); ShapeKey key{filter._flags}; diff --git a/libraries/render/src/render/drawItemBounds.slv b/libraries/render/src/render/drawItemBounds.slv index af1e31fbf4..0bb2b795bd 100644 --- a/libraries/render/src/render/drawItemBounds.slv +++ b/libraries/render/src/render/drawItemBounds.slv @@ -18,10 +18,35 @@ <@include gpu/Color.slh@> <$declareColorWheel()$> -uniform vec3 inBoundPos; -uniform vec3 inBoundDim; uniform vec4 inColor; + +struct ItemBound { + vec4 id_boundPos; + vec4 boundDim_s; +}; + +#if defined(GPU_GL410) +uniform samplerBuffer ssbo0Buffer; +ItemBound getItemBound(int i) { + int offset = 2 * i; + ItemBound bound; + bound.id_boundPos = texelFetch(ssbo0Buffer, offset); + bound.boundDim_s = texelFetch(ssbo0Buffer, offset + 1); + return bound; +} +#else +layout(std140) buffer ssbo0Buffer { + ItemBound bounds[]; +}; +ItemBound getItemBound(int i) { + ItemBound bound = bounds[i]; + return bound; +} +#endif + + + out vec4 varColor; out vec2 varTexcoord; @@ -50,16 +75,28 @@ void main(void) { 0, 4, 1, 5 ); - vec4 cubeVec = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - vec4 pos = vec4(inBoundPos + inBoundDim * cubeVec.xyz, 1.0); + int boundID = gl_VertexID / 24; + int vertexID = gl_VertexID - boundID * 24; + + vec4 cubeVec = UNIT_BOX[UNIT_BOX_LINE_INDICES[vertexID]]; + + ItemBound bound = getItemBound(boundID); + vec3 boundPos = bound.id_boundPos.yzw; + vec3 boundDim = bound.boundDim_s.xyz; + + vec4 pos = vec4(boundPos + boundDim * cubeVec.xyz, 1.0); // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); <$transformModelToClipPos(cam, obj, pos, gl_Position)$> - varColor = vec4(colorWheel(inColor.x), 1.0); - varTexcoord = vec2(cubeVec.w, length(inBoundDim)); + if (inColor.w < 0.0) { + varColor = vec4(colorWheel(float(boundID)/(-inColor.w)), 1.0); + } else { + varColor = vec4(colorWheel(float(inColor.w)), 1.0); + } + varTexcoord = vec2(cubeVec.w, length(boundDim)); } \ No newline at end of file diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 1adfa8d333..585a0d00ef 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -196,9 +196,10 @@ public: std::string vsSource = HMD_REPROJECTION_VERT; std::string fsSource = HMD_REPROJECTION_FRAG; GLuint vertexShader { 0 }, fragmentShader { 0 }; - ::gl::compileShader(GL_VERTEX_SHADER, vsSource, "", vertexShader); - ::gl::compileShader(GL_FRAGMENT_SHADER, fsSource, "", fragmentShader); - _program = ::gl::compileProgram({ { vertexShader, fragmentShader } }); + std::string error; + ::gl::compileShader(GL_VERTEX_SHADER, vsSource, "", vertexShader, error); + ::gl::compileShader(GL_FRAGMENT_SHADER, fsSource, "", fragmentShader, error); + _program = ::gl::compileProgram({ { vertexShader, fragmentShader } }, error); glDeleteShader(vertexShader); glDeleteShader(fragmentShader); qDebug() << "Rebuild proigram";