From 23a6326aa175e696e1b8f611dcd99e9e66a11499 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sun, 8 Mar 2015 10:53:29 -0700 Subject: [PATCH] testing the shader features in Model and refining the shader making workflow --- libraries/gpu/src/gpu/Context.cpp | 11 + libraries/gpu/src/gpu/Context.h | 9 + libraries/gpu/src/gpu/Format.h | 22 +- libraries/gpu/src/gpu/GLBackend.h | 2 +- libraries/gpu/src/gpu/GLBackendShader.cpp | 244 ++++++++++++++-------- libraries/gpu/src/gpu/Resource.h | 12 ++ libraries/gpu/src/gpu/Shader.cpp | 9 + libraries/gpu/src/gpu/Shader.h | 43 +++- libraries/model/src/model/Stage.cpp | 3 +- libraries/render-utils/src/Model.cpp | 91 +++++++- libraries/render-utils/src/Model.h | 1 + 11 files changed, 326 insertions(+), 121 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 85227e0557..54387e8f71 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -10,3 +10,14 @@ // #include "Context.h" +// this include should disappear! as soon as the gpu::Context is in place +#include "GLBackend.h" + +using namespace gpu; + +bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) { + if (shader.isProgram()) { + return GLBackend::makeProgram(shader, bindings); + } + return false; +} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 632c5f96de..ecff65fd8d 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -92,8 +92,17 @@ public: void enqueueBatch(Batch& batch); + + protected: + // This function can only be called by "static Shader::makeProgram()" + // makeProgramShader(...) 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. + // If the shader passed is not a program, nothing happens. + static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); + + friend class Shader; }; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 73c3c92c0a..8a754bb564 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -122,24 +122,10 @@ enum Semantic { SBGRA, UNIFORM, - - TEXTURE, - BUFFER, - - SAMPLER_1D, - SAMPLER_2D, - SAMPLER_2D_MS, - SAMPLER_3D, - SAMPLER_CUBE, - SAMPLER_1D_ARRAY, - SAMPLER_2D_ARRAY, - SAMPLER_2D_MS_ARRAY, - SAMPLER_3D_ARRAY, - SAMPLER_CUBE_ARRAY, - SAMPLER_2D_SHADOW, - SAMPLER_2D_SHADOW_ARRAY, - SAMPLER_CUBE_SHADOW, - SAMPLER_CUBE_SHADOW_ARRAY, + UNIFORM_BUFFER, + SAMPLER, + SAMPLER_MULTISAMPLE, + SAMPLER_SHADOW, NUM_SEMANTICS, diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 535d7a3e1f..974bb6fb8b 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -33,7 +33,7 @@ public: static void checkGLError(); - static bool makeShader(Shader& shader); + static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); class GLBuffer : public GPUObject { diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 724f1ad019..5136461f5c 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -28,7 +28,6 @@ GLBackend::GLShader::~GLShader() { } } - void makeBindings(GLBackend::GLShader* shader) { if(!shader || !shader->_program) { return; @@ -36,7 +35,7 @@ void makeBindings(GLBackend::GLShader* shader) { GLuint glprogram = shader->_program; GLint loc = -1; - //Check for gpu specific attribute bindings + //Check for gpu specific attribute slotBindings loc = glGetAttribLocation(glprogram, "position"); if (loc >= 0) { glBindAttribLocation(glprogram, gpu::Stream::POSITION, "position"); @@ -77,7 +76,18 @@ void makeBindings(GLBackend::GLShader* shader) { glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "clusterWeights"); } - //Check for gpu specific uniform bindings + // Link again to take into account the assigned attrib location + glLinkProgram(glprogram); + + GLint linked = 0; + glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); + if (!linked) { + qDebug() << "GLShader::makeBindings - failed to link after assigning slotBindings?"; + } + + // now assign the ubo binding, then DON't relink! + + //Check for gpu specific uniform slotBindings loc = glGetUniformBlockIndex(glprogram, "transformObjectBuffer"); if (loc >= 0) { glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); @@ -90,14 +100,6 @@ void makeBindings(GLBackend::GLShader* shader) { shader->_transformCameraSlot = gpu::TRANSFORM_OBJECT_SLOT; } - // Link again - glLinkProgram(glprogram); - - GLint linked = 0; - glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); - if (!linked) { - qDebug() << "GLShader::makeBindings - failed to link after assigning bindings?"; - } } GLBackend::GLShader* compileShader(const Shader& shader) { @@ -344,37 +346,45 @@ GLuint GLBackend::getShaderID(const ShaderPointer& shader) { } } -Element getFormatFromGLUniform(GLenum gltype) { +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 Element(SCALAR, gpu::FLOAT, UNIFORM); - case GL_FLOAT_VEC2: return Element(VEC2, gpu::FLOAT, UNIFORM); - case GL_FLOAT_VEC3: return Element(VEC3, gpu::FLOAT, UNIFORM); - case GL_FLOAT_VEC4: return Element(VEC4, gpu::FLOAT, UNIFORM); + 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 Element(SCALAR, gpu::FLOAT, UNIFORM); - case GL_DOUBLE_VEC2: return Element(VEC2, gpu::FLOAT, UNIFORM); - case GL_DOUBLE_VEC3: return Element(VEC3, gpu::FLOAT, UNIFORM); - case GL_DOUBLE_VEC4: return Element(VEC4, gpu::FLOAT, UNIFORM); + 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 Element(SCALAR, gpu::INT32, UNIFORM); - case GL_INT_VEC2: return Element(VEC2, gpu::INT32, UNIFORM); - case GL_INT_VEC3: return Element(VEC3, gpu::INT32, UNIFORM); - case GL_INT_VEC4: return Element(VEC4, gpu::INT32, UNIFORM); + 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 Element(SCALAR, gpu::UINT32, UNIFORM); - case GL_UNSIGNED_INT_VEC2: return Element(VEC2, gpu::UINT32, UNIFORM); - case GL_UNSIGNED_INT_VEC3: return Element(VEC3, gpu::UINT32, UNIFORM); - case GL_UNSIGNED_INT_VEC4: return Element(VEC4, gpu::UINT32, UNIFORM); + case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER); + 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); - case GL_BOOL: return Element(SCALAR, gpu::BOOL, UNIFORM); - case GL_BOOL_VEC2: return Element(VEC2, gpu::BOOL, UNIFORM); - case GL_BOOL_VEC3: return Element(VEC3, gpu::BOOL, UNIFORM); - case GL_BOOL_VEC4: return Element(VEC4, gpu::BOOL, UNIFORM); + 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 Element(gpu::MAT2, gpu::FLOAT, UNIFORM); - case GL_FLOAT_MAT3: return Element(MAT3, gpu::FLOAT, UNIFORM); - case GL_FLOAT_MAT4: return Element(MAT4, gpu::FLOAT, UNIFORM); + 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}, @@ -393,20 +403,20 @@ Element getFormatFromGLUniform(GLenum gltype) { {GL_DOUBLE_MAT4x3 dmat4x3}, */ - case GL_SAMPLER_1D: return Element(SCALAR, gpu::FLOAT, SAMPLER_1D); - case GL_SAMPLER_2D: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D); - case GL_SAMPLER_2D_MULTISAMPLE: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_MS); - case GL_SAMPLER_3D: return Element(SCALAR, gpu::FLOAT, SAMPLER_3D); - case GL_SAMPLER_CUBE: return Element(SCALAR, gpu::FLOAT, SAMPLER_CUBE); + 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_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), 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); - case GL_SAMPLER_1D_ARRAY: return Element(SCALAR, gpu::FLOAT, SAMPLER_1D_ARRAY); - case GL_SAMPLER_2D_ARRAY: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_ARRAY); - case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_MS_ARRAY); + 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); - case GL_SAMPLER_2D_SHADOW: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_SHADOW); - case GL_SAMPLER_CUBE_SHADOW: return Element(SCALAR, gpu::FLOAT, SAMPLER_CUBE_SHADOW); + case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D); + case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE); - case GL_SAMPLER_2D_ARRAY_SHADOW: return Element(SCALAR, gpu::FLOAT, SAMPLER_2D_SHADOW_ARRAY); + case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY); // {GL_SAMPLER_1D_SHADOW sampler1DShadow}, // {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow}, @@ -415,28 +425,28 @@ Element getFormatFromGLUniform(GLenum gltype) { // {GL_SAMPLER_2D_RECT sampler2DRect}, // {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow}, - case GL_INT_SAMPLER_1D: return Element(SCALAR, gpu::INT32, SAMPLER_1D); - case GL_INT_SAMPLER_2D: return Element(SCALAR, gpu::INT32, SAMPLER_2D); - case GL_INT_SAMPLER_2D_MULTISAMPLE: return Element(SCALAR, gpu::INT32, SAMPLER_2D_MS); - case GL_INT_SAMPLER_3D: return Element(SCALAR, gpu::INT32, SAMPLER_3D); - case GL_INT_SAMPLER_CUBE: return Element(SCALAR, gpu::INT32, SAMPLER_CUBE); + 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 Element(SCALAR, gpu::INT32, SAMPLER_1D_ARRAY); - case GL_INT_SAMPLER_2D_ARRAY: return Element(SCALAR, gpu::INT32, SAMPLER_2D_ARRAY); - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return Element(SCALAR, gpu::INT32, SAMPLER_2D_MS_ARRAY); + 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 Element(SCALAR, gpu::UINT32, SAMPLER_1D); - case GL_UNSIGNED_INT_SAMPLER_2D: return Element(SCALAR, gpu::UINT32, SAMPLER_2D); - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return Element(SCALAR, gpu::UINT32, SAMPLER_2D_MS); - case GL_UNSIGNED_INT_SAMPLER_3D: return Element(SCALAR, gpu::UINT32, SAMPLER_3D); - case GL_UNSIGNED_INT_SAMPLER_CUBE: return Element(SCALAR, gpu::UINT32, SAMPLER_CUBE); + 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 Element(SCALAR, gpu::UINT32, SAMPLER_1D_ARRAY); - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return Element(SCALAR, gpu::UINT32, SAMPLER_2D_ARRAY); - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return Element(SCALAR, gpu::UINT32, SAMPLER_2D_MS_ARRAY); + 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); // {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer}, // {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect}, @@ -475,13 +485,13 @@ Element getFormatFromGLUniform(GLenum gltype) { {GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint} */ default: - return Element(); + return ElementResource(Element(), Resource::BUFFER); } }; -int makeUniformSlots(GLuint glprogram, Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { +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); @@ -493,19 +503,56 @@ int makeUniformSlots(GLuint glprogram, Shader::SlotSet& uniforms, Shader::SlotSe 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; - auto element = getFormatFromGLUniform(type); - uniforms.insert(Shader::Slot(name, i, element)); + // 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) { + uniforms.insert(Shader::Slot(name, 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(name)); + if (requestedBinding != slotBindings.end()) { + if (binding != (*requestedBinding)._location) { + binding = (*requestedBinding)._location; + glUniform1i(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 makeUniformBlockSlots(GLuint glprogram, Shader::SlotSet& buffers) { - GLint buffersCount = 0; +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); + for (int i = 0; i < buffersCount; i++) { const GLint NAME_LENGTH = 256; GLchar name[NAME_LENGTH]; @@ -513,19 +560,46 @@ int makeUniformBlockSlots(GLuint glprogram, Shader::SlotSet& buffers) { GLint size = 0; GLenum type = 0; GLint binding = -1; - glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding); - glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size); + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length); glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, name); + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding); + glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size); + + GLuint blockIndex = glGetUniformBlockIndex(glprogram, name); - Element element(SCALAR, gpu::FLOAT, BUFFER); - buffers.insert(Shader::Slot(name, binding, element)); + // CHeck if there is a requested binding for this block + auto requestedBinding = slotBindings.find(std::string(name)); + if (requestedBinding != slotBindings.end()) { + // If yes force it + if (binding != (*requestedBinding)._location) { + binding = (*requestedBinding)._location; + glUniformBlockBinding(glprogram, blockIndex, binding); + } + } else if (binding == 0) { + // 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()) { + binding = slotIt - uniformBufferSlotMap.begin(); + glUniformBlockBinding(glprogram, blockIndex, binding); + } else { + // This should neve happen, an active ubo cannot find an available slot among the max available?! + binding = -1; + } + } + // If binding is valid record it + if (binding >= 0) { + uniformBufferSlotMap[binding] = blockIndex; + } + + Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER); + buffers.insert(Shader::Slot(name, binding, element, Resource::BUFFER)); } return buffersCount; } -int makeInputSlots(GLuint glprogram, Shader::SlotSet& inputs) { +int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) { GLint inputsCount = 0; glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount); @@ -538,14 +612,16 @@ int makeInputSlots(GLuint glprogram, Shader::SlotSet& inputs) { GLenum type = 0; glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name); - auto element = getFormatFromGLUniform(type); - inputs.insert(Shader::Slot(name, i, element)); + GLint binding = glGetAttribLocation(glprogram, name); + + auto elementResource = getFormatFromGLUniform(type); + inputs.insert(Shader::Slot(name, binding, elementResource._element, -1)); } return inputsCount; } -int makeOutputSlots(GLuint glprogram, Shader::SlotSet& outputs) { +int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) { /* GLint outputsCount = 0; glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount); @@ -565,28 +641,28 @@ int makeOutputSlots(GLuint glprogram, Shader::SlotSet& outputs) { return 0; //inputsCount; } -bool GLBackend::makeShader(Shader& shader) { +bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) { - // First make sure the SHader has been compiled + // First make sure the Shader has been compiled GLShader* object = GLBackend::syncGPUObject(shader); if (!object) { return false; } if (object->_program) { + Shader::SlotSet buffers; + makeUniformBlockSlots(object->_program, slotBindings, buffers); + Shader::SlotSet uniforms; Shader::SlotSet textures; Shader::SlotSet samplers; - makeUniformSlots(object->_program, uniforms, textures, samplers); - - Shader::SlotSet buffers; - makeUniformBlockSlots(object->_program, buffers); + makeUniformSlots(object->_program, slotBindings, uniforms, textures, samplers); Shader::SlotSet inputs; - makeInputSlots(object->_program, inputs); + makeInputSlots(object->_program, slotBindings, inputs); Shader::SlotSet outputs; - makeOutputSlots(object->_program, outputs); + makeOutputSlots(object->_program, slotBindings, outputs); shader.defineSlots(uniforms, buffers, textures, samplers, inputs, outputs); diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 225e3fd927..3da25ae78f 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -38,6 +38,18 @@ public: // The size in bytes of data stored in the resource virtual Size getSize() const = 0; + enum Type { + BUFFER = 0, + TEXTURE_1D, + TEXTURE_2D, + TEXTURE_3D, + TEXTURE_CUBE, + TEXTURE_1D_ARRAY, + TEXTURE_2D_ARRAY, + TEXTURE_3D_ARRAY, + TEXTURE_CUBE_ARRAY, + }; + protected: Resource() {} diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp index 164778b0e2..59838fae9c 100755 --- a/libraries/gpu/src/gpu/Shader.cpp +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -13,6 +13,8 @@ #include #include +#include "Context.h" + using namespace gpu; Shader::Shader(Type type, const Source& source): @@ -62,3 +64,10 @@ void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const _inputs = inputs; _outputs = outputs; } + +bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings) { + if (shader.isProgram()) { + return Context::makeProgram(shader, bindings); + } + return false; +} diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 3a374d91c8..9a5bec313b 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -45,18 +45,28 @@ public: public: std::string _name; - uint16 _location; + uint32 _location; Element _element; + uint16 _resourceType; - Slot(const std::string& name, uint16 location, const Element& element) : _name(name), _location(location), _element(element) {} + Slot(const std::string& name, uint16 location, const Element& element, uint16 resourceType = Resource::BUFFER) : + _name(name), _location(location), _element(element), _resourceType(resourceType) {} - - class Less { - public: - bool operator() (const Slot& x, const Slot& y) const { return x._name < y._name; } - }; }; - typedef std::set SlotSet; + + class Binding { + public: + std::string _name; + uint32 _location; + Binding(const std::string&& name, uint32 loc = 0) : _name(name), _location(loc) {} + }; + + template class Less { + public: + bool operator() (const T& x, const T& y) const { return x._name < y._name; } + }; + typedef std::set> SlotSet; + typedef std::set> BindingSet; enum Type { @@ -89,6 +99,7 @@ public: const SlotSet& getBuffers() const { return _buffers; } const SlotSet& getTextures() const { return _textures; } const SlotSet& getSamplers() const { return _samplers; } + const SlotSet& getInputs() const { return _inputs; } const SlotSet& getOutputs() const { return _outputs; } @@ -96,9 +107,23 @@ public: // This call is intendend to build the list of exposed slots in order // to correctly bind resource to the shader. // These can be build "manually" from knowledge of the atual shader code - // or automatically by calling "Context::makeShader()", this is the preferred way + // 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); + // 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. + // If the shader passed is not a program, nothing happens. + // + // It is possible to provide a set of slot bindings (from the name of the slot to a unit number) allowing + // to make sure slots with the same semantics can be always bound on the same location from shader to shader. + // For example, the "diffuseMap" can always be bound to texture unit #1 for different shaders by specifying a Binding("diffuseMap", 1) + // + // As of now (03/2015), the call to makeProgram is in fact calling gpu::Context::makeProgram and does rely + // on the underneath gpu::Context::Backend available. Since we only support glsl, this means that it relies + // on a glContext and the driver to compile the glsl shader. + // Hoppefully in a few years the shader compilation will be completely abstracted in a separate shader compiler library + // independant of the graphics api in use underneath (looking at you opengl & vulkan). + static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet()); protected: Shader(Type type, const Source& source); diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 1ebb2e6ece..d470d841bc 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -15,6 +15,7 @@ #include "SkyFromAtmosphere_vert.h" #include "SkyFromAtmosphere_frag.h" +#include "gpu/Context.h" #include "gpu/GLBackend.h" using namespace model; @@ -221,7 +222,7 @@ void SunSkyStage::updateGraphicsObject() const { static int firstTime = 0; if (firstTime == 0) { firstTime++; - gpu::GLBackend::makeShader(*_skyShader); + gpu::Shader::makeProgram(*_skyShader); } } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 50ae3fd882..8f8f19c72a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -299,18 +299,93 @@ void Model::initJointTransforms() { void Model::init() { if (!_program.isLinked()) { +/* + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); + slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3)); + + // Vertex shaders + auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))); + auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert))); + auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert))); + auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert))); + auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert))); + auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert))); + auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert))); + auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert))); + + // Pixel shaders + auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag))); + auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag))); + auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag))); + auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag))); + auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag))); + auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag))); + auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag))); + auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag))); + auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag))); + auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag))); + + + bool makeResult = false; + + // Programs + auto program = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelPixel)); + makeResult = gpu::Shader::makeProgram(*program, slotBindings); + + auto normalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalMapPixel)); + makeResult = gpu::Shader::makeProgram(*normalMapProgram, slotBindings); + + auto specularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*specularMapProgram, slotBindings); + + auto normalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*normalSpecularMapProgram, slotBindings); + + auto translucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelTranslucentPixel)); + makeResult = gpu::Shader::makeProgram(*translucentProgram, slotBindings); + + auto shadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelShadowVertex, modelShadowPixel)); + makeResult = gpu::Shader::makeProgram(*shadowProgram, slotBindings); + + auto lightmapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapPixel)); + makeResult = gpu::Shader::makeProgram(*lightmapProgram, slotBindings); + + auto lightmapNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalMapPixel)); + makeResult = gpu::Shader::makeProgram(*lightmapNormalMapProgram, slotBindings); + + auto lightmapSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*lightmapSpecularMapProgram, slotBindings); + + auto lightmapNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*lightmapNormalSpecularMapProgram, slotBindings); + + auto skinProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelPixel)); + makeResult = gpu::Shader::makeProgram(*skinProgram, slotBindings); + + auto skinNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalMapPixel)); + makeResult = gpu::Shader::makeProgram(*skinNormalMapProgram, slotBindings); + + auto skinSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*skinSpecularMapProgram, slotBindings); + + auto skinNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*skinNormalSpecularMapProgram, slotBindings); + + auto skinShadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelShadowVertex, modelShadowPixel)); + makeResult = gpu::Shader::makeProgram(*skinShadowProgram, slotBindings); + + auto skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel)); + makeResult = gpu::Shader::makeProgram(*skinTranslucentProgram, slotBindings); +*/ + _program.addShaderFromSourceCode(QGLShader::Vertex, model_vert); _program.addShaderFromSourceCode(QGLShader::Fragment, model_frag); initProgram(_program, _locations); - - auto defaultShader = gpu::ShaderPointer( - gpu::Shader::createProgram( - gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))), - gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag))) - ) - ); - gpu::GLBackend::makeShader(*defaultShader); _normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); _normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 303fa770ad..453d721962 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -309,6 +309,7 @@ private: int _blendNumber; int _appliedBlendNumber; + static ProgramObject _program; static ProgramObject _normalMapProgram; static ProgramObject _specularMapProgram;